#include <stdint.h>
#include <limits.h>
#include <byteswap.h>
#include <errno.h>
#include <assert.h>
#include <gpxe/list.h>
#include <gpxe/blockdev.h>
#include <gpxe/memmap.h>
#include <realmode.h>
#include <bios.h>
#include <biosint.h>
#include <bootsector.h>
#include <int13.h>
Go to the source code of this file.
Defines | |
| #define | int13_vector __use_text16 ( int13_vector ) |
Functions | |
| FILE_LICENCE (GPL2_OR_LATER) | |
| static struct segoff | __text16 (int13_vector) |
| Vector for chaining to other INT 13 handlers. | |
| void | int13_wrapper (void) |
| Assembly wrapper. | |
| static | LIST_HEAD (drives) |
| List of registered emulated drives. | |
| static void | int13_set_num_drives (void) |
| Update BIOS drive count. | |
| static void | int13_check_num_drives (void) |
| Check number of drives. | |
| static int | int13_reset (struct int13_drive *drive __unused, struct i386_all_regs *ix86 __unused) |
| INT 13, 00 - Reset disk system. | |
| static int | int13_get_last_status (struct int13_drive *drive, struct i386_all_regs *ix86 __unused) |
| INT 13, 01 - Get status of last operation. | |
| static int | int13_rw_sectors (struct int13_drive *drive, struct i386_all_regs *ix86, int(*io)(struct block_device *blockdev, uint64_t block, unsigned long count, userptr_t buffer)) |
| Read / write sectors. | |
| static int | int13_read_sectors (struct int13_drive *drive, struct i386_all_regs *ix86) |
| INT 13, 02 - Read sectors. | |
| static int | int13_write_sectors (struct int13_drive *drive, struct i386_all_regs *ix86) |
| INT 13, 03 - Write sectors. | |
| static int | int13_get_parameters (struct int13_drive *drive, struct i386_all_regs *ix86) |
| INT 13, 08 - Get drive parameters. | |
| static int | int13_get_disk_type (struct int13_drive *drive, struct i386_all_regs *ix86) |
| INT 13, 15 - Get disk type. | |
| static int | int13_extension_check (struct int13_drive *drive __unused, struct i386_all_regs *ix86) |
| INT 13, 41 - Extensions installation check. | |
| static int | int13_extended_rw (struct int13_drive *drive, struct i386_all_regs *ix86, int(*io)(struct block_device *blockdev, uint64_t block, unsigned long count, userptr_t buffer)) |
| Extended read / write. | |
| static int | int13_extended_read (struct int13_drive *drive, struct i386_all_regs *ix86) |
| INT 13, 42 - Extended read. | |
| static int | int13_extended_write (struct int13_drive *drive, struct i386_all_regs *ix86) |
| INT 13, 43 - Extended write. | |
| static int | int13_get_extended_parameters (struct int13_drive *drive, struct i386_all_regs *ix86) |
| INT 13, 48 - Get extended parameters. | |
| static __asmcall void | int13 (struct i386_all_regs *ix86) |
| INT 13 handler. | |
| static void | hook_int13 (void) |
| Hook INT 13 handler. | |
| static void | unhook_int13 (void) |
| Unhook INT 13 handler. | |
| static void | guess_int13_geometry (struct int13_drive *drive) |
| Guess INT 13 drive geometry. | |
| void | register_int13_drive (struct int13_drive *drive) |
| Register INT 13 emulated drive. | |
| void | unregister_int13_drive (struct int13_drive *drive) |
| Unregister INT 13 emulated drive. | |
| int | int13_boot (unsigned int drive) |
| Attempt to boot from an INT 13 drive. | |
Variables | |
| static uint8_t | num_drives |
| Number of BIOS drives. | |
This module provides a mechanism for exporting block devices via the BIOS INT 13 disk interrupt interface.
Definition in file int13.c.
| #define int13_vector __use_text16 ( int13_vector ) |
| FILE_LICENCE | ( | GPL2_OR_LATER | ) |
| static struct segoff __text16 | ( | int13_vector | ) | [static, read] |
Vector for chaining to other INT 13 handlers.
| void int13_wrapper | ( | void | ) |
| static LIST_HEAD | ( | drives | ) | [static] |
List of registered emulated drives.
| static void int13_set_num_drives | ( | void | ) | [static] |
Update BIOS drive count.
Definition at line 66 of file int13.c.
References BDA_NUM_DRIVES, BDA_SEG, int13_drive::drive, get_real, int13_drive::list, list_for_each_entry, num_drives, and put_real.
Referenced by int13_check_num_drives(), and register_int13_drive().
00066 { 00067 struct int13_drive *drive; 00068 00069 /* Get current drive count */ 00070 get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES ); 00071 00072 /* Ensure count is large enough to cover all of our emulated drives */ 00073 list_for_each_entry ( drive, &drives, list ) { 00074 if ( num_drives <= ( drive->drive & 0x7f ) ) 00075 num_drives = ( ( drive->drive & 0x7f ) + 1 ); 00076 } 00077 00078 /* Update current drive count */ 00079 put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES ); 00080 }
| static void int13_check_num_drives | ( | void | ) | [static] |
Check number of drives.
Definition at line 85 of file int13.c.
References BDA_NUM_DRIVES, BDA_SEG, DBG, get_real, int13_set_num_drives(), and num_drives.
Referenced by int13().
00085 { 00086 uint8_t check_num_drives; 00087 00088 get_real ( check_num_drives, BDA_SEG, BDA_NUM_DRIVES ); 00089 if ( check_num_drives != num_drives ) { 00090 int13_set_num_drives(); 00091 DBG ( "INT13 fixing up number of drives from %d to %d\n", 00092 check_num_drives, num_drives ); 00093 } 00094 }
| static int int13_reset | ( | struct int13_drive *drive | __unused, | |
| struct i386_all_regs *ix86 | __unused | |||
| ) | [static] |
| static int int13_get_last_status | ( | struct int13_drive * | drive, | |
| struct i386_all_regs *ix86 | __unused | |||
| ) | [static] |
INT 13, 01 - Get status of last operation.
| drive | Emulated drive |
| status | Status code |
Definition at line 114 of file int13.c.
References DBG, and int13_drive::last_status.
Referenced by int13().
00115 { 00116 DBG ( "Get status of last operation\n" ); 00117 return drive->last_status; 00118 }
| static int int13_rw_sectors | ( | struct int13_drive * | drive, | |
| struct i386_all_regs * | ix86, | |||
| int(*)(struct block_device *blockdev, uint64_t block, unsigned long count, userptr_t buffer) | io | |||
| ) | [static] |
Read / write sectors.
| drive | Emulated drive | |
| al | Number of sectors to read or write (must be nonzero) | |
| ch | Low bits of cylinder number | |
| cl | (bits 7:6) High bits of cylinder number | |
| cl | (bits 5:0) Sector number | |
| dh | Head number | |
| es:bx | Data buffer | |
| io | Read / write method |
| status | Status code | |
| al | Number of sectors read or written |
Definition at line 134 of file int13.c.
References i386_regs::al, assert, block_device::blksize, int13_drive::blockdev, i386_regs::bx, i386_regs::ch, i386_regs::cl, DBG, i386_regs::dh, i386_seg_regs::es, int13_drive::heads, INT13_BLKSIZE, INT13_STATUS_INVALID, INT13_STATUS_READ_ERROR, real_to_user(), i386_all_regs::regs, int13_drive::sectors_per_track, i386_all_regs::segs, and strerror().
Referenced by int13_read_sectors(), and int13_write_sectors().
00139 { 00140 struct block_device *blockdev = drive->blockdev; 00141 unsigned int cylinder, head, sector; 00142 unsigned long lba; 00143 unsigned int count; 00144 userptr_t buffer; 00145 int rc; 00146 00147 /* Validate blocksize */ 00148 if ( blockdev->blksize != INT13_BLKSIZE ) { 00149 DBG ( "Invalid blocksize (%zd) for non-extended read/write\n", 00150 blockdev->blksize ); 00151 return -INT13_STATUS_INVALID; 00152 } 00153 00154 /* Calculate parameters */ 00155 cylinder = ( ( ( ix86->regs.cl & 0xc0 ) << 2 ) | ix86->regs.ch ); 00156 assert ( cylinder < drive->cylinders ); 00157 head = ix86->regs.dh; 00158 assert ( head < drive->heads ); 00159 sector = ( ix86->regs.cl & 0x3f ); 00160 assert ( ( sector >= 1 ) && ( sector <= drive->sectors_per_track ) ); 00161 lba = ( ( ( ( cylinder * drive->heads ) + head ) 00162 * drive->sectors_per_track ) + sector - 1 ); 00163 count = ix86->regs.al; 00164 buffer = real_to_user ( ix86->segs.es, ix86->regs.bx ); 00165 00166 DBG ( "C/H/S %d/%d/%d = LBA %#lx <-> %04x:%04x (count %d)\n", cylinder, 00167 head, sector, lba, ix86->segs.es, ix86->regs.bx, count ); 00168 00169 /* Read from / write to block device */ 00170 if ( ( rc = io ( blockdev, lba, count, buffer ) ) != 0 ) { 00171 DBG ( "INT 13 failed: %s\n", strerror ( rc ) ); 00172 return -INT13_STATUS_READ_ERROR; 00173 } 00174 00175 return 0; 00176 }
| static int int13_read_sectors | ( | struct int13_drive * | drive, | |
| struct i386_all_regs * | ix86 | |||
| ) | [static] |
INT 13, 02 - Read sectors.
| drive | Emulated drive | |
| al | Number of sectors to read (must be nonzero) | |
| ch | Low bits of cylinder number | |
| cl | (bits 7:6) High bits of cylinder number | |
| cl | (bits 5:0) Sector number | |
| dh | Head number | |
| es:bx | Data buffer |
| status | Status code | |
| al | Number of sectors read |
Definition at line 191 of file int13.c.
References int13_drive::blockdev, DBG, int13_rw_sectors(), block_device::op, and block_device_operations::read.
Referenced by int13().
00192 { 00193 DBG ( "Read: " ); 00194 return int13_rw_sectors ( drive, ix86, drive->blockdev->op->read ); 00195 }
| static int int13_write_sectors | ( | struct int13_drive * | drive, | |
| struct i386_all_regs * | ix86 | |||
| ) | [static] |
INT 13, 03 - Write sectors.
| drive | Emulated drive | |
| al | Number of sectors to write (must be nonzero) | |
| ch | Low bits of cylinder number | |
| cl | (bits 7:6) High bits of cylinder number | |
| cl | (bits 5:0) Sector number | |
| dh | Head number | |
| es:bx | Data buffer |
| status | Status code | |
| al | Number of sectors written |
Definition at line 210 of file int13.c.
References int13_drive::blockdev, DBG, int13_rw_sectors(), block_device::op, and block_device_operations::write.
Referenced by int13().
00211 { 00212 DBG ( "Write: " ); 00213 return int13_rw_sectors ( drive, ix86, drive->blockdev->op->write ); 00214 }
| static int int13_get_parameters | ( | struct int13_drive * | drive, | |
| struct i386_all_regs * | ix86 | |||
| ) | [static] |
INT 13, 08 - Get drive parameters.
| drive | Emulated drive |
| status | Status code | |
| ch | Low bits of maximum cylinder number | |
| cl | (bits 7:6) High bits of maximum cylinder number | |
| cl | (bits 5:0) Maximum sector number | |
| dh | Maximum head number | |
| dl | Number of drives |
Definition at line 227 of file int13.c.
References BDA_NUM_DRIVES, BDA_SEG, i386_regs::ch, i386_regs::cl, int13_drive::cylinders, DBG, i386_regs::dh, i386_regs::dl, get_real, int13_drive::heads, i386_all_regs::regs, and int13_drive::sectors_per_track.
Referenced by int13().
00228 { 00229 unsigned int max_cylinder = drive->cylinders - 1; 00230 unsigned int max_head = drive->heads - 1; 00231 unsigned int max_sector = drive->sectors_per_track; /* sic */ 00232 00233 DBG ( "Get drive parameters\n" ); 00234 00235 ix86->regs.ch = ( max_cylinder & 0xff ); 00236 ix86->regs.cl = ( ( ( max_cylinder >> 8 ) << 6 ) | max_sector ); 00237 ix86->regs.dh = max_head; 00238 get_real ( ix86->regs.dl, BDA_SEG, BDA_NUM_DRIVES ); 00239 return 0; 00240 }
| static int int13_get_disk_type | ( | struct int13_drive * | drive, | |
| struct i386_all_regs * | ix86 | |||
| ) | [static] |
INT 13, 15 - Get disk type.
| drive | Emulated drive |
| ah | Type code | |
| cx:dx | Sector count | |
| status | Status code / disk type |
Definition at line 250 of file int13.c.
References int13_drive::blockdev, block_device::blocks, i386_regs::cx, DBG, i386_regs::dx, INT13_DISK_TYPE_HDD, and i386_all_regs::regs.
Referenced by int13().
00251 { 00252 uint32_t blocks; 00253 00254 DBG ( "Get disk type\n" ); 00255 blocks = ( ( drive->blockdev->blocks <= 0xffffffffUL ) ? 00256 drive->blockdev->blocks : 0xffffffffUL ); 00257 ix86->regs.cx = ( blocks >> 16 ); 00258 ix86->regs.dx = ( blocks & 0xffff ); 00259 return INT13_DISK_TYPE_HDD; 00260 }
| static int int13_extension_check | ( | struct int13_drive *drive | __unused, | |
| struct i386_all_regs * | ix86 | |||
| ) | [static] |
INT 13, 41 - Extensions installation check.
| drive | Emulated drive | |
| bx | 0x55aa |
| bx | 0xaa55 | |
| cx | Extensions API support bitmap | |
| status | Status code / API version |
Definition at line 271 of file int13.c.
References i386_regs::bx, i386_regs::cx, DBG, INT13_EXTENSION_LINEAR, INT13_EXTENSION_VER_1_X, INT13_STATUS_INVALID, and i386_all_regs::regs.
Referenced by int13().
00272 { 00273 if ( ix86->regs.bx == 0x55aa ) { 00274 DBG ( "INT 13 extensions installation check\n" ); 00275 ix86->regs.bx = 0xaa55; 00276 ix86->regs.cx = INT13_EXTENSION_LINEAR; 00277 return INT13_EXTENSION_VER_1_X; 00278 } else { 00279 return -INT13_STATUS_INVALID; 00280 } 00281 }
| static int int13_extended_rw | ( | struct int13_drive * | drive, | |
| struct i386_all_regs * | ix86, | |||
| int(*)(struct block_device *blockdev, uint64_t block, unsigned long count, userptr_t buffer) | io | |||
| ) | [static] |
Extended read / write.
| drive | Emulated drive | |
| ds:si | Disk address packet | |
| io | Read / write method |
| status | Status code |
Definition at line 291 of file int13.c.
References int13_drive::blockdev, int13_disk_address::buffer, copy_from_real, int13_disk_address::count, DBG, i386_seg_regs::ds, INT13_STATUS_READ_ERROR, int13_disk_address::lba, segoff::offset, real_to_user(), i386_all_regs::regs, segoff::segment, i386_all_regs::segs, i386_regs::si, and strerror().
Referenced by int13_extended_read(), and int13_extended_write().
00296 { 00297 struct block_device *blockdev = drive->blockdev; 00298 struct int13_disk_address addr; 00299 uint64_t lba; 00300 unsigned long count; 00301 userptr_t buffer; 00302 int rc; 00303 00304 /* Read parameters from disk address structure */ 00305 copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si, sizeof ( addr )); 00306 lba = addr.lba; 00307 count = addr.count; 00308 buffer = real_to_user ( addr.buffer.segment, addr.buffer.offset ); 00309 00310 DBG ( "LBA %#llx <-> %04x:%04x (count %ld)\n", (unsigned long long)lba, 00311 addr.buffer.segment, addr.buffer.offset, count ); 00312 00313 /* Read from / write to block device */ 00314 if ( ( rc = io ( blockdev, lba, count, buffer ) ) != 0 ) { 00315 DBG ( "INT 13 failed: %s\n", strerror ( rc ) ); 00316 return -INT13_STATUS_READ_ERROR; 00317 } 00318 00319 return 0; 00320 }
| static int int13_extended_read | ( | struct int13_drive * | drive, | |
| struct i386_all_regs * | ix86 | |||
| ) | [static] |
INT 13, 42 - Extended read.
| drive | Emulated drive | |
| ds:si | Disk address packet |
| status | Status code |
Definition at line 329 of file int13.c.
References int13_drive::blockdev, DBG, int13_extended_rw(), block_device::op, and block_device_operations::read.
Referenced by int13().
00330 { 00331 DBG ( "Extended read: " ); 00332 return int13_extended_rw ( drive, ix86, drive->blockdev->op->read ); 00333 }
| static int int13_extended_write | ( | struct int13_drive * | drive, | |
| struct i386_all_regs * | ix86 | |||
| ) | [static] |
INT 13, 43 - Extended write.
| drive | Emulated drive | |
| ds:si | Disk address packet |
| status | Status code |
Definition at line 342 of file int13.c.
References int13_drive::blockdev, DBG, int13_extended_rw(), block_device::op, and block_device_operations::write.
Referenced by int13().
00343 { 00344 DBG ( "Extended write: " ); 00345 return int13_extended_rw ( drive, ix86, drive->blockdev->op->write ); 00346 }
| static int int13_get_extended_parameters | ( | struct int13_drive * | drive, | |
| struct i386_all_regs * | ix86 | |||
| ) | [static] |
INT 13, 48 - Get extended parameters.
| drive | Emulated drive | |
| ds:si | Drive parameter table |
| status | Status code |
Definition at line 355 of file int13.c.
References block_device::blksize, int13_drive::blockdev, block_device::blocks, int13_disk_parameters::bufsize, copy_to_real, int13_drive::cylinders, int13_disk_parameters::cylinders, DBG, i386_seg_regs::ds, int13_disk_parameters::flags, int13_drive::heads, INT13_FL_DMA_TRANSPARENT, i386_all_regs::regs, int13_drive::sectors_per_track, i386_all_regs::segs, and i386_regs::si.
Referenced by int13().
00356 { 00357 struct int13_disk_parameters params = { 00358 .bufsize = sizeof ( params ), 00359 .flags = INT13_FL_DMA_TRANSPARENT, 00360 .cylinders = drive->cylinders, 00361 .heads = drive->heads, 00362 .sectors_per_track = drive->sectors_per_track, 00363 .sectors = drive->blockdev->blocks, 00364 .sector_size = drive->blockdev->blksize, 00365 }; 00366 00367 DBG ( "Get extended drive parameters to %04x:%04x\n", 00368 ix86->segs.ds, ix86->regs.si ); 00369 00370 copy_to_real ( ix86->segs.ds, ix86->regs.si, ¶ms, 00371 sizeof ( params ) ); 00372 return 0; 00373 }
| static __asmcall void int13 | ( | struct i386_all_regs * | ix86 | ) | [static] |
INT 13 handler.
Definition at line 379 of file int13.c.
References i386_regs::ah, i386_regs::ax, CF, DBG, i386_regs::dl, int13_drive::drive, i386_all_regs::flags, int13_check_num_drives(), int13_extended_read(), INT13_EXTENDED_READ, int13_extended_write(), INT13_EXTENDED_WRITE, int13_extension_check(), INT13_EXTENSION_CHECK, int13_get_disk_type(), INT13_GET_DISK_TYPE, int13_get_extended_parameters(), INT13_GET_EXTENDED_PARAMETERS, int13_get_last_status(), INT13_GET_LAST_STATUS, int13_get_parameters(), INT13_GET_PARAMETERS, int13_read_sectors(), INT13_READ_SECTORS, int13_reset(), INT13_RESET, INT13_STATUS_INVALID, int13_write_sectors(), INT13_WRITE_SECTORS, int13_drive::last_status, int13_drive::list, list_for_each_entry, int13_drive::natural_drive, OF, and i386_all_regs::regs.
Referenced by hook_int13().
00379 { 00380 int command = ix86->regs.ah; 00381 unsigned int bios_drive = ix86->regs.dl; 00382 struct int13_drive *drive; 00383 int status; 00384 00385 /* Check BIOS hasn't killed off our drive */ 00386 int13_check_num_drives(); 00387 00388 list_for_each_entry ( drive, &drives, list ) { 00389 00390 if ( bios_drive != drive->drive ) { 00391 /* Remap any accesses to this drive's natural number */ 00392 if ( bios_drive == drive->natural_drive ) { 00393 DBG ( "INT 13,%04x (%02x) remapped to " 00394 "(%02x)\n", ix86->regs.ax, 00395 bios_drive, drive->drive ); 00396 ix86->regs.dl = drive->drive; 00397 return; 00398 } 00399 continue; 00400 } 00401 00402 DBG ( "INT 13,%04x (%02x): ", ix86->regs.ax, drive->drive ); 00403 00404 switch ( command ) { 00405 case INT13_RESET: 00406 status = int13_reset ( drive, ix86 ); 00407 break; 00408 case INT13_GET_LAST_STATUS: 00409 status = int13_get_last_status ( drive, ix86 ); 00410 break; 00411 case INT13_READ_SECTORS: 00412 status = int13_read_sectors ( drive, ix86 ); 00413 break; 00414 case INT13_WRITE_SECTORS: 00415 status = int13_write_sectors ( drive, ix86 ); 00416 break; 00417 case INT13_GET_PARAMETERS: 00418 status = int13_get_parameters ( drive, ix86 ); 00419 break; 00420 case INT13_GET_DISK_TYPE: 00421 status = int13_get_disk_type ( drive, ix86 ); 00422 break; 00423 case INT13_EXTENSION_CHECK: 00424 status = int13_extension_check ( drive, ix86 ); 00425 break; 00426 case INT13_EXTENDED_READ: 00427 status = int13_extended_read ( drive, ix86 ); 00428 break; 00429 case INT13_EXTENDED_WRITE: 00430 status = int13_extended_write ( drive, ix86 ); 00431 break; 00432 case INT13_GET_EXTENDED_PARAMETERS: 00433 status = int13_get_extended_parameters ( drive, ix86 ); 00434 break; 00435 default: 00436 DBG ( "*** Unrecognised INT 13 ***\n" ); 00437 status = -INT13_STATUS_INVALID; 00438 break; 00439 } 00440 00441 /* Store status for INT 13,01 */ 00442 drive->last_status = status; 00443 00444 /* Negative status indicates an error */ 00445 if ( status < 0 ) { 00446 status = -status; 00447 DBG ( "INT 13 returning failure status %x\n", status ); 00448 } else { 00449 ix86->flags &= ~CF; 00450 } 00451 ix86->regs.ah = status; 00452 00453 /* Set OF to indicate to wrapper not to chain this call */ 00454 ix86->flags |= OF; 00455 00456 return; 00457 } 00458 }
| static void hook_int13 | ( | void | ) | [static] |
Hook INT 13 handler.
Definition at line 464 of file int13.c.
References __asm__(), BDA_NUM_DRIVES, BDA_SEG, hook_bios_interrupt(), int13(), int13_vector, int13_wrapper(), and TEXT16_CODE.
Referenced by register_int13_drive().
00464 { 00465 /* Assembly wrapper to call int13(). int13() sets OF if we 00466 * should not chain to the previous handler. (The wrapper 00467 * clears CF and OF before calling int13()). 00468 */ 00469 __asm__ __volatile__ ( 00470 TEXT16_CODE ( "\nint13_wrapper:\n\t" 00471 /* Preserve %ax and %dx for future reference */ 00472 "pushw %%bp\n\t" 00473 "movw %%sp, %%bp\n\t" 00474 "pushw %%ax\n\t" 00475 "pushw %%dx\n\t" 00476 /* Clear OF, set CF, call int13() */ 00477 "orb $0, %%al\n\t" 00478 "stc\n\t" 00479 "pushl %0\n\t" 00480 "pushw %%cs\n\t" 00481 "call prot_call\n\t" 00482 /* Chain if OF not set */ 00483 "jo 1f\n\t" 00484 "pushfw\n\t" 00485 "lcall *%%cs:int13_vector\n\t" 00486 "\n1:\n\t" 00487 /* Overwrite flags for iret */ 00488 "pushfw\n\t" 00489 "popw 6(%%bp)\n\t" 00490 /* Fix up %dl: 00491 * 00492 * INT 13,15 : do nothing 00493 * INT 13,08 : load with number of drives 00494 * all others: restore original value 00495 */ 00496 "cmpb $0x15, -1(%%bp)\n\t" 00497 "je 2f\n\t" 00498 "movb -4(%%bp), %%dl\n\t" 00499 "cmpb $0x08, -1(%%bp)\n\t" 00500 "jne 2f\n\t" 00501 "pushw %%ds\n\t" 00502 "pushw %1\n\t" 00503 "popw %%ds\n\t" 00504 "movb %c2, %%dl\n\t" 00505 "popw %%ds\n\t" 00506 /* Return */ 00507 "\n2:\n\t" 00508 "movw %%bp, %%sp\n\t" 00509 "popw %%bp\n\t" 00510 "iret\n\t" ) 00511 : : "i" ( int13 ), "i" ( BDA_SEG ), "i" ( BDA_NUM_DRIVES ) ); 00512 00513 hook_bios_interrupt ( 0x13, ( unsigned int ) int13_wrapper, 00514 &int13_vector ); 00515 }
| static void unhook_int13 | ( | void | ) | [static] |
Unhook INT 13 handler.
Definition at line 520 of file int13.c.
References int13_vector, int13_wrapper(), and unhook_bios_interrupt().
Referenced by unregister_int13_drive().
00520 { 00521 unhook_bios_interrupt ( 0x13, ( unsigned int ) int13_wrapper, 00522 &int13_vector ); 00523 }
| static void guess_int13_geometry | ( | struct int13_drive * | drive | ) | [static] |
Guess INT 13 drive geometry.
| drive | Emulated drive |
Definition at line 532 of file int13.c.
References assert, block_device::blksize, int13_drive::blockdev, block_device::blocks, partition_table_entry::chs_end, int13_drive::cylinders, DBG, int13_drive::heads, INT13_BLKSIZE, block_device::op, PART_HEAD, PART_SECTOR, master_boot_record::partitions, block_device_operations::read, int13_drive::sectors_per_track, partition_table_entry::type, ULONG_MAX, and virt_to_user().
Referenced by register_int13_drive().
00532 { 00533 struct master_boot_record mbr; 00534 struct partition_table_entry *partition; 00535 unsigned int guessed_heads = 255; 00536 unsigned int guessed_sectors_per_track = 63; 00537 unsigned long blocks; 00538 unsigned long blocks_per_cyl; 00539 unsigned int i; 00540 00541 /* Don't even try when the blksize is invalid for C/H/S access */ 00542 if ( drive->blockdev->blksize != INT13_BLKSIZE ) 00543 return; 00544 00545 /* Scan through partition table and modify guesses for heads 00546 * and sectors_per_track if we find any used partitions. 00547 */ 00548 if ( drive->blockdev->op->read ( drive->blockdev, 0, 1, 00549 virt_to_user ( &mbr ) ) == 0 ) { 00550 for ( i = 0 ; i < 4 ; i++ ) { 00551 partition = &mbr.partitions[i]; 00552 if ( ! partition->type ) 00553 continue; 00554 guessed_heads = 00555 ( PART_HEAD ( partition->chs_end ) + 1 ); 00556 guessed_sectors_per_track = 00557 PART_SECTOR ( partition->chs_end ); 00558 DBG ( "Guessing C/H/S xx/%d/%d based on partition " 00559 "%d\n", guessed_heads, 00560 guessed_sectors_per_track, ( i + 1 ) ); 00561 } 00562 } else { 00563 DBG ( "Could not read partition table to guess geometry\n" ); 00564 } 00565 00566 /* Apply guesses if no geometry already specified */ 00567 if ( ! drive->heads ) 00568 drive->heads = guessed_heads; 00569 if ( ! drive->sectors_per_track ) 00570 drive->sectors_per_track = guessed_sectors_per_track; 00571 if ( ! drive->cylinders ) { 00572 /* Avoid attempting a 64-bit divide on a 32-bit system */ 00573 blocks = ( ( drive->blockdev->blocks <= ULONG_MAX ) ? 00574 drive->blockdev->blocks : ULONG_MAX ); 00575 blocks_per_cyl = ( drive->heads * drive->sectors_per_track ); 00576 assert ( blocks_per_cyl != 0 ); 00577 drive->cylinders = ( blocks / blocks_per_cyl ); 00578 if ( drive->cylinders > 1024 ) 00579 drive->cylinders = 1024; 00580 } 00581 }
| void register_int13_drive | ( | struct int13_drive * | drive | ) |
Register INT 13 emulated drive.
| drive | Emulated drive |
The underlying block device must be valid. A drive number and geometry will be assigned if left blank.
Definition at line 594 of file int13.c.
References BDA_NUM_DRIVES, BDA_SEG, int13_drive::cylinders, DBG, int13_drive::drive, get_real, guess_int13_geometry(), int13_drive::heads, hook_int13(), int13_set_num_drives(), int13_drive::list, list_add, list_empty(), int13_drive::natural_drive, num_drives, and int13_drive::sectors_per_track.
Referenced by aoeboot(), eltorito_exec(), ib_srpboot(), and iscsiboot().
00594 { 00595 uint8_t num_drives; 00596 00597 /* Give drive a default geometry if none specified */ 00598 guess_int13_geometry ( drive ); 00599 00600 /* Assign natural drive number */ 00601 get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES ); 00602 drive->natural_drive = ( num_drives | 0x80 ); 00603 00604 /* Assign drive number */ 00605 if ( ( drive->drive & 0xff ) == 0xff ) { 00606 /* Drive number == -1 => use natural drive number */ 00607 drive->drive = drive->natural_drive; 00608 } else { 00609 /* Use specified drive number (+0x80 if necessary) */ 00610 drive->drive |= 0x80; 00611 } 00612 00613 DBG ( "Registered INT13 drive %02x (naturally %02x) with C/H/S " 00614 "geometry %d/%d/%d\n", drive->drive, drive->natural_drive, 00615 drive->cylinders, drive->heads, drive->sectors_per_track ); 00616 00617 /* Hook INT 13 vector if not already hooked */ 00618 if ( list_empty ( &drives ) ) 00619 hook_int13(); 00620 00621 /* Add to list of emulated drives */ 00622 list_add ( &drive->list, &drives ); 00623 00624 /* Update BIOS drive count */ 00625 int13_set_num_drives(); 00626 }
| void unregister_int13_drive | ( | struct int13_drive * | drive | ) |
Unregister INT 13 emulated drive.
| drive | Emulated drive |
Definition at line 637 of file int13.c.
References DBG, int13_drive::drive, int13_drive::list, list_del, list_empty(), and unhook_int13().
Referenced by aoeboot(), eltorito_exec(), ib_srpboot(), and iscsiboot().
00637 { 00638 /* Remove from list of emulated drives */ 00639 list_del ( &drive->list ); 00640 00641 /* Should adjust BIOS drive count, but it's difficult to do so 00642 * reliably. 00643 */ 00644 00645 DBG ( "Unregistered INT13 drive %02x\n", drive->drive ); 00646 00647 /* Unhook INT 13 vector if no more drives */ 00648 if ( list_empty ( &drives ) ) 00649 unhook_int13(); 00650 }
| int int13_boot | ( | unsigned int | drive | ) |
Attempt to boot from an INT 13 drive.
| drive | Drive number |
| rc | Return status code |
Note that this function can never return success, by definition.
Definition at line 665 of file int13.c.
References __asm__(), be16_to_cpu, call_bootsector(), cpu_to_be16, DBG, ECANCELED, EIO, ENOEXEC, get_memmap(), REAL_CODE, and strerror().
Referenced by aoeboot(), ib_srpboot(), and iscsiboot().
00665 { 00666 struct memory_map memmap; 00667 int status, signature; 00668 int discard_c, discard_d; 00669 int rc; 00670 00671 DBG ( "Booting from INT 13 drive %02x\n", drive ); 00672 00673 /* Use INT 13 to read the boot sector */ 00674 __asm__ __volatile__ ( REAL_CODE ( "pushw %%es\n\t" 00675 "pushw $0\n\t" 00676 "popw %%es\n\t" 00677 "stc\n\t" 00678 "sti\n\t" 00679 "int $0x13\n\t" 00680 "sti\n\t" /* BIOS bugs */ 00681 "jc 1f\n\t" 00682 "xorl %%eax, %%eax\n\t" 00683 "\n1:\n\t" 00684 "movzwl %%es:0x7dfe, %%ebx\n\t" 00685 "popw %%es\n\t" ) 00686 : "=a" ( status ), "=b" ( signature ), 00687 "=c" ( discard_c ), "=d" ( discard_d ) 00688 : "a" ( 0x0201 ), "b" ( 0x7c00 ), 00689 "c" ( 1 ), "d" ( drive ) ); 00690 if ( status ) 00691 return -EIO; 00692 00693 /* Check signature is correct */ 00694 if ( signature != be16_to_cpu ( 0x55aa ) ) { 00695 DBG ( "Invalid disk signature %#04x (should be 0x55aa)\n", 00696 cpu_to_be16 ( signature ) ); 00697 return -ENOEXEC; 00698 } 00699 00700 /* Dump out memory map prior to boot, if memmap debugging is 00701 * enabled. Not required for program flow, but we have so 00702 * many problems that turn out to be memory-map related that 00703 * it's worth doing. 00704 */ 00705 get_memmap ( &memmap ); 00706 00707 /* Jump to boot sector */ 00708 if ( ( rc = call_bootsector ( 0x0, 0x7c00, drive ) ) != 0 ) { 00709 DBG ( "INT 13 drive %02x boot returned: %s\n", 00710 drive, strerror ( rc ) ); 00711 return rc; 00712 } 00713 00714 return -ECANCELED; /* -EIMPOSSIBLE */ 00715 }
uint8_t num_drives [static] |
Number of BIOS drives.
Note that this is the number of drives in the system as a whole (i.e. a mirror of the counter at 40:75), rather than a count of the number of emulated drives.
Definition at line 61 of file int13.c.
Referenced by int13_check_num_drives(), int13_set_num_drives(), and register_int13_drive().
1.5.7.1