iPXE
Data Structures | Defines | Functions | Variables
int13.c File Reference

INT 13 emulation. More...

#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
#include <byteswap.h>
#include <errno.h>
#include <assert.h>
#include <ipxe/blockdev.h>
#include <ipxe/io.h>
#include <ipxe/acpi.h>
#include <ipxe/sanboot.h>
#include <ipxe/device.h>
#include <ipxe/pci.h>
#include <ipxe/eltorito.h>
#include <realmode.h>
#include <bios.h>
#include <biosint.h>
#include <bootsector.h>
#include <int13.h>

Go to the source code of this file.

Data Structures

struct  int13_data
 INT 13 SAN device private data. More...

Defines

#define int13_vector   __use_text16 ( int13_vector )
#define int13_fdd_params   __use_data16 ( int13_fdd_params )
#define num_fdds   __use_text16 ( num_fdds )
#define num_drives   __use_text16 ( num_drives )
#define eltorito_cmd   __use_data16 ( eltorito_cmd )
#define eltorito_address   __use_data16 ( eltorito_address )
#define XBFTAB_SIZE   768
 Maximum size of boot firmware table(s)
#define XBFTAB_ALIGN   16
 Alignment of boot firmware table entries.
#define xbftab   __use_data16 ( xbftab )

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static struct segoff __text16 (int13_vector)
 Vector for chaining to other INT 13 handlers.
void int13_wrapper (void)
 Assembly wrapper.
static struct int13_fdd_parameters __data16 (int13_fdd_params)
 Dummy floppy disk parameter table.
static uint8_t __text16 (num_fdds)
 Number of BIOS floppy disk drives.
static uint8_t __text16 (num_drives)
 Number of BIOS hard disk drives.
static uint32_t int13_capacity32 (struct san_device *sandev)
 Calculate SAN device capacity (limited to 32 bits)
static int int13_is_fdd (struct san_device *sandev)
 Test if SAN device is a floppy disk drive.
static int int13_parse_eltorito (struct san_device *sandev, void *scratch)
 Parse El Torito parameters.
static int int13_guess_geometry_hdd (struct san_device *sandev, void *scratch, unsigned int *heads, unsigned int *sectors)
 Guess INT 13 hard disk drive geometry.
static int int13_guess_geometry_fdd (struct san_device *sandev, unsigned int *heads, unsigned int *sectors)
 Guess INT 13 floppy disk drive geometry.
static int int13_guess_geometry (struct san_device *sandev, void *scratch)
 Guess INT 13 drive geometry.
static void int13_sync_num_drives (void)
 Update BIOS drive count.
static void int13_check_num_drives (void)
 Check number of drives.
static int int13_reset (struct san_device *sandev, struct i386_all_regs *ix86 __unused)
 INT 13, 00 - Reset disk system.
static int int13_get_last_status (struct san_device *sandev, struct i386_all_regs *ix86 __unused)
 INT 13, 01 - Get status of last operation.
static int int13_rw_sectors (struct san_device *sandev, struct i386_all_regs *ix86, int(*sandev_rw)(struct san_device *sandev, uint64_t lba, unsigned int count, userptr_t buffer))
 Read / write sectors.
static int int13_read_sectors (struct san_device *sandev, struct i386_all_regs *ix86)
 INT 13, 02 - Read sectors.
static int int13_write_sectors (struct san_device *sandev, struct i386_all_regs *ix86)
 INT 13, 03 - Write sectors.
static int int13_get_parameters (struct san_device *sandev, struct i386_all_regs *ix86)
 INT 13, 08 - Get drive parameters.
static int int13_get_disk_type (struct san_device *sandev, struct i386_all_regs *ix86)
 INT 13, 15 - Get disk type.
static int int13_extension_check (struct san_device *sandev __unused, struct i386_all_regs *ix86)
 INT 13, 41 - Extensions installation check.
static int int13_extended_rw (struct san_device *sandev, struct i386_all_regs *ix86, int(*sandev_rw)(struct san_device *sandev, uint64_t lba, unsigned int count, userptr_t buffer))
 Extended read / write.
static int int13_extended_read (struct san_device *sandev, struct i386_all_regs *ix86)
 INT 13, 42 - Extended read.
static int int13_extended_write (struct san_device *sandev, struct i386_all_regs *ix86)
 INT 13, 43 - Extended write.
static int int13_extended_verify (struct san_device *sandev, struct i386_all_regs *ix86)
 INT 13, 44 - Verify sectors.
static int int13_extended_seek (struct san_device *sandev, struct i386_all_regs *ix86)
 INT 13, 44 - Extended seek.
static int int13_device_path_info (struct san_device *sandev, struct edd_device_path_information *dpi)
 Build device path information.
static int int13_get_extended_parameters (struct san_device *sandev, struct i386_all_regs *ix86)
 INT 13, 48 - Get extended parameters.
static int int13_cdrom_status_terminate (struct san_device *sandev, struct i386_all_regs *ix86)
 INT 13, 4b - Get status or terminate CD-ROM emulation.
static int int13_cdrom_read_boot_catalog (struct san_device *sandev, struct i386_all_regs *ix86)
 INT 13, 4d - Read CD-ROM boot catalog.
static __asmcall void int13 (struct i386_all_regs *ix86)
 INT 13 handler.
static void int13_hook_vector (void)
 Hook INT 13 handler.
static void int13_unhook_vector (void)
 Unhook INT 13 handler.
static int int13_hook (unsigned int drive, struct uri **uris, unsigned int count, unsigned int flags)
 Hook INT 13 SAN device.
static void int13_unhook (unsigned int drive)
 Unhook INT 13 SAN device.
static int int13_load_mbr (unsigned int drive, struct segoff *address)
 Load and verify master boot record from INT 13 drive.
static struct
int13_cdrom_boot_catalog_command 
__data16 (eltorito_cmd)
 El Torito boot catalog command packet.
static struct int13_disk_address __bss16 (eltorito_address)
 El Torito disk address packet.
static int int13_load_eltorito (unsigned int drive, struct segoff *address)
 Load and verify El Torito boot record from INT 13 drive.
static int int13_boot (unsigned int drive, const char *filename __unused)
 Attempt to boot from an INT 13 drive.
static uint8_t __bss16_array (xbftab,[XBFTAB_SIZE])
 The boot firmware table(s) generated by iPXE.
static int int13_install (struct acpi_header *acpi)
 Install ACPI table.
static int int13_describe (void)
 Describe SAN devices for SAN-booted operating system.
 PROVIDE_SANBOOT (pcbios, san_hook, int13_hook)
 PROVIDE_SANBOOT (pcbios, san_unhook, int13_unhook)
 PROVIDE_SANBOOT (pcbios, san_boot, int13_boot)
 PROVIDE_SANBOOT (pcbios, san_describe, int13_describe)

Variables

static uint16_t equipment_word
 Equipment word.
static struct int13_fdd_geometry int13_fdd_geometries []
 Recognised floppy disk geometries.
static size_t xbftab_used
 Total used length of boot firmware tables.

Detailed Description

INT 13 emulation.

This module provides a mechanism for exporting block devices via the BIOS INT 13 disk interrupt interface.

Definition in file int13.c.


Define Documentation

Definition at line 101 of file int13.c.

Referenced by int13_hook_vector(), and int13_unhook_vector().

Definition at line 113 of file int13.c.

Referenced by int13_get_parameters().

#define num_fdds   __use_text16 ( num_fdds )

Definition at line 130 of file int13.c.

Referenced by int13_get_parameters(), int13_hook(), and int13_sync_num_drives().

Definition at line 1415 of file int13.c.

Referenced by int13_load_eltorito().

Definition at line 1419 of file int13.c.

Referenced by int13_load_eltorito().

#define XBFTAB_SIZE   768

Maximum size of boot firmware table(s)

Definition at line 1545 of file int13.c.

#define XBFTAB_ALIGN   16

Alignment of boot firmware table entries.

Definition at line 1548 of file int13.c.

#define xbftab   __use_data16 ( xbftab )

Definition at line 1553 of file int13.c.

Referenced by int13_describe(), and int13_install().


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static struct segoff __text16 ( int13_vector  ) [static, read]

Vector for chaining to other INT 13 handlers.

void int13_wrapper ( void  )

Assembly wrapper.

Referenced by int13_hook_vector(), and int13_unhook_vector().

static struct int13_fdd_parameters __data16 ( int13_fdd_params  ) [static, read]

Dummy floppy disk parameter table.

static uint8_t __text16 ( num_fdds  ) [static]

Number of BIOS floppy disk drives.

This is derived from the equipment word. It is held in .text16 to allow for easy access by the INT 13,08 wrapper.

static uint8_t __text16 ( num_drives  ) [static]

Number of BIOS hard disk drives.

This is a cached copy of the BIOS Data Area number of hard disk drives at 40:75. It is held in .text16 to allow for easy access by the INT 13,08 wrapper.

static uint32_t int13_capacity32 ( struct san_device sandev) [inline, static]

Calculate SAN device capacity (limited to 32 bits)

Parameters:
sandevSAN device
Return values:
blocksNumber of blocks

Definition at line 148 of file int13.c.

References sandev_capacity().

Referenced by int13_get_disk_type(), and int13_guess_geometry().

                                                                      {
        uint64_t capacity = sandev_capacity ( sandev );
        return ( ( capacity <= 0xffffffffUL ) ? capacity : 0xffffffff );
}
static int int13_is_fdd ( struct san_device sandev) [inline, static]

Test if SAN device is a floppy disk drive.

Parameters:
sandevSAN device
Return values:
is_fddSAN device is a floppy disk drive

Definition at line 159 of file int13.c.

References san_device::drive.

Referenced by int13_extended_rw(), int13_get_disk_type(), int13_get_parameters(), int13_guess_geometry(), and int13_sync_num_drives().

                                                             {
        return ( ! ( sandev->drive & 0x80 ) );
}
static int int13_parse_eltorito ( struct san_device sandev,
void *  scratch 
) [static]

Parse El Torito parameters.

Parameters:
sandevSAN device
scratchScratch area for single-sector reads
Return values:
rcReturn status code

Reads and parses El Torito parameters, if present.

Definition at line 172 of file int13.c.

References int13_data::boot_catalog, DBGC, san_device::drive, ELTORITO_LBA, int13(), ISO9660_ID, ISO9660_TYPE_BOOT, memcmp(), san_device::priv, rc, sandev_read(), eltorito_descriptor::sector, strerror(), eltorito_descriptor_fixed::type, and virt_to_user().

Referenced by int13_hook().

                                                                             {
        struct int13_data *int13 = sandev->priv;
        static const struct eltorito_descriptor_fixed boot_check = {
                .type = ISO9660_TYPE_BOOT,
                .id = ISO9660_ID,
                .version = 1,
                .system_id = "EL TORITO SPECIFICATION",
        };
        struct eltorito_descriptor *boot = scratch;
        int rc;

        /* Read boot record volume descriptor */
        if ( ( rc = sandev_read ( sandev, ELTORITO_LBA, 1,
                                  virt_to_user ( boot ) ) ) != 0 ) {
                DBGC ( sandev, "INT13 drive %02x could not read El Torito boot "
                       "record volume descriptor: %s\n",
                       sandev->drive, strerror ( rc ) );
                return rc;
        }

        /* Check for an El Torito boot catalog */
        if ( memcmp ( boot, &boot_check, sizeof ( boot_check ) ) == 0 ) {
                int13->boot_catalog = boot->sector;
                DBGC ( sandev, "INT13 drive %02x has an El Torito boot catalog "
                       "at LBA %08x\n", sandev->drive, int13->boot_catalog );
        } else {
                DBGC ( sandev, "INT13 drive %02x has no El Torito boot "
                       "catalog\n", sandev->drive );
        }

        return 0;
}
static int int13_guess_geometry_hdd ( struct san_device sandev,
void *  scratch,
unsigned int *  heads,
unsigned int *  sectors 
) [static]

Guess INT 13 hard disk drive geometry.

Parameters:
sandevSAN device
scratchScratch area for single-sector reads
Return values:
headsGuessed number of heads
sectorsGuessed number of sectors per track
rcReturn status code

Guesses the drive geometry by inspecting the partition table.

Definition at line 216 of file int13.c.

References partition_table_entry::chs_end, partition_table_entry::chs_start, DBGC, DBGC2, DBGC2_HDA, san_device::drive, PART_CYLINDER, PART_HEAD, PART_SECTOR, master_boot_record::partitions, rc, sandev_read(), master_boot_record::signature, partition_table_entry::start, strerror(), partition_table_entry::type, and virt_to_user().

Referenced by int13_guess_geometry().

                                                              {
        struct master_boot_record *mbr = scratch;
        struct partition_table_entry *partition;
        unsigned int i;
        unsigned int start_cylinder;
        unsigned int start_head;
        unsigned int start_sector;
        unsigned int end_head;
        unsigned int end_sector;
        int rc;

        /* Read partition table */
        if ( ( rc = sandev_read ( sandev, 0, 1, virt_to_user ( mbr ) ) ) != 0 ) {
                DBGC ( sandev, "INT13 drive %02x could not read "
                       "partition table to guess geometry: %s\n",
                       sandev->drive, strerror ( rc ) );
                return rc;
        }
        DBGC2 ( sandev, "INT13 drive %02x has MBR:\n", sandev->drive );
        DBGC2_HDA ( sandev, 0, mbr, sizeof ( *mbr ) );
        DBGC ( sandev, "INT13 drive %02x has signature %08x\n",
               sandev->drive, mbr->signature );

        /* Scan through partition table and modify guesses for
         * heads and sectors_per_track if we find any used
         * partitions.
         */
        *heads = 0;
        *sectors = 0;
        for ( i = 0 ; i < 4 ; i++ ) {

                /* Skip empty partitions */
                partition = &mbr->partitions[i];
                if ( ! partition->type )
                        continue;

                /* If partition starts on cylinder 0 then we can
                 * unambiguously determine the number of sectors.
                 */
                start_cylinder = PART_CYLINDER ( partition->chs_start );
                start_head = PART_HEAD ( partition->chs_start );
                start_sector = PART_SECTOR ( partition->chs_start );
                if ( ( start_cylinder == 0 ) && ( start_head != 0 ) ) {
                        *sectors = ( ( partition->start + 1 - start_sector ) /
                                     start_head );
                        DBGC ( sandev, "INT13 drive %02x guessing C/H/S "
                               "xx/xx/%d based on partition %d\n",
                               sandev->drive, *sectors, ( i + 1 ) );
                }

                /* If partition ends on a higher head or sector number
                 * than our current guess, then increase the guess.
                 */
                end_head = PART_HEAD ( partition->chs_end );
                end_sector = PART_SECTOR ( partition->chs_end );
                if ( ( end_head + 1 ) > *heads ) {
                        *heads = ( end_head + 1 );
                        DBGC ( sandev, "INT13 drive %02x guessing C/H/S "
                               "xx/%d/xx based on partition %d\n",
                               sandev->drive, *heads, ( i + 1 ) );
                }
                if ( end_sector > *sectors ) {
                        *sectors = end_sector;
                        DBGC ( sandev, "INT13 drive %02x guessing C/H/S "
                               "xx/xx/%d based on partition %d\n",
                               sandev->drive, *sectors, ( i + 1 ) );
                }
        }

        /* Default guess is xx/255/63 */
        if ( ! *heads )
                *heads = 255;
        if ( ! *sectors )
                *sectors = 63;

        return 0;
}
static int int13_guess_geometry_fdd ( struct san_device sandev,
unsigned int *  heads,
unsigned int *  sectors 
) [static]

Guess INT 13 floppy disk drive geometry.

Parameters:
sandevSAN device
Return values:
headsGuessed number of heads
sectorsGuessed number of sectors per track
rcReturn status code

Guesses the drive geometry by inspecting the disk size.

Definition at line 330 of file int13.c.

References blocks, cylinders, DBGC, san_device::drive, INT13_FDD_CYLINDERS, int13_fdd_geometries, INT13_FDD_HEADS, INT13_FDD_SECTORS, and sandev_capacity().

Referenced by int13_guess_geometry().

                                                              {
        unsigned int blocks = sandev_capacity ( sandev );
        const struct int13_fdd_geometry *geometry;
        unsigned int cylinders;
        unsigned int i;

        /* Look for a match against a known geometry */
        for ( i = 0 ; i < ( sizeof ( int13_fdd_geometries ) /
                            sizeof ( int13_fdd_geometries[0] ) ) ; i++ ) {
                geometry = &int13_fdd_geometries[i];
                cylinders = INT13_FDD_CYLINDERS ( geometry );
                *heads = INT13_FDD_HEADS ( geometry );
                *sectors = INT13_FDD_SECTORS ( geometry );
                if ( ( cylinders * (*heads) * (*sectors) ) == blocks ) {
                        DBGC ( sandev, "INT13 drive %02x guessing C/H/S "
                               "%d/%d/%d based on size %dK\n", sandev->drive,
                               cylinders, *heads, *sectors, ( blocks / 2 ) );
                        return 0;
                }
        }

        /* Otherwise, assume a partial disk image in the most common
         * format (1440K, 80/2/18).
         */
        *heads = 2;
        *sectors = 18;
        DBGC ( sandev, "INT13 drive %02x guessing C/H/S xx/%d/%d based on size "
               "%dK\n", sandev->drive, *heads, *sectors, ( blocks / 2 ) );
        return 0;
}
static int int13_guess_geometry ( struct san_device sandev,
void *  scratch 
) [static]

Guess INT 13 drive geometry.

Parameters:
sandevSAN device
scratchScratch area for single-sector reads
Return values:
rcReturn status code

Definition at line 370 of file int13.c.

References assert, blocks, int13_data::cylinders, int13_data::heads, int13(), int13_capacity32(), int13_guess_geometry_fdd(), int13_guess_geometry_hdd(), int13_is_fdd(), san_device::priv, rc, and int13_data::sectors_per_track.

Referenced by int13_hook().

                                                                             {
        struct int13_data *int13 = sandev->priv;
        unsigned int guessed_heads;
        unsigned int guessed_sectors;
        unsigned int blocks;
        unsigned int blocks_per_cyl;
        int rc;

        /* Guess geometry according to drive type */
        if ( int13_is_fdd ( sandev ) ) {
                if ( ( rc = int13_guess_geometry_fdd ( sandev, &guessed_heads,
                                                       &guessed_sectors )) != 0)
                        return rc;
        } else {
                if ( ( rc = int13_guess_geometry_hdd ( sandev, scratch,
                                                       &guessed_heads,
                                                       &guessed_sectors )) != 0)
                        return rc;
        }

        /* Apply guesses if no geometry already specified */
        if ( ! int13->heads )
                int13->heads = guessed_heads;
        if ( ! int13->sectors_per_track )
                int13->sectors_per_track = guessed_sectors;
        if ( ! int13->cylinders ) {
                /* Avoid attempting a 64-bit divide on a 32-bit system */
                blocks = int13_capacity32 ( sandev );
                blocks_per_cyl = ( int13->heads * int13->sectors_per_track );
                assert ( blocks_per_cyl != 0 );
                int13->cylinders = ( blocks / blocks_per_cyl );
                if ( int13->cylinders > 1024 )
                        int13->cylinders = 1024;
        }

        return 0;
}
static void int13_sync_num_drives ( void  ) [static]

Update BIOS drive count.

Definition at line 411 of file int13.c.

References BDA_EQUIPMENT_WORD, BDA_NUM_DRIVES, BDA_SEG, DBGC, san_device::drive, equipment_word, for_each_sandev, get_real, int13(), int13_is_fdd(), int13_data::natural_drive, num_drives, num_fdds, san_device::priv, and put_real.

Referenced by int13_check_num_drives(), and int13_hook().

                                           {
        struct san_device *sandev;
        struct int13_data *int13;
        uint8_t *counter;
        uint8_t max_drive;
        uint8_t required;

        /* Get current drive counts */
        get_real ( equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD );
        get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
        num_fdds = ( ( equipment_word & 0x0001 ) ?
                     ( ( ( equipment_word >> 6 ) & 0x3 ) + 1 ) : 0 );

        /* Ensure count is large enough to cover all of our SAN devices */
        for_each_sandev ( sandev ) {
                int13 = sandev->priv;
                counter = ( int13_is_fdd ( sandev ) ? &num_fdds : &num_drives );
                max_drive = sandev->drive;
                if ( max_drive < int13->natural_drive )
                        max_drive = int13->natural_drive;
                required = ( ( max_drive & 0x7f ) + 1 );
                if ( *counter < required ) {
                        *counter = required;
                        DBGC ( sandev, "INT13 drive %02x added to drive count: "
                               "%d HDDs, %d FDDs\n",
                               sandev->drive, num_drives, num_fdds );
                }
        }

        /* Update current drive count */
        equipment_word &= ~( ( 0x3 << 6 ) | 0x0001 );
        if ( num_fdds ) {
                equipment_word |= ( 0x0001 |
                                    ( ( ( num_fdds - 1 ) & 0x3 ) << 6 ) );
        }
        put_real ( equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD );
        put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
}
static void int13_check_num_drives ( void  ) [static]

Check number of drives.

Definition at line 453 of file int13.c.

References BDA_EQUIPMENT_WORD, BDA_NUM_DRIVES, BDA_SEG, equipment_word, get_real, int13_sync_num_drives(), and num_drives.

Referenced by int13().

                                            {
        uint16_t check_equipment_word;
        uint8_t check_num_drives;

        get_real ( check_equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD );
        get_real ( check_num_drives, BDA_SEG, BDA_NUM_DRIVES );
        if ( ( check_equipment_word != equipment_word ) ||
             ( check_num_drives != num_drives ) ) {
                int13_sync_num_drives();
        }
}
static int int13_reset ( struct san_device sandev,
struct i386_all_regs *ix86  __unused 
) [static]

INT 13, 00 - Reset disk system.

Parameters:
sandevSAN device
Return values:
statusStatus code

Definition at line 471 of file int13.c.

References DBGC2, INT13_STATUS_RESET_FAILED, rc, and sandev_reset().

Referenced by int13().

                                                               {
        int rc;

        DBGC2 ( sandev, "Reset drive\n" );

        /* Reset SAN device */
        if ( ( rc = sandev_reset ( sandev ) ) != 0 )
                return -INT13_STATUS_RESET_FAILED;

        return 0;
}
static int int13_get_last_status ( struct san_device sandev,
struct i386_all_regs *ix86  __unused 
) [static]

INT 13, 01 - Get status of last operation.

Parameters:
sandevSAN device
Return values:
statusStatus code

Definition at line 490 of file int13.c.

References DBGC2, int13(), int13_data::last_status, and san_device::priv.

Referenced by int13().

                                                                         {
        struct int13_data *int13 = sandev->priv;

        DBGC2 ( sandev, "Get status of last operation\n" );
        return int13->last_status;
}
static int int13_rw_sectors ( struct san_device sandev,
struct i386_all_regs ix86,
int(*)(struct san_device *sandev, uint64_t lba, unsigned int count, userptr_t buffer sandev_rw 
) [static]

Read / write sectors.

Parameters:
sandevSAN device
alNumber of sectors to read or write (must be nonzero)
chLow bits of cylinder number
cl(bits 7:6) High bits of cylinder number
cl(bits 5:0) Sector number
dhHead number
es:bxData buffer
sandev_rwSAN device read/write method
Return values:
statusStatus code
alNumber of sectors read or written

Definition at line 512 of file int13.c.

References i386_regs::al, buffer, i386_regs::bx, i386_regs::ch, i386_regs::cl, count, int13_data::cylinders, DBGC, DBGC2, i386_regs::dh, san_device::drive, i386_seg_regs::es, head, int13_data::heads, int13(), INT13_BLKSIZE, INT13_STATUS_INVALID, INT13_STATUS_READ_ERROR, lba, san_device::priv, rc, real_to_user(), i386_all_regs::regs, sandev_blksize(), sandev_rw(), sector, int13_data::sectors_per_track, i386_all_regs::segs, and strerror().

Referenced by int13_read_sectors(), and int13_write_sectors().

                                                                         {
        struct int13_data *int13 = sandev->priv;
        unsigned int cylinder, head, sector;
        unsigned long lba;
        unsigned int count;
        userptr_t buffer;
        int rc;

        /* Validate blocksize */
        if ( sandev_blksize ( sandev ) != INT13_BLKSIZE ) {
                DBGC ( sandev, "\nINT 13 drive %02x invalid blocksize (%zd) "
                       "for non-extended read/write\n",
                       sandev->drive, sandev_blksize ( sandev ) );
                return -INT13_STATUS_INVALID;
        }

        /* Calculate parameters */
        cylinder = ( ( ( ix86->regs.cl & 0xc0 ) << 2 ) | ix86->regs.ch );
        head = ix86->regs.dh;
        sector = ( ix86->regs.cl & 0x3f );
        if ( ( cylinder >= int13->cylinders ) ||
             ( head >= int13->heads ) ||
             ( sector < 1 ) || ( sector > int13->sectors_per_track ) ) {
                DBGC ( sandev, "C/H/S %d/%d/%d out of range for geometry "
                       "%d/%d/%d\n", cylinder, head, sector, int13->cylinders,
                       int13->heads, int13->sectors_per_track );
                return -INT13_STATUS_INVALID;
        }
        lba = ( ( ( ( cylinder * int13->heads ) + head )
                  * int13->sectors_per_track ) + sector - 1 );
        count = ix86->regs.al;
        buffer = real_to_user ( ix86->segs.es, ix86->regs.bx );

        DBGC2 ( sandev, "C/H/S %d/%d/%d = LBA %08lx <-> %04x:%04x (count %d)\n",
                cylinder, head, sector, lba, ix86->segs.es, ix86->regs.bx,
                count );

        /* Read from / write to block device */
        if ( ( rc = sandev_rw ( sandev, lba, count, buffer ) ) != 0 ){
                DBGC ( sandev, "INT13 drive %02x I/O failed: %s\n",
                       sandev->drive, strerror ( rc ) );
                return -INT13_STATUS_READ_ERROR;
        }

        return 0;
}
static int int13_read_sectors ( struct san_device sandev,
struct i386_all_regs ix86 
) [static]

INT 13, 02 - Read sectors.

Parameters:
sandevSAN device
alNumber of sectors to read (must be nonzero)
chLow bits of cylinder number
cl(bits 7:6) High bits of cylinder number
cl(bits 5:0) Sector number
dhHead number
es:bxData buffer
Return values:
statusStatus code
alNumber of sectors read

Definition at line 577 of file int13.c.

References DBGC2, int13_rw_sectors(), and sandev_read().

Referenced by int13().

                                                             {

        DBGC2 ( sandev, "Read: " );
        return int13_rw_sectors ( sandev, ix86, sandev_read );
}
static int int13_write_sectors ( struct san_device sandev,
struct i386_all_regs ix86 
) [static]

INT 13, 03 - Write sectors.

Parameters:
sandevSAN device
alNumber of sectors to write (must be nonzero)
chLow bits of cylinder number
cl(bits 7:6) High bits of cylinder number
cl(bits 5:0) Sector number
dhHead number
es:bxData buffer
Return values:
statusStatus code
alNumber of sectors written

Definition at line 597 of file int13.c.

References DBGC2, int13_rw_sectors(), and sandev_write().

Referenced by int13().

                                                              {

        DBGC2 ( sandev, "Write: " );
        return int13_rw_sectors ( sandev, ix86, sandev_write );
}
static int int13_get_parameters ( struct san_device sandev,
struct i386_all_regs ix86 
) [static]

INT 13, 08 - Get drive parameters.

Parameters:
sandevSAN device
Return values:
statusStatus code
chLow bits of maximum cylinder number
cl(bits 7:6) High bits of maximum cylinder number
cl(bits 5:0) Maximum sector number
dhMaximum head number
dlNumber of drives

Definition at line 615 of file int13.c.

References __from_data16, i386_regs::bl, i386_regs::ch, i386_regs::cl, int13_data::cylinders, DBGC, DBGC2, i386_regs::dh, i386_regs::di, i386_regs::dl, san_device::drive, i386_seg_regs::es, int13_data::heads, int13(), INT13_BLKSIZE, int13_fdd_params, INT13_FDD_TYPE_1M44, int13_is_fdd(), INT13_STATUS_INVALID, num_drives, num_fdds, san_device::priv, i386_all_regs::regs, rm_ds, sandev_blksize(), int13_data::sectors_per_track, and i386_all_regs::segs.

Referenced by int13().

                                                               {
        struct int13_data *int13 = sandev->priv;
        unsigned int max_cylinder = int13->cylinders - 1;
        unsigned int max_head = int13->heads - 1;
        unsigned int max_sector = int13->sectors_per_track; /* sic */

        DBGC2 ( sandev, "Get drive parameters\n" );

        /* Validate blocksize */
        if ( sandev_blksize ( sandev ) != INT13_BLKSIZE ) {
                DBGC ( sandev, "\nINT 13 drive %02x invalid blocksize (%zd) "
                       "for non-extended parameters\n",
                       sandev->drive, sandev_blksize ( sandev ) );
                return -INT13_STATUS_INVALID;
        }

        /* Common parameters */
        ix86->regs.ch = ( max_cylinder & 0xff );
        ix86->regs.cl = ( ( ( max_cylinder >> 8 ) << 6 ) | max_sector );
        ix86->regs.dh = max_head;
        ix86->regs.dl = ( int13_is_fdd ( sandev ) ? num_fdds : num_drives );

        /* Floppy-specific parameters */
        if ( int13_is_fdd ( sandev ) ) {
                ix86->regs.bl = INT13_FDD_TYPE_1M44;
                ix86->segs.es = rm_ds;
                ix86->regs.di = __from_data16 ( &int13_fdd_params );
        }

        return 0;
}
static int int13_get_disk_type ( struct san_device sandev,
struct i386_all_regs ix86 
) [static]

INT 13, 15 - Get disk type.

Parameters:
sandevSAN device
Return values:
ahType code
cx:dxSector count
statusStatus code / disk type

Definition at line 656 of file int13.c.

References blocks, i386_regs::cx, DBGC2, i386_regs::dx, int13_capacity32(), INT13_DISK_TYPE_FDD, INT13_DISK_TYPE_HDD, int13_is_fdd(), and i386_all_regs::regs.

Referenced by int13().

                                                              {
        uint32_t blocks;

        DBGC2 ( sandev, "Get disk type\n" );

        if ( int13_is_fdd ( sandev ) ) {
                return INT13_DISK_TYPE_FDD;
        } else {
                blocks = int13_capacity32 ( sandev );
                ix86->regs.cx = ( blocks >> 16 );
                ix86->regs.dx = ( blocks & 0xffff );
                return INT13_DISK_TYPE_HDD;
        }
}
static int int13_extension_check ( struct san_device *sandev  __unused,
struct i386_all_regs ix86 
) [static]

INT 13, 41 - Extensions installation check.

Parameters:
sandevSAN device
bx0x55aa
Return values:
bx0xaa55
cxExtensions API support bitmap
statusStatus code / API version

Definition at line 681 of file int13.c.

References i386_regs::bx, i386_regs::cx, DBGC2, INT13_EXTENSION_64BIT, INT13_EXTENSION_EDD, INT13_EXTENSION_LINEAR, INT13_EXTENSION_VER_3_0, INT13_STATUS_INVALID, and i386_all_regs::regs.

Referenced by int13().

                                                                {

        if ( ix86->regs.bx == 0x55aa ) {
                DBGC2 ( sandev, "INT13 extensions installation check\n" );
                ix86->regs.bx = 0xaa55;
                ix86->regs.cx = ( INT13_EXTENSION_LINEAR |
                                  INT13_EXTENSION_EDD |
                                  INT13_EXTENSION_64BIT );
                return INT13_EXTENSION_VER_3_0;
        } else {
                return -INT13_STATUS_INVALID;
        }
}
static int int13_extended_rw ( struct san_device sandev,
struct i386_all_regs ix86,
int(*)(struct san_device *sandev, uint64_t lba, unsigned int count, userptr_t buffer sandev_rw 
) [static]

Extended read / write.

Parameters:
sandevSAN device
ds:siDisk address packet
sandev_rwSAN device read/write method
Return values:
statusStatus code

Definition at line 704 of file int13.c.

References int13_disk_address::buffer, buffer, int13_disk_address::buffer_phys, buffer_phys, bufsize, copy_from_real, int13_disk_address::count, count, DBGC, DBGC2, san_device::drive, i386_seg_regs::ds, get_real, int13_is_fdd(), INT13_STATUS_INVALID, INT13_STATUS_READ_ERROR, lba, int13_disk_address::lba, int13_disk_address::long_count, memset(), segoff::offset, offsetof, phys_to_user(), put_real, rc, real_to_user(), i386_all_regs::regs, sandev_rw(), segoff::segment, i386_all_regs::segs, i386_regs::si, and strerror().

Referenced by int13_extended_read(), and int13_extended_write().

                                                                          {
        struct int13_disk_address addr;
        uint8_t bufsize;
        uint64_t lba;
        unsigned long count;
        userptr_t buffer;
        int rc;

        /* Extended reads are not allowed on floppy drives.
         * ELTORITO.SYS seems to assume that we are really a CD-ROM if
         * we support extended reads for a floppy drive.
         */
        if ( int13_is_fdd ( sandev ) )
                return -INT13_STATUS_INVALID;

        /* Get buffer size */
        get_real ( bufsize, ix86->segs.ds,
                   ( ix86->regs.si + offsetof ( typeof ( addr ), bufsize ) ) );
        if ( bufsize < offsetof ( typeof ( addr ), buffer_phys ) ) {
                DBGC2 ( sandev, "<invalid buffer size %#02x\n>\n", bufsize );
                return -INT13_STATUS_INVALID;
        }

        /* Read parameters from disk address structure */
        memset ( &addr, 0, sizeof ( addr ) );
        copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si, bufsize );
        lba = addr.lba;
        DBGC2 ( sandev, "LBA %08llx <-> ", ( ( unsigned long long ) lba ) );
        if ( ( addr.count == 0xff ) ||
             ( ( addr.buffer.segment == 0xffff ) &&
               ( addr.buffer.offset == 0xffff ) ) ) {
                buffer = phys_to_user ( addr.buffer_phys );
                DBGC2 ( sandev, "%08llx",
                        ( ( unsigned long long ) addr.buffer_phys ) );
        } else {
                buffer = real_to_user ( addr.buffer.segment,
                                        addr.buffer.offset );
                DBGC2 ( sandev, "%04x:%04x", addr.buffer.segment,
                        addr.buffer.offset );
        }
        if ( addr.count <= 0x7f ) {
                count = addr.count;
        } else if ( addr.count == 0xff ) {
                count = addr.long_count;
        } else {
                DBGC2 ( sandev, " <invalid count %#02x>\n", addr.count );
                return -INT13_STATUS_INVALID;
        }
        DBGC2 ( sandev, " (count %ld)\n", count );

        /* Read from / write to block device */
        if ( ( rc = sandev_rw ( sandev, lba, count, buffer ) ) != 0 ) {
                DBGC ( sandev, "INT13 drive %02x extended I/O failed: %s\n",
                       sandev->drive, strerror ( rc ) );
                /* Record that no blocks were transferred successfully */
                addr.count = 0;
                put_real ( addr.count, ix86->segs.ds,
                           ( ix86->regs.si +
                             offsetof ( typeof ( addr ), count ) ) );
                return -INT13_STATUS_READ_ERROR;
        }

        return 0;
}
static int int13_extended_read ( struct san_device sandev,
struct i386_all_regs ix86 
) [static]

INT 13, 42 - Extended read.

Parameters:
sandevSAN device
ds:siDisk address packet
Return values:
statusStatus code

Definition at line 781 of file int13.c.

References DBGC2, int13_extended_rw(), and sandev_read().

Referenced by int13().

                                                              {

        DBGC2 ( sandev, "Extended read: " );
        return int13_extended_rw ( sandev, ix86, sandev_read );
}
static int int13_extended_write ( struct san_device sandev,
struct i386_all_regs ix86 
) [static]

INT 13, 43 - Extended write.

Parameters:
sandevSAN device
ds:siDisk address packet
Return values:
statusStatus code

Definition at line 795 of file int13.c.

References DBGC2, int13_extended_rw(), and sandev_write().

Referenced by int13().

                                                               {

        DBGC2 ( sandev, "Extended write: " );
        return int13_extended_rw ( sandev, ix86, sandev_write );
}
static int int13_extended_verify ( struct san_device sandev,
struct i386_all_regs ix86 
) [static]

INT 13, 44 - Verify sectors.

Parameters:
sandevSAN device
ds:siDisk address packet
Return values:
statusStatus code

Definition at line 809 of file int13.c.

References copy_from_real, int13_disk_address::count, count, DBG_EXTRA, DBGC2, i386_seg_regs::ds, INT13_STATUS_INVALID, lba, int13_disk_address::lba, i386_all_regs::regs, i386_all_regs::segs, and i386_regs::si.

Referenced by int13().

                                                                {
        struct int13_disk_address addr;
        uint64_t lba;
        unsigned long count;

        /* Read parameters from disk address structure */
        if ( DBG_EXTRA ) {
                copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si,
                                 sizeof ( addr ));
                lba = addr.lba;
                count = addr.count;
                DBGC2 ( sandev, "Verify: LBA %08llx (count %ld)\n",
                        ( ( unsigned long long ) lba ), count );
        }

        /* We have no mechanism for verifying sectors */
        return -INT13_STATUS_INVALID;
}
static int int13_extended_seek ( struct san_device sandev,
struct i386_all_regs ix86 
) [static]

INT 13, 44 - Extended seek.

Parameters:
sandevSAN device
ds:siDisk address packet
Return values:
statusStatus code

Definition at line 836 of file int13.c.

References copy_from_real, int13_disk_address::count, count, DBG_EXTRA, DBGC2, i386_seg_regs::ds, lba, int13_disk_address::lba, i386_all_regs::regs, i386_all_regs::segs, and i386_regs::si.

Referenced by int13().

                                                              {
        struct int13_disk_address addr;
        uint64_t lba;
        unsigned long count;

        /* Read parameters from disk address structure */
        if ( DBG_EXTRA ) {
                copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si,
                                 sizeof ( addr ));
                lba = addr.lba;
                count = addr.count;
                DBGC2 ( sandev, "Seek: LBA %08llx (count %ld)\n",
                        ( ( unsigned long long ) lba ), count );
        }

        /* Ignore and return success */
        return 0;
}
static int int13_device_path_info ( struct san_device sandev,
struct edd_device_path_information dpi 
) [static]

Build device path information.

Parameters:
sandevSAN device
dpiDevice path information
Return values:
rcReturn status code

Definition at line 863 of file int13.c.

References san_device::active, assert, san_path::block, edd_interface_path::bus, device_description::bus_type, BUS_TYPE_PCI, edd_interface_path::channel, DBGC, device::desc, device, edd_device_path_information::device_path, san_device::drive, EDD_BUS_TYPE_PCI, edd_describe(), EDD_DEVICE_PATH_INFO_KEY, ENODEV, ENOTSUP, edd_interface_path::function, edd_device_path_information::host_bus_type, identify_device(), edd_device_path_information::interface_path, edd_device_path_information::interface_type, edd_device_path_information::key, edd_device_path_information::len, device_description::location, NULL, PCI_BUS, PCI_FUNC, PCI_SLOT, rc, sandev_needs_reopen(), sandev_reopen(), edd_interface_path::slot, strerror(), and edd_host_bus_type::type.

Referenced by int13_get_extended_parameters().

                                                                              {
        struct san_path *sanpath;
        struct device *device;
        struct device_description *desc;
        unsigned int i;
        uint8_t sum = 0;
        int rc;

        /* Reopen block device if necessary */
        if ( sandev_needs_reopen ( sandev ) &&
             ( ( rc = sandev_reopen ( sandev ) ) != 0 ) )
                return rc;
        sanpath = sandev->active;
        assert ( sanpath != NULL );

        /* Get underlying hardware device */
        device = identify_device ( &sanpath->block );
        if ( ! device ) {
                DBGC ( sandev, "INT13 drive %02x cannot identify hardware "
                       "device\n", sandev->drive );
                return -ENODEV;
        }

        /* Fill in bus type and interface path */
        desc = &device->desc;
        switch ( desc->bus_type ) {
        case BUS_TYPE_PCI:
                dpi->host_bus_type.type = EDD_BUS_TYPE_PCI;
                dpi->interface_path.pci.bus = PCI_BUS ( desc->location );
                dpi->interface_path.pci.slot = PCI_SLOT ( desc->location );
                dpi->interface_path.pci.function = PCI_FUNC ( desc->location );
                dpi->interface_path.pci.channel = 0xff; /* unused */
                break;
        default:
                DBGC ( sandev, "INT13 drive %02x unrecognised bus type %d\n",
                       sandev->drive, desc->bus_type );
                return -ENOTSUP;
        }

        /* Get EDD block device description */
        if ( ( rc = edd_describe ( &sanpath->block, &dpi->interface_type,
                                   &dpi->device_path ) ) != 0 ) {
                DBGC ( sandev, "INT13 drive %02x cannot identify block device: "
                       "%s\n", sandev->drive, strerror ( rc ) );
                return rc;
        }

        /* Fill in common fields and fix checksum */
        dpi->key = EDD_DEVICE_PATH_INFO_KEY;
        dpi->len = sizeof ( *dpi );
        for ( i = 0 ; i < sizeof ( *dpi ) ; i++ )
                sum += *( ( ( uint8_t * ) dpi ) + i );
        dpi->checksum -= sum;

        return 0;
}
static int int13_get_extended_parameters ( struct san_device sandev,
struct i386_all_regs ix86 
) [static]

INT 13, 48 - Get extended parameters.

Parameters:
sandevSAN device
ds:siDrive parameter table
Return values:
statusStatus code

Definition at line 928 of file int13.c.

References bufsize, int13_disk_parameters::bufsize, copy_to_real, int13_data::cylinders, int13_disk_parameters::cylinders, DBGC, DBGC2, DBGC_HDA, int13_disk_parameters::dpi, dpi, int13_disk_parameters::dpte, dpte, san_device::drive, i386_seg_regs::ds, int13_disk_parameters::flags, get_real, int13_data::heads, int13_disk_parameters::heads, int13(), int13_device_path_info(), INT13_FL_CHS_VALID, INT13_FL_DMA_TRANSPARENT, INT13_MAX_CHS_SECTORS, INT13_STATUS_INVALID, len, memset(), segoff::offset, offsetof, params, san_device::priv, rc, i386_all_regs::regs, sandev_blksize(), sandev_capacity(), int13_disk_parameters::sector_size, int13_disk_parameters::sectors, int13_data::sectors_per_track, int13_disk_parameters::sectors_per_track, segoff::segment, i386_all_regs::segs, i386_regs::si, and strerror().

Referenced by int13().

                                                                        {
        struct int13_data *int13 = sandev->priv;
        struct int13_disk_parameters params;
        struct segoff address;
        size_t len = sizeof ( params );
        uint16_t bufsize;
        int rc;

        /* Get buffer size */
        get_real ( bufsize, ix86->segs.ds,
                   ( ix86->regs.si + offsetof ( typeof ( params ), bufsize )));

        DBGC2 ( sandev, "Get extended drive parameters to %04x:%04x+%02x\n",
                ix86->segs.ds, ix86->regs.si, bufsize );

        /* Build drive parameters */
        memset ( &params, 0, sizeof ( params ) );
        params.flags = INT13_FL_DMA_TRANSPARENT;
        if ( ( int13->cylinders < 1024 ) &&
             ( sandev_capacity ( sandev ) <= INT13_MAX_CHS_SECTORS ) ) {
                params.flags |= INT13_FL_CHS_VALID;
        }
        params.cylinders = int13->cylinders;
        params.heads = int13->heads;
        params.sectors_per_track = int13->sectors_per_track;
        params.sectors = sandev_capacity ( sandev );
        params.sector_size = sandev_blksize ( sandev );
        memset ( &params.dpte, 0xff, sizeof ( params.dpte ) );
        if ( ( rc = int13_device_path_info ( sandev, &params.dpi ) ) != 0 ) {
                DBGC ( sandev, "INT13 drive %02x could not provide device "
                       "path information: %s\n",
                       sandev->drive, strerror ( rc ) );
                len = offsetof ( typeof ( params ), dpi );
        }

        /* Calculate returned "buffer size" (which will be less than
         * the length actually copied if device path information is
         * present).
         */
        if ( bufsize < offsetof ( typeof ( params ), dpte ) )
                return -INT13_STATUS_INVALID;
        if ( bufsize < offsetof ( typeof ( params ), dpi ) ) {
                params.bufsize = offsetof ( typeof ( params ), dpte );
        } else {
                params.bufsize = offsetof ( typeof ( params ), dpi );
        }

        DBGC ( sandev, "INT 13 drive %02x described using extended "
               "parameters:\n", sandev->drive );
        address.segment = ix86->segs.ds;
        address.offset = ix86->regs.si;
        DBGC_HDA ( sandev, address, &params, len );

        /* Return drive parameters */
        if ( len > bufsize )
                len = bufsize;
        copy_to_real ( ix86->segs.ds, ix86->regs.si, &params, len );

        return 0;
}
static int int13_cdrom_status_terminate ( struct san_device sandev,
struct i386_all_regs ix86 
) [static]

INT 13, 4b - Get status or terminate CD-ROM emulation.

Parameters:
sandevSAN device
ds:siSpecification packet
Return values:
statusStatus code

Definition at line 997 of file int13.c.

References i386_regs::al, copy_to_real, DBGC, DBGC2, san_device::drive, int13_cdrom_specification::drive, i386_seg_regs::ds, INT13_STATUS_INVALID, san_device::is_cdrom, memset(), i386_all_regs::regs, i386_all_regs::segs, i386_regs::si, and int13_cdrom_specification::size.

Referenced by int13().

                                                                       {
        struct int13_cdrom_specification specification;

        DBGC2 ( sandev, "Get CD-ROM emulation status to %04x:%04x%s\n",
                ix86->segs.ds, ix86->regs.si,
                ( ix86->regs.al ? "" : " and terminate" ) );

        /* Fail if we are not a CD-ROM */
        if ( ! sandev->is_cdrom ) {
                DBGC ( sandev, "INT13 drive %02x is not a CD-ROM\n",
                       sandev->drive );
                return -INT13_STATUS_INVALID;
        }

        /* Build specification packet */
        memset ( &specification, 0, sizeof ( specification ) );
        specification.size = sizeof ( specification );
        specification.drive = sandev->drive;

        /* Return specification packet */
        copy_to_real ( ix86->segs.ds, ix86->regs.si, &specification,
                       sizeof ( specification ) );

        return 0;
}
static int int13_cdrom_read_boot_catalog ( struct san_device sandev,
struct i386_all_regs ix86 
) [static]

INT 13, 4d - Read CD-ROM boot catalog.

Parameters:
sandevSAN device
ds:siCommand packet
Return values:
statusStatus code

Definition at line 1032 of file int13.c.

References int13_data::boot_catalog, int13_cdrom_boot_catalog_command::buffer, copy_from_real, int13_cdrom_boot_catalog_command::count, DBGC, DBGC2, san_device::drive, i386_seg_regs::ds, int13(), INT13_STATUS_INVALID, INT13_STATUS_READ_ERROR, phys_to_user(), san_device::priv, rc, i386_all_regs::regs, sandev_read(), i386_all_regs::segs, i386_regs::si, start, int13_cdrom_boot_catalog_command::start, and strerror().

Referenced by int13().

                                                                        {
        struct int13_data *int13 = sandev->priv;
        struct int13_cdrom_boot_catalog_command command;
        unsigned int start;
        int rc;

        /* Read parameters from command packet */
        copy_from_real ( &command, ix86->segs.ds, ix86->regs.si,
                         sizeof ( command ) );
        DBGC2 ( sandev, "Read CD-ROM boot catalog to %08x\n", command.buffer );

        /* Fail if we have no boot catalog */
        if ( ! int13->boot_catalog ) {
                DBGC ( sandev, "INT13 drive %02x has no boot catalog\n",
                       sandev->drive );
                return -INT13_STATUS_INVALID;
        }
        start = ( int13->boot_catalog + command.start );

        /* Read from boot catalog */
        if ( ( rc = sandev_read ( sandev, start, command.count,
                                  phys_to_user ( command.buffer ) ) ) != 0 ) {
                DBGC ( sandev, "INT13 drive %02x could not read boot catalog: "
                       "%s\n", sandev->drive, strerror ( rc ) );
                return -INT13_STATUS_READ_ERROR;
        }

        return 0;
}
static __asmcall void int13 ( struct i386_all_regs ix86) [static]

INT 13 handler.

Definition at line 1067 of file int13.c.

References i386_regs::ah, CF, DBGC, DBGC2, i386_regs::dl, san_device::drive, i386_all_regs::flags, for_each_sandev, INT13_CDROM_READ_BOOT_CATALOG, int13_cdrom_read_boot_catalog(), INT13_CDROM_STATUS_TERMINATE, int13_cdrom_status_terminate(), int13_check_num_drives(), INT13_EXTENDED_READ, int13_extended_read(), INT13_EXTENDED_SEEK, int13_extended_seek(), INT13_EXTENDED_VERIFY, int13_extended_verify(), 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(), san_device::is_cdrom, int13_data::last_status, int13_data::natural_drive, OF, san_device::priv, i386_all_regs::regs, and status.

Referenced by int13_cdrom_read_boot_catalog(), int13_get_extended_parameters(), int13_get_last_status(), int13_get_parameters(), int13_guess_geometry(), int13_hook(), int13_hook_vector(), int13_parse_eltorito(), int13_rw_sectors(), and int13_sync_num_drives().

                                                           {
        int command = ix86->regs.ah;
        unsigned int bios_drive = ix86->regs.dl;
        struct san_device *sandev;
        struct int13_data *int13;
        int status;

        /* Check BIOS hasn't killed off our drive */
        int13_check_num_drives();

        for_each_sandev ( sandev ) {

                int13 = sandev->priv;
                if ( bios_drive != sandev->drive ) {
                        /* Remap any accesses to this drive's natural number */
                        if ( bios_drive == int13->natural_drive ) {
                                DBGC2 ( sandev, "INT13,%02x (%02x) remapped to "
                                        "(%02x)\n", ix86->regs.ah,
                                        bios_drive, sandev->drive );
                                ix86->regs.dl = sandev->drive;
                                return;
                        } else if ( ( ( bios_drive & 0x7f ) == 0x7f ) &&
                                    ( command == INT13_CDROM_STATUS_TERMINATE )
                                    && sandev->is_cdrom ) {
                                /* Catch non-drive-specific CD-ROM calls */
                        } else {
                                continue;
                        }
                }
                
                DBGC2 ( sandev, "INT13,%02x (%02x): ",
                        ix86->regs.ah, bios_drive );

                switch ( command ) {
                case INT13_RESET:
                        status = int13_reset ( sandev, ix86 );
                        break;
                case INT13_GET_LAST_STATUS:
                        status = int13_get_last_status ( sandev, ix86 );
                        break;
                case INT13_READ_SECTORS:
                        status = int13_read_sectors ( sandev, ix86 );
                        break;
                case INT13_WRITE_SECTORS:
                        status = int13_write_sectors ( sandev, ix86 );
                        break;
                case INT13_GET_PARAMETERS:
                        status = int13_get_parameters ( sandev, ix86 );
                        break;
                case INT13_GET_DISK_TYPE:
                        status = int13_get_disk_type ( sandev, ix86 );
                        break;
                case INT13_EXTENSION_CHECK:
                        status = int13_extension_check ( sandev, ix86 );
                        break;
                case INT13_EXTENDED_READ:
                        status = int13_extended_read ( sandev, ix86 );
                        break;
                case INT13_EXTENDED_WRITE:
                        status = int13_extended_write ( sandev, ix86 );
                        break;
                case INT13_EXTENDED_VERIFY:
                        status = int13_extended_verify ( sandev, ix86 );
                        break;
                case INT13_EXTENDED_SEEK:
                        status = int13_extended_seek ( sandev, ix86 );
                        break;
                case INT13_GET_EXTENDED_PARAMETERS:
                        status = int13_get_extended_parameters ( sandev, ix86 );
                        break;
                case INT13_CDROM_STATUS_TERMINATE:
                        status = int13_cdrom_status_terminate ( sandev, ix86 );
                        break;
                case INT13_CDROM_READ_BOOT_CATALOG:
                        status = int13_cdrom_read_boot_catalog ( sandev, ix86 );
                        break;
                default:
                        DBGC2 ( sandev, "*** Unrecognised INT13 ***\n" );
                        status = -INT13_STATUS_INVALID;
                        break;
                }

                /* Store status for INT 13,01 */
                int13->last_status = status;

                /* Negative status indicates an error */
                if ( status < 0 ) {
                        status = -status;
                        DBGC ( sandev, "INT13,%02x (%02x) failed with status "
                               "%02x\n", ix86->regs.ah, sandev->drive, status );
                } else {
                        ix86->flags &= ~CF;
                }
                ix86->regs.ah = status;

                /* Set OF to indicate to wrapper not to chain this call */
                ix86->flags |= OF;

                return;
        }
}
static void int13_hook_vector ( void  ) [static]

Hook INT 13 handler.

Definition at line 1173 of file int13.c.

References __asm__(), hook_bios_interrupt(), int13(), int13_vector, int13_wrapper(), TEXT16_CODE, and VIRT_CALL.

Referenced by int13_hook().

                                       {
        /* Assembly wrapper to call int13().  int13() sets OF if we
         * should not chain to the previous handler.  (The wrapper
         * clears CF and OF before calling int13()).
         */
        __asm__  __volatile__ (
               TEXT16_CODE ( "\nint13_wrapper:\n\t"
                             /* Preserve %ax and %dx for future reference */
                             "pushw %%bp\n\t"
                             "movw %%sp, %%bp\n\t"                           
                             "pushw %%ax\n\t"
                             "pushw %%dx\n\t"
                             /* Clear OF, set CF, call int13() */
                             "orb $0, %%al\n\t" 
                             "stc\n\t"
                             VIRT_CALL ( int13 )
                             /* Chain if OF not set */
                             "jo 1f\n\t"
                             "pushfw\n\t"
                             "lcall *%%cs:int13_vector\n\t"
                             "\n1:\n\t"
                             /* Overwrite flags for iret */
                             "pushfw\n\t"
                             "popw 6(%%bp)\n\t"
                             /* Fix up %dl:
                              *
                              * INT 13,15 : do nothing if hard disk
                              * INT 13,08 : load with number of drives
                              * all others: restore original value
                              */
                             "cmpb $0x15, -1(%%bp)\n\t"
                             "jne 2f\n\t"
                             "testb $0x80, -4(%%bp)\n\t"
                             "jnz 3f\n\t"
                             "\n2:\n\t"
                             "movb -4(%%bp), %%dl\n\t"
                             "cmpb $0x08, -1(%%bp)\n\t"
                             "jne 3f\n\t"
                             "testb $0x80, %%dl\n\t"
                             "movb %%cs:num_drives, %%dl\n\t"
                             "jnz 3f\n\t"
                             "movb %%cs:num_fdds, %%dl\n\t"
                             /* Return */
                             "\n3:\n\t"
                             "movw %%bp, %%sp\n\t"
                             "popw %%bp\n\t"
                             "iret\n\t" ) : : );

        hook_bios_interrupt ( 0x13, ( intptr_t ) int13_wrapper, &int13_vector );
}
static void int13_unhook_vector ( void  ) [static]

Unhook INT 13 handler.

Definition at line 1227 of file int13.c.

References int13_vector, int13_wrapper(), and unhook_bios_interrupt().

Referenced by int13_unhook().

static int int13_hook ( unsigned int  drive,
struct uri **  uris,
unsigned int  count,
unsigned int  flags 
) [static]

Hook INT 13 SAN device.

Parameters:
driveDrive number
urisList of URIs
countNumber of URIs
flagsFlags
Return values:
driveDrive number, or negative error

Registers the drive with the INT 13 emulation subsystem, and hooks the INT 13 interrupt vector (if not already hooked).

Definition at line 1244 of file int13.c.

References alloc_sandev(), int13_data::cylinders, DBGC, devices_get(), san_device::drive, drive, ENOMEM, free, have_sandevs(), int13_data::heads, int13(), INT13_BLKSIZE, int13_guess_geometry(), int13_hook_vector(), int13_parse_eltorito(), int13_sync_num_drives(), san_device::is_cdrom, malloc(), int13_data::natural_drive, num_drives, num_fdds, san_device::priv, rc, register_sandev(), sandev_blksize(), sandev_put(), int13_data::sectors_per_track, strerror(), and unregister_sandev().

                                                                 {
        struct san_device *sandev;
        struct int13_data *int13;
        unsigned int natural_drive;
        void *scratch;
        int need_hook = ( ! have_sandevs() );
        int rc;

        /* Calculate natural drive number */
        int13_sync_num_drives();
        natural_drive = ( ( drive & 0x80 ) ? ( num_drives | 0x80 ) : num_fdds );

        /* Use natural drive number if directed to do so */
        if ( ( drive & 0x7f ) == 0x7f )
                drive = natural_drive;

        /* Allocate SAN device */
        sandev = alloc_sandev ( uris, count, sizeof ( *int13 ) );
        if ( ! sandev ) {
                rc = -ENOMEM;
                goto err_alloc;
        }
        int13 = sandev->priv;
        int13->natural_drive = natural_drive;

        /* Register SAN device */
        if ( ( rc = register_sandev ( sandev, drive, flags ) ) != 0 ) {
                DBGC ( sandev, "INT13 drive %02x could not register: %s\n",
                       drive, strerror ( rc ) );
                goto err_register;
        }

        /* Allocate scratch area */
        scratch = malloc ( sandev_blksize ( sandev ) );
        if ( ! scratch )
                goto err_alloc_scratch;

        /* Parse parameters, if present */
        if ( sandev->is_cdrom &&
             ( ( rc = int13_parse_eltorito ( sandev, scratch ) ) != 0 ) )
                goto err_parse_eltorito;

        /* Give drive a default geometry, if applicable */
        if ( ( sandev_blksize ( sandev ) == INT13_BLKSIZE ) &&
             ( ( rc = int13_guess_geometry ( sandev, scratch ) ) != 0 ) )
                goto err_guess_geometry;

        DBGC ( sandev, "INT13 drive %02x (naturally %02x) registered with "
               "C/H/S geometry %d/%d/%d\n",
               sandev->drive, int13->natural_drive, int13->cylinders,
               int13->heads, int13->sectors_per_track );

        /* Hook INT 13 vector if not already hooked */
        if ( need_hook ) {
                int13_hook_vector();
                devices_get();
        }

        /* Update BIOS drive count */
        int13_sync_num_drives();

        free ( scratch );
        return drive;

 err_guess_geometry:
 err_parse_eltorito:
        free ( scratch );
 err_alloc_scratch:
        unregister_sandev ( sandev );
 err_register:
        sandev_put ( sandev );
 err_alloc:
        return rc;
}
static void int13_unhook ( unsigned int  drive) [static]

Unhook INT 13 SAN device.

Parameters:
driveDrive number

Unregisters the drive from the INT 13 emulation subsystem. If this is the last SAN device, the INT 13 vector is unhooked (if possible).

Definition at line 1329 of file int13.c.

References DBG, DBGC, devices_put(), san_device::drive, have_sandevs(), int13_unhook_vector(), sandev_find(), sandev_put(), and unregister_sandev().

                                                {
        struct san_device *sandev;

        /* Find drive */
        sandev = sandev_find ( drive );
        if ( ! sandev ) {
                DBG ( "INT13 cannot find drive %02x\n", drive );
                return;
        }

        /* Unregister SAN device */
        unregister_sandev ( sandev );

        /* Should adjust BIOS drive count, but it's difficult
         * to do so reliably.
         */

        DBGC ( sandev, "INT13 drive %02x unregistered\n", sandev->drive );

        /* Unhook INT 13 vector if no more drives */
        if ( ! have_sandevs() ) {
                devices_put();
                int13_unhook_vector();
        }

        /* Drop reference to drive */
        sandev_put ( sandev );
}
static int int13_load_mbr ( unsigned int  drive,
struct segoff address 
) [static]

Load and verify master boot record from INT 13 drive.

Parameters:
driveDrive number
addressBoot code address to fill in
Return values:
rcReturn status code

Definition at line 1365 of file int13.c.

References __asm__(), DBG, EIO, ENOEXEC, get_real, INT13_MBR_MAGIC, magic, segoff::offset, offsetof, REAL_CODE, segoff::segment, and status.

Referenced by int13_boot().

                                                                         {
        uint16_t status;
        int discard_b, discard_c, discard_d;
        uint16_t magic;

        /* Use INT 13, 02 to read the MBR */
        address->segment = 0;
        address->offset = 0x7c00;
        __asm__ __volatile__ ( REAL_CODE ( "pushw %%es\n\t"
                                           "pushl %%ebx\n\t"
                                           "popw %%bx\n\t"
                                           "popw %%es\n\t"
                                           "stc\n\t"
                                           "sti\n\t"
                                           "int $0x13\n\t"
                                           "sti\n\t" /* BIOS bugs */
                                           "jc 1f\n\t"
                                           "xorw %%ax, %%ax\n\t"
                                           "\n1:\n\t"
                                           "popw %%es\n\t" )
                               : "=a" ( status ), "=b" ( discard_b ),
                                 "=c" ( discard_c ), "=d" ( discard_d )
                               : "a" ( 0x0201 ), "b" ( *address ),
                                 "c" ( 1 ), "d" ( drive ) );
        if ( status ) {
                DBG ( "INT13 drive %02x could not read MBR (status %04x)\n",
                      drive, status );
                return -EIO;
        }

        /* Check magic signature */
        get_real ( magic, address->segment,
                   ( address->offset +
                     offsetof ( struct master_boot_record, magic ) ) );
        if ( magic != INT13_MBR_MAGIC ) {
                DBG ( "INT13 drive %02x does not contain a valid MBR\n",
                      drive );
                return -ENOEXEC;
        }

        return 0;
}
static struct int13_cdrom_boot_catalog_command __data16 ( eltorito_cmd  ) [static, read]

El Torito boot catalog command packet.

static struct int13_disk_address __bss16 ( eltorito_address  ) [static, read]

El Torito disk address packet.

static int int13_load_eltorito ( unsigned int  drive,
struct segoff address 
) [static]

Load and verify El Torito boot record from INT 13 drive.

Parameters:
driveDrive number
addressBoot code address to fill in
Return values:
rcReturn status code

Definition at line 1428 of file int13.c.

References __asm__(), __attribute__, __from_data16, address, buffer_phys, copy_from_user(), DBG, EIO, eltorito_address, ELTORITO_BOOTABLE, eltorito_cmd, ELTORITO_NO_EMULATION, ELTORITO_PLATFORM_X86, ENOEXEC, ENOTSUP, segoff::offset, offsetof, phys_to_user(), REAL_CODE, segoff::segment, and status.

Referenced by int13_boot().

                                                                              {
        struct {
                struct eltorito_validation_entry valid;
                struct eltorito_boot_entry boot;
        } __attribute__ (( packed )) catalog;
        uint16_t status;

        /* Use INT 13, 4d to read the boot catalog */
        __asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
                                           "sti\n\t"
                                           "int $0x13\n\t"
                                           "sti\n\t" /* BIOS bugs */
                                           "jc 1f\n\t"
                                           "xorw %%ax, %%ax\n\t"
                                           "\n1:\n\t" )
                               : "=a" ( status )
                               : "a" ( 0x4d00 ), "d" ( drive ),
                                 "S" ( __from_data16 ( &eltorito_cmd ) ) );
        if ( status ) {
                DBG ( "INT13 drive %02x could not read El Torito boot catalog "
                      "(status %04x)\n", drive, status );
                return -EIO;
        }
        copy_from_user ( &catalog, phys_to_user ( eltorito_cmd.buffer ), 0,
                         sizeof ( catalog ) );

        /* Sanity checks */
        if ( catalog.valid.platform_id != ELTORITO_PLATFORM_X86 ) {
                DBG ( "INT13 drive %02x El Torito specifies unknown platform "
                      "%02x\n", drive, catalog.valid.platform_id );
                return -ENOEXEC;
        }
        if ( catalog.boot.indicator != ELTORITO_BOOTABLE ) {
                DBG ( "INT13 drive %02x El Torito is not bootable\n", drive );
                return -ENOEXEC;
        }
        if ( catalog.boot.media_type != ELTORITO_NO_EMULATION ) {
                DBG ( "INT13 drive %02x El Torito requires emulation "
                       "type %02x\n", drive, catalog.boot.media_type );
                return -ENOTSUP;
        }
        DBG ( "INT13 drive %02x El Torito boot image at LBA %08x (count %d)\n",
              drive, catalog.boot.start, catalog.boot.length );
        address->segment = ( catalog.boot.load_segment ?
                             catalog.boot.load_segment : 0x7c0 );
        address->offset = 0;
        DBG ( "INT13 drive %02x El Torito boot image loads at %04x:%04x\n",
              drive, address->segment, address->offset );

        /* Use INT 13, 42 to read the boot image */
        eltorito_address.bufsize =
                offsetof ( typeof ( eltorito_address ), buffer_phys );
        eltorito_address.count = catalog.boot.length;
        eltorito_address.buffer = *address;
        eltorito_address.lba = catalog.boot.start;
        __asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
                                           "sti\n\t"
                                           "int $0x13\n\t"
                                           "sti\n\t" /* BIOS bugs */
                                           "jc 1f\n\t"
                                           "xorw %%ax, %%ax\n\t"
                                           "\n1:\n\t" )
                               : "=a" ( status )
                               : "a" ( 0x4200 ), "d" ( drive ),
                                 "S" ( __from_data16 ( &eltorito_address ) ) );
        if ( status ) {
                DBG ( "INT13 drive %02x could not read El Torito boot image "
                      "(status %04x)\n", drive, status );
                return -EIO;
        }

        return 0;
}
static int int13_boot ( unsigned int  drive,
const char *filename  __unused 
) [static]

Attempt to boot from an INT 13 drive.

Parameters:
driveDrive number
filenameFilename (or NULL to use default)
Return values:
rcReturn status code

This boots from the specified INT 13 drive by loading the Master Boot Record to 0000:7c00 and jumping to it. INT 18 is hooked to capture an attempt by the MBR to boot the next device. (This is the closest thing to a return path from an MBR).

Note that this function can never return success, by definition.

Definition at line 1516 of file int13.c.

References call_bootsector(), DBG, ECANCELED, get_memmap(), int13_load_eltorito(), int13_load_mbr(), segoff::offset, rc, segoff::segment, and strerror().

                                                                            {
        struct memory_map memmap;
        struct segoff address;
        int rc;

        /* Look for a usable boot sector */
        if ( ( ( rc = int13_load_mbr ( drive, &address ) ) != 0 ) &&
             ( ( rc = int13_load_eltorito ( drive, &address ) ) != 0 ) )
                return rc;

        /* Dump out memory map prior to boot, if memmap debugging is
         * enabled.  Not required for program flow, but we have so
         * many problems that turn out to be memory-map related that
         * it's worth doing.
         */
        get_memmap ( &memmap );

        /* Jump to boot sector */
        if ( ( rc = call_bootsector ( address.segment, address.offset,
                                      drive ) ) != 0 ) {
                DBG ( "INT13 drive %02x boot returned: %s\n",
                      drive, strerror ( rc ) );
                return rc;
        }

        return -ECANCELED; /* -EIMPOSSIBLE */
}
static uint8_t __bss16_array ( xbftab  ) [static]

The boot firmware table(s) generated by iPXE.

static int int13_install ( struct acpi_header acpi) [static]

Install ACPI table.

Parameters:
acpiACPI description header
Return values:
rcReturn status code

Definition at line 1564 of file int13.c.

References __from_data16, acpi_fix_checksum(), acpi_name(), DBGC, DBGC_HDA, ENOSPC, len, acpi_header::length, memcpy(), acpi_header::oem_id, acpi_header::oem_table_id, segoff::offset, rm_ds, segoff::segment, acpi_header::signature, strncpy(), xbftab, and xbftab_used.

Referenced by int13_describe().

                                                      {
        struct segoff xbft_address;
        struct acpi_header *installed;
        size_t len;

        /* Check length */
        len = acpi->length;
        if ( len > ( sizeof ( xbftab ) - xbftab_used ) ) {
                DBGC ( acpi, "INT13 out of space for %s table\n",
                       acpi_name ( acpi->signature ) );
                return -ENOSPC;
        }

        /* Install table */
        installed = ( ( ( void * ) xbftab ) + xbftab_used );
        memcpy ( installed, acpi, len );
        xbft_address.segment = rm_ds;
        xbft_address.offset = __from_data16 ( installed );

        /* Fill in common parameters */
        strncpy ( installed->oem_id, "FENSYS",
                  sizeof ( installed->oem_id ) );
        strncpy ( installed->oem_table_id, "iPXE",
                  sizeof ( installed->oem_table_id ) );

        /* Fix checksum */
        acpi_fix_checksum ( installed );

        /* Update used length */
        xbftab_used = ( ( xbftab_used + len + XBFTAB_ALIGN - 1 ) &
                        ~( XBFTAB_ALIGN - 1 ) );

        DBGC ( acpi, "INT13 installed %s:\n",
               acpi_name ( installed->signature ) );
        DBGC_HDA ( acpi, xbft_address, installed, len );
        return 0;
}
static int int13_describe ( void  ) [static]

Describe SAN devices for SAN-booted operating system.

Return values:
rcReturn status code

Definition at line 1607 of file int13.c.

References acpi_install(), DBG, int13_install(), memset(), rc, strerror(), and xbftab.

                                   {
        int rc;

        /* Clear tables */
        memset ( &xbftab, 0, sizeof ( xbftab ) );
        xbftab_used = 0;

        /* Install ACPI tables */
        if ( ( rc = acpi_install ( int13_install ) ) != 0 ) {
                DBG ( "INT13 could not install ACPI tables: %s\n",
                      strerror ( rc ) );
                return rc;
        }

        return 0;
}
PROVIDE_SANBOOT ( pcbios  ,
san_hook  ,
int13_hook   
)
PROVIDE_SANBOOT ( pcbios  ,
san_unhook  ,
int13_unhook   
)
PROVIDE_SANBOOT ( pcbios  ,
san_boot  ,
int13_boot   
)
PROVIDE_SANBOOT ( pcbios  ,
san_describe  ,
int13_describe   
)

Variable Documentation

Equipment word.

This is a cached copy of the BIOS Data Area equipment word at 40:10.

Definition at line 121 of file int13.c.

Referenced by int13_check_num_drives(), and int13_sync_num_drives().

Initial value:
 {
        INT13_FDD_GEOMETRY ( 40, 1, 8 ),
        INT13_FDD_GEOMETRY ( 40, 1, 9 ),
        INT13_FDD_GEOMETRY ( 40, 2, 8 ),
        INT13_FDD_GEOMETRY ( 40, 1, 9 ),
        INT13_FDD_GEOMETRY ( 80, 2, 8 ),
        INT13_FDD_GEOMETRY ( 80, 2, 9 ),
        INT13_FDD_GEOMETRY ( 80, 2, 15 ),
        INT13_FDD_GEOMETRY ( 80, 2, 18 ),
        INT13_FDD_GEOMETRY ( 80, 2, 20 ),
        INT13_FDD_GEOMETRY ( 80, 2, 21 ),
        INT13_FDD_GEOMETRY ( 82, 2, 21 ),
        INT13_FDD_GEOMETRY ( 83, 2, 21 ),
        INT13_FDD_GEOMETRY ( 80, 2, 22 ),
        INT13_FDD_GEOMETRY ( 80, 2, 23 ),
        INT13_FDD_GEOMETRY ( 80, 2, 24 ),
        INT13_FDD_GEOMETRY ( 80, 2, 36 ),
        INT13_FDD_GEOMETRY ( 80, 2, 39 ),
        INT13_FDD_GEOMETRY ( 80, 2, 40 ),
        INT13_FDD_GEOMETRY ( 80, 2, 44 ),
        INT13_FDD_GEOMETRY ( 80, 2, 48 ),
}

Recognised floppy disk geometries.

Definition at line 297 of file int13.c.

Referenced by int13_guess_geometry_fdd().

size_t xbftab_used [static]

Total used length of boot firmware tables.

Definition at line 1556 of file int13.c.

Referenced by int13_install().