2 * bootsect.S Copyright (C) 1991, 1992 Linus Torvalds
4 * modified by Drew Eckhardt
5 * modified by Bruce Evans (bde)
6 * modified by Chris Noe (May 1999) (as86 -> gas)
8 * 360k/720k disk support: Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl>
10 * BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment
11 * addresses must be multiplied by 16 to obtain their respective linear
12 * addresses. To avoid confusion, linear addresses are written using leading
13 * hex while segment addresses are written as segment:offset.
15 * bde - should not jump blindly, there may be systems with only 512K low
16 * memory. Use int 0x12 to get the top of memory, etc.
18 * It then loads 'setup' directly after itself (0x90200), and the system
19 * at 0x10000, using BIOS interrupts.
21 * NOTE! currently system is at most (8*65536-4096) bytes long. This should
22 * be no problem, even in the future. I want to keep it simple. This 508 kB
23 * kernel size should be enough, especially as this doesn't contain the
24 * buffer cache as in minix (and especially now that the kernel is
27 * The loader has been made as simple as possible, and continuous
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.
34 SETUPSECTS = 4 /* default 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 SYSSIZE = DEF_SYSSIZE /* system size: # of 16-byte clicks */
41 ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */
42 SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */
45 #define SVGA_MODE ASK_VGA
62 # First things first. Move ourself from 0x7C00 -> 0x90000 and jump there.
65 movw %ax, %ds # %ds = BOOTSEG
67 movw %ax, %es # %ax = %es = INITSEG
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
82 go: movw $0x4000-12, %di # 0x4000 is an arbitrary value >=
83 # length of bootsect + length of
84 # setup + room for stack;
85 # 12 is disk parm size.
86 movw %ax, %ds # %ax and %es already contain INITSEG
88 movw %di, %sp # put stack at INITSEG:0x4000-12.
90 # Many BIOS's default disk parameter tables will not recognize
91 # multi-sector reads beyond the maximum sector number specified
92 # in the default diskette parameter tables - this may mean 7
93 # sectors in some cases.
95 # Since single sector reads are slow and out of the question,
96 # we must take care of this by creating new parameter tables
97 # (for the first disk) in RAM. We will set the maximum sector
98 # count to 36 - the most we will encounter on an ED 2.88.
100 # High doesn't hurt. Low does.
102 # Segments are as follows: %cs = %ds = %es = %ss = INITSEG, %fs = 0,
105 movw %cx, %fs # %fs = 0
106 movw $0x78, %bx # %fs:%bx is parameter table address
108 ldsw %fs:(%bx), %si # %ds:%si is source
109 movb $6, %cl # copy 12 bytes
110 pushw %di # %di = 0x4000-12.
111 rep # don't worry about cld
112 movsw # already done above
115 movb $36, 0x4(%di) # patch sector count
119 # Get disk drive parameters, specifically number of sectors/track.
121 # It seems that there is no BIOS call to get the number of sectors.
122 # Guess 36 sectors if sector 36 can be read, 18 sectors if sector 18
123 # can be read, 15 if sector 15 can be read. Otherwise guess 9.
124 # Note that %cx = 0 from rep movsw above.
126 movw $disksizes, %si # table of sizes to try
129 cbtw # extend to word
131 cmpw $disksizes+4, %si
132 jae got_sectors # If all else fails, try 9
134 xchgw %cx, %ax # %cx = track and sector
135 xorw %dx, %dx # drive 0, head 0
136 movw $0x0200, %bx # address = 512, in INITSEG (%es = %cs)
137 movw $0x0201, %ax # service 2, 1 sector
139 jc probe_loop # try next value
142 movb $0x03, %ah # read cursor pos
146 movb $0x07, %bl # page 0, attribute 7 (normal)
147 # %bh is set above; int10 doesn't
150 movw $0x1301, %ax # write string, move cursor
151 int $0x10 # tell the user we're loading..
153 # Load the setup-sectors directly after the moved bootblock (at 0x90200).
154 # We should know the drive geometry to do it, as setup may exceed first
155 # cylinder (for 9-sector 360K and 720K floppies).
157 movw $0x0001, %ax # set sread (sector-to-read) to 1 as
158 movw $sread, %si # the boot sector has already been read
161 xorw %ax, %ax # reset FDC
164 movw $0x0200, %bx # address = 512, in INITSEG
166 movb setup_sects, %al
168 subw (%si), %cx # (%si) = sread
172 subw (%si), %ax # (%si) = sread
176 call set_next # set %bx properly; it uses %ax,%cx,%dx
178 subb %al, setup_sects # rest - for next step
182 popw %es # %es = SYSSEG
187 # After that we check which root-device to use. If the device is
188 # defined (!= 0), nothing is done and the given device is used.
189 # Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8)
190 # depending on the number of sectors we pretend to know we have.
192 # Segments are as follows: %cs = %ds = %ss = INITSEG,
193 # %es = SYSSEG, %fs = 0, %gs is unused.
200 movw $0x0208, %ax # /dev/ps0 - 1.2Mb
204 movb $0x1c, %al # /dev/PS0 - 1.44Mb
208 movb $0x20, %al # /dev/fd0H2880 - 2.88Mb
212 movb $0, %al # /dev/fd0 - autodetect
216 # After that (everything loaded), we jump to the setup-routine
217 # loaded directly after the bootblock:
221 # These variables are addressed via %si register as it gives shorter code.
223 sread: .word 0 # sectors read of current track
224 head: .word 0 # current head
225 track: .word 0 # current track
227 # This routine loads the system at address SYSSEG, making sure
228 # no 64kB boundaries are crossed. We try to load it as fast as
229 # possible, loading whole tracks whenever we can.
232 movw %es, %ax # %es = SYSSEG when called
234 die: jne die # %es must be at 64kB boundary
235 xorw %bx, %bx # %bx is starting address within segment
237 #ifdef __BIG_KERNEL__
238 # look in setup.S for bootsect_kludge
239 bootsect_kludge = 0x220 # 0x200 + 0x20 which is the size of the
240 lcall bootsect_kludge # bootsector + bootsect_kludge offset
246 add %cx, %ax # check offset
248 cmpw syssize, %ax # have we loaded everything yet?
255 subw (%si), %ax # (%si) = sread
274 movw $0xe2e, %ax # loading... message 2e = .
279 # Accessing head, track, sread via %si gives shorter code.
281 movw 4(%si), %dx # 4(%si) = track
282 movw (%si), %cx # (%si) = sread
285 movw 2(%si), %dx # 2(%si) = head
289 pushw %dx # save for error dump
302 addw (%si), %ax # (%si) = sread
306 xorw %ax, 2(%si) # change head
308 incw 4(%si) # next track
312 movw %ax, (%si) # set sread
324 pushw %ax # save error code
325 call print_all # %ah = error, %al = read
333 # print_all is for debugging purposes.
335 # it will print out all of the registers. The assumption is that this is
336 # called from a routine, with a stack frame like
346 movw $5, %cx # error code + 4 registers
349 pushw %cx # save count remaining
350 call print_nl # <-- for readability
352 jae no_reg # see if register name is needed
354 movw $0xe05 + 'A' - 1, %ax
362 addw $2, %bp # next register
363 call print_hex # print it
369 movw $0xe0d, %ax # CR
375 # print_hex is for debugging purposes, and prints the word
376 # pointed to by %ss:%bp in hexadecimal.
379 movw $4, %cx # 4 hex digits
380 movw (%bp), %dx # load word into %dx
382 rolw $4, %dx # rotate to use low 4 bits
383 movw $0xe0f, %ax # %ah = request
384 andb %dl, %al # %al = mask for nybble
385 addb $0x90, %al # convert %al to ascii hex
386 daa # in only four instructions!
393 # This procedure turns off the floppy drive motor, so
394 # that we enter the kernel in a known state, and
395 # don't have to worry about it later.
396 # NOTE: Doesn't save %ax or %dx; do it yourself if you need to.
400 xorw %ax, %ax # reset FDC
411 disksizes: .byte 36, 18, 15, 9
415 # XXX: This is a fairly snug fit.
418 setup_sects: .byte SETUPSECTS
419 root_flags: .word ROOT_RDONLY
420 syssize: .word SYSSIZE
421 swap_dev: .word SWAP_DEV
422 ram_size: .word RAMDISK
423 vid_mode: .word SVGA_MODE
424 root_dev: .word ROOT_DEV
425 boot_flag: .word 0xAA55