summaryrefslogtreecommitdiff
path: root/src/bootloader/bios_disk.asm
blob: 5992920863612c714a6af432d96eb5449ca9b866 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
bios_disk:
.init:
mov [boot_device], dl
mov ah, 0x8
int 0x13
;TODO defaults

jc .init_use_defaults

mov [max_head], dh
mov [max_sector], cl
and WORD [max_sector], 0x3f

mov [max_cylinder], cl
shl WORD [max_cylinder], 8
or [max_cylinder], ch
and WORD [max_cylinder], 0x3ff

ret

.init_use_defaults:
mov BYTE [max_sector], 63
mov WORD [max_head], 15
mov BYTE [max_cylinder], 1023

ret

;	Return:
;	CH = low eight bits of maximum cylinder number
;	CL = maximum sector number (bits 5-0), high two bits of maximum cylinder number (bits 7-6)
;	DH = maximum head number

.load_sectors_v2:
;AH = 02h
;AL = number of sectors to read (must be nonzero)
;CH = low eight bits of cylinder number
;CL = sector number 1-63 (bits 0-5) high two bits of cylinder (bits 6-7)
;DH = head number
;DL = drive number (bit 7 set for hard disk)
;ES:BX -> data buffer

; I don't understand i8086. The base pointer needs to be above the stack pointer,
; yet the stack grows down,
; and we can't address using sp, or by subtraction.
; it's like it's forcing us to use the whole push/pop thing.

sub sp, 16
mov bp, sp

; sector:       rbp + 0 (uint8_t)
; head:         rbp + 1 (uint8_t)
; cylinder:     rbp + 2 (uint16_t)
; sector_cnt:   rbp + 4 (uint16_t)
; destination:  rbp + 6 (uint32_t)

; set up variables ______________________________________________

;destination to stack
mov [bp + 6], edi

; find init chs ________________________________________________

; divide sector_start / max_sectors
; TODO test for overflow
mov ax, si
shr esi, 16
mov dx, si

;find sector
div DWORD [max_sector]
inc dx
mov [bp], edx ; remainder is sector variable

;find head and cylinder
mov dx, 0
div DWORD [max_head]
mov [bp + 1], dx ; head
mov [bp + 2], ax ; cylinder

.sector_for_loop:
mov [bp + 4], cx

; do bios call ___________________________________________________
mov ah, 2
mov al, 1
; sets up ch and cl
mov cx, [bp + 2] 
xchg ch, cl
shl cl, 6
or cl, [bp]

mov dh, [bp + 1]
mov dl, [boot_device]
mov bx, 0x500 ; where we store the sector temporarily

int 0x13
jc .read_failed

; mempcy __________________________________________________________

; we move it to the place at edi, which I don't think changes 
mov esi, 0x500
mov ecx, 512
a32 rep movsb

; recalc chs ______________________________________________________

; need to test for more overflows I think
inc WORD [bp]
mov al, [bp]; increase the sector we're on
cmp al, [max_sector]
jbe .continue_loop
mov WORD [bp], 1

inc WORD [bp + 1]
mov al, [bp + 1]
cmp al, [max_head]
jbe .continue_loop
mov WORD [bp + 1], 0
inc DWORD [bp + 2]

; loopin back ____________________________________________________
.continue_loop:
mov cx, [bp + 4]


loop .sector_for_loop
add bp, 16
mov sp, bp


ret




.read_failed:
mov bx, .loadsectors_error
call bios_print
cli
hlt

.loadsectors_error: db "Error loading required sector!", 0

boot_device: db 0
max_sector:  db 0
max_cylinder: dw 0
max_head: db 0