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