1 !
2 ! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
3 ! 0x3000 is 0x30000 bytes = 196kB, more than enough for current
4 ! versions of linux
5 !
6 #include <linux/config.h>
7 SYSSIZE = DEF_SYSSIZE
8 !
9 ! bootsect.s Copyright (C) 1991, 1992 Linus Torvalds
10 ! modified by Drew Eckhardt
11 ! modified by Bruce Evans (bde)
12 !
13 ! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
14 ! itself out of the way to address 0x90000, and jumps there.
15 !
16 ! bde - should not jump blindly, there may be systems with only 512K low
17 ! memory. Use int 0x12 to get the top of memory, etc.
18 !
19 ! It then loads 'setup' directly after itself (0x90200), and the system
20 ! at 0x10000, using BIOS interrupts.
21 !
22 ! NOTE! currently system is at most 8*65536 bytes long. This should be no
23 ! problem, even in the future. I want to keep it simple. This 512 kB
24 ! kernel size should be enough, especially as this doesn't contain the
25 ! buffer cache as in minix
26 !
27 ! The loader has been made as simple as possible, and continuos
28 ! read errors will result in a unbreakable loop. Reboot by hand. It
29 ! loads pretty fast by getting whole tracks at a time whenever possible.
30
31 .text
32
33 SETUPSECS = 4 ! nr of setup-sectors
34 BOOTSEG = 0x07C0 ! original address of boot-sector
35 INITSEG = DEF_INITSEG ! we move boot here - out of the way
36 SETUPSEG = DEF_SETUPSEG ! setup starts here
37 SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536).
38 ENDSEG = SYSSEG + SYSSIZE ! where to stop loading
39
40 ! ROOT_DEV & SWAP_DEV are now written by "build".
41 ROOT_DEV = 0
42 SWAP_DEV = 0
43
44 ! ld86 requires an entry symbol. This may as well be the usual one.
45 .globl _main
46 _main:
47 #if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */ 48 int 3
49 #endif 50 mov ax,#BOOTSEG
51 mov ds,ax
52 mov ax,#INITSEG
53 mov es,ax
54 mov cx,#256
55 sub si,si
56 sub di,di
57 cld
58 rep
59 movsw
60 jmpi go,INITSEG
61
62 go: mov ax,cs
63 mov dx,#0x4000-12 ! 0x4000 is arbitrary value >= length of
64 ! bootsect + length of setup + room for stack
65 ! 12 is disk parm size
66
67 ! bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We
68 ! wouldn't have to worry about this if we checked the top of memory. Also
69 ! my BIOS can be configured to put the wini drive tables in high memory
70 ! instead of in the vector table. The old stack might have clobbered the
71 ! drive table.
72
73 mov ds,ax
74 mov es,ax
75 push ax
76
77 mov ss,ax ! put stack at INITSEG:0x4000-12.
78 mov sp,dx
79 /* 80 * Many BIOS's default disk parameter tables will not 81 * recognize multi-sector reads beyond the maximum sector number 82 * specified in the default diskette parameter tables - this may 83 * mean 7 sectors in some cases. 84 * 85 * Since single sector reads are slow and out of the question, 86 * we must take care of this by creating new parameter tables 87 * (for the first disk) in RAM. We will set the maximum sector 88 * count to 18 - the most we will encounter on an HD 1.44. 89 * 90 * High doesn't hurt. Low does. 91 * 92 * Segments are as follows: ds=es=ss=cs - INITSEG, 93 * fs = 0, gs = parameter table segment 94 */ 95
96 push #0
97 pop fs
98 mov bx,#0x78 ! fs:bx is parameter table address
99 seg fs
100 lgs si,(bx) ! gs:si is source
101
102 mov di,dx ! es:di is destination
103 mov cx,#6 ! copy 12 bytes
104 cld
105
106 rep
107 seg gs
108 movsw
109
110 mov di,dx
111 movb 4(di),*18 ! patch sector count
112
113 seg fs
114 mov (bx),di
115 seg fs
116 mov 2(bx),es
117
118 pop ax
119 mov fs,ax
120 mov gs,ax
121
122 xor ah,ah ! reset FDC
123 xor dl,dl
124 int 0x13
125
126 ! load the setup-sectors directly after the bootblock.
127 ! Note that 'es' is already set up.
128
129 load_setup:
130 xor dx, dx ! drive 0, head 0
131 mov cx,#0x0002 ! sector 2, track 0
132 mov bx,#0x0200 ! address = 512, in INITSEG
133 mov ax,#0x0200+SETUPSECS ! service 2, nr of sectors
134 ! (assume all on head 0, track 0)
135 int 0x13 ! read it
136 jnc ok_load_setup ! ok - continue
137
138 push ax ! dump error code
139 call print_nl
140 mov bp, sp
141 call print_hex
142 pop ax
143
144 xor dl, dl ! reset FDC
145 xor ah, ah
146 int 0x13
147 jmp load_setup
148
149 ok_load_setup:
150
151 ! Get disk drive parameters, specifically nr of sectors/track
152
153 #if 0
154
155 ! bde - the Phoenix BIOS manual says function 0x08 only works for fixed
156 ! disks. It doesn't work for one of my BIOS's (1987 Award). It was
157 ! fatal not to check the error code.
158
159 xor dl,dl
160 mov ah,#0x08 ! AH=8 is get drive parameters
161 int 0x13
162 xor ch,ch
163 #else 164
165 ! It seems that there is no BIOS call to get the number of sectors. Guess
166 ! 18 sectors if sector 18 can be read, 15 if sector 15 can be read.
167 ! Otherwise guess 9.
168
169 xor dx, dx ! drive 0, head 0
170 mov cx,#0x0012 ! sector 18, track 0
171 mov bx,#0x0200+SETUPSECS*0x200 ! address after setup (es = cs)
172 mov ax,#0x0201 ! service 2, 1 sector
173 int 0x13
174 jnc got_sectors
175 mov cl,#0x0f ! sector 15
176 mov ax,#0x0201 ! service 2, 1 sector
177 int 0x13
178 jnc got_sectors
179 mov cl,#0x09
180
181 #endif 182
183 got_sectors:
184 seg cs
185 mov sectors,cx
186 mov ax,#INITSEG
187 mov es,ax
188
189 ! Print some inane message
190
191 mov ah,#0x03 ! read cursor pos
192 xor bh,bh
193 int 0x10
194
195 mov cx,#9
196 mov bx,#0x0007 ! page 0, attribute 7 (normal)
197 mov bp,#msg1
198 mov ax,#0x1301 ! write string, move cursor
199 int 0x10
200
201 ! ok, we've written the message, now
202 ! we want to load the system (at 0x10000)
203
204 mov ax,#SYSSEG
205 mov es,ax ! segment of 0x010000
206 call read_it
207 call kill_motor
208 call print_nl
209
210 ! After that we check which root-device to use. If the device is
211 ! defined (!= 0), nothing is done and the given device is used.
212 ! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
213 ! on the number of sectors that the BIOS reports currently.
214
215 seg cs
216 mov ax,root_dev
217 or ax,ax
218 jne root_defined
219 seg cs
220 mov bx,sectors
221 mov ax,#0x0208 ! /dev/ps0 - 1.2Mb
222 cmp bx,#15
223 je root_defined
224 mov ax,#0x021c ! /dev/PS0 - 1.44Mb
225 cmp bx,#18
226 je root_defined
227 mov ax,#0x0200 ! /dev/fd0 - autodetect
228 root_defined:
229 seg cs
230 mov root_dev,ax
231
232 ! after that (everyting loaded), we jump to
233 ! the setup-routine loaded directly after
234 ! the bootblock:
235
236 jmpi 0,SETUPSEG
237
238 ! This routine loads the system at address 0x10000, making sure
239 ! no 64kB boundaries are crossed. We try to load it as fast as
240 ! possible, loading whole tracks whenever we can.
241 !
242 ! in: es - starting address segment (normally 0x1000)
243 !
244 sread: .word 1+SETUPSECS ! sectors read of current track
245 head: .word 0 ! current head
246 track: .word 0 ! current track
247
248 read_it:
249 mov ax,es
250 test ax,#0x0fff
251 die: jne die ! es must be at 64kB boundary
252 xor bx,bx ! bx is starting address within segment
253 rp_read:
254 mov ax,es
255 cmp ax,#ENDSEG ! have we loaded all yet?
256 jb ok1_read
257 ret
258 ok1_read:
259 seg cs
260 mov ax,sectors
261 sub ax,sread
262 mov cx,ax
263 shl cx,#9
264 add cx,bx
265 jnc ok2_read
266 je ok2_read
267 xor ax,ax
268 sub ax,bx
269 shr ax,#9
270 ok2_read:
271 call read_track
272 mov cx,ax
273 add ax,sread
274 seg cs
275 cmp ax,sectors
276 jne ok3_read
277 mov ax,#1
278 sub ax,head
279 jne ok4_read
280 inc track
281 ok4_read:
282 mov head,ax
283 xor ax,ax
284 ok3_read:
285 mov sread,ax
286 shl cx,#9
287 add bx,cx
288 jnc rp_read
289 mov ax,es
290 add ah,#0x10
291 mov es,ax
292 xor bx,bx
293 jmp rp_read
294
295 read_track:
296 pusha
297 pusha
298 mov ax, #0xe2e ! loading... message 2e = .
299 mov bx, #7
300 int 0x10
301 popa
302
303 mov dx,track
304 mov cx,sread
305 inc cx
306 mov ch,dl
307 mov dx,head
308 mov dh,dl
309 and dx,#0x0100
310 mov ah,#2
311
312 push dx ! save for error dump
313 push cx
314 push bx
315 push ax
316
317 int 0x13
318 jc bad_rt
319 add sp, #8
320 popa
321 ret
322
323 bad_rt: push ax ! save error code
324 call print_all ! ah = error, al = read
325
326
327 xor ah,ah
328 xor dl,dl
329 int 0x13
330
331
332 add sp, #10
333 popa
334 jmp read_track
335
336 /* 337 * print_all is for debugging purposes. 338 * It will print out all of the registers. The assumption is that this is 339 * called from a routine, with a stack frame like 340 * dx 341 * cx 342 * bx 343 * ax 344 * error 345 * ret <- sp 346 * 347 */ 348
349 print_all:
350 mov cx, #5 ! error code + 4 registers
351 mov bp, sp
352
353 print_loop:
354 push cx ! save count left
355 call print_nl ! nl for readability
356
357 cmp cl, 5
358 jae no_reg ! see if register name is needed
359
360 mov ax, #0xe05 + 'A - 1
361 sub al, cl
362 int 0x10
363
364 mov al, #'X
365 int 0x10
366
367 mov al, #':
368 int 0x10
369
370 no_reg:
371 add bp, #2 ! next register
372 call print_hex ! print it
373 pop cx
374 loop print_loop
375 ret
376
377 print_nl:
378 mov ax, #0xe0d ! CR
379 int 0x10
380 mov al, #0xa ! LF
381 int 0x10
382 ret
383
384 /* 385 * print_hex is for debugging purposes, and prints the word 386 * pointed to by ss:bp in hexadecmial. 387 */ 388
389 print_hex:
390 mov cx, #4 ! 4 hex digits
391 mov dx, (bp) ! load word into dx
392 print_digit:
393 rol dx, #4 ! rotate so that lowest 4 bits are used
394 mov ah, #0xe
395 mov al, dl ! mask off so we have only next nibble
396 and al, #0xf
397 add al, #'0 ! convert to 0-based digit
398 cmp al, #'9 ! check for overflow
399 jbe good_digit
400 add al, #'A - '0 - 10
401
402 good_digit:
403 int 0x10
404 loop print_digit
405 ret
406
407
408 /* 409 * This procedure turns off the floppy drive motor, so 410 * that we enter the kernel in a known state, and 411 * don't have to worry about it later. 412 */ 413 kill_motor:
414 push dx
415 mov dx,#0x3f2
416 xor al, al
417 outb
418 pop dx
419 ret
420
421 sectors:
422 .word 0
423
424 msg1:
425 .byte 13,10
426 .ascii "Loading"
427
428 .org 506
429 swap_dev:
430 .word SWAP_DEV
431 root_dev:
432 .word ROOT_DEV
433 boot_flag:
434 .word 0xAA55