You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

int13.c 18KB

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