second stage loader loading semi-works
[bootcensus] / src / boot / boot.s
1         .code16
2         .section .boot,"a"
3
4         cli
5         cld
6         # move stack to just below the code
7         xor %ax, %ax
8         mov %ax, %ss
9         mov $0x7c00, %sp
10         # use the code segment for data access
11         mov %cs, %ax
12         mov %ax, %ds
13         mov %ax, %es
14
15         mov %dl, drive_number
16
17         call clearscr
18
19         mov $_boot2_size, %eax
20         call print_num
21
22         # load the second stage boot loader and jump to it
23         mov $_boot2_size, %eax
24         mov %eax, %ebx
25         shr $9, %eax
26         and $0x1ff, %ebx
27         jz 0f
28         inc %ax
29 0:      pushw %ax
30         pushw $1
31         # set es to the start of the destination buffer to allow reading in
32         # full 64k chunks
33         mov $boot2_addr, %bx
34         shr $4, %bx
35         mov %bx, %es
36         xor %bx, %bx
37         call read_sectors
38         jmp boot2_addr
39
40         cli
41         hlt
42
43         .set SECT_PER_TRACK, 18
44
45         .set ARG_NSECT, 6
46         .set ARG_SIDX, 4
47
48 # read_sectors(first, num)
49 read_sectors:
50         push %bp
51         mov %sp, %bp
52
53         mov ARG_SIDX(%bp), %ax
54         xor %cx, %cx
55
56         jmp 1f
57 0:      push %ax
58         call read_sector
59         pop %ax
60         inc %ax
61         inc %cx
62 1:      cmp ARG_NSECT(%bp), %cx
63         jnz 0b
64
65         pop %bp
66         ret
67
68         .set VAR_ATTEMPTS, -2
69
70 # read_sector(sidx)
71 read_sector:
72         push %bp
73         mov %sp, %bp
74         sub $2, %sp
75         push %cx
76         push %dx
77
78         movw $3, VAR_ATTEMPTS(%bp)
79
80 .Lread_try:
81         # calculate the track (sidx / sectors_per_track)
82         mov 4(%bp), %ax
83         xor %dx, %dx
84         mov $SECT_PER_TRACK, %cx
85         div %cx
86         mov %ax, %cx
87         # save the remainder in ax
88         mov %dx, %ax
89         # head in dh
90         mov %cl, %dh
91         and $1, %dh
92         # cylinder (track/2) in ch [0-7] and cl[6,7]<-[8,9]
93         rol $7, %cx
94         ror $2, %cl
95         and $0xc0, %cl
96         # sector num cl[0-5] is sidx % sectors_per_track (saved in ax)
97         inc %al
98         or %al, %cl 
99         # ah = 2 (read), al = 1 sectors
100         mov $0x0201, %ax
101         movb drive_number, %dl
102         int $0x13
103         jnc .Lread_ok
104
105         # abort after 3 attempts
106         decw VAR_ATTEMPTS(%bp)
107         jz .Lread_fail
108
109         # error detected, reset controller and retry
110         xor %ah, %ah
111         int $0x13
112         jmp .Lread_try
113
114 .Lread_fail:
115         mov 4(%bp), %ax
116         jmp abort_read
117
118 .Lread_ok:
119         # increment es:bx accordingly (advance es if bx overflows)
120         add $512, %bx
121         jno 0f
122         mov %es, %ax
123         add $4096, %ax
124         mov %ax, %es
125
126 0:      pop %dx
127         pop %cx
128         add $2, %sp
129         pop %bp
130         ret
131
132 str_read_error: .asciz "Failed to read sector: "
133
134 abort_read:
135         push %ax
136         mov $str_read_error, %si
137         call print_str
138
139         xor %eax, %eax
140         pop %ax
141         call print_num
142
143         cli
144         hlt
145
146 clearscr:
147         push %es
148         pushw $0xb800
149         pop %es
150         xor %eax, %eax
151         xor %di, %di
152         movl $500, %ecx
153         rep stosl
154         pop %es
155         ret
156
157 cursor_x: .byte 0
158
159 # expects string pointer in ds:si
160 print_str:
161         push %es
162         pushw $0xb800
163         pop %es
164         xor %di, %di
165         movb $0, cursor_x
166
167 0:      mov (%si), %al
168         mov %al, %es:(%di)
169         movb $7, %es:1(%di)
170         inc %si
171         add $2, %di
172         incb cursor_x
173         cmp $0, %al
174         jnz 0b
175
176         pop %es
177         ret
178
179 # expects number in eax
180 print_num:
181         # save es
182         push %es
183
184         xor %cx, %cx
185         movw $numbuf, %si
186         mov $10, %ebx
187
188 0:      xor %edx, %edx
189         div %ebx
190         add $48, %dl
191         mov %dl, (%si)
192         inc %si
193         inc %cx
194         cmp $0, %eax
195         jnz 0b
196
197         # print the backwards string
198         pushw $0xb800
199         pop %es
200         movb cursor_x, %al
201         xor %ah, %ah
202         shl $1, %ax
203         mov %ax, %di
204
205 0:      dec %si
206         mov (%si), %al
207         movb %al, %es:(%di)
208         inc %di
209         mov $7, %al
210         movb %al, %es:(%di)
211         inc %di
212         dec %cx
213         jnz 0b
214
215         # restore es
216         pop %es
217         ret
218
219 drive_number: .byte 0
220 numbuf: .space 10
221         .org 510
222         .byte 0x55
223         .byte 0xaa
224
225 boot2_addr: