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 */ 181start: 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 210main: 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 */ 238disable_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 */ 247save_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 */ 268read_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 295next_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 */ 323print_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 */ 332print_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 */ 342beep: movb $ASCII_BEL,%al # Input error, print or beep 343 callw putchr 344 345start_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 353read_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 */ 375use_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 */ 386got_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 */ 416check_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 */ 513putx: 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 519putn: movw $crlf,%si # To next line 520 jmp putstr 521 522putkey: 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 530putstr.1: callw putchr # Display char 531putstr: 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 536putchr: 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 character 545bioscom: 546 pushw %dx # Save 547 xorw %dx,%dx # Use COM1 548 int $0x14 # BIOS: Serial I/O 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 */ 561intx13: # 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 */ 591prompt: 592#ifdef PXE 593 .ascii "\nF6 PXE\r" 594#endif 595 .ascii "\nBoot:" 596item: .ascii " "; .byte ' '|0x80 597crlf: .ascii "\r"; .byte '\n'|0x80 598 599/* Partition type tables */ 600 601bootable_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 616desc_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 */ 643os_misc: .byte '?'|0x80 644os_dos: 645#ifndef SAVE_MORE_MEMORY /* 'DOS' remapped to 'WIN' if no room */ 646 .ascii "DO"; .byte 'S'|0x80 647#endif 648os_win: .ascii "Wi"; .byte 'n'|0x80 649os_linux: .ascii "Linu"; .byte 'x'|0x80 650os_freebsd: .ascii "Free" 651os_bsd: .ascii "BS"; .byte 'D'|0x80 652#ifndef SAVE_MORE_MEMORY 653os_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 */ 665drive: .ascii "Drive " 666nxtdrv: .byte 0x0 # Next drive number 667opt: .byte 0x0 # Option 668setdrv_num: .byte 0x80 # Drive to force 669flags: .byte FLAGS # Flags 670#ifdef VOLUME_SERIAL 671 .byte 0xa8,0xa8,0xa8,0xa8 # Volume Serial Number 672#endif 673ticks: .word TICKS # Delay 674 675 .org PRT_OFF 676/* 677 * Here is the 64 byte partition table that fdisk would fiddle with. 678 */ 679partbl: .fill 0x40,0x1,0x0 # Partition table 680 .word MAGIC # Magic number 681 .org 0x200 # again, safety check 682endblock: 683