]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/boot/i386/boot0/boot0.S
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / boot / i386 / boot0 / boot0.S
1 /*
2  * Copyright (c) 2008 Luigi Rizzo (mostly documentation)
3  * Copyright (c) 2002 Bruce M. Simpson
4  * Copyright (c) 1998 Robert Nordier
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms are freely
8  * permitted provided that the above copyright notice and this
9  * paragraph and the following disclaimer are duplicated in all
10  * such forms.
11  *
12  * This software is provided "AS IS" and without any express or
13  * implied warranties, including, without limitation, the implied
14  * warranties of merchantability and fitness for a particular
15  * purpose.
16  *
17  * $FreeBSD$
18  */
19
20 /* build options: */
21 #ifdef SIO              /* use serial console on COM1.  */
22 #endif
23
24 #ifdef PXE              /* enable PXE/INT18 booting with F6 */
25 #define SAVE_MORE_MEMORY
26 #endif
27
28 #ifdef CHECK_DRIVE      /* make sure we boot from a HD. */
29 #endif
30
31 #ifdef ONLY_F_KEYS      /* Only F1..F6, no digits on console */
32 #endif
33
34 #ifdef VOLUME_SERIAL    /* support Volume serial number */
35 #define B0_BASE 0x1ae   /* move the internal data area */
36 #define SAVE_MEMORY
37 #else
38 #define B0_BASE 0x1b2
39 #endif
40
41 #ifdef TEST             /* enable some test code */
42 #define SAVE_MEMORY
43 #define SAVE_MORE_MEMORY
44 #endif
45
46 /*
47  * Note - this code uses many tricks to save space and fit in one sector.
48  * This includes using side effects of certain instructions, reusing
49  * register values from previous operations, etc.
50  * Be extremely careful when changing the code, even for simple things.
51  */
52
53 /*
54  *              BOOT BLOCK STRUCTURE
55  *
56  * This code implements a Master Boot Record (MBR) for an Intel/PC disk.
57  * It is 512 bytes long and it is normally loaded by the BIOS (or another
58  * bootloader) at 0:0x7c00. This code depends on %cs:%ip being 0:0x7c00
59  *
60  * The initial chunk of instructions is used as a signature by external
61  * tools (e.g. boot0cfg) which can manipulate the block itself.
62  *
63  * The area at offset 0x1b2 contains a magic string ('Drive '), also
64  * used as a signature to detect the block, and some variables that can
65  * be updated by boot0cfg (and optionally written back to the disk).
66  * These variables control the operation of the bootloader itself,
67  * e.g. which partitions to enable, the timeout, the use of LBA
68  * (called 'packet') or CHS mode, whether to force a drive number,
69  * and whether to write back the user's selection back to disk.
70  *
71  * As in every Master Boot Record, the partition table is at 0x1be,
72  * made of four 16-byte entries each containing:
73  *
74  *   OFF SIZE   DESCRIPTION
75  *    0   1     status (0x80: bootable, 0: non bootable)
76  *    1   3     start sector CHS
77  *                 8:head, 6:sector, 2:cyl bit 9..8, 8:cyl bit 7..0
78  *    4   1     partition type
79  *    5   3     end sector CHS
80  *    8   4     LBA of first sector
81  *   12   4     partition size in sectors
82  *
83  * and followed by the two bytes 0x55, 0xAA (MBR signature).
84  */
85
86
87 /*
88  *              BOOT BLOCK OPERATION
89  *
90  * On entry, the registers contain the following values:
91  *
92  *      %cs:%ip 0:0x7c00
93  *      %dl     drive number (0x80, 0x81, ... )
94  *      %si     pointer to the partition table from which we were loaded.
95  *              Some boot code (e.g. syslinux) use this info to relocate
96  *              themselves, so we want to pass a valid one to the next stage.
97  *              NOTE: the use of %si is not a standard.
98  *
99  * This boot block first relocates itself at a different address (0:0x600),
100  * to free the space at 0:0x7c00 for the next stage boot block.
101  *
102  * It then initializes some memory at 0:0x800 and above (pointed by %bp)
103  * to store the original drive number (%dl) passed to us, and to construct a
104  * fake partition entry. The latter is used by the disk I/O routine and,
105  * in some cases, passed in %si to the next stage boot code.
106  *
107  * The variables at 0x1b2 are accessed as negative offsets from %bp.
108  *
109  * After the relocation, the code scans the partition table printing
110  * out enabled partition or disks, and waits for user input.
111  *
112  * When a partition is selected, or a timeout expires, the currently
113  * selected partition is used to load the next stage boot code,
114  * %dl and %si are set appropriately as when we were called, and
115  * control is transferred to the newly loaded code at 0:0x7c00.
116  */
117
118 /*
119  *      CONSTANTS
120  *
121  * NHRDRV is the address in segment 0 where the BIOS writes the
122  *      total number of hard disks in the system.
123  * LOAD is the original load address and cannot be changed.
124  * ORIGIN is the relocation address. If you change it, you also need
125  *      to change the value passed to the linker in the Makefile
126  * PRT_OFF is the location of the partition table (from the MBR standard).
127  * B0_OFF is the location of the data area, known to boot0cfg so
128  *      it cannot be changed. Computed as a negative offset from 0x200
129  * MAGIC is the signature of a boot block.
130  */
131
132                 .set NHRDRV,0x475               # Number of hard drives
133                 .set ORIGIN,0x600               # Execution address
134                 .set LOAD,0x7c00                # Load address
135
136                 .set PRT_OFF,0x1be              # Partition table
137                 .set B0_OFF,(B0_BASE-0x200)     # Offset of boot0 data
138
139                 .set MAGIC,0xaa55               # Magic: bootable
140
141                 .set KEY_ENTER,0x1c             # Enter key scan code
142                 .set KEY_F1,0x3b                # F1 key scan code
143                 .set KEY_1,0x02                 # #1 key scan code
144
145                 .set ASCII_BEL,'#'              # ASCII code for <BEL>
146                 .set ASCII_CR,0x0D              # ASCII code for <CR>
147
148 /*
149  * Offsets of variables in the block at B0_OFF, and in the volatile
150  * data area, computed as displacement from %bp.
151  * We need to define them as constant as the assembler cannot
152  * compute them in its single pass.
153  */
154                 .set _NXTDRV,   B0_OFF+6        # Next drive
155                 .set _OPT,      B0_OFF+7        # Default option
156                 .set _SETDRV,   B0_OFF+8        # Drive to force
157                 .set _FLAGS,    B0_OFF+9        # Flags
158                 .set SETDRV,    0x20            # the 'setdrv' flag
159                 .set NOUPDATE,  0x40            # the 'noupdate' flag
160                 .set USEPACKET, 0x80            # the 'packet' flag
161
162         /* ticks is at a fixed position */
163                 .set _TICKS,    (PRT_OFF - 0x200 - 2)   # Timeout ticks
164                 .set _MNUOPT, 0x10              # Saved menu entries
165
166                 .set TLEN, (desc_ofs - bootable_ids)    # size of bootable ids
167                 .globl start                    # Entry point
168                 .code16                         # This runs in real mode
169
170 /*
171  *      MAIN ENTRY POINT
172  * Initialise segments and registers to known values.
173  * segments start at 0.
174  * The stack is immediately below the address we were loaded to.
175  * NOTE: the initial section of the code (up to movw $LOAD,%sp)
176  * is used by boot0cfg, together with the 'Drive ' string and
177  * the 0x55, 0xaa at the end, as an identifier for version 1.0
178  * of the boot code. Do not change it.
179  * In version 1.0 the parameter table (_NEXTDRV etc) is at 0x1b9
180  */
181 start:          cld                             # String ops inc
182                 xorw %ax,%ax                    # Zero
183                 movw %ax,%es                    # Address
184                 movw %ax,%ds                    #  data
185                 movw %ax,%ss                    # Set up
186                 movw $LOAD,%sp                  #  stack
187
188         /*
189          * Copy this code to the address it was linked for, 0x600 by default.
190          */
191                 movw %sp,%si                    # Source
192                 movw $start,%di                 # Destination
193                 movw $0x100,%cx                 # Word count
194                 rep                             # Relocate
195                 movsw                           #  code
196         /*
197          * After the code, (i.e. at %di+0, 0x800) create a partition entry,
198          * initialized to LBA 0 / CHS 0:0:1.
199          * Set %bp to point to the partition and also, with negative offsets,
200          * to the variables embedded in the bootblock (nextdrv and so on).
201          */
202                 movw %di,%bp                    # Address variables
203                 movb $0x8,%cl                   # Words to clear
204                 rep                             # Zero
205                 stosw                           #  them
206                 incb -0xe(%di)                  # Set the S field to 1
207
208                 jmp main-LOAD+ORIGIN            # Jump to relocated code
209
210 main:
211 #if defined(SIO) && COMSPEED != 0
212         /*
213          * Init the serial port. bioscom preserves the driver number in DX.
214          */
215                 movw $COMSPEED,%ax              # defined by Makefile
216                 callw bioscom
217 #endif
218
219         /*
220          * If the 'setdrv' flag is set in the boot sector, use the drive
221          * number from the boot sector at 'setdrv_num'.
222          * Optionally, do the same if the BIOS gives us an invalid number
223          * (note though that the override prevents booting from a floppy
224          * or a ZIP/flash drive in floppy emulation).
225          * The test costs 4 bytes of code so it is disabled by default.
226          */
227                 testb $SETDRV,_FLAGS(%bp)       # Set drive number?
228 #ifndef CHECK_DRIVE     /* disable drive checks */
229                 jz save_curdrive                # no, use the default
230 #else
231                 jnz disable_update              # Yes
232                 testb %dl,%dl                   # Drive number valid?
233                 js save_curdrive                # Possibly (0x80 set)
234 #endif
235         /*
236          * Disable updates if the drive number is forced.
237          */
238 disable_update: orb $NOUPDATE,_FLAGS(%bp)       # Disable updates
239                 movb _SETDRV(%bp),%dl           # Use stored drive number
240
241         /*
242          * Whatever drive we decided to use, store it at (%bp). The byte
243          * is normally used for the state of the partition (0x80 or 0x00),
244          * but we abuse it as it is very convenient to access at offset 0.
245          * The value is read back after 'check_selection'
246          */
247 save_curdrive:  movb %dl, (%bp)                 # Save drive number
248                 pushw %dx                       # Also in the stack
249 #ifdef  TEST    /* test code, print internal bios drive */
250                 rolb $1, %dl
251                 movw $drive, %si
252                 call putkey
253 #endif
254                 callw putn                      # Print a newline
255         /*
256          * Start out with a pointer to the 4th byte of the first table entry
257          * so that after 4 iterations it's beyond the end of the sector
258          * and beyond a 256 byte boundary. We use the latter trick to check for
259          * end of the loop without using an extra register (see start.5).
260          */
261                 movw $(partbl+0x4),%bx          # Partition table (+4)
262                 xorw %dx,%dx                    # Item number
263
264         /*
265          * Loop around on the partition table, printing values until we
266          * pass a 256 byte boundary.
267          */
268 read_entry:     movb %ch,-0x4(%bx)              # Zero active flag (ch == 0)
269                 btw %dx,_FLAGS(%bp)             # Entry enabled?
270                 jnc next_entry                  # No
271                 movb (%bx),%al                  # Load type
272                 test %al, %al                   # skip empty partition
273                 jz next_entry
274         /*
275          * Scan the table of bootable ids, which starts at %di and has
276          * length TLEN. On a match, %di points to the element following the
277          * match; the corresponding offset to the description is $(TLEN-1)
278          * bytes ahead. We use a count of TLEN+1 so if we don't find a match
279          * within the first TLEN entries, we hit the 'unknown' entry.
280          */
281                 movw $bootable_ids,%di          # Lookup tables
282                 movb $(TLEN+1),%cl              # Number of entries
283                 repne                           # Locate
284                 scasb                           #  type
285         /*
286          * Get the matching element in the next array.
287          * The byte at $(TLEN-1)(%di) contains the offset of the description
288          * string from %di, so we add the number and print the string.
289          */
290                 addw $(TLEN-1), %di             # Adjust
291                 movb (%di),%cl                  # Partition
292                 addw %cx,%di                    #  description
293                 callw putx                      # Display it
294
295 next_entry:     incw %dx                        # Next item
296                 addb $0x10,%bl                  # Next entry
297                 jnc read_entry                  # Till done
298         /*
299          * We are past a 256 byte boundary: the partition table is finished.
300          * Add one to the drive number and check it is valid.
301          * Note that if we started from a floppy, %dl was 0 so we still
302          * get an entry for the next drive, which is the first Hard Disk.
303          */
304                 popw %ax                        # Drive number
305                 subb $0x80-0x1,%al              # Does next
306                 cmpb NHRDRV,%al                 #  drive exist? (from BIOS?)
307                 jb print_drive                  # Yes
308         /*
309          * If this is the only drive, don't display it as an option.
310          */
311                 decw %ax                        # Already drive 0?
312                 jz print_prompt                 # Yes
313         /*
314          * If it was illegal or we cycled through them, go back to drive 0.
315          */
316                 xorb %al,%al                    # Drive 0
317         /*
318          * Whatever drive we selected, make it an ascii digit and save it
319          * back to the "nxtdrv" location in case we want to save it to disk.
320          * This digit is also part of the printed drive string, so add 0x80
321          * to indicate end of string.
322          */
323 print_drive:    addb $'0'|0x80,%al              # Save next
324                 movb %al,_NXTDRV(%bp)           #  drive number
325                 movw $drive,%di                 # Display
326                 callw putx                      #  item
327         /*
328          * Menu is complete, display a prompt followed by current selection.
329          * 'decw %si' makes the register point to the space after 'Boot: '
330          * so we do not see an extra CRLF on the screen.
331          */
332 print_prompt:   movw $prompt,%si                # Display
333                 callw putstr                    #  prompt
334                 movb _OPT(%bp),%dl              # Display
335                 decw %si                        #  default
336                 callw putkey                    #  key
337                 jmp start_input                 # Skip beep
338
339 /*
340  * Here we have the code waiting for user input or a timeout.
341  */
342 beep:           movb $ASCII_BEL,%al             # Input error, print or beep
343                 callw putchr
344
345 start_input:
346         /*
347          * Actual Start of input loop.  Take note of time
348          */
349                 xorb %ah,%ah                    # BIOS: Get
350                 int $0x1a                       #  system time
351                 movw %dx,%di                    # Ticks when
352                 addw _TICKS(%bp),%di            #  timeout
353 read_key:
354         /*
355          * Busy loop, looking for keystrokes but keeping one eye on the time.
356          */
357 #ifndef SIO
358                 movb $0x1,%ah                   # BIOS: Check
359                 int $0x16                       #  for keypress
360 #else /* SIO */
361                 movb $0x03,%ah                  # BIOS: Read COM
362                 call bioscom
363                 testb $0x01,%ah                 # Check line status
364                                                 # (bit 1 indicates input)
365 #endif /* SIO */
366                 jnz got_key                     # Have input
367                 xorb %ah,%ah                    # BIOS: int 0x1a, 00
368                 int $0x1a                       #  get system time
369                 cmpw %di,%dx                    # Timeout?
370                 jb read_key                     # No
371
372         /*
373          * Timed out or default selection
374          */
375 use_default:    movb _OPT(%bp),%al              # Load default
376                 orb $NOUPDATE,_FLAGS(%bp)       # Disable updates
377                 jmp check_selection             # Join common code
378
379         /*
380          * Get the keystroke.
381          * ENTER or CR confirm the current selection (same as a timeout).
382          * Otherwise convert F1..F6 (or '1'..'6') to 0..5 and check if the
383          * selection is valid.
384          * The SIO code uses ascii chars, the console code uses scancodes.
385          */
386 got_key:
387 #ifndef SIO
388                 xorb %ah,%ah                    # BIOS: int 0x16, 00
389                 int $0x16                       #  get keypress
390                 movb %ah,%al                    # move scan code to %al
391                 cmpb $KEY_ENTER,%al
392 #else
393                 movb $0x02,%ah                  # BIOS: Receive
394                 call bioscom
395                 cmpb $ASCII_CR,%al
396 #endif
397                 je use_default                  # enter -> default
398         /*
399          * Check if the key is acceptable, and loop back if not.
400          * The console (non-SIO) code looks at scancodes and accepts
401          * both F1..F6 and 1..6 (the latter costs 6 bytes of code),
402          * relying on the fact that F1..F6 have higher scancodes than 1..6
403          * The SIO code only takes 1..6
404          */
405 #ifdef SIO /* SIO mode, use ascii values */
406                 subb $'1',%al                   # Subtract '1' ascii code
407 #else /*  console mode -- use scancodes */
408                 subb $KEY_F1,%al                /* Subtract F1 scan code */
409 #if !defined(ONLY_F_KEYS)
410                 cmpb $0x5,%al                   # F1..F6
411                 jna 3f                          # Yes
412                 subb $(KEY_1 - KEY_F1),%al      # Less #1 scan code
413         3:
414 #endif /* ONLY_F_KEYS */
415 #endif /* SIO */
416 check_selection:
417                 cmpb $0x5,%al                   # F1..F6 or 1..6 ?
418 #ifdef PXE /* enable PXE/INT18 using F6 */
419                 jne 1f;
420                 int $0x18                       # found F6, try INT18
421         1:
422 #endif /* PXE */
423                 jae beep                        # Not in F1..F5, beep
424
425         /*
426          * We have a selection.  If it's a bad selection go back to complain.
427          * The bits in MNUOPT were set when the options were printed.
428          * Anything not printed is not an option.
429          */
430                 cbtw                            # Extend (%ah=0 used later)
431                 btw %ax,_MNUOPT(%bp)            # Option enabled?
432                 jnc beep                        # No
433         /*
434          * Save the info in the original tables
435          * for rewriting to the disk.
436          */
437                 movb %al,_OPT(%bp)              # Save option
438
439         /*
440          * Make %si and %bx point to the fake partition at LBA 0 (CHS 0:0:1).
441          * Because the correct address is already in %bp, just use it.
442          * Set %dl with the drive number saved in byte 0.
443          * If we have pressed F5 or 5, then this is a good, fake value
444          * to present to the next stage boot code.
445          */
446                 movw %bp,%si                    # Partition for write
447                 movb (%si),%dl                  # Drive number, saved above
448                 movw %si,%bx                    # Partition for read
449                 cmpb $0x4,%al                   # F5/#5 pressed?
450                 pushf                           # Save results for later
451                 je 1f                           # Yes, F5
452
453         /*
454          * F1..F4 was pressed, so make %bx point to the currently
455          * selected partition, and leave the drive number unchanged.
456          */
457                 shlb $0x4,%al                   # Point to
458                 addw $partbl,%ax                #  selected
459                 xchgw %bx,%ax                   #  partition
460                 movb $0x80,(%bx)                # Flag active
461         /*
462          * If not asked to do a write-back (flags 0x40) don't do one.
463          * Around the call, save the partition pointer to %bx and
464          * restore to %si which is where the next stage expects it.
465          */
466         1:      pushw %bx                       # Save
467                 testb $NOUPDATE,_FLAGS(%bp)     # No updates?
468                 jnz 2f                          # skip update
469                 movw $start,%bx                 # Data to write
470                 movb $0x3,%ah                   # Write sector
471                 callw intx13                    #  to disk
472         2:      popw %si                        # Restore
473
474         /*
475          * If going to next drive, replace drive with selected one.
476          * Remember to un-ascii it. Hey 0x80 is already set, cool!
477          */
478                 popf                            # Restore %al test results
479                 jne 3f                          # If not F5/#5
480                 movb _NXTDRV(%bp),%dl           # Next drive
481                 subb $'0',%dl                   #  number
482         /*
483          * Load selected bootsector to the LOAD location in RAM. If read
484          * fails or there is no 0x55aa marker, treat it as a bad selection.
485          */
486         3:      movw $LOAD,%bx                  # Address for read
487                 movb $0x2,%ah                   # Read sector
488                 callw intx13                    #  from disk
489                 jc beep                         # If error
490                 cmpw $MAGIC,0x1fe(%bx)          # Bootable?
491                 jne beep                        # No
492                 pushw %si                       # Save ptr to selected part.
493                 callw putn                      # Leave some space
494                 popw %si                        # Restore, next stage uses it
495                 jmp *%bx                        # Invoke bootstrap
496
497 /*
498  * Display routines
499  * putkey       prints the option selected in %dl (F1..F5 or 1..5) followed by
500  *              the string at %si
501  * putx:        print the option in %dl followed by the string at %di
502  *              also record the drive as valid.
503  * putn:        print a crlf
504  * putstr:      print the string at %si
505  * putchr:      print the char in al
506  */
507
508 /*
509  * Display the option and record the drive as valid in the options.
510  * That last point is done using the btsw instruction which does
511  * a test and set. We don't care for the test part.
512  */
513 putx:           btsw %dx,_MNUOPT(%bp)           # Enable menu option
514                 movw $item,%si                  # Display
515                 callw putkey                    #  key
516                 movw %di,%si                    # Display the rest
517                 callw putstr                    # Display string
518
519 putn:           movw $crlf,%si                  # To next line
520                 jmp putstr
521
522 putkey:
523 #ifndef SIO
524                 movb $'F',%al                   # Display
525                 callw putchr                    #  'F'
526 #endif
527                 movb $'1',%al                   # Prepare
528                 addb %dl,%al                    #  digit
529
530 putstr.1:       callw putchr                    # Display char
531 putstr:         lodsb                           # Get byte
532                 testb $0x80,%al                 # End of string?
533                 jz putstr.1                     # No
534                 andb $~0x80,%al                 # Clear MSB then print last 
535
536 putchr:
537 #ifndef SIO
538                 pushw %bx                       # Save
539                 movw $0x7,%bx                   # Page:attribute
540                 movb $0xe,%ah                   # BIOS: Display
541                 int $0x10                       #  character
542                 popw %bx                        # Restore
543 #else /* SIO */
544                 movb $0x01,%ah                  # BIOS: Send
545 bioscom:
546                 pushw %dx                       # Save
547                 xorw %dx,%dx                    # Use COM1
548                 int $0x14                       #  Character
549                 popw %dx                        # Restore
550 #endif /* SIO */
551                 retw                            # To caller
552
553 /* One-sector disk I/O routine */
554
555 /*
556  * %dl: drive, %si partition entry, %es:%bx transfer buffer.
557  * Load the CHS values and possibly the LBA address from the block
558  * at %si, and use the appropriate method to load the sector.
559  * Don't use packet mode for a floppy.
560  */
561 intx13:                                         # Prepare CHS parameters
562                 movb 0x1(%si),%dh               # Load head
563                 movw 0x2(%si),%cx               # Load cylinder:sector
564                 movb $0x1,%al                   # Sector count
565                 pushw %si                       # Save
566                 movw %sp,%di                    # Save
567 #ifndef CHECK_DRIVE                             /* floppy support */
568                 testb %dl, %dl                  # is this a floppy ?
569                 jz 1f                           # Yes, use CHS mode
570 #endif
571                 testb $USEPACKET,_FLAGS(%bp)    # Use packet interface?
572                 jz 1f                           # No
573                 pushl $0x0                      # Set the
574                 pushl 0x8(%si)                  # LBA address
575                 pushw %es                       # Set the transfer
576                 pushw %bx                       #  buffer address
577                 push  $0x1                      # Block count
578                 push  $0x10                     # Packet size
579                 movw %sp,%si                    # Packet pointer
580                 decw %ax                        # Verify off
581                 orb $0x40,%ah                   # Use disk packet
582         1:      int $0x13                       # BIOS: Disk I/O
583                 movw %di,%sp                    # Restore
584                 popw %si                        # Restore
585                 retw                            # To caller
586
587 /*
588  * Various menu strings. 'item' goes after 'prompt' to save space.
589  * Also use shorter versions to make room for the PXE/INT18 code.
590  */
591 prompt:
592 #ifdef PXE
593                 .ascii "\nF6 PXE\r"
594 #endif
595                 .ascii "\nBoot:"
596 item:           .ascii " ";          .byte ' '|0x80
597 crlf:           .ascii "\r";         .byte '\n'|0x80
598
599 /* Partition type tables */
600
601 bootable_ids:
602         /*
603          * These values indicate bootable types we know about.
604          * Corresponding descriptions are at desc_ofs:
605          * Entries don't need to be sorted.
606          */
607                 .byte 0x83, 0xa5, 0xa6, 0xa9, 0x06, 0x07, 0x0b
608 #ifndef SAVE_MORE_MEMORY
609                 .byte 0x05      # extended partition
610 #endif
611 #ifndef SAVE_MEMORY     /* other DOS partitions */
612                 .byte 0x01      # FAT12
613                 .byte 0x04      # FAT16 < 32M
614 #endif
615
616 desc_ofs:
617         /*
618          * Offsets that match the known types above, used to point to the
619          * actual partition name. The last entry must point to os_misc,
620          * which is used for non-matching names.
621          */
622                 .byte os_linux-.                # 131, Linux
623                 .byte os_freebsd-.              # 165, FreeBSD
624                 .byte os_bsd-.                  # 166, OpenBSD
625                 .byte os_bsd-.                  # 169, NetBSD
626                 .byte os_dos-.                  #   6, FAT16 >= 32M
627                 .byte os_win-.                  #   7, NTFS
628                 .byte os_win-.                  #  11, FAT32
629
630 #ifndef SAVE_MORE_MEMORY
631                 .byte os_ext-.                  #   5, DOS Ext
632 #endif
633 #ifndef SAVE_MEMORY
634                 .byte os_dos-.                  #   1, FAT12 DOS
635                 .byte os_dos-.                  #   4, FAT16 <32M
636 #endif
637                 .byte os_misc-.                 # Unknown
638
639         /*
640          * And here are the strings themselves. The last byte of
641          * the string has bit 7 set.
642          */
643 os_misc:        .byte '?'|0x80
644 os_dos:
645 #ifndef SAVE_MORE_MEMORY        /* 'DOS' remapped to 'WIN' if no room */
646                 .ascii "DO";   .byte 'S'|0x80
647 #endif
648 os_win:         .ascii "Wi";   .byte 'n'|0x80
649 os_linux:       .ascii "Linu"; .byte 'x'|0x80
650 os_freebsd:     .ascii "Free"
651 os_bsd:         .ascii "BS";   .byte 'D'|0x80
652 #ifndef SAVE_MORE_MEMORY
653 os_ext:         .ascii "EX";   .byte 'T'|0x80
654 #endif
655
656                 .org (0x200 + B0_OFF),0x90
657 /*
658  * The boot0 version 1.0 parameter table.
659  * Do not move it nor change the "Drive " string, boot0cfg
660  * uses its offset and content to identify the boot sector.
661  * The other fields are sometimes changed before writing back to the drive
662  * Be especially careful that nxtdrv: must come after drive:, as it
663  * is part of the same string.
664  */
665 drive:          .ascii "Drive "
666 nxtdrv:         .byte 0x0                       # Next drive number
667 opt:            .byte 0x0                       # Option
668 setdrv_num:     .byte 0x80                      # Drive to force
669 flags:          .byte FLAGS                     # Flags
670 #ifdef VOLUME_SERIAL
671                 .byte 0xa8,0xa8,0xa8,0xa8       # Volume Serial Number
672 #endif
673 ticks:          .word TICKS                     # Delay
674
675                 .org PRT_OFF
676 /*
677  * Here is the 64 byte partition table that fdisk would fiddle with.
678  */
679 partbl:         .fill 0x40,0x1,0x0              # Partition table
680                 .word MAGIC                     # Magic number
681                 .org 0x200                      # again, safety check
682 endblock: