693bba3f7a60472aaa4d7c2827caed8552fff5e4
[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         mov byte [read_retries], 3
91 .read_try:
92         push cx         ; save linear sector number
93         ; calculate track (sidx / sectors_per_track)
94         mov ax, cx
95         xor dx, dx
96         mov cx, [sect_per_track]
97         div cx
98         mov cx, ax
99         ; save the remainder
100         push dx
101         ; head in dh
102         mov dh, cl
103         and dh, [heads_mask]
104         ; cylinder (track/heads) in ch [0-7] and cl[6,7]<-[8,9]
105         push dx
106         xor dx, dx
107         mov word cx, [num_heads]
108         div cx
109         pop dx  ; restore sidx % sectors_per_track to dx
110         mov cx, ax
111         rol cx, 8
112         ror cl, 2
113         and cl, 0xc0
114         ; sector num cl[0-5] is sidx % sectors_per_track + 1
115         pop ax
116         inc al
117         or cl, al
118
119         ; ah = 2 (read), al = 1 sectors
120         mov ax, 0201h
121         mov byte dl, [DRIVENO_ADDR]
122         int 13h
123         jnc .success
124
125         dec word [read_retries]
126         jz .failed
127
128         ; error detected, reset controller and retry
129         xor ah, ah
130         int 13h
131         pop cx  ; we push that at the top of the loop
132         jmp .read_try
133
134 .failed:
135         jmp abort_read
136 .success:
137         mov al, '.'
138         call putchar
139
140         pop cx
141         ret
142
143 abort_read:
144         mov si, rderr_str
145         call putstr
146         cli
147         hlt
148
149 putstr:
150         mov al, [si]
151         inc si
152         cmp al, 0
153         jz .done
154         call putchar
155         jmp putstr
156 .done:  ret
157
158 putchar:
159         mov ah, 0eh
160         mov bl, 7
161         int 10h
162         ret
163
164
165         global sect_per_track
166 sect_per_track: dw 18
167         global num_cylinders
168 num_cylinders:  dw 80
169         global num_heads
170 num_heads:      dw 2
171         global heads_mask
172 heads_mask:     db 1
173
174 read_retries: db 0
175
176 binsize_sect: dw 0
177
178 rderr_str: db 'read error',13,10,0
179 newline_str: db 13,10,0
180
181 bootend:
182         times 510-($-$$) db 0
183         dw 0xaa55