3 ! Copyright (C) 1991, 1992 Linus Torvalds
5 ! modified by Drew Eckhardt
6 ! modified by Bruce Evans (bde)
7 ! modified by John Coffman (2000, 2001)
8 ! modified by Joachim Wiedorn (2011)
11 ! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
12 ! itself out of the way to address 0x90000, and jumps there.
14 ! bde - should not jump blindly, there may be systems with only 512K low
15 ! memory. Use int 0x12 to get the top of memory, etc.
17 ! It then loads 'setup' directly after itself (0x90200), and the system
18 ! at 0x10000, using BIOS interrupts.
20 ! NOTE! currently system is at most (8*65536-4096) bytes long. This should
21 ! be no problem, even in the future. I want to keep it simple. This 508 kB
22 ! kernel size should be enough, especially as this doesn't contain the
23 ! buffer cache as in minix (and especially now that the kernel is
26 ! The loader has been made as simple as possible, and continuous
27 ! read errors will result in a unbreakable loop. Reboot by hand. It
28 ! loads pretty fast by getting whole tracks at a time whenever possible.
30 ;#include <linux/config.h> /* for CONFIG_ROOT_RDONLY */
31 ;#include <asm/boot.h>
35 SIZEBYTES = SIZEDISKB+511 ! round disk.b size for division
36 SETUPSECS = SIZEBYTES/512 ! size of disk.b in sectors
37 BOOTSEG = 0x07C0 ! original address of boot-sector
38 INITSEG = 0x9000 ! we move boot here - out of the way
39 SETUPSEG = INITSEG+0x20 ! setup starts here
40 SYSSEG = 0x1000 ! system loaded at 0x10000 (65536).
41 MAX_SETUPSECS = 63 ! same as lilo.h (for kernel >= 2.4.0)
42 STK_SIZE = MAX_SETUPSECS*512+512 ! 0x4000
45 SYSSIZE = 0x8000 ! system size: number of 16-byte clicks
48 SIZEKRNLP = SIZEKRNL+15
49 SYSSIZE = SIZEKRNLP/16
53 ! ROOT_DEV & SWAP_DEV are now written by "build".
57 #define SVGA_MODE ASK_VGA
62 #ifndef CONFIG_ROOT_RDONLY
63 #define CONFIG_ROOT_RDONLY 1
66 ! ld86 requires an entry symbol. This may as well be the usual one.
88 mov di,#STK_SIZE-12 ! 0x4000 is arbitrary value >= length of
89 ! bootsect + length of setup + room for stack
90 ! 12 is disk parm size
92 ! bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We
93 ! wouldn't have to worry about this if we checked the top of memory. Also
94 ! my BIOS can be configured to put the wini drive tables in high memory
95 ! instead of in the vector table. The old stack might have clobbered the
99 mov ss,ax ! put stack at INITSEG:0x4000-12.
106 ! ax and es already contain INITSEG
109 add ax,#0x20 ! seg offset to SETUPSEG
113 * Many BIOS's default disk parameter tables will not
114 * recognize multi-sector reads beyond the maximum sector number
115 * specified in the default diskette parameter tables - this may
116 * mean 7 sectors in some cases.
118 * Since single sector reads are slow and out of the question,
119 * we must take care of this by creating new parameter tables
120 * (for the first disk) in RAM. We will set the maximum sector
121 * count to 36 - the most we will encounter on an ED 2.88.
123 * High doesn't hurt. Low does.
125 * Segments are as follows: ds=es=ss=cs - INITSEG,
126 * fs = 0, gs is unused.
129 ! cx contains 0 from rep movsw above
131 mov bx,#0x78 ! fs:bx is parameter table address
133 push cx ! contains 0 from rep movsw above
135 lds si,(bx) ! ds:si is source
137 mov cl,#6 ! copy 12 bytes
147 movb 4(di),*36 ! patch sector count
158 ! load the setup-sectors directly after the bootblock.
159 ! Note that 'es' is already set up.
160 ! Also cx is 0 from rep movsw above.
163 xor ah,ah ! reset FDC
167 xor dx, dx ! drive 0, head 0
168 mov cl,#0x02 ! sector 2, track 0
169 mov bx,#0x0200 ! address = 512, in INITSEG
170 mov ah,#0x02 ! service 2, nr of sectors
171 mov al,setup_sects ! (assume all on head 0, track 0)
173 jnc ok_load_setup ! ok - continue
175 push ax ! dump error code
185 ! Get disk drive parameters, specifically nr of sectors/track
189 ! bde - the Phoenix BIOS manual says function 0x08 only works for fixed
190 ! disks. It doesn't work for one of my BIOS's (1987 Award). It was
191 ! fatal not to check the error code.
194 mov ah,#0x08 ! AH=8 is get drive parameters
199 ! It seems that there is no BIOS call to get the number of sectors. Guess
200 ! 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
201 ! 15 if sector 15 can be read. Otherwise guess 9.
203 mov si,#disksizes ! table of sizes to try
210 jae got_sectors ! if all else fails, try 9
211 xchg ax, cx ! cx = track and sector
212 xor dx, dx ! drive 0, head 0
216 shl bh,#1 ! address after setup (es = cs)
217 mov ax,#0x0201 ! service 2, 1 sector
219 jc probe_loop ! try next value
226 ! Print some inane message
228 mov ah,#0x03 ! read cursor pos
233 mov bx,#0x0007 ! page 0, attribute 7 (normal)
235 mov ax,#0x1301 ! write string, move cursor
238 ! ok, we've written the message, now
239 ! we want to load the system (at 0x10000)
243 mov es,ax ! segment of 0x010000
254 ! After that we check which root-device to use. If the device is
255 ! defined (!= 0), nothing is done and the given device is used.
256 ! Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8),
257 ! depending on the number of sectors we pretend to know we have.
266 mov ax,#0x0208 ! /dev/ps0 - 1.2Mb
269 mov al,#0x1c ! /dev/PS0 - 1.44Mb
272 mov al,#0x20 ! /dev/fd0H2880 - 2.88Mb
275 mov al,#0 ! /dev/fd0 - autodetect
281 ! after that (everything loaded), we jump to
282 ! the setup-routine loaded directly after
288 ! This routine loads the system at address 0x10000, making sure
289 ! no 64kB boundaries are crossed. We try to load it as fast as
290 ! possible, loading whole tracks whenever we can.
292 ! in: es - starting address segment (normally 0x1000)
294 sread: .word 0 ! sectors read of current track
295 head: .word 0 ! current head
296 track: .word 0 ! current track
304 die: jne die ! es must be at 64kB boundary
305 xor bx,bx ! bx is starting address within segment
307 #ifdef __BIG_KERNEL__
308 #define CALL_HIGHLOAD_KLUDGE .word 0x1eff,0x220 ! call far * bootsect_kludge
309 ! NOTE: as86 can't assemble this
310 CALL_HIGHLOAD_KLUDGE ! this is within setup.S
315 cmp ax,syssize ! have we loaded all yet?
356 mov ax, #0xe2e ! loading... message 2e = .
370 push dx ! save for error dump
381 bad_rt: push ax ! save error code
382 call print_all ! ah = error, al = read
395 * print_all is for debugging purposes.
396 * It will print out all of the registers. The assumption is that this is
397 * called from a routine, with a stack frame like
408 mov cx, #5 ! error code + 4 registers
412 push cx ! save count left
413 call print_nl ! nl for readability
416 jae no_reg ! see if register name is needed
418 mov ax, #0xe05 + 'A - 1
429 add bp, #2 ! next register
430 call print_hex ! print it
443 * print_hex is for debugging purposes, and prints the word
444 * pointed to by ss:bp in hexadecimal.
448 mov cx, #4 ! 4 hex digits
449 mov dx, (bp) ! load word into dx
451 rol dx, #4 ! rotate so that lowest 4 bits are used
452 mov ax, #0xe0f ! ah = request, al = mask for nybble
455 add al, #0x90 ! convert al to ASCII hex (four instructions)
460 daa ! shorter conversion routine
462 adc al,#0x40 ! is now a hex char 0..9A..F
470 * This procedure turns off the floppy drive motor, so
471 * that we enter the kernel in a known state, and
472 * don't have to worry about it later.
497 .word CONFIG_ROOT_RDONLY