1 /* 2 * Copyright (C) 2006 Michael Brown <mbrown (at) fensystems.co.uk>. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation; either version 2 of the 7 * License, or any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 */ 18 19 FILE_LICENCE ( GPL2_OR_LATER ); 20 21 #include <stdint.h> 22 #include <limits.h> 23 #include <byteswap.h> 24 #include <errno.h> 25 #include <assert.h> 26 #include <gpxe/list.h> 27 #include <gpxe/blockdev.h> 28 #include <gpxe/memmap.h> 29 #include <realmode.h> 30 #include <bios.h> 31 #include <biosint.h> 32 #include <bootsector.h> 33 #include <int13.h> 34 35 /** @file 36 * 37 * INT 13 emulation 38 * 39 * This module provides a mechanism for exporting block devices via 40 * the BIOS INT 13 disk interrupt interface. 41 * 42 */ 43 44 /** Vector for chaining to other INT 13 handlers */ 45 static struct segoff __text16 ( int13_vector ); 46 #define int13_vector __use_text16 ( int13_vector ) 47 48 /** Assembly wrapper */ 49 extern void int13_wrapper ( void ); 50 51 /** List of registered emulated drives */ 52 static LIST_HEAD ( drives ); 53 54 /** 55 * Number of BIOS drives 56 * 57 * Note that this is the number of drives in the system as a whole 58 * (i.e. a mirror of the counter at 40:75), rather than a count of the 59 * number of emulated drives. 60 */ 61 static uint8_t num_drives; 62 63 /** 64 * Update BIOS drive count 65 */ 66 static void int13_set_num_drives ( void ) { 67 struct int13_drive *drive; 68 69 /* Get current drive count */ 70 get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES ); 71 72 /* Ensure count is large enough to cover all of our emulated drives */ 73 list_for_each_entry ( drive, &drives, list ) { 74 if ( num_drives <= ( drive->drive & 0x7f ) ) 75 num_drives = ( ( drive->drive & 0x7f ) + 1 ); 76 } 77 78 /* Update current drive count */ 79 put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES ); 80 } 81 82 /** 83 * Check number of drives 84 */ 85 static void int13_check_num_drives ( void ) { 86 uint8_t check_num_drives; 87 88 get_real ( check_num_drives, BDA_SEG, BDA_NUM_DRIVES ); 89 if ( check_num_drives != num_drives ) { 90 int13_set_num_drives(); 91 DBG ( "INT13 fixing up number of drives from %d to %d\n", 92 check_num_drives, num_drives ); 93 } 94 } 95 96 /** 97 * INT 13, 00 - Reset disk system 98 * 99 * @v drive Emulated drive 100 * @ret status Status code 101 */ 102 static int int13_reset ( struct int13_drive *drive __unused, 103 struct i386_all_regs *ix86 __unused ) { 104 DBG ( "Reset drive\n" ); 105 return 0; 106 } 107 108 /** 109 * INT 13, 01 - Get status of last operation 110 * 111 * @v drive Emulated drive 112 * @ret status Status code 113 */ 114 static int int13_get_last_status ( struct int13_drive *drive, 115 struct i386_all_regs *ix86 __unused ) { 116 DBG ( "Get status of last operation\n" ); 117 return drive->last_status; 118 } 119 120 /** 121 * Read / write sectors 122 * 123 * @v drive Emulated drive 124 * @v al Number of sectors to read or write (must be nonzero) 125 * @v ch Low bits of cylinder number 126 * @v cl (bits 7:6) High bits of cylinder number 127 * @v cl (bits 5:0) Sector number 128 * @v dh Head number 129 * @v es:bx Data buffer 130 * @v io Read / write method 131 * @ret status Status code 132 * @ret al Number of sectors read or written 133 */ 134 static int int13_rw_sectors ( struct int13_drive *drive, 135 struct i386_all_regs *ix86, 136 int ( * io ) ( struct block_device *blockdev, 137 uint64_t block, 138 unsigned long count, 139 userptr_t buffer ) ) { 140 struct block_device *blockdev = drive->blockdev; 141 unsigned int cylinder, head, sector; 142 unsigned long lba; 143 unsigned int count; 144 userptr_t buffer; 145 int rc; 146 147 /* Validate blocksize */ 148 if ( blockdev->blksize != INT13_BLKSIZE ) { 149 DBG ( "Invalid blocksize (%zd) for non-extended read/write\n", 150 blockdev->blksize ); 151 return -INT13_STATUS_INVALID; 152 } 153 154 /* Calculate parameters */ 155 cylinder = ( ( ( ix86->regs.cl & 0xc0 ) << 2 ) | ix86->regs.ch ); 156 assert ( cylinder < drive->cylinders ); 157 head = ix86->regs.dh; 158 assert ( head < drive->heads ); 159 sector = ( ix86->regs.cl & 0x3f ); 160 assert ( ( sector >= 1 ) && ( sector <= drive->sectors_per_track ) ); 161 lba = ( ( ( ( cylinder * drive->heads ) + head ) 162 * drive->sectors_per_track ) + sector - 1 ); 163 count = ix86->regs.al; 164 buffer = real_to_user ( ix86->segs.es, ix86->regs.bx ); 165 166 DBG ( "C/H/S %d/%d/%d = LBA %#lx <-> %04x:%04x (count %d)\n", cylinder, 167 head, sector, lba, ix86->segs.es, ix86->regs.bx, count ); 168 169 /* Read from / write to block device */ 170 if ( ( rc = io ( blockdev, lba, count, buffer ) ) != 0 ) { 171 DBG ( "INT 13 failed: %s\n", strerror ( rc ) ); 172 return -INT13_STATUS_READ_ERROR; 173 } 174 175 return 0; 176 } 177 178 /** 179 * INT 13, 02 - Read sectors 180 * 181 * @v drive Emulated drive 182 * @v al Number of sectors to read (must be nonzero) 183 * @v ch Low bits of cylinder number 184 * @v cl (bits 7:6) High bits of cylinder number 185 * @v cl (bits 5:0) Sector number 186 * @v dh Head number 187 * @v es:bx Data buffer 188 * @ret status Status code 189 * @ret al Number of sectors read 190 */ 191 static int int13_read_sectors ( struct int13_drive *drive, 192 struct i386_all_regs *ix86 ) { 193 DBG ( "Read: " ); 194 return int13_rw_sectors ( drive, ix86, drive->blockdev->op->read ); 195 } 196 197 /** 198 * INT 13, 03 - Write sectors 199 * 200 * @v drive Emulated drive 201 * @v al Number of sectors to write (must be nonzero) 202 * @v ch Low bits of cylinder number 203 * @v cl (bits 7:6) High bits of cylinder number 204 * @v cl (bits 5:0) Sector number 205 * @v dh Head number 206 * @v es:bx Data buffer 207 * @ret status Status code 208 * @ret al Number of sectors written 209 */ 210 static int int13_write_sectors ( struct int13_drive *drive, 211 struct i386_all_regs *ix86 ) { 212 DBG ( "Write: " ); 213 return int13_rw_sectors ( drive, ix86, drive->blockdev->op->write ); 214 } 215 216 /** 217 * INT 13, 08 - Get drive parameters 218 * 219 * @v drive Emulated drive 220 * @ret status Status code 221 * @ret ch Low bits of maximum cylinder number 222 * @ret cl (bits 7:6) High bits of maximum cylinder number 223 * @ret cl (bits 5:0) Maximum sector number 224 * @ret dh Maximum head number 225 * @ret dl Number of drives 226 */ 227 static int int13_get_parameters ( struct int13_drive *drive, 228 struct i386_all_regs *ix86 ) { 229 unsigned int max_cylinder = drive->cylinders - 1; 230 unsigned int max_head = drive->heads - 1; 231 unsigned int max_sector = drive->sectors_per_track; /* sic */ 232 233 DBG ( "Get drive parameters\n" ); 234 235 ix86->regs.ch = ( max_cylinder & 0xff ); 236 ix86->regs.cl = ( ( ( max_cylinder >> 8 ) << 6 ) | max_sector ); 237 ix86->regs.dh = max_head; 238 get_real ( ix86->regs.dl, BDA_SEG, BDA_NUM_DRIVES ); 239 return 0; 240 } 241 242 /** 243 * INT 13, 15 - Get disk type 244 * 245 * @v drive Emulated drive 246 * @ret ah Type code 247 * @ret cx:dx Sector count 248 * @ret status Status code / disk type 249 */ 250 static int int13_get_disk_type ( struct int13_drive *drive, 251 struct i386_all_regs *ix86 ) { 252 uint32_t blocks; 253 254 DBG ( "Get disk type\n" ); 255 blocks = ( ( drive->blockdev->blocks <= 0xffffffffUL ) ? 256 drive->blockdev->blocks : 0xffffffffUL ); 257 ix86->regs.cx = ( blocks >> 16 ); 258 ix86->regs.dx = ( blocks & 0xffff ); 259 return INT13_DISK_TYPE_HDD; 260 } 261 262 /** 263 * INT 13, 41 - Extensions installation check 264 * 265 * @v drive Emulated drive 266 * @v bx 0x55aa 267 * @ret bx 0xaa55 268 * @ret cx Extensions API support bitmap 269 * @ret status Status code / API version 270 */ 271 static int int13_extension_check ( struct int13_drive *drive __unused, 272 struct i386_all_regs *ix86 ) { 273 if ( ix86->regs.bx == 0x55aa ) { 274 DBG ( "INT 13 extensions installation check\n" ); 275 ix86->regs.bx = 0xaa55; 276 ix86->regs.cx = INT13_EXTENSION_LINEAR; 277 return INT13_EXTENSION_VER_1_X; 278 } else { 279 return -INT13_STATUS_INVALID; 280 } 281 } 282 283 /** 284 * Extended read / write 285 * 286 * @v drive Emulated drive 287 * @v ds:si Disk address packet 288 * @v io Read / write method 289 * @ret status Status code 290 */ 291 static int int13_extended_rw ( struct int13_drive *drive, 292 struct i386_all_regs *ix86, 293 int ( * io ) ( struct block_device *blockdev, 294 uint64_t block, 295 unsigned long count, 296 userptr_t buffer ) ) { 297 struct block_device *blockdev = drive->blockdev; 298 struct int13_disk_address addr; 299 uint64_t lba; 300 unsigned long count; 301 userptr_t buffer; 302 int rc; 303 304 /* Read parameters from disk address structure */ 305 copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si, sizeof ( addr )); 306 lba = addr.lba; 307 count = addr.count; 308 buffer = real_to_user ( addr.buffer.segment, addr.buffer.offset ); 309 310 DBG ( "LBA %#llx <-> %04x:%04x (count %ld)\n", (unsigned long long)lba, 311 addr.buffer.segment, addr.buffer.offset, count ); 312 313 /* Read from / write to block device */ 314 if ( ( rc = io ( blockdev, lba, count, buffer ) ) != 0 ) { 315 DBG ( "INT 13 failed: %s\n", strerror ( rc ) ); 316 return -INT13_STATUS_READ_ERROR; 317 } 318 319 return 0; 320 } 321 322 /** 323 * INT 13, 42 - Extended read 324 * 325 * @v drive Emulated drive 326 * @v ds:si Disk address packet 327 * @ret status Status code 328 */ 329 static int int13_extended_read ( struct int13_drive *drive, 330 struct i386_all_regs *ix86 ) { 331 DBG ( "Extended read: " ); 332 return int13_extended_rw ( drive, ix86, drive->blockdev->op->read ); 333 } 334 335 /** 336 * INT 13, 43 - Extended write 337 * 338 * @v drive Emulated drive 339 * @v ds:si Disk address packet 340 * @ret status Status code 341 */ 342 static int int13_extended_write ( struct int13_drive *drive, 343 struct i386_all_regs *ix86 ) { 344 DBG ( "Extended write: " ); 345 return int13_extended_rw ( drive, ix86, drive->blockdev->op->write ); 346 } 347 348 /** 349 * INT 13, 48 - Get extended parameters 350 * 351 * @v drive Emulated drive 352 * @v ds:si Drive parameter table 353 * @ret status Status code 354 */ 355 static int int13_get_extended_parameters ( struct int13_drive *drive, 356 struct i386_all_regs *ix86 ) { 357 struct int13_disk_parameters params = { 358 .bufsize = sizeof ( params ), 359 .flags = INT13_FL_DMA_TRANSPARENT, 360 .cylinders = drive->cylinders, 361 .heads = drive->heads, 362 .sectors_per_track = drive->sectors_per_track, 363 .sectors = drive->blockdev->blocks, 364 .sector_size = drive->blockdev->blksize, 365 }; 366 367 DBG ( "Get extended drive parameters to %04x:%04x\n", 368 ix86->segs.ds, ix86->regs.si ); 369 370 copy_to_real ( ix86->segs.ds, ix86->regs.si, ¶ms, 371 sizeof ( params ) ); 372 return 0; 373 } 374 375 /** 376 * INT 13 handler 377 * 378 */ 379 static __asmcall void int13 ( struct i386_all_regs *ix86 ) { 380 int command = ix86->regs.ah; 381 unsigned int bios_drive = ix86->regs.dl; 382 struct int13_drive *drive; 383 int status; 384 385 /* Check BIOS hasn't killed off our drive */ 386 int13_check_num_drives(); 387 388 list_for_each_entry ( drive, &drives, list ) { 389 390 if ( bios_drive != drive->drive ) { 391 /* Remap any accesses to this drive's natural number */ 392 if ( bios_drive == drive->natural_drive ) { 393 DBG ( "INT 13,%04x (%02x) remapped to " 394 "(%02x)\n", ix86->regs.ax, 395 bios_drive, drive->drive ); 396 ix86->regs.dl = drive->drive; 397 return; 398 } 399 continue; 400 } 401 402 DBG ( "INT 13,%04x (%02x): ", ix86->regs.ax, drive->drive ); 403 404 switch ( command ) { 405 case INT13_RESET: 406 status = int13_reset ( drive, ix86 ); 407 break; 408 case INT13_GET_LAST_STATUS: 409 status = int13_get_last_status ( drive, ix86 ); 410 break; 411 case INT13_READ_SECTORS: 412 status = int13_read_sectors ( drive, ix86 ); 413 break; 414 case INT13_WRITE_SECTORS: 415 status = int13_write_sectors ( drive, ix86 ); 416 break; 417 case INT13_GET_PARAMETERS: 418 status = int13_get_parameters ( drive, ix86 ); 419 break; 420 case INT13_GET_DISK_TYPE: 421 status = int13_get_disk_type ( drive, ix86 ); 422 break; 423 case INT13_EXTENSION_CHECK: 424 status = int13_extension_check ( drive, ix86 ); 425 break; 426 case INT13_EXTENDED_READ: 427 status = int13_extended_read ( drive, ix86 ); 428 break; 429 case INT13_EXTENDED_WRITE: 430 status = int13_extended_write ( drive, ix86 ); 431 break; 432 case INT13_GET_EXTENDED_PARAMETERS: 433 status = int13_get_extended_parameters ( drive, ix86 ); 434 break; 435 default: 436 DBG ( "*** Unrecognised INT 13 ***\n" ); 437 status = -INT13_STATUS_INVALID; 438 break; 439 } 440 441 /* Store status for INT 13,01 */ 442 drive->last_status = status; 443 444 /* Negative status indicates an error */ 445 if ( status < 0 ) { 446 status = -status; 447 DBG ( "INT 13 returning failure status %x\n", status ); 448 } else { 449 ix86->flags &= ~CF; 450 } 451 ix86->regs.ah = status; 452 453 /* Set OF to indicate to wrapper not to chain this call */ 454 ix86->flags |= OF; 455 456 return; 457 } 458 } 459 460 /** 461 * Hook INT 13 handler 462 * 463 */ 464 static void hook_int13 ( void ) { 465 /* Assembly wrapper to call int13(). int13() sets OF if we 466 * should not chain to the previous handler. (The wrapper 467 * clears CF and OF before calling int13()). 468 */ 469 __asm__ __volatile__ ( 470 TEXT16_CODE ( "\nint13_wrapper:\n\t" 471 /* Preserve %ax and %dx for future reference */ 472 "pushw %%bp\n\t" 473 "movw %%sp, %%bp\n\t" 474 "pushw %%ax\n\t" 475 "pushw %%dx\n\t" 476 /* Clear OF, set CF, call int13() */ 477 "orb $0, %%al\n\t" 478 "stc\n\t" 479 "pushl %0\n\t" 480 "pushw %%cs\n\t" 481 "call prot_call\n\t" 482 /* Chain if OF not set */ 483 "jo 1f\n\t" 484 "pushfw\n\t" 485 "lcall *%%cs:int13_vector\n\t" 486 "\n1:\n\t" 487 /* Overwrite flags for iret */ 488 "pushfw\n\t" 489 "popw 6(%%bp)\n\t" 490 /* Fix up %dl: 491 * 492 * INT 13,15 : do nothing 493 * INT 13,08 : load with number of drives 494 * all others: restore original value 495 */ 496 "cmpb $0x15, -1(%%bp)\n\t" 497 "je 2f\n\t" 498 "movb -4(%%bp), %%dl\n\t" 499 "cmpb $0x08, -1(%%bp)\n\t" 500 "jne 2f\n\t" 501 "pushw %%ds\n\t" 502 "pushw %1\n\t" 503 "popw %%ds\n\t" 504 "movb %c2, %%dl\n\t" 505 "popw %%ds\n\t" 506 /* Return */ 507 "\n2:\n\t" 508 "movw %%bp, %%sp\n\t" 509 "popw %%bp\n\t" 510 "iret\n\t" ) 511 : : "i" ( int13 ), "i" ( BDA_SEG ), "i" ( BDA_NUM_DRIVES ) ); 512 513 hook_bios_interrupt ( 0x13, ( unsigned int ) int13_wrapper, 514 &int13_vector ); 515 } 516 517 /** 518 * Unhook INT 13 handler 519 */ 520 static void unhook_int13 ( void ) { 521 unhook_bios_interrupt ( 0x13, ( unsigned int ) int13_wrapper, 522 &int13_vector ); 523 } 524 525 /** 526 * Guess INT 13 drive geometry 527 * 528 * @v drive Emulated drive 529 * 530 * Guesses the drive geometry by inspecting the partition table. 531 */ 532 static void guess_int13_geometry ( struct int13_drive *drive ) { 533 struct master_boot_record mbr; 534 struct partition_table_entry *partition; 535 unsigned int guessed_heads = 255; 536 unsigned int guessed_sectors_per_track = 63; 537 unsigned long blocks; 538 unsigned long blocks_per_cyl; 539 unsigned int i; 540 541 /* Don't even try when the blksize is invalid for C/H/S access */ 542 if ( drive->blockdev->blksize != INT13_BLKSIZE ) 543 return; 544 545 /* Scan through partition table and modify guesses for heads 546 * and sectors_per_track if we find any used partitions. 547 */ 548 if ( drive->blockdev->op->read ( drive->blockdev, 0, 1, 549 virt_to_user ( &mbr ) ) == 0 ) { 550 for ( i = 0 ; i < 4 ; i++ ) { 551 partition = &mbr.partitions[i]; 552 if ( ! partition->type ) 553 continue; 554 guessed_heads = 555 ( PART_HEAD ( partition->chs_end ) + 1 ); 556 guessed_sectors_per_track = 557 PART_SECTOR ( partition->chs_end ); 558 DBG ( "Guessing C/H/S xx/%d/%d based on partition " 559 "%d\n", guessed_heads, 560 guessed_sectors_per_track, ( i + 1 ) ); 561 } 562 } else { 563 DBG ( "Could not read partition table to guess geometry\n" ); 564 } 565 566 /* Apply guesses if no geometry already specified */ 567 if ( ! drive->heads ) 568 drive->heads = guessed_heads; 569 if ( ! drive->sectors_per_track ) 570 drive->sectors_per_track = guessed_sectors_per_track; 571 if ( ! drive->cylinders ) { 572 /* Avoid attempting a 64-bit divide on a 32-bit system */ 573 blocks = ( ( drive->blockdev->blocks <= ULONG_MAX ) ? 574 drive->blockdev->blocks : ULONG_MAX ); 575 blocks_per_cyl = ( drive->heads * drive->sectors_per_track ); 576 assert ( blocks_per_cyl != 0 ); 577 drive->cylinders = ( blocks / blocks_per_cyl ); 578 if ( drive->cylinders > 1024 ) 579 drive->cylinders = 1024; 580 } 581 } 582 583 /** 584 * Register INT 13 emulated drive 585 * 586 * @v drive Emulated drive 587 * 588 * Registers the drive with the INT 13 emulation subsystem, and hooks 589 * the INT 13 interrupt vector (if not already hooked). 590 * 591 * The underlying block device must be valid. A drive number and 592 * geometry will be assigned if left blank. 593 */ 594 void register_int13_drive ( struct int13_drive *drive ) { 595 uint8_t num_drives; 596 597 /* Give drive a default geometry if none specified */ 598 guess_int13_geometry ( drive ); 599 600 /* Assign natural drive number */ 601 get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES ); 602 drive->natural_drive = ( num_drives | 0x80 ); 603 604 /* Assign drive number */ 605 if ( ( drive->drive & 0xff ) == 0xff ) { 606 /* Drive number == -1 => use natural drive number */ 607 drive->drive = drive->natural_drive; 608 } else { 609 /* Use specified drive number (+0x80 if necessary) */ 610 drive->drive |= 0x80; 611 } 612 613 DBG ( "Registered INT13 drive %02x (naturally %02x) with C/H/S " 614 "geometry %d/%d/%d\n", drive->drive, drive->natural_drive, 615 drive->cylinders, drive->heads, drive->sectors_per_track ); 616 617 /* Hook INT 13 vector if not already hooked */ 618 if ( list_empty ( &drives ) ) 619 hook_int13(); 620 621 /* Add to list of emulated drives */ 622 list_add ( &drive->list, &drives ); 623 624 /* Update BIOS drive count */ 625 int13_set_num_drives(); 626 } 627 628 /** 629 * Unregister INT 13 emulated drive 630 * 631 * @v drive Emulated drive 632 * 633 * Unregisters the drive from the INT 13 emulation subsystem. If this 634 * is the last emulated drive, the INT 13 vector is unhooked (if 635 * possible). 636 */ 637 void unregister_int13_drive ( struct int13_drive *drive ) { 638 /* Remove from list of emulated drives */ 639 list_del ( &drive->list ); 640 641 /* Should adjust BIOS drive count, but it's difficult to do so 642 * reliably. 643 */ 644 645 DBG ( "Unregistered INT13 drive %02x\n", drive->drive ); 646 647 /* Unhook INT 13 vector if no more drives */ 648 if ( list_empty ( &drives ) ) 649 unhook_int13(); 650 } 651 652 /** 653 * Attempt to boot from an INT 13 drive 654 * 655 * @v drive Drive number 656 * @ret rc Return status code 657 * 658 * This boots from the specified INT 13 drive by loading the Master 659 * Boot Record to 0000:7c00 and jumping to it. INT 18 is hooked to 660 * capture an attempt by the MBR to boot the next device. (This is 661 * the closest thing to a return path from an MBR). 662 * 663 * Note that this function can never return success, by definition. 664 */ 665 int int13_boot ( unsigned int drive ) { 666 struct memory_map memmap; 667 int status, signature; 668 int discard_c, discard_d; 669 int rc; 670 671 DBG ( "Booting from INT 13 drive %02x\n", drive ); 672 673 /* Use INT 13 to read the boot sector */ 674 __asm__ __volatile__ ( REAL_CODE ( "pushw %%es\n\t" 675 "pushw $0\n\t" 676 "popw %%es\n\t" 677 "stc\n\t" 678 "sti\n\t" 679 "int $0x13\n\t" 680 "sti\n\t" /* BIOS bugs */ 681 "jc 1f\n\t" 682 "xorl %%eax, %%eax\n\t" 683 "\n1:\n\t" 684 "movzwl %%es:0x7dfe, %%ebx\n\t" 685 "popw %%es\n\t" ) 686 : "=a" ( status ), "=b" ( signature ), 687 "=c" ( discard_c ), "=d" ( discard_d ) 688 : "a" ( 0x0201 ), "b" ( 0x7c00 ), 689 "c" ( 1 ), "d" ( drive ) ); 690 if ( status ) 691 return -EIO; 692 693 /* Check signature is correct */ 694 if ( signature != be16_to_cpu ( 0x55aa ) ) { 695 DBG ( "Invalid disk signature %#04x (should be 0x55aa)\n", 696 cpu_to_be16 ( signature ) ); 697 return -ENOEXEC; 698 } 699 700 /* Dump out memory map prior to boot, if memmap debugging is 701 * enabled. Not required for program flow, but we have so 702 * many problems that turn out to be memory-map related that 703 * it's worth doing. 704 */ 705 get_memmap ( &memmap ); 706 707 /* Jump to boot sector */ 708 if ( ( rc = call_bootsector ( 0x0, 0x7c00, drive ) ) != 0 ) { 709 DBG ( "INT 13 drive %02x boot returned: %s\n", 710 drive, strerror ( rc ) ); 711 return rc; 712 } 713 714 return -ECANCELED; /* -EIMPOSSIBLE */ 715 } 716