2 ! bootsect.s Copyright (C) 1991, 1992 Linus Torvalds
3 ! modified by Drew Eckhardt
4 ! modified by Bruce Evans (bde)
5 ! modified by John Coffman for LILO disk.b diagnostic (27-Mar-2000)
9 ! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
10 ! itself out of the way to address 0x90000, and jumps there.
12 ! bde - should not jump blindly, there may be systems with only 512K low
13 ! memory. Use int 0x12 to get the top of memory, etc.
15 ! It then loads 'setup' directly after itself (0x90200), and the system
16 ! at 0x10000, using BIOS interrupts.
18 ! NOTE! currently system is at most (8*65536-4096) bytes long. This should
19 ! be no problem, even in the future. I want to keep it simple. This 508 kB
20 ! kernel size should be enough, especially as this doesn't contain the
21 ! buffer cache as in minix (and especially now that the kernel is
24 ! The loader has been made as simple as possible, and continuous
25 ! read errors will result in a unbreakable loop. Reboot by hand. It
26 ! loads pretty fast by getting whole tracks at a time whenever possible.
28 ;#include <linux/config.h> /* for CONFIG_ROOT_RDONLY */
29 ;#include <asm/boot.h>
33 SIZEBYTES = SIZEDISKB+511 ! round disk.b size for division
34 SETUPSECS = SIZEBYTES/512 ! size of disk.b in sectors
35 BOOTSEG = 0x07C0 ! original address of boot-sector
36 INITSEG = 0x9000 ! we move boot here - out of the way
37 SETUPSEG = INITSEG+0x20 ! setup starts here
38 SYSSEG = 0x1000 ! system loaded at 0x10000 (65536).
39 MAX_SETUPSECS = 31 ! same as lilo.h
40 STK_SIZE = MAX_SETUPSECS*512+512 ! 0x4000
43 SYSSIZE = 0x8000 ! system size: number of 16-byte clicks
46 SIZEKRNLP = SIZEKRNL+15
47 SYSSIZE = SIZEKRNLP/16
51 ! ROOT_DEV & SWAP_DEV are now written by "build".
55 #define SVGA_MODE ASK_VGA
60 #ifndef CONFIG_ROOT_RDONLY
61 #define CONFIG_ROOT_RDONLY 1
64 ! ld86 requires an entry symbol. This may as well be the usual one.
86 mov di,#STK_SIZE-12 ! 0x4000 is arbitrary value >= length of
87 ! bootsect + length of setup + room for stack
88 ! 12 is disk parm size
90 ! bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We
91 ! wouldn't have to worry about this if we checked the top of memory. Also
92 ! my BIOS can be configured to put the wini drive tables in high memory
93 ! instead of in the vector table. The old stack might have clobbered the
97 mov ss,ax ! put stack at INITSEG:0x4000-12.
104 ! ax and es already contain INITSEG
107 add ax,#0x20 ! seg offset to SETUPSEG
111 * Many BIOS's default disk parameter tables will not
112 * recognize multi-sector reads beyond the maximum sector number
113 * specified in the default diskette parameter tables - this may
114 * mean 7 sectors in some cases.
116 * Since single sector reads are slow and out of the question,
117 * we must take care of this by creating new parameter tables
118 * (for the first disk) in RAM. We will set the maximum sector
119 * count to 36 - the most we will encounter on an ED 2.88.
121 * High doesn't hurt. Low does.
123 * Segments are as follows: ds=es=ss=cs - INITSEG,
124 * fs = 0, gs is unused.
127 ! cx contains 0 from rep movsw above
129 mov bx,#0x78 ! fs:bx is parameter table address
131 push cx ! contains 0 from rep movsw above
133 lds si,(bx) ! ds:si is source
135 mov cl,#6 ! copy 12 bytes
145 movb 4(di),*36 ! patch sector count
156 ! load the setup-sectors directly after the bootblock.
157 ! Note that 'es' is already set up.
158 ! Also cx is 0 from rep movsw above.
161 xor ah,ah ! reset FDC
165 xor dx, dx ! drive 0, head 0
166 mov cl,#0x02 ! sector 2, track 0
167 mov bx,#0x0200 ! address = 512, in INITSEG
168 mov ah,#0x02 ! service 2, nr of sectors
169 mov al,setup_sects ! (assume all on head 0, track 0)
171 jnc ok_load_setup ! ok - continue
173 push ax ! dump error code
183 ! Get disk drive parameters, specifically nr of sectors/track
187 ! bde - the Phoenix BIOS manual says function 0x08 only works for fixed
188 ! disks. It doesn't work for one of my BIOS's (1987 Award). It was
189 ! fatal not to check the error code.
192 mov ah,#0x08 ! AH=8 is get drive parameters
197 ! It seems that there is no BIOS call to get the number of sectors. Guess
198 ! 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
199 ! 15 if sector 15 can be read. Otherwise guess 9.
201 mov si,#disksizes ! table of sizes to try
208 jae got_sectors ! if all else fails, try 9
209 xchg ax, cx ! cx = track and sector
210 xor dx, dx ! drive 0, head 0
214 shl bh,#1 ! address after setup (es = cs)
215 mov ax,#0x0201 ! service 2, 1 sector
217 jc probe_loop ! try next value
224 ! Print some inane message
226 mov ah,#0x03 ! read cursor pos
231 mov bx,#0x0007 ! page 0, attribute 7 (normal)
233 mov ax,#0x1301 ! write string, move cursor
236 ! ok, we've written the message, now
237 ! we want to load the system (at 0x10000)
241 mov es,ax ! segment of 0x010000
252 ! After that we check which root-device to use. If the device is
253 ! defined (!= 0), nothing is done and the given device is used.
254 ! Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8),
255 ! depending on the number of sectors we pretend to know we have.
264 mov ax,#0x0208 ! /dev/ps0 - 1.2Mb
267 mov al,#0x1c ! /dev/PS0 - 1.44Mb
270 mov al,#0x20 ! /dev/fd0H2880 - 2.88Mb
273 mov al,#0 ! /dev/fd0 - autodetect
279 ! after that (everything loaded), we jump to
280 ! the setup-routine loaded directly after
286 ! This routine loads the system at address 0x10000, making sure
287 ! no 64kB boundaries are crossed. We try to load it as fast as
288 ! possible, loading whole tracks whenever we can.
290 ! in: es - starting address segment (normally 0x1000)
292 sread: .word 0 ! sectors read of current track
293 head: .word 0 ! current head
294 track: .word 0 ! current track
302 die: jne die ! es must be at 64kB boundary
303 xor bx,bx ! bx is starting address within segment
305 #ifdef __BIG_KERNEL__
306 #define CALL_HIGHLOAD_KLUDGE .word 0x1eff,0x220 ! call far * bootsect_kludge
307 ! NOTE: as86 can't assemble this
308 CALL_HIGHLOAD_KLUDGE ! this is within setup.S
313 cmp ax,syssize ! have we loaded all yet?
354 mov ax, #0xe2e ! loading... message 2e = .
368 push dx ! save for error dump
379 bad_rt: push ax ! save error code
380 call print_all ! ah = error, al = read
393 * print_all is for debugging purposes.
394 * It will print out all of the registers. The assumption is that this is
395 * called from a routine, with a stack frame like
406 mov cx, #5 ! error code + 4 registers
410 push cx ! save count left
411 call print_nl ! nl for readability
414 jae no_reg ! see if register name is needed
416 mov ax, #0xe05 + 'A - 1
427 add bp, #2 ! next register
428 call print_hex ! print it
441 * print_hex is for debugging purposes, and prints the word
442 * pointed to by ss:bp in hexadecimal.
446 mov cx, #4 ! 4 hex digits
447 mov dx, (bp) ! load word into dx
449 rol dx, #4 ! rotate so that lowest 4 bits are used
450 mov ax, #0xe0f ! ah = request, al = mask for nybble
453 add al, #0x90 ! convert al to ASCII hex (four instructions)
458 daa ! shorter conversion routine
460 adc al,#0x40 ! is now a hex char 0..9A..F
468 * This procedure turns off the floppy drive motor, so
469 * that we enter the kernel in a known state, and
470 * don't have to worry about it later.
495 .word CONFIG_ROOT_RDONLY