interrupts half-done
[ld45_start_nothing] / src / boot / boot.asm
1 ; vi:filetype=nasm ts=8 sts=8 sw=8:
2         bits 16
3         section .boot
4
5 STACKTOP equ 7b00h
6 DRIVENO_ADDR equ 7bf0h
7 LOADADDR equ 7e00h
8
9         extern _boot2_size
10
11 start:
12         cli
13         ; setup stack and the rest of the segment registers
14         xor ax, ax
15         mov ss, ax
16         mov sp, STACKTOP
17         mov ds, ax
18         mov es, ax
19         mov fs, ax
20         mov gs, ax
21
22         ; dl: drive number, save it
23         mov [DRIVENO_ADDR], dl
24         call get_drive_chs
25
26         mov si, newline_str
27         call putstr
28
29         ; load the second stage boot loader and jump there
30         mov bx, LOADADDR  ; es:bx <- destination
31         mov cx, _boot2_size
32         add cx, 511
33         shr cx, 9       ; cx <- binsize in sectors
34         mov [binsize_sect], cx
35
36         xor cx, cx
37 .loadsect_loop:
38         inc cx          ; start from sector 1 (after boot sector)
39         call read_sector
40
41         ; inc dest addr by 512
42         add bx, 512
43         jnz .skipsegbump
44         ; offset rolled over, bump es to the next 64k
45         mov ax, es
46         add ax, 1000h
47         mov es, ax
48 .skipsegbump:
49
50         cmp cx, [binsize_sect]
51         jnz .loadsect_loop
52
53         ; done loading
54         mov si, newline_str
55         call putstr
56         jmp LOADADDR
57
58
59 get_drive_chs:
60         push es
61         mov ah, 8
62         mov dl, [DRIVENO_ADDR]
63         xor di, di
64         int 13h
65         pop es
66         jnc .success
67         ret
68 .success:
69         xor ax, ax
70         mov al, ch      ; low 8 bits of max cylinder
71         mov ah, cl      ; bits 6,7 high bits of max cylinder
72         rol ah, 2
73         and ax, 3ffh
74         inc ax          ; inc to make it number of cylinders
75         mov [num_cylinders], ax
76
77         and cx, 3fh     ; bits 0-5: sect_per_track
78         mov [sect_per_track], cx
79
80         ; dh: max head number
81         shr dx, 8
82         mov [heads_mask], dl
83         inc dx
84         mov [num_heads], dx
85         ret
86
87         ; read_sector expects a linear sector number in cx, converts it to CHS
88         ; and loads the sector at es:bx
89 read_sector:
90         push bx         ; save dest offset
91         mov byte [read_retries], 3
92 .read_try:
93         push cx         ; save linear sector number
94         ; calculate track (sidx / sectors_per_track)
95         mov ax, cx
96         xor dx, dx
97         mov cx, [sect_per_track]
98         div cx
99         mov cx, ax
100         ; save the remainder
101         push dx
102         ; head in dh
103         mov dh, cl
104         and dh, [heads_mask]
105         ; cylinder (track/heads) in ch [0-7] and cl[6,7]<-[8,9]
106         push dx
107         xor dx, dx
108         mov word cx, [num_heads]
109         div cx
110         pop dx  ; restore sidx % sectors_per_track to dx
111         mov cx, ax
112         rol cx, 8
113         ror cl, 2
114         and cl, 0xc0
115         ; sector num cl[0-5] is sidx % sectors_per_track + 1
116         pop ax
117         inc al
118         or cl, al
119
120         ; ah = 2 (read), al = 1 sectors
121         mov ax, 0201h
122         mov byte dl, [DRIVENO_ADDR]
123         int 13h
124         jnc .success
125
126         dec word [read_retries]
127         jz .failed
128
129         ; error detected, reset controller and retry
130         xor ah, ah
131         int 13h
132         pop cx  ; we push that at the top of the loop
133         jmp .read_try
134
135 .failed:
136         jmp abort_read
137 .success:
138         mov al, '.'
139         call putchar
140
141         pop cx
142         pop bx
143         ret
144
145 abort_read:
146         mov si, rderr_str
147         call putstr
148         cli
149         hlt
150
151 putstr:
152         mov al, [si]
153         inc si
154         cmp al, 0
155         jz .done
156         call putchar
157         jmp putstr
158 .done:  ret
159
160 putchar:
161         mov ah, 0eh
162         mov bl, 7
163         int 10h
164         ret
165
166
167         global sect_per_track
168 sect_per_track: dw 18
169         global num_cylinders
170 num_cylinders:  dw 80
171         global num_heads
172 num_heads:      dw 2
173         global heads_mask
174 heads_mask:     db 1
175
176 read_retries: db 0
177
178 binsize_sect: dw 0
179
180 rderr_str: db 'read error',13,10,0
181 newline_str: db 13,10,0
182
183 bootend:
184         times 510-($-$$) db 0
185         dw 0xaa55