2 * Copyright (c) 1998 Robert Nordier
3 * Copyright (c) 2004 by Matthew Dillon, All rights reserved.
5 * Redistribution and use in source and binary forms are freely
6 * permitted provided that the above copyright notice and this
7 * paragraph and the following disclaimer are duplicated in all
10 * This software is provided "AS IS" and without any express or
11 * implied warranties, including, without limitation, the implied
12 * warranties of merchantability and fitness for a particular
15 * $DragonFly: src/sys/boot/i386/bootn0/Attic/boot0.S,v 1.2 2004/07/18 18:42:08 dillon Exp $
17 * A 512-byte boot manager.
20 .set NHRDRV,0x475 # Number of hard drives
21 .set FAKE,0x800 # Partition entry
22 .set BIOS_LOAD,0x7c00 # BIOS Load address
23 .set ORG_ADDR,0x91000 # 'start' symbol
24 .set ORG_SEG,0x900 # leave room in segment for stk
27 .set PRT_OFF,0x1be # Partition table
29 .set TBL0SZ,3 # Table 0 size
30 .set TBL1SZ,9 # Table 1 size
32 .set MAGIC,0xaa55 # Magic: bootable
33 .set B0MAGIC,0xbb66 # Identification
35 .set KEY_ENTER,0x1c # Enter key scan code
36 .set KEY_F1,0x3b # F1 key scan code
37 .set KEY_1,0x02 # #1 key scan code
40 # Addresses in the sector of embedded data values. Accessed
41 # with negative offsets from the end of the relocated sector
44 .set _NXTDRV,-0x48 # Next drive
45 .set _OPT,-0x47 # Default option
46 .set _SETDRV,-0x46 # Drive to force
47 .set _FLAGS,-0x45 # Flags
48 .set _TICKS,-0x44 # Timeout ticks
49 .set _FAKE,0x0 # Fake partition entry
50 .set _MNUOPT,0xc # Menu options
52 #define DRELOC(symbol) (symbol-start+ORG_OFF)
54 .globl start # Entry point
55 .code16 # This runs in real mode
57 # Initialize segments and relocate the boot sector. Our
58 # stack starts at our target relocation address and grows
59 # downward while the copy of boot0 grows upwards.
62 start: cld # String ops inc
63 movw $ORG_SEG,%ax # Setup various segments
65 movw %ax,%ss # (coupled with next instruction)
66 movw $ORG_OFF,%sp # stack downward from start
69 movw %ax,%ds # source is in segment 0
70 movw $BIOS_LOAD,%si # source is the BIOS load address
72 movw $0x100,%cx # 256x2 = 512 bytes
76 # Note: %ds points at segment 0
77 # %es points at our relocated segment
78 # %ss points at our relocated segment
81 # Remember that %bp relative addresses uses the stack segment
83 movw %di,%bp # address variables
84 movb $8,%cl # clear 16 bytes
88 # Point %ds at our relocated segment, cleanup, and
89 # jump to our relocated segment.
93 incb _FAKE+2(%bp) # Start with sector 1
94 ljmp $ORG_SEG,$DRELOC(main)
96 # Check what flags were loaded with us. Specifically, use a
97 # predefined drive. If the BIOS gives us junk use the '0'
98 # in the block instead, as well.
100 main: testb $0x20,_FLAGS(%bp) # Set number drive?
102 testb %dl,%dl # Drive number valid?
103 js main.2 # Possibly (0x80 set)
104 main.1: movb _SETDRV(%bp),%dl # Drive number to use
106 # Save our working drive in a temporary variable
108 main.2: movb %dl,_FAKE(%bp) # Save drive number
109 callw putn # To new line
110 pushw %dx # Save drive number
112 # Start out with a pointer to the 4th byte of the first table
113 # entry so that after 4 iterations it is beyond the end of
114 # the sector (hits a 256 byte boundary and overflows 8 bits)
116 # Remember that the table starts 2 bytes earlier then you
117 # would expect as the bootable flag is after it in the block.
119 movw $DRELOC(partbl+0x4),%bx # Partition table (+4)
120 xorw %dx,%dx # Item number
122 # Loop on the partition table printing values until we
123 # hit the 256 byte boundary (at main.5).
125 main.3: movb %ch,-4(%bx) # Zero active flag (ch == 0)
126 btw %dx,_FLAGS(%bp) # Entry enabled?
129 # If any of the table entries match 'type' in the slice
130 # table entry, then this is an empty or non bootable partition.
133 movb (%bx),%al # Load type
134 movw $DRELOC(tables),%di # Lookup tables
135 movb $TBL0SZ,%cl # Number of entries
136 repne # Exclude partition?
137 scasb # (note: uses %es by default)
141 # Now scan the table of known types
143 movb $TBL1SZ,%cl # Number of entries
149 * If it matches get the matching element in the next
150 * array. If it doesn't we are already pointing at the
151 * first element, which points to a "?".
153 addw $TBL1SZ,%di # Adjust
154 main.4: movb (%di),%cl # Partition description
156 callw putx # Display it
157 main.5: incw %dx # Next item
158 addb $0x10,%bl # Next entry
159 jnc main.3 # Till done
161 # End of loop. Add one to the drive number and check validity.
163 popw %ax # Drive number
164 subb $0x80-0x1,%al # Does next drive exist? (BIOS)
168 # If %ax is 1 there is only one drive in the system and we
169 # skip the drive selection code. Note that %ax becomes an
172 decw %ax # Already drive 0?
175 # No, loop on drive selection starting with 0
177 xorb %al,%al # Drive 0
178 main.6: addb $'0'|0x80,%al # Save next drive number
179 movb %al,_NXTDRV(%bp)
180 movw $DRELOC(drive),%di # Display item
183 # Prompt and setup for input but do not yet initiate the
186 main.7: movw $DRELOC(prompt),%si # Display prompt
188 movb _OPT(%bp),%dl # Display default key
191 xorb %ah,%ah # BIOS: Get system time
193 movw %dx,%di # Figure out tick value of timeout
198 main.8: movb $0x1,%ah # BIOS: Check for keypress
201 xorb %ah,%ah # BIOS: Get system time
203 cmpw %di,%dx # loop if no timeout
206 # A timeout or default comes to here
208 main.9: movb _OPT(%bp),%al # Load default
209 jmp main.12 # Join common code
212 * If the user's last try was bad, beep. Since nothing was
213 * printed, continue as if the user hadn't done anything.
215 main.10: movb $0x7,%al # Signal error
218 # Obtain the keystroke we previously polled successfully for
220 main.11: xorb %ah,%ah # BIOS: Get keypress
222 movb %ah,%al # Scan code
224 # An ENTER is equivalent to a timeout
226 cmpb $KEY_ENTER,%al # Enter pressed?
229 # Look for a legal keystroke, jump to main.10 (beep) and
230 # retry if it is not legal.
232 subb $KEY_F1,%al # Less F1 scan code
233 cmpb $0x4,%al # F1..F5?
235 subb $(KEY_1-KEY_F1),%al # Less #1 scan code
236 cmpb $0x4,%al # #1..#5?
239 # Check the selection, complain if its bad. Only options
240 # that were printed (MNUOPT bit set) are valid.
242 main.12: cbtw # Option enabled?
247 * We're good. Save the data for later rewriting back to disk
249 movb %al,_OPT(%bp) # Save for future action
250 leaw _FAKE(%bp),%si # Partition for write
251 movb (%si),%dl # Drive number
252 movw %si,%bx # Partition for read
253 cmpb $0x4,%al # F5 pressed?
254 pushf # Save result of check
256 shlb $0x4,%al # Point to selected partition
257 addw $DRELOC(partbl),%ax
259 movb $0x80,(%bx) # Flag active
261 # Only writeback if we were told to in _FLAGS
263 main.13: pushw %bx # Save
264 testb $0x40,_FLAGS(%bp) # No updates?
266 movw $DRELOC(start),%bx # Data to write (relative to %es)
267 movb $0x3,%ah # Write sector to disk
269 main.14: popw %si # Restore %si for next intx13
271 # Retrieve the perviously saved F5 (next drive) request
272 # status and move us to the next drive if necessary
276 movb _NXTDRV(%bp),%dl
280 * Load the selected bootsector to the LOAD location in RAM.
281 * We are already relocated so it will not overwrite us
282 * in particular. If it fails to read or isn't marked bootable,
283 * treat it was a bad selection.
285 * note: drive number in %dl
287 main.15: movw $BIOS_LOAD,%bx # Address for read
290 movb $0x2,%ah # Read sector from disk
292 movw %es:0x1fe(%bx),%ax # (these do not effect carry)
295 jc main.10 # error on carry
296 subw $MAGIC,%ax # Bootable?
298 pushw %ax # seg: setup for lret (note %ax is 0)
299 pushw %bx # offset: setup for lret
300 pushw %ax # (so we can clear %ds)
307 # Display functions. %bx is not modified by any of these
310 putkey: movb $'F',%al # Display 'F'
312 movb $'1',%al # Display digit and remainder of prompt
316 # Display the option and note that it is a valid option
317 # by setting the appropriate bit in _MNUOPT.
319 putx: btsw %dx,_MNUOPT(%bp) # Enable menu option
320 movw $DRELOC(item),%si # Display key
322 movw %di,%si # Display the option string
323 puts: callw putstr # Display string in %si
325 putn: movw $DRELOC(crlf),%si # Output a CR+LF
327 putstr.1: callw putchr # Output %al + string at (%si)
328 putstr: lodsb # Output string at (%si)
332 putchr: pusha # %bx is not modified by this call
333 movw $0x7,%bx # Page:attribute
334 movb $0xe,%ah # BIOS: Display character
339 # One-sector disk I/O routine
341 # note: drive number in %dl, %si points to local variable
342 # area holding (driveno, head, w:cylinder/sector)
344 intx13: movb 0x1(%si),%dh # Load head
345 movw 0x2(%si),%cx # Load cylinder:sector
346 movb $0x1,%al # Sector count
348 pushl $0x0 # Set the LBA Address
350 pushw %es # Set the Transfer Buffer Address
352 pushw $0x1 # Block count
353 pushw $0x10 # Packet size
354 testb $0x80,_FLAGS(%bp) # Use packet interface?
356 movw %sp,%si # Packet pointer (%es?)
357 decw %ax # Verify off
358 orb $0x40,%ah # Use disk packet
359 intx13.1: int $0x13 # BIOS: Disk I/O
363 retw # WARNING: carry must be preserved
371 prompt: .ascii "\nDefault:"
377 * Partition table types
381 * These entries identify invalid or NON BOOT types and
387 * These values indicate bootable types we know the names of
389 .byte 0xb, 0xc, 0xe, 0x83
390 .byte 0xa5, 0xa6, 0xa9
393 * These are offsets that match the known names above and
394 * point to the strings that will be printed.
396 .byte os_misc-. # Unknown
397 .byte os_dos-. # Windows
398 .byte os_dos-. # Windows
399 .byte os_dos-. # Windows
400 .byte os_linux-. # Linux
401 .byte os_bsd-. # FreeBSD/DragonFly
402 .byte os_bsd-. # OpenBSD
403 .byte os_bsd-. # NetBSD
406 * And here are the strings themselves. 0x80 or'd into a
407 * byte indicates the end of the string. (not so great
408 * for Russians but...)
410 os_misc: .ascii "?"; .byte '?'|0x80
411 os_dos: .ascii "DO"; .byte 'S'|0x80
412 os_linux: .ascii "Linu"; .byte 'x'|0x80
413 os_bsd: .ascii "BS"; .byte 'D'|0x80
415 .org PRT_OFF-0xe,0x90
418 * 14 bytes then partition table. Some of these values may
419 * be adjusted by the above code and then written back to the
420 * drive. Be especially careful in that nxtdrv: must come
421 * after drive:, as it is part of the same string.
423 .word B0MAGIC # Magic number
425 drive: .ascii "Drive "
426 nxtdrv: .byte 0x0 # Next drive number
427 opt: .byte 0x0 # Option
428 setdrv: .byte 0x80 # Drive to force
429 flags: .byte FLAGS # Flags
430 ticks: .word TICKS # Delay
433 * here is the 64 byte partition table that fdisk would
436 partbl: .fill 0x40,0x1,0x0 # Partition table
437 .word MAGIC # Magic number