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