summaryrefslogtreecommitdiffstats
path: root/src/arch
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch')
-rw-r--r--src/arch/i386/image/eltorito.c336
-rw-r--r--src/arch/i386/include/bits/eltorito.h3
-rw-r--r--src/arch/i386/include/bits/sanboot.h14
-rw-r--r--src/arch/i386/include/int13.h61
-rw-r--r--src/arch/i386/include/ipxe/abft.h37
-rw-r--r--src/arch/i386/include/ipxe/bios_sanboot.h18
-rw-r--r--src/arch/i386/include/ipxe/ibft.h302
-rw-r--r--src/arch/i386/include/ipxe/sbft.h125
-rw-r--r--src/arch/i386/interface/pcbios/abft.c62
-rw-r--r--src/arch/i386/interface/pcbios/aoeboot.c78
-rw-r--r--src/arch/i386/interface/pcbios/ib_srpboot.c73
-rw-r--r--src/arch/i386/interface/pcbios/ibft.c451
-rw-r--r--src/arch/i386/interface/pcbios/int13.c890
-rw-r--r--src/arch/i386/interface/pcbios/iscsiboot.c75
-rw-r--r--src/arch/i386/interface/pcbios/keepsan.c26
-rw-r--r--src/arch/i386/interface/pcbios/sbft.c105
-rw-r--r--src/arch/x86_64/include/bits/sanboot.h12
17 files changed, 744 insertions, 1924 deletions
diff --git a/src/arch/i386/image/eltorito.c b/src/arch/i386/image/eltorito.c
deleted file mode 100644
index a416d15bf..000000000
--- a/src/arch/i386/image/eltorito.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-/**
- * @file
- *
- * El Torito bootable ISO image format
- *
- */
-
-#include <stdint.h>
-#include <errno.h>
-#include <assert.h>
-#include <realmode.h>
-#include <bootsector.h>
-#include <int13.h>
-#include <ipxe/uaccess.h>
-#include <ipxe/image.h>
-#include <ipxe/segment.h>
-#include <ipxe/ramdisk.h>
-#include <ipxe/init.h>
-
-#define ISO9660_BLKSIZE 2048
-#define ELTORITO_VOL_DESC_OFFSET ( 17 * ISO9660_BLKSIZE )
-
-/** An El Torito Boot Record Volume Descriptor */
-struct eltorito_vol_desc {
- /** Boot record indicator; must be 0 */
- uint8_t record_indicator;
- /** ISO-9660 identifier; must be "CD001" */
- uint8_t iso9660_id[5];
- /** Version, must be 1 */
- uint8_t version;
- /** Boot system indicator; must be "EL TORITO SPECIFICATION" */
- uint8_t system_indicator[32];
- /** Unused */
- uint8_t unused[32];
- /** Boot catalog sector */
- uint32_t sector;
-} __attribute__ (( packed ));
-
-/** An El Torito Boot Catalog Validation Entry */
-struct eltorito_validation_entry {
- /** Header ID; must be 1 */
- uint8_t header_id;
- /** Platform ID
- *
- * 0 = 80x86
- * 1 = PowerPC
- * 2 = Mac
- */
- uint8_t platform_id;
- /** Reserved */
- uint16_t reserved;
- /** ID string */
- uint8_t id_string[24];
- /** Checksum word */
- uint16_t checksum;
- /** Signature; must be 0xaa55 */
- uint16_t signature;
-} __attribute__ (( packed ));
-
-/** A bootable entry in the El Torito Boot Catalog */
-struct eltorito_boot_entry {
- /** Boot indicator
- *
- * Must be @c ELTORITO_BOOTABLE for a bootable ISO image
- */
- uint8_t indicator;
- /** Media type
- *
- */
- uint8_t media_type;
- /** Load segment */
- uint16_t load_segment;
- /** System type */
- uint8_t filesystem;
- /** Unused */
- uint8_t reserved_a;
- /** Sector count */
- uint16_t length;
- /** Starting sector */
- uint32_t start;
- /** Unused */
- uint8_t reserved_b[20];
-} __attribute__ (( packed ));
-
-/** Boot indicator for a bootable ISO image */
-#define ELTORITO_BOOTABLE 0x88
-
-/** El Torito media types */
-enum eltorito_media_type {
- /** No emulation */
- ELTORITO_NO_EMULATION = 0,
-};
-
-struct image_type eltorito_image_type __image_type ( PROBE_NORMAL );
-
-/**
- * Calculate 16-bit word checksum
- *
- * @v data Data to checksum
- * @v len Length (in bytes, must be even)
- * @ret sum Checksum
- */
-static unsigned int word_checksum ( void *data, size_t len ) {
- uint16_t *words;
- uint16_t sum = 0;
-
- for ( words = data ; len ; words++, len -= 2 ) {
- sum += *words;
- }
- return sum;
-}
-
-/**
- * Execute El Torito image
- *
- * @v image El Torito image
- * @ret rc Return status code
- */
-static int eltorito_exec ( struct image *image ) {
- struct ramdisk ramdisk;
- struct int13_drive int13_drive;
- unsigned int load_segment = image->priv.ul;
- unsigned int load_offset = ( load_segment ? 0 : 0x7c00 );
- int rc;
-
- memset ( &ramdisk, 0, sizeof ( ramdisk ) );
- init_ramdisk ( &ramdisk, image->data, image->len, ISO9660_BLKSIZE );
-
- memset ( &int13_drive, 0, sizeof ( int13_drive ) );
- int13_drive.blockdev = &ramdisk.blockdev;
- register_int13_drive ( &int13_drive );
-
- if ( ( rc = call_bootsector ( load_segment, load_offset,
- int13_drive.drive ) ) != 0 ) {
- DBGC ( image, "ElTorito %p boot failed: %s\n",
- image, strerror ( rc ) );
- goto err;
- }
-
- rc = -ECANCELED; /* -EIMPOSSIBLE */
- err:
- unregister_int13_drive ( &int13_drive );
- return rc;
-}
-
-/**
- * Read and verify El Torito Boot Record Volume Descriptor
- *
- * @v image El Torito file
- * @ret catalog_offset Offset of Boot Catalog
- * @ret rc Return status code
- */
-static int eltorito_read_voldesc ( struct image *image,
- unsigned long *catalog_offset ) {
- static const struct eltorito_vol_desc vol_desc_signature = {
- .record_indicator = 0,
- .iso9660_id = "CD001",
- .version = 1,
- .system_indicator = "EL TORITO SPECIFICATION",
- };
- struct eltorito_vol_desc vol_desc;
-
- /* Sanity check */
- if ( image->len < ( ELTORITO_VOL_DESC_OFFSET + ISO9660_BLKSIZE ) ) {
- DBGC ( image, "ElTorito %p too short\n", image );
- return -ENOEXEC;
- }
-
- /* Read and verify Boot Record Volume Descriptor */
- copy_from_user ( &vol_desc, image->data, ELTORITO_VOL_DESC_OFFSET,
- sizeof ( vol_desc ) );
- if ( memcmp ( &vol_desc, &vol_desc_signature,
- offsetof ( typeof ( vol_desc ), sector ) ) != 0 ) {
- DBGC ( image, "ElTorito %p invalid Boot Record Volume "
- "Descriptor\n", image );
- return -ENOEXEC;
- }
- *catalog_offset = ( vol_desc.sector * ISO9660_BLKSIZE );
-
- DBGC ( image, "ElTorito %p boot catalog at offset %#lx\n",
- image, *catalog_offset );
-
- return 0;
-}
-
-/**
- * Read and verify El Torito Boot Catalog
- *
- * @v image El Torito file
- * @v catalog_offset Offset of Boot Catalog
- * @ret boot_entry El Torito boot entry
- * @ret rc Return status code
- */
-static int eltorito_read_catalog ( struct image *image,
- unsigned long catalog_offset,
- struct eltorito_boot_entry *boot_entry ) {
- struct eltorito_validation_entry validation_entry;
-
- /* Sanity check */
- if ( image->len < ( catalog_offset + ISO9660_BLKSIZE ) ) {
- DBGC ( image, "ElTorito %p bad boot catalog offset %#lx\n",
- image, catalog_offset );
- return -ENOEXEC;
- }
-
- /* Read and verify the Validation Entry of the Boot Catalog */
- copy_from_user ( &validation_entry, image->data, catalog_offset,
- sizeof ( validation_entry ) );
- if ( word_checksum ( &validation_entry,
- sizeof ( validation_entry ) ) != 0 ) {
- DBGC ( image, "ElTorito %p bad Validation Entry checksum\n",
- image );
- return -ENOEXEC;
- }
-
- /* Read and verify the Initial/Default entry */
- copy_from_user ( boot_entry, image->data,
- ( catalog_offset + sizeof ( validation_entry ) ),
- sizeof ( *boot_entry ) );
- if ( boot_entry->indicator != ELTORITO_BOOTABLE ) {
- DBGC ( image, "ElTorito %p not bootable\n", image );
- return -ENOEXEC;
- }
- if ( boot_entry->media_type != ELTORITO_NO_EMULATION ) {
- DBGC ( image, "ElTorito %p cannot support media type %d\n",
- image, boot_entry->media_type );
- return -ENOTSUP;
- }
-
- DBGC ( image, "ElTorito %p media type %d segment %04x\n",
- image, boot_entry->media_type, boot_entry->load_segment );
-
- return 0;
-}
-
-/**
- * Load El Torito virtual disk image into memory
- *
- * @v image El Torito file
- * @v boot_entry El Torito boot entry
- * @ret rc Return status code
- */
-static int eltorito_load_disk ( struct image *image,
- struct eltorito_boot_entry *boot_entry ) {
- unsigned long start = ( boot_entry->start * ISO9660_BLKSIZE );
- unsigned long length = ( boot_entry->length * ISO9660_BLKSIZE );
- unsigned int load_segment;
- userptr_t buffer;
- int rc;
-
- /* Sanity check */
- if ( image->len < ( start + length ) ) {
- DBGC ( image, "ElTorito %p virtual disk lies outside image\n",
- image );
- return -ENOEXEC;
- }
- DBGC ( image, "ElTorito %p virtual disk at %#lx+%#lx\n",
- image, start, length );
-
- /* Calculate load address */
- load_segment = boot_entry->load_segment;
- buffer = real_to_user ( load_segment, ( load_segment ? 0 : 0x7c00 ) );
-
- /* Verify and prepare segment */
- if ( ( rc = prep_segment ( buffer, length, length ) ) != 0 ) {
- DBGC ( image, "ElTorito %p could not prepare segment: %s\n",
- image, strerror ( rc ) );
- return rc;
- }
-
- /* Copy image to segment */
- memcpy_user ( buffer, 0, image->data, start, length );
-
- return 0;
-}
-
-/**
- * Load El Torito image into memory
- *
- * @v image El Torito file
- * @ret rc Return status code
- */
-static int eltorito_load ( struct image *image ) {
- struct eltorito_boot_entry boot_entry;
- unsigned long bootcat_offset;
- int rc;
-
- /* Read Boot Record Volume Descriptor, if present */
- if ( ( rc = eltorito_read_voldesc ( image, &bootcat_offset ) ) != 0 )
- return rc;
-
- /* This is an El Torito image, valid or otherwise */
- if ( ! image->type )
- image->type = &eltorito_image_type;
-
- /* Read Boot Catalog */
- if ( ( rc = eltorito_read_catalog ( image, bootcat_offset,
- &boot_entry ) ) != 0 )
- return rc;
-
- /* Load Virtual Disk image */
- if ( ( rc = eltorito_load_disk ( image, &boot_entry ) ) != 0 )
- return rc;
-
- /* Record load segment in image private data field */
- image->priv.ul = boot_entry.load_segment;
-
- return 0;
-}
-
-/** El Torito image type */
-struct image_type eltorito_image_type __image_type ( PROBE_NORMAL ) = {
- .name = "El Torito",
- .load = eltorito_load,
- .exec = eltorito_exec,
-};
diff --git a/src/arch/i386/include/bits/eltorito.h b/src/arch/i386/include/bits/eltorito.h
deleted file mode 100644
index d43e9aacf..000000000
--- a/src/arch/i386/include/bits/eltorito.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifndef ELTORITO_PLATFORM
-#define ELTORITO_PLATFORM ELTORITO_PLATFORM_X86
-#endif /* ELTORITO_PLATFORM */
diff --git a/src/arch/i386/include/bits/sanboot.h b/src/arch/i386/include/bits/sanboot.h
new file mode 100644
index 000000000..9c77a4d42
--- /dev/null
+++ b/src/arch/i386/include/bits/sanboot.h
@@ -0,0 +1,14 @@
+#ifndef _BITS_SANBOOT_H
+#define _BITS_SANBOOT_H
+
+/** @file
+ *
+ * i386-specific sanboot API implementations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/bios_sanboot.h>
+
+#endif /* _BITS_SANBOOT_H */
diff --git a/src/arch/i386/include/int13.h b/src/arch/i386/include/int13.h
index ed085d575..2a0f19cfb 100644
--- a/src/arch/i386/include/int13.h
+++ b/src/arch/i386/include/int13.h
@@ -13,8 +13,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/list.h>
#include <realmode.h>
-struct block_device;
-
/**
* @defgroup int13ops INT 13 operation codes
* @{
@@ -56,6 +54,8 @@ struct block_device;
#define INT13_STATUS_INVALID 0x01
/** Read error */
#define INT13_STATUS_READ_ERROR 0x04
+/** Reset failed */
+#define INT13_STATUS_RESET_FAILED 0x05
/** Write error */
#define INT13_STATUS_WRITE_ERROR 0xcc
@@ -64,57 +64,6 @@ struct block_device;
/** Block size for non-extended INT 13 calls */
#define INT13_BLKSIZE 512
-/** An INT 13 emulated drive */
-struct int13_drive {
- /** List of all registered drives */
- struct list_head list;
-
- /** Underlying block device */
- struct block_device *blockdev;
-
- /** BIOS in-use drive number (0x80-0xff) */
- unsigned int drive;
- /** BIOS natural drive number (0x80-0xff)
- *
- * This is the drive number that would have been assigned by
- * 'naturally' appending the drive to the end of the BIOS
- * drive list.
- *
- * If the emulated drive replaces a preexisting drive, this is
- * the drive number that the preexisting drive gets remapped
- * to.
- */
- unsigned int natural_drive;
-
- /** Number of cylinders
- *
- * The cylinder number field in an INT 13 call is ten bits
- * wide, giving a maximum of 1024 cylinders. Conventionally,
- * when the 7.8GB limit of a CHS address is exceeded, it is
- * the number of cylinders that is increased beyond the
- * addressable limit.
- */
- unsigned int cylinders;
- /** Number of heads
- *
- * The head number field in an INT 13 call is eight bits wide,
- * giving a maximum of 256 heads. However, apparently all
- * versions of MS-DOS up to and including Win95 fail with 256
- * heads, so the maximum encountered in practice is 255.
- */
- unsigned int heads;
- /** Number of sectors per track
- *
- * The sector number field in an INT 13 call is six bits wide,
- * giving a maximum of 63 sectors, since sector numbering
- * (unlike head and cylinder numbering) starts at 1, not 0.
- */
- unsigned int sectors_per_track;
-
- /** Status of last operation */
- int last_status;
-};
-
/** An INT 13 disk address packet */
struct int13_disk_address {
/** Size of the packet, in bytes */
@@ -147,7 +96,6 @@ struct int13_disk_parameters {
uint64_t sectors;
/** Bytes per sector */
uint16_t sector_size;
-
} __attribute__ (( packed ));
/**
@@ -285,8 +233,7 @@ struct master_boot_record {
uint16_t signature;
} __attribute__ (( packed ));
-extern void register_int13_drive ( struct int13_drive *drive );
-extern void unregister_int13_drive ( struct int13_drive *drive );
-extern int int13_boot ( unsigned int drive );
+/** Use natural BIOS drive number */
+#define INT13_USE_NATURAL_DRIVE 0xff
#endif /* INT13_H */
diff --git a/src/arch/i386/include/ipxe/abft.h b/src/arch/i386/include/ipxe/abft.h
deleted file mode 100644
index ca9630202..000000000
--- a/src/arch/i386/include/ipxe/abft.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef _IPXE_ABFT_H
-#define _IPXE_ABFT_H
-
-/** @file
- *
- * AoE boot firmware table
- *
- */
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#include <stdint.h>
-#include <ipxe/acpi.h>
-#include <ipxe/if_ether.h>
-
-/** AoE boot firmware table signature */
-#define ABFT_SIG "aBFT"
-
-/**
- * AoE Boot Firmware Table (aBFT)
- */
-struct abft_table {
- /** ACPI header */
- struct acpi_description_header acpi;
- /** AoE shelf */
- uint16_t shelf;
- /** AoE slot */
- uint8_t slot;
- /** Reserved */
- uint8_t reserved_a;
- /** MAC address */
- uint8_t mac[ETH_ALEN];
-} __attribute__ (( packed ));
-
-extern void abft_fill_data ( struct aoe_session *aoe );
-
-#endif /* _IPXE_ABFT_H */
diff --git a/src/arch/i386/include/ipxe/bios_sanboot.h b/src/arch/i386/include/ipxe/bios_sanboot.h
new file mode 100644
index 000000000..097945487
--- /dev/null
+++ b/src/arch/i386/include/ipxe/bios_sanboot.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_BIOS_SANBOOT_H
+#define _IPXE_BIOS_SANBOOT_H
+
+/** @file
+ *
+ * Standard PC-BIOS sanboot interface
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef SANBOOT_PCBIOS
+#define SANBOOT_PREFIX_pcbios
+#else
+#define SANBOOT_PREFIX_pcbios __pcbios_
+#endif
+
+#endif /* _IPXE_BIOS_SANBOOT_H */
diff --git a/src/arch/i386/include/ipxe/ibft.h b/src/arch/i386/include/ipxe/ibft.h
deleted file mode 100644
index 8525fe819..000000000
--- a/src/arch/i386/include/ipxe/ibft.h
+++ /dev/null
@@ -1,302 +0,0 @@
-#ifndef _IPXE_IBFT_H
-#define _IPXE_IBFT_H
-
-/*
- * Copyright Fen Systems Ltd. 2007. Portions of this code are derived
- * from IBM Corporation Sample Programs. Copyright IBM Corporation
- * 2004, 2007. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-FILE_LICENCE ( BSD2 );
-
-/** @file
- *
- * iSCSI boot firmware table
- *
- * The information in this file is derived from the document "iSCSI
- * Boot Firmware Table (iBFT)" as published by IBM at
- *
- * ftp://ftp.software.ibm.com/systems/support/system_x_pdf/ibm_iscsi_boot_firmware_table_v1.02.pdf
- *
- */
-
-#include <stdint.h>
-#include <ipxe/acpi.h>
-#include <ipxe/in.h>
-
-/** iSCSI Boot Firmware Table signature */
-#define IBFT_SIG "iBFT"
-
-/** An offset from the start of the iBFT */
-typedef uint16_t ibft_off_t;
-
-/** Length of a string within the iBFT (excluding terminating NUL) */
-typedef uint16_t ibft_size_t;
-
-/** A string within the iBFT */
-struct ibft_string {
- /** Length of string */
- ibft_size_t length;
- /** Offset to string */
- ibft_off_t offset;
-} __attribute__ (( packed ));
-
-/** An IP address within the iBFT */
-struct ibft_ipaddr {
- /** Reserved; must be zero */
- uint16_t zeroes[5];
- /** Must be 0xffff if IPv4 address is present, otherwise zero */
- uint16_t ones;
- /** The IPv4 address, or zero if not present */
- struct in_addr in;
-} __attribute__ (( packed ));
-
-/**
- * iBFT structure header
- *
- * This structure is common to several sections within the iBFT.
- */
-struct ibft_header {
- /** Structure ID
- *
- * This is an IBFT_STRUCTURE_ID_XXX constant
- */
- uint8_t structure_id;
- /** Version (always 1) */
- uint8_t version;
- /** Length, including this header */
- uint16_t length;
- /** Index
- *
- * This is the number of the NIC or Target, when applicable.
- */
- uint8_t index;
- /** Flags */
- uint8_t flags;
-} __attribute__ (( packed ));
-
-/**
- * iBFT Control structure
- *
- */
-struct ibft_control {
- /** Common header */
- struct ibft_header header;
- /** Extensions */
- uint16_t extensions;
- /** Offset to Initiator structure */
- ibft_off_t initiator;
- /** Offset to NIC structure for NIC 0 */
- ibft_off_t nic_0;
- /** Offset to Target structure for target 0 */
- ibft_off_t target_0;
- /** Offset to NIC structure for NIC 1 */
- ibft_off_t nic_1;
- /** Offset to Target structure for target 1 */
- ibft_off_t target_1;
-} __attribute__ (( packed ));
-
-/** Structure ID for Control section */
-#define IBFT_STRUCTURE_ID_CONTROL 0x01
-
-/** Attempt login only to specified target
- *
- * If this flag is not set, all targets will be logged in to.
- */
-#define IBFT_FL_CONTROL_SINGLE_LOGIN_ONLY 0x01
-
-/**
- * iBFT Initiator structure
- *
- */
-struct ibft_initiator {
- /** Common header */
- struct ibft_header header;
- /** iSNS server */
- struct ibft_ipaddr isns_server;
- /** SLP server */
- struct ibft_ipaddr slp_server;
- /** Primary and secondary Radius servers */
- struct ibft_ipaddr radius[2];
- /** Initiator name */
- struct ibft_string initiator_name;
-} __attribute__ (( packed ));
-
-/** Structure ID for Initiator section */
-#define IBFT_STRUCTURE_ID_INITIATOR 0x02
-
-/** Initiator block valid */
-#define IBFT_FL_INITIATOR_BLOCK_VALID 0x01
-
-/** Initiator firmware boot selected */
-#define IBFT_FL_INITIATOR_FIRMWARE_BOOT_SELECTED 0x02
-
-/**
- * iBFT NIC structure
- *
- */
-struct ibft_nic {
- /** Common header */
- struct ibft_header header;
- /** IP address */
- struct ibft_ipaddr ip_address;
- /** Subnet mask
- *
- * This is the length of the subnet mask in bits (e.g. /24).
- */
- uint8_t subnet_mask_prefix;
- /** Origin */
- uint8_t origin;
- /** Default gateway */
- struct ibft_ipaddr gateway;
- /** Primary and secondary DNS servers */
- struct ibft_ipaddr dns[2];
- /** DHCP server */
- struct ibft_ipaddr dhcp;
- /** VLAN tag */
- uint16_t vlan;
- /** MAC address */
- uint8_t mac_address[6];
- /** PCI bus:dev:fn */
- uint16_t pci_bus_dev_func;
- /** Hostname */
- struct ibft_string hostname;
-} __attribute__ (( packed ));
-
-/** Structure ID for NIC section */
-#define IBFT_STRUCTURE_ID_NIC 0x03
-
-/** NIC block valid */
-#define IBFT_FL_NIC_BLOCK_VALID 0x01
-
-/** NIC firmware boot selected */
-#define IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED 0x02
-
-/** NIC global / link local */
-#define IBFT_FL_NIC_GLOBAL 0x04
-
-/**
- * iBFT Target structure
- *
- */
-struct ibft_target {
- /** Common header */
- struct ibft_header header;
- /** IP address */
- struct ibft_ipaddr ip_address;
- /** TCP port */
- uint16_t socket;
- /** Boot LUN */
- uint64_t boot_lun;
- /** CHAP type
- *
- * This is an IBFT_CHAP_XXX constant.
- */
- uint8_t chap_type;
- /** NIC association */
- uint8_t nic_association;
- /** Target name */
- struct ibft_string target_name;
- /** CHAP name */
- struct ibft_string chap_name;
- /** CHAP secret */
- struct ibft_string chap_secret;
- /** Reverse CHAP name */
- struct ibft_string reverse_chap_name;
- /** Reverse CHAP secret */
- struct ibft_string reverse_chap_secret;
-} __attribute__ (( packed ));
-
-/** Structure ID for Target section */
-#define IBFT_STRUCTURE_ID_TARGET 0x04
-
-/** Target block valid */
-#define IBFT_FL_TARGET_BLOCK_VALID 0x01
-
-/** Target firmware boot selected */
-#define IBFT_FL_TARGET_FIRMWARE_BOOT_SELECTED 0x02
-
-/** Target use Radius CHAP */
-#define IBFT_FL_TARGET_USE_CHAP 0x04
-
-/** Target use Radius rCHAP */
-#define IBFT_FL_TARGET_USE_RCHAP 0x08
-
-/* Values for chap_type */
-#define IBFT_CHAP_NONE 0 /**< No CHAP authentication */
-#define IBFT_CHAP_ONE_WAY 1 /**< One-way CHAP */
-#define IBFT_CHAP_MUTUAL 2 /**< Mutual CHAP */
-
-/**
- * iSCSI Boot Firmware Table (iBFT)
- */
-struct ibft_table {
- /** ACPI header */
- struct acpi_description_header acpi;
- /** Reserved */
- uint8_t reserved[12];
- /** Control structure */
- struct ibft_control control;
-} __attribute__ (( packed ));
-
-/**
- * iSCSI string block descriptor
- *
- * This is an internal structure that we use to keep track of the
- * allocation of string data.
- */
-struct ibft_string_block {
- /** The iBFT containing these strings */
- struct ibft_table *table;
- /** Offset of first free byte within iBFT */
- unsigned int offset;
-};
-
-/** Amount of space reserved for strings in a iPXE iBFT */
-#define IBFT_STRINGS_SIZE 384
-
-/**
- * An iBFT created by iPXE
- *
- */
-struct ipxe_ibft {
- /** The fixed section */
- struct ibft_table table;
- /** The Initiator section */
- struct ibft_initiator initiator __attribute__ (( aligned ( 16 ) ));
- /** The NIC section */
- struct ibft_nic nic __attribute__ (( aligned ( 16 ) ));
- /** The Target section */
- struct ibft_target target __attribute__ (( aligned ( 16 ) ));
- /** Strings block */
- char strings[IBFT_STRINGS_SIZE];
-} __attribute__ (( packed, aligned ( 16 ) ));
-
-struct net_device;
-struct iscsi_session;
-
-extern int ibft_fill_data ( struct net_device *netdev,
- struct iscsi_session *iscsi );
-
-#endif /* _IPXE_IBFT_H */
diff --git a/src/arch/i386/include/ipxe/sbft.h b/src/arch/i386/include/ipxe/sbft.h
deleted file mode 100644
index f99106247..000000000
--- a/src/arch/i386/include/ipxe/sbft.h
+++ /dev/null
@@ -1,125 +0,0 @@
-#ifndef _IPXE_SBFT_H
-#define _IPXE_SBFT_H
-
-/*
- * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-FILE_LICENCE ( BSD2 );
-
-/** @file
- *
- * SRP boot firmware table
- *
- * The working draft specification for the SRP boot firmware table can
- * be found at
- *
- * http://ipxe.org/wiki/srp/sbft
- *
- */
-
-#include <stdint.h>
-#include <ipxe/acpi.h>
-#include <ipxe/scsi.h>
-#include <ipxe/srp.h>
-#include <ipxe/ib_srp.h>
-
-/** SRP Boot Firmware Table signature */
-#define SBFT_SIG "sBFT"
-
-/** An offset from the start of the sBFT */
-typedef uint16_t sbft_off_t;
-
-/**
- * SRP Boot Firmware Table
- */
-struct sbft_table {
- /** ACPI header */
- struct acpi_description_header acpi;
- /** Offset to SCSI subtable */
- sbft_off_t scsi_offset;
- /** Offset to SRP subtable */
- sbft_off_t srp_offset;
- /** Offset to IB subtable, if present */
- sbft_off_t ib_offset;
- /** Reserved */
- uint8_t reserved[6];
-} __attribute__ (( packed ));
-
-/**
- * sBFT SCSI subtable
- */
-struct sbft_scsi_subtable {
- /** LUN */
- struct scsi_lun lun;
-} __attribute__ (( packed ));
-
-/**
- * sBFT SRP subtable
- */
-struct sbft_srp_subtable {
- /** Initiator and target ports */
- struct srp_port_ids port_ids;
-} __attribute__ (( packed ));
-
-/**
- * sBFT IB subtable
- */
-struct sbft_ib_subtable {
- /** Source GID */
- struct ib_gid sgid;
- /** Destination GID */
- struct ib_gid dgid;
- /** Service ID */
- struct ib_gid_half service_id;
- /** Partition key */
- uint16_t pkey;
- /** Reserved */
- uint8_t reserved[6];
-} __attribute__ (( packed ));
-
-/**
- * An sBFT created by iPXE
- */
-struct ipxe_sbft {
- /** The table header */
- struct sbft_table table;
- /** The SCSI subtable */
- struct sbft_scsi_subtable scsi;
- /** The SRP subtable */
- struct sbft_srp_subtable srp;
- /** The IB subtable */
- struct sbft_ib_subtable ib;
-} __attribute__ (( packed, aligned ( 16 ) ));
-
-struct srp_device;
-
-extern int sbft_fill_data ( struct srp_device *srp );
-
-#endif /* _IPXE_SBFT_H */
diff --git a/src/arch/i386/interface/pcbios/abft.c b/src/arch/i386/interface/pcbios/abft.c
deleted file mode 100644
index 9aa2f0987..000000000
--- a/src/arch/i386/interface/pcbios/abft.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#include <realmode.h>
-#include <ipxe/aoe.h>
-#include <ipxe/netdevice.h>
-#include <ipxe/abft.h>
-
-/** @file
- *
- * AoE Boot Firmware Table
- *
- */
-
-#define abftab __use_data16 ( abftab )
-/** The aBFT used by iPXE */
-struct abft_table __data16 ( abftab ) __attribute__ (( aligned ( 16 ) )) = {
- /* ACPI header */
- .acpi = {
- .signature = ABFT_SIG,
- .length = sizeof ( abftab ),
- .revision = 1,
- .oem_id = "FENSYS",
- .oem_table_id = "iPXE",
- },
-};
-
-/**
- * Fill in all variable portions of aBFT
- *
- * @v aoe AoE session
- */
-void abft_fill_data ( struct aoe_session *aoe ) {
-
- /* Fill in boot parameters */
- abftab.shelf = aoe->major;
- abftab.slot = aoe->minor;
- memcpy ( abftab.mac, aoe->netdev->ll_addr, sizeof ( abftab.mac ) );
-
- /* Update checksum */
- acpi_fix_checksum ( &abftab.acpi );
-
- DBG ( "AoE boot firmware table:\n" );
- DBG_HD ( &abftab, sizeof ( abftab ) );
-}
diff --git a/src/arch/i386/interface/pcbios/aoeboot.c b/src/arch/i386/interface/pcbios/aoeboot.c
deleted file mode 100644
index 388cd1407..000000000
--- a/src/arch/i386/interface/pcbios/aoeboot.c
+++ /dev/null
@@ -1,78 +0,0 @@
-#include <stdint.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <ipxe/aoe.h>
-#include <ipxe/ata.h>
-#include <ipxe/netdevice.h>
-#include <ipxe/sanboot.h>
-#include <ipxe/abft.h>
-#include <int13.h>
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-static int aoeboot ( const char *root_path ) {
- struct ata_device *ata;
- struct int13_drive *drive;
- int rc;
-
- ata = zalloc ( sizeof ( *ata ) );
- if ( ! ata ) {
- rc = -ENOMEM;
- goto err_alloc_ata;
- }
- drive = zalloc ( sizeof ( *drive ) );
- if ( ! drive ) {
- rc = -ENOMEM;
- goto err_alloc_drive;
- }
-
- /* FIXME: ugly, ugly hack */
- struct net_device *netdev = last_opened_netdev();
-
- if ( ( rc = aoe_attach ( ata, netdev, root_path ) ) != 0 ) {
- printf ( "Could not attach AoE device: %s\n",
- strerror ( rc ) );
- goto err_attach;
- }
- if ( ( rc = init_atadev ( ata ) ) != 0 ) {
- printf ( "Could not initialise AoE device: %s\n",
- strerror ( rc ) );
- goto err_init;
- }
-
- /* FIXME: ugly, ugly hack */
- struct aoe_session *aoe =
- container_of ( ata->backend, struct aoe_session, refcnt );
- abft_fill_data ( aoe );
-
- drive->blockdev = &ata->blockdev;
-
- register_int13_drive ( drive );
- printf ( "Registered as BIOS drive %#02x\n", drive->drive );
- printf ( "Booting from BIOS drive %#02x\n", drive->drive );
- rc = int13_boot ( drive->drive );
- printf ( "Boot failed\n" );
-
- /* Leave drive registered, if instructed to do so */
- if ( keep_san() )
- return rc;
-
- printf ( "Unregistering BIOS drive %#02x\n", drive->drive );
- unregister_int13_drive ( drive );
-
- err_init:
- aoe_detach ( ata );
- err_attach:
- free ( drive );
- err_alloc_drive:
- free ( ata );
- err_alloc_ata:
- return rc;
-}
-
-struct sanboot_protocol aoe_sanboot_protocol __sanboot_protocol = {
- .prefix = "aoe:",
- .boot = aoeboot,
-};
diff --git a/src/arch/i386/interface/pcbios/ib_srpboot.c b/src/arch/i386/interface/pcbios/ib_srpboot.c
deleted file mode 100644
index 711c1e936..000000000
--- a/src/arch/i386/interface/pcbios/ib_srpboot.c
+++ /dev/null
@@ -1,73 +0,0 @@
-#include <stdint.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <ipxe/sanboot.h>
-#include <int13.h>
-#include <ipxe/srp.h>
-#include <ipxe/sbft.h>
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-static int ib_srpboot ( const char *root_path ) {
- struct scsi_device *scsi;
- struct int13_drive *drive;
- int rc;
-
- scsi = zalloc ( sizeof ( *scsi ) );
- if ( ! scsi ) {
- rc = -ENOMEM;
- goto err_alloc_scsi;
- }
- drive = zalloc ( sizeof ( *drive ) );
- if ( ! drive ) {
- rc = -ENOMEM;
- goto err_alloc_drive;
- }
-
- if ( ( rc = srp_attach ( scsi, root_path ) ) != 0 ) {
- printf ( "Could not attach IB_SRP device: %s\n",
- strerror ( rc ) );
- goto err_attach;
- }
- if ( ( rc = init_scsidev ( scsi ) ) != 0 ) {
- printf ( "Could not initialise IB_SRP device: %s\n",
- strerror ( rc ) );
- goto err_init;
- }
-
- drive->blockdev = &scsi->blockdev;
-
- /* FIXME: ugly, ugly hack */
- struct srp_device *srp =
- container_of ( scsi->backend, struct srp_device, refcnt );
- sbft_fill_data ( srp );
-
- register_int13_drive ( drive );
- printf ( "Registered as BIOS drive %#02x\n", drive->drive );
- printf ( "Booting from BIOS drive %#02x\n", drive->drive );
- rc = int13_boot ( drive->drive );
- printf ( "Boot failed\n" );
-
- /* Leave drive registered, if instructed to do so */
- if ( keep_san() )
- return rc;
-
- printf ( "Unregistering BIOS drive %#02x\n", drive->drive );
- unregister_int13_drive ( drive );
-
- err_init:
- srp_detach ( scsi );
- err_attach:
- free ( drive );
- err_alloc_drive:
- free ( scsi );
- err_alloc_scsi:
- return rc;
-}
-
-struct sanboot_protocol ib_srp_sanboot_protocol __sanboot_protocol = {
- .prefix = "ib_srp:",
- .boot = ib_srpboot,
-};
diff --git a/src/arch/i386/interface/pcbios/ibft.c b/src/arch/i386/interface/pcbios/ibft.c
deleted file mode 100644
index 63dba65e5..000000000
--- a/src/arch/i386/interface/pcbios/ibft.c
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * Copyright Fen Systems Ltd. 2007. Portions of this code are derived
- * from IBM Corporation Sample Programs. Copyright IBM Corporation
- * 2004, 2007. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-FILE_LICENCE ( BSD2 );
-
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <byteswap.h>
-#include <realmode.h>
-#include <ipxe/pci.h>
-#include <ipxe/acpi.h>
-#include <ipxe/in.h>
-#include <ipxe/netdevice.h>
-#include <ipxe/ethernet.h>
-#include <ipxe/dhcp.h>
-#include <ipxe/iscsi.h>
-#include <ipxe/ibft.h>
-
-/** @file
- *
- * iSCSI boot firmware table
- *
- * The information in this file is derived from the document "iSCSI
- * Boot Firmware Table (iBFT)" as published by IBM at
- *
- * ftp://ftp.software.ibm.com/systems/support/system_x_pdf/ibm_iscsi_boot_firmware_table_v1.02.pdf
- *
- */
-
-#define ibftab __use_data16 ( ibftab )
-/** The iBFT used by iPXE */
-struct ipxe_ibft __data16 ( ibftab ) = {
- /* Table header */
- .table = {
- /* ACPI header */
- .acpi = {
- .signature = IBFT_SIG,
- .length = sizeof ( ibftab ),
- .revision = 1,
- .oem_id = "FENSYS",
- .oem_table_id = "iPXE",
- },
- /* Control block */
- .control = {
- .header = {
- .structure_id = IBFT_STRUCTURE_ID_CONTROL,
- .version = 1,
- .length = sizeof ( ibftab.table.control ),
- .flags = 0,
- },
- .initiator = offsetof ( typeof ( ibftab ), initiator ),
- .nic_0 = offsetof ( typeof ( ibftab ), nic ),
- .target_0 = offsetof ( typeof ( ibftab ), target ),
- },
- },
- /* iSCSI initiator information */
- .initiator = {
- .header = {
- .structure_id = IBFT_STRUCTURE_ID_INITIATOR,
- .version = 1,
- .length = sizeof ( ibftab.initiator ),
- .flags = ( IBFT_FL_INITIATOR_BLOCK_VALID |
- IBFT_FL_INITIATOR_FIRMWARE_BOOT_SELECTED ),
- },
- },
- /* NIC information */
- .nic = {
- .header = {
- .structure_id = IBFT_STRUCTURE_ID_NIC,
- .version = 1,
- .length = sizeof ( ibftab.nic ),
- .flags = ( IBFT_FL_NIC_BLOCK_VALID |
- IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED ),
- },
- },
- /* iSCSI target information */
- .target = {
- .header = {
- .structure_id = IBFT_STRUCTURE_ID_TARGET,
- .version = 1,
- .length = sizeof ( ibftab.target ),
- .flags = ( IBFT_FL_TARGET_BLOCK_VALID |
- IBFT_FL_TARGET_FIRMWARE_BOOT_SELECTED ),
- },
- },
-};
-
-/**
- * Fill in an IP address field within iBFT
- *
- * @v ipaddr IP address field
- * @v in IPv4 address
- */
-static void ibft_set_ipaddr ( struct ibft_ipaddr *ipaddr, struct in_addr in ) {
- memset ( ipaddr, 0, sizeof ( ipaddr ) );
- if ( in.s_addr ) {
- ipaddr->in = in;
- ipaddr->ones = 0xffff;
- }
-}
-
-/**
- * Fill in an IP address within iBFT from configuration setting
- *
- * @v ipaddr IP address field
- * @v setting Configuration setting
- * @v tag DHCP option tag
- */
-static void ibft_set_ipaddr_option ( struct ibft_ipaddr *ipaddr,
- struct setting *setting ) {
- struct in_addr in = { 0 };
- fetch_ipv4_setting ( NULL, setting, &in );
- ibft_set_ipaddr ( ipaddr, in );
-}
-
-/**
- * Read IP address from iBFT (for debugging)
- *
- * @v strings iBFT string block descriptor
- * @v string String field
- * @ret ipaddr IP address string
- */
-static const char * ibft_ipaddr ( struct ibft_ipaddr *ipaddr ) {
- return inet_ntoa ( ipaddr->in );
-}
-
-/**
- * Allocate a string within iBFT
- *
- * @v strings iBFT string block descriptor
- * @v string String field to fill in
- * @v len Length of string to allocate (excluding NUL)
- * @ret rc Return status code
- */
-static int ibft_alloc_string ( struct ibft_string_block *strings,
- struct ibft_string *string, size_t len ) {
- char *dest;
- unsigned int remaining;
-
- dest = ( ( ( char * ) strings->table ) + strings->offset );
- remaining = ( strings->table->acpi.length - strings->offset );
- if ( len >= remaining )
- return -ENOMEM;
-
- string->offset = strings->offset;
- string->length = len;
- strings->offset += ( len + 1 );
- return 0;
-}
-
-/**
- * Fill in a string field within iBFT
- *
- * @v strings iBFT string block descriptor
- * @v string String field
- * @v data String to fill in, or NULL
- * @ret rc Return status code
- */
-static int ibft_set_string ( struct ibft_string_block *strings,
- struct ibft_string *string, const char *data ) {
- char *dest;
- int rc;
-
- if ( ! data )
- return 0;
-
- if ( ( rc = ibft_alloc_string ( strings, string,
- strlen ( data ) ) ) != 0 )
- return rc;
- dest = ( ( ( char * ) strings->table ) + string->offset );
- strcpy ( dest, data );
-
- return 0;
-}
-
-/**
- * Fill in a string field within iBFT from configuration setting
- *
- * @v strings iBFT string block descriptor
- * @v string String field
- * @v setting Configuration setting
- * @ret rc Return status code
- */
-static int ibft_set_string_option ( struct ibft_string_block *strings,
- struct ibft_string *string,
- struct setting *setting ) {
- int len;
- char *dest;
- int rc;
-
- len = fetch_setting_len ( NULL, setting );
- if ( len < 0 ) {
- string->offset = 0;
- string->length = 0;
- return 0;
- }
-
- if ( ( rc = ibft_alloc_string ( strings, string, len ) ) != 0 )
- return rc;
- dest = ( ( ( char * ) strings->table ) + string->offset );
- fetch_string_setting ( NULL, setting, dest, ( len + 1 ) );
- return 0;
-}
-
-/**
- * Read string from iBFT (for debugging)
- *
- * @v strings iBFT string block descriptor
- * @v string String field
- * @ret data String content (or "<empty>")
- */
-static const char * ibft_string ( struct ibft_string_block *strings,
- struct ibft_string *string ) {
- return ( string->offset ?
- ( ( ( char * ) strings->table ) + string->offset ) : NULL );
-}
-
-/**
- * Fill in NIC portion of iBFT
- *
- * @v nic NIC portion of iBFT
- * @v strings iBFT string block descriptor
- * @v netdev Network device
- * @ret rc Return status code
- */
-static int ibft_fill_nic ( struct ibft_nic *nic,
- struct ibft_string_block *strings,
- struct net_device *netdev ) {
- struct ll_protocol *ll_protocol = netdev->ll_protocol;
- struct in_addr netmask_addr = { 0 };
- unsigned int netmask_count = 0;
- int rc;
-
- /* Extract values from DHCP configuration */
- ibft_set_ipaddr_option ( &nic->ip_address, &ip_setting );
- DBG ( "iBFT NIC IP = %s\n", ibft_ipaddr ( &nic->ip_address ) );
- ibft_set_ipaddr_option ( &nic->gateway, &gateway_setting );
- DBG ( "iBFT NIC gateway = %s\n", ibft_ipaddr ( &nic->gateway ) );
- ibft_set_ipaddr_option ( &nic->dns[0], &dns_setting );
- DBG ( "iBFT NIC DNS = %s\n", ibft_ipaddr ( &nic->dns[0] ) );
- if ( ( rc = ibft_set_string_option ( strings, &nic->hostname,
- &hostname_setting ) ) != 0 )
- return rc;
- DBG ( "iBFT NIC hostname = %s\n",
- ibft_string ( strings, &nic->hostname ) );
-
- /* Derive subnet mask prefix from subnet mask */
- fetch_ipv4_setting ( NULL, &netmask_setting, &netmask_addr );
- while ( netmask_addr.s_addr ) {
- if ( netmask_addr.s_addr & 0x1 )
- netmask_count++;
- netmask_addr.s_addr >>= 1;
- }
- nic->subnet_mask_prefix = netmask_count;
- DBG ( "iBFT NIC subnet = /%d\n", nic->subnet_mask_prefix );
-
- /* Extract values from net-device configuration */
- if ( ( rc = ll_protocol->eth_addr ( netdev->ll_addr,
- nic->mac_address ) ) != 0 ) {
- DBG ( "Could not determine iBFT MAC: %s\n", strerror ( rc ) );
- return rc;
- }
- DBG ( "iBFT NIC MAC = %s\n", eth_ntoa ( nic->mac_address ) );
- nic->pci_bus_dev_func = netdev->dev->desc.location;
- DBG ( "iBFT NIC PCI = %04x\n", nic->pci_bus_dev_func );
-
- return 0;
-}
-
-/**
- * Fill in Initiator portion of iBFT
- *
- * @v initiator Initiator portion of iBFT
- * @v strings iBFT string block descriptor
- * @ret rc Return status code
- */
-static int ibft_fill_initiator ( struct ibft_initiator *initiator,
- struct ibft_string_block *strings ) {
- const char *initiator_iqn = iscsi_initiator_iqn();
- int rc;
-
- if ( ( rc = ibft_set_string ( strings, &initiator->initiator_name,
- initiator_iqn ) ) != 0 )
- return rc;
- DBG ( "iBFT initiator hostname = %s\n",
- ibft_string ( strings, &initiator->initiator_name ) );
-
- return 0;
-}
-
-/**
- * Fill in Target CHAP portion of iBFT
- *
- * @v target Target portion of iBFT
- * @v strings iBFT string block descriptor
- * @v iscsi iSCSI session
- * @ret rc Return status code
- */
-static int ibft_fill_target_chap ( struct ibft_target *target,
- struct ibft_string_block *strings,
- struct iscsi_session *iscsi ) {
- int rc;
-
- if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_FORWARD_REQUIRED ) )
- return 0;
-
- assert ( iscsi->initiator_username );
- assert ( iscsi->initiator_password );
-
- target->chap_type = IBFT_CHAP_ONE_WAY;
- if ( ( rc = ibft_set_string ( strings, &target->chap_name,
- iscsi->initiator_username ) ) != 0 )
- return rc;
- DBG ( "iBFT target username = %s\n",
- ibft_string ( strings, &target->chap_name ) );
- if ( ( rc = ibft_set_string ( strings, &target->chap_secret,
- iscsi->initiator_password ) ) != 0 )
- return rc;
- DBG ( "iBFT target password = <redacted>\n" );
-
- return 0;
-}
-
-/**
- * Fill in Target Reverse CHAP portion of iBFT
- *
- * @v target Target portion of iBFT
- * @v strings iBFT string block descriptor
- * @v iscsi iSCSI session
- * @ret rc Return status code
- */
-static int ibft_fill_target_reverse_chap ( struct ibft_target *target,
- struct ibft_string_block *strings,
- struct iscsi_session *iscsi ) {
- int rc;
-
- if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_REQUIRED ) )
- return 0;
-
- assert ( iscsi->initiator_username );
- assert ( iscsi->initiator_password );
- assert ( iscsi->target_username );
- assert ( iscsi->target_password );
-
- target->chap_type = IBFT_CHAP_MUTUAL;
- if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_name,
- iscsi->target_username ) ) != 0 )
- return rc;
- DBG ( "iBFT target reverse username = %s\n",
- ibft_string ( strings, &target->chap_name ) );
- if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_secret,
- iscsi->target_password ) ) != 0 )
- return rc;
- DBG ( "iBFT target reverse password = <redacted>\n" );
-
- return 0;
-}
-
-/**
- * Fill in Target portion of iBFT
- *
- * @v target Target portion of iBFT
- * @v strings iBFT string block descriptor
- * @v iscsi iSCSI session
- * @ret rc Return status code
- */
-static int ibft_fill_target ( struct ibft_target *target,
- struct ibft_string_block *strings,
- struct iscsi_session *iscsi ) {
- struct sockaddr_in *sin_target =
- ( struct sockaddr_in * ) &iscsi->target_sockaddr;
- int rc;
-
- /* Fill in Target values */
- ibft_set_ipaddr ( &target->ip_address, sin_target->sin_addr );
- DBG ( "iBFT target IP = %s\n", ibft_ipaddr ( &target->ip_address ) );
- target->socket = ntohs ( sin_target->sin_port );
- DBG ( "iBFT target port = %d\n", target->socket );
- if ( ( rc = ibft_set_string ( strings, &target->target_name,
- iscsi->target_iqn ) ) != 0 )
- return rc;
- DBG ( "iBFT target name = %s\n",
- ibft_string ( strings, &target->target_name ) );
- if ( ( rc = ibft_fill_target_chap ( target, strings, iscsi ) ) != 0 )
- return rc;
- if ( ( rc = ibft_fill_target_reverse_chap ( target, strings,
- iscsi ) ) != 0 )
- return rc;
-
- return 0;
-}
-
-/**
- * Fill in all variable portions of iBFT
- *
- * @v netdev Network device
- * @v initiator_iqn Initiator IQN
- * @v st_target Target socket address
- * @v target_iqn Target IQN
- * @ret rc Return status code
- *
- */
-int ibft_fill_data ( struct net_device *netdev,
- struct iscsi_session *iscsi ) {
- struct ibft_string_block strings = {
- .table = &ibftab.table,
- .offset = offsetof ( typeof ( ibftab ), strings ),
- };
- int rc;
-
- /* Fill in NIC, Initiator and Target portions */
- if ( ( rc = ibft_fill_nic ( &ibftab.nic, &strings, netdev ) ) != 0 )
- return rc;
- if ( ( rc = ibft_fill_initiator ( &ibftab.initiator,
- &strings ) ) != 0 )
- return rc;
- if ( ( rc = ibft_fill_target ( &ibftab.target, &strings,
- iscsi ) ) != 0 )
- return rc;
-
- /* Update checksum */
- acpi_fix_checksum ( &ibftab.table.acpi );
-
- return 0;
-}
diff --git a/src/arch/i386/interface/pcbios/int13.c b/src/arch/i386/interface/pcbios/int13.c
index f72dc5fa9..97110fde1 100644
--- a/src/arch/i386/interface/pcbios/int13.c
+++ b/src/arch/i386/interface/pcbios/int13.c
@@ -19,6 +19,7 @@
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
+#include <stdlib.h>
#include <limits.h>
#include <byteswap.h>
#include <errno.h>
@@ -26,6 +27,14 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/list.h>
#include <ipxe/blockdev.h>
#include <ipxe/io.h>
+#include <ipxe/open.h>
+#include <ipxe/uri.h>
+#include <ipxe/process.h>
+#include <ipxe/xfer.h>
+#include <ipxe/retry.h>
+#include <ipxe/timer.h>
+#include <ipxe/acpi.h>
+#include <ipxe/sanboot.h>
#include <realmode.h>
#include <bios.h>
#include <biosint.h>
@@ -41,6 +50,77 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
+/**
+ * Overall timeout for INT 13 commands (independent of underlying device
+ *
+ * Underlying devices should ideally never become totally stuck.
+ * However, if they do, then the INT 13 mechanism provides no means
+ * for the caller to cancel the operation, and the machine appears to
+ * hang. Use an overall timeout for all commands to avoid this
+ * problem and bounce timeout failures to the caller.
+ */
+#define INT13_COMMAND_TIMEOUT ( 15 * TICKS_PER_SEC )
+
+/** An INT 13 emulated drive */
+struct int13_drive {
+ /** Reference count */
+ struct refcnt refcnt;
+ /** List of all registered drives */
+ struct list_head list;
+
+ /** Block device URI */
+ struct uri *uri;
+ /** Underlying block device interface */
+ struct interface block;
+
+ /** BIOS in-use drive number (0x80-0xff) */
+ unsigned int drive;
+ /** BIOS natural drive number (0x80-0xff)
+ *
+ * This is the drive number that would have been assigned by
+ * 'naturally' appending the drive to the end of the BIOS
+ * drive list.
+ *
+ * If the emulated drive replaces a preexisting drive, this is
+ * the drive number that the preexisting drive gets remapped
+ * to.
+ */
+ unsigned int natural_drive;
+
+ /** Block device capacity */
+ struct block_device_capacity capacity;
+
+ /** Number of cylinders
+ *
+ * The cylinder number field in an INT 13 call is ten bits
+ * wide, giving a maximum of 1024 cylinders. Conventionally,
+ * when the 7.8GB limit of a CHS address is exceeded, it is
+ * the number of cylinders that is increased beyond the
+ * addressable limit.
+ */
+ unsigned int cylinders;
+ /** Number of heads
+ *
+ * The head number field in an INT 13 call is eight bits wide,
+ * giving a maximum of 256 heads. However, apparently all
+ * versions of MS-DOS up to and including Win95 fail with 256
+ * heads, so the maximum encountered in practice is 255.
+ */
+ unsigned int heads;
+ /** Number of sectors per track
+ *
+ * The sector number field in an INT 13 call is six bits wide,
+ * giving a maximum of 63 sectors, since sector numbering
+ * (unlike head and cylinder numbering) starts at 1, not 0.
+ */
+ unsigned int sectors_per_track;
+
+ /** Underlying device status, if in error */
+ int block_rc;
+ /** Status of last operation */
+ int last_status;
+};
+
/** Vector for chaining to other INT 13 handlers */
static struct segoff __text16 ( int13_vector );
#define int13_vector __use_text16 ( int13_vector )
@@ -49,7 +129,7 @@ static struct segoff __text16 ( int13_vector );
extern void int13_wrapper ( void );
/** List of registered emulated drives */
-static LIST_HEAD ( drives );
+static LIST_HEAD ( int13s );
/**
* Number of BIOS drives
@@ -60,19 +140,309 @@ static LIST_HEAD ( drives );
*/
static uint8_t num_drives;
+/** An INT 13 command */
+struct int13_command {
+ /** Status */
+ int rc;
+ /** INT 13 drive */
+ struct int13_drive *int13;
+ /** Underlying block device interface */
+ struct interface block;
+ /** Command timeout timer */
+ struct retry_timer timer;
+};
+
+/**
+ * Record INT 13 drive capacity
+ *
+ * @v command INT 13 command
+ * @v capacity Block device capacity
+ */
+static void int13_command_capacity ( struct int13_command *command,
+ struct block_device_capacity *capacity ) {
+ memcpy ( &command->int13->capacity, capacity,
+ sizeof ( command->int13->capacity ) );
+}
+
+/**
+ * Close INT 13 command
+ *
+ * @v command INT 13 command
+ * @v rc Reason for close
+ */
+static void int13_command_close ( struct int13_command *command, int rc ) {
+ intf_restart ( &command->block, rc );
+ stop_timer ( &command->timer );
+ command->rc = rc;
+}
+
+/**
+ * Handle INT 13 command timer expiry
+ *
+ * @v timer Timer
+ */
+static void int13_command_expired ( struct retry_timer *timer,
+ int over __unused ) {
+ struct int13_command *command =
+ container_of ( timer, struct int13_command, timer );
+
+ int13_command_close ( command, -ETIMEDOUT );
+}
+
+/** INT 13 command interface operations */
+static struct interface_operation int13_command_op[] = {
+ INTF_OP ( intf_close, struct int13_command *, int13_command_close ),
+ INTF_OP ( block_capacity, struct int13_command *,
+ int13_command_capacity ),
+};
+
+/** INT 13 command interface descriptor */
+static struct interface_descriptor int13_command_desc =
+ INTF_DESC ( struct int13_command, block, int13_command_op );
+
+/**
+ * Prepare to issue INT 13 command
+ *
+ * @v command INT 13 command
+ * @v int13 Emulated drive
+ * @ret rc Return status code
+ */
+static int int13_command_start ( struct int13_command *command,
+ struct int13_drive *int13 ) {
+
+ /* Sanity check */
+ assert ( command->int13 == NULL );
+ assert ( ! timer_running ( &command->timer ) );
+
+ /* Initialise command */
+ command->rc = -EINPROGRESS;
+ command->int13 = int13;
+ start_timer_fixed ( &command->timer, INT13_COMMAND_TIMEOUT );
+
+ /* Wait for block control interface to become ready */
+ while ( ( command->rc == -EINPROGRESS ) &&
+ ( xfer_window ( &int13->block ) == 0 ) ) {
+ step();
+ }
+
+ return ( ( command->rc == -EINPROGRESS ) ?
+ int13->block_rc : command->rc );
+}
+
+/**
+ * Wait for INT 13 command to complete
+ *
+ * @v command INT 13 command
+ * @ret rc Return status code
+ */
+static int int13_command_wait ( struct int13_command *command ) {
+
+ /* Sanity check */
+ assert ( timer_running ( &command->timer ) );
+
+ /* Wait for command to complete */
+ while ( command->rc == -EINPROGRESS )
+ step();
+
+ assert ( ! timer_running ( &command->timer ) );
+ return command->rc;
+}
+
+/**
+ * Terminate INT 13 command
+ *
+ * @v command INT 13 command
+ */
+static void int13_command_stop ( struct int13_command *command ) {
+ stop_timer ( &command->timer );
+ command->int13 = NULL;
+}
+
+/** The single active INT 13 command */
+static struct int13_command int13_command = {
+ .block = INTF_INIT ( int13_command_desc ),
+ .timer = TIMER_INIT ( int13_command_expired ),
+};
+
+/**
+ * Read from or write to INT 13 drive
+ *
+ * @v int13 Emulated drive
+ * @v lba Starting logical block address
+ * @v count Number of logical blocks
+ * @v buffer Data buffer
+ * @v block_rw Block read/write method
+ * @ret rc Return status code
+ */
+static int int13_rw ( struct int13_drive *int13, uint64_t lba,
+ unsigned int count, userptr_t buffer,
+ int ( * block_rw ) ( struct interface *control,
+ struct interface *data,
+ uint64_t lba, unsigned int count,
+ userptr_t buffer, size_t len ) ) {
+ struct int13_command *command = &int13_command;
+ unsigned int frag_count;
+ size_t frag_len;
+ int rc;
+
+ while ( count ) {
+
+ /* Determine fragment length */
+ frag_count = count;
+ if ( frag_count > int13->capacity.max_count )
+ frag_count = int13->capacity.max_count;
+ frag_len = ( int13->capacity.blksize * frag_count );
+
+ /* Issue command */
+ if ( ( ( rc = int13_command_start ( command, int13 ) ) != 0 ) ||
+ ( ( rc = block_rw ( &int13->block, &command->block, lba,
+ frag_count, buffer,
+ frag_len ) ) != 0 ) ||
+ ( ( rc = int13_command_wait ( command ) ) != 0 ) ) {
+ int13_command_stop ( command );
+ return rc;
+ }
+ int13_command_stop ( command );
+
+ /* Move to next fragment */
+ lba += frag_count;
+ count -= frag_count;
+ buffer = userptr_add ( buffer, frag_len );
+ }
+
+ return 0;
+}
+
+/**
+ * Read INT 13 drive capacity
+ *
+ * @v int13 Emulated drive
+ * @ret rc Return status code
+ */
+static int int13_read_capacity ( struct int13_drive *int13 ) {
+ struct int13_command *command = &int13_command;
+ int rc;
+
+ /* Issue command */
+ if ( ( ( rc = int13_command_start ( command, int13 ) ) != 0 ) ||
+ ( ( rc = block_read_capacity ( &int13->block,
+ &command->block ) ) != 0 ) ||
+ ( ( rc = int13_command_wait ( command ) ) != 0 ) ) {
+ int13_command_stop ( command );
+ return rc;
+ }
+
+ int13_command_stop ( command );
+ return 0;
+}
+
+/**
+ * Guess INT 13 drive geometry
+ *
+ * @v int13 Emulated drive
+ * @ret rc Return status code
+ *
+ * Guesses the drive geometry by inspecting the partition table.
+ */
+static int int13_guess_geometry ( struct int13_drive *int13 ) {
+ struct master_boot_record mbr;
+ struct partition_table_entry *partition;
+ unsigned int guessed_heads = 255;
+ unsigned int guessed_sectors_per_track = 63;
+ unsigned long blocks;
+ unsigned long blocks_per_cyl;
+ unsigned int i;
+ int rc;
+
+ /* Don't even try when the blksize is invalid for C/H/S access */
+ if ( int13->capacity.blksize != INT13_BLKSIZE )
+ return 0;
+
+ /* Read partition table */
+ if ( ( rc = int13_rw ( int13, 0, 1, virt_to_user ( &mbr ),
+ block_read ) ) != 0 ) {
+ DBGC ( int13, "INT13 drive %02x could not read partition "
+ "table to guess geometry: %s\n",
+ int13->drive, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Scan through partition table and modify guesses for heads
+ * and sectors_per_track if we find any used partitions.
+ */
+ for ( i = 0 ; i < 4 ; i++ ) {
+ partition = &mbr.partitions[i];
+ if ( ! partition->type )
+ continue;
+ guessed_heads = ( PART_HEAD ( partition->chs_end ) + 1 );
+ guessed_sectors_per_track = PART_SECTOR ( partition->chs_end );
+ DBGC ( int13, "INT13 drive %02x guessing C/H/S xx/%d/%d based "
+ "on partition %d\n", int13->drive, guessed_heads,
+ guessed_sectors_per_track, ( i + 1 ) );
+ }
+
+ /* 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_per_track;
+ if ( ! int13->cylinders ) {
+ /* Avoid attempting a 64-bit divide on a 32-bit system */
+ blocks = ( ( int13->capacity.blocks <= ULONG_MAX ) ?
+ int13->capacity.blocks : ULONG_MAX );
+ 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;
+}
+
+/**
+ * Open (or reopen) INT 13 emulated drive underlying block device
+ *
+ * @v int13 Emulated drive
+ * @ret rc Return status code
+ */
+static int int13_reopen_block ( struct int13_drive *int13 ) {
+ int rc;
+
+ /* Close any existing block device */
+ intf_restart ( &int13->block, -ECONNRESET );
+
+ /* Open block device */
+ if ( ( rc = xfer_open_uri ( &int13->block, int13->uri ) ) != 0 ) {
+ DBGC ( int13, "INT13 drive %02x could not reopen block "
+ "device: %s\n", int13->drive, strerror ( rc ) );
+ int13->block_rc = rc;
+ return rc;
+ }
+
+ /* Clear block device error status */
+ int13->block_rc = 0;
+
+ /* Read device capacity */
+ if ( ( rc = int13_read_capacity ( int13 ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
/**
* Update BIOS drive count
*/
static void int13_set_num_drives ( void ) {
- struct int13_drive *drive;
+ struct int13_drive *int13;
/* Get current drive count */
get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
/* Ensure count is large enough to cover all of our emulated drives */
- list_for_each_entry ( drive, &drives, list ) {
- if ( num_drives <= ( drive->drive & 0x7f ) )
- num_drives = ( ( drive->drive & 0x7f ) + 1 );
+ list_for_each_entry ( int13, &int13s, list ) {
+ if ( num_drives <= ( int13->drive & 0x7f ) )
+ num_drives = ( ( int13->drive & 0x7f ) + 1 );
}
/* Update current drive count */
@@ -96,48 +466,56 @@ static void int13_check_num_drives ( void ) {
/**
* INT 13, 00 - Reset disk system
*
- * @v drive Emulated drive
+ * @v int13 Emulated drive
* @ret status Status code
*/
-static int int13_reset ( struct int13_drive *drive __unused,
+static int int13_reset ( struct int13_drive *int13,
struct i386_all_regs *ix86 __unused ) {
- DBG ( "Reset drive\n" );
+ int rc;
+
+ DBGC2 ( int13, "Reset drive\n" );
+
+ /* Reopen underlying block device */
+ if ( ( rc = int13_reopen_block ( int13 ) ) != 0 )
+ return -INT13_STATUS_RESET_FAILED;
+
return 0;
}
/**
* INT 13, 01 - Get status of last operation
*
- * @v drive Emulated drive
+ * @v int13 Emulated drive
* @ret status Status code
*/
-static int int13_get_last_status ( struct int13_drive *drive,
+static int int13_get_last_status ( struct int13_drive *int13,
struct i386_all_regs *ix86 __unused ) {
- DBG ( "Get status of last operation\n" );
- return drive->last_status;
+ DBGC2 ( int13, "Get status of last operation\n" );
+ return int13->last_status;
}
/**
* Read / write sectors
*
- * @v drive Emulated drive
+ * @v int13 Emulated drive
* @v al Number of sectors to read or write (must be nonzero)
* @v ch Low bits of cylinder number
* @v cl (bits 7:6) High bits of cylinder number
* @v cl (bits 5:0) Sector number
* @v dh Head number
* @v es:bx Data buffer
- * @v io Read / write method
+ * @v block_rw Block read/write method
* @ret status Status code
* @ret al Number of sectors read or written
*/
-static int int13_rw_sectors ( struct int13_drive *drive,
+static int int13_rw_sectors ( struct int13_drive *int13,
struct i386_all_regs *ix86,
- int ( * io ) ( struct block_device *blockdev,
- uint64_t block,
- unsigned long count,
- userptr_t buffer ) ) {
- struct block_device *blockdev = drive->blockdev;
+ int ( * block_rw ) ( struct interface *control,
+ struct interface *data,
+ uint64_t lba,
+ unsigned int count,
+ userptr_t buffer,
+ size_t len ) ) {
unsigned int cylinder, head, sector;
unsigned long lba;
unsigned int count;
@@ -145,30 +523,33 @@ static int int13_rw_sectors ( struct int13_drive *drive,
int rc;
/* Validate blocksize */
- if ( blockdev->blksize != INT13_BLKSIZE ) {
- DBG ( "Invalid blocksize (%zd) for non-extended read/write\n",
- blockdev->blksize );
+ if ( int13->capacity.blksize != INT13_BLKSIZE ) {
+ DBGC ( int13, "\nINT 13 drive %02x invalid blocksize (%zd) "
+ "for non-extended read/write\n",
+ int13->drive, int13->capacity.blksize );
return -INT13_STATUS_INVALID;
}
/* Calculate parameters */
cylinder = ( ( ( ix86->regs.cl & 0xc0 ) << 2 ) | ix86->regs.ch );
- assert ( cylinder < drive->cylinders );
+ assert ( cylinder < int13->cylinders );
head = ix86->regs.dh;
- assert ( head < drive->heads );
+ assert ( head < int13->heads );
sector = ( ix86->regs.cl & 0x3f );
- assert ( ( sector >= 1 ) && ( sector <= drive->sectors_per_track ) );
- lba = ( ( ( ( cylinder * drive->heads ) + head )
- * drive->sectors_per_track ) + sector - 1 );
+ assert ( ( sector >= 1 ) && ( sector <= int13->sectors_per_track ) );
+ 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 );
- DBG ( "C/H/S %d/%d/%d = LBA %#lx <-> %04x:%04x (count %d)\n", cylinder,
- head, sector, lba, ix86->segs.es, ix86->regs.bx, count );
+ DBGC2 ( int13, "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 = io ( blockdev, lba, count, buffer ) ) != 0 ) {
- DBG ( "INT 13 failed: %s\n", strerror ( rc ) );
+ if ( ( rc = int13_rw ( int13, lba, count, buffer, block_rw ) ) != 0 ) {
+ DBGC ( int13, "INT13 drive %02x I/O failed: %s\n",
+ int13->drive, strerror ( rc ) );
return -INT13_STATUS_READ_ERROR;
}
@@ -178,7 +559,7 @@ static int int13_rw_sectors ( struct int13_drive *drive,
/**
* INT 13, 02 - Read sectors
*
- * @v drive Emulated drive
+ * @v int13 Emulated drive
* @v al Number of sectors to read (must be nonzero)
* @v ch Low bits of cylinder number
* @v cl (bits 7:6) High bits of cylinder number
@@ -188,16 +569,16 @@ static int int13_rw_sectors ( struct int13_drive *drive,
* @ret status Status code
* @ret al Number of sectors read
*/
-static int int13_read_sectors ( struct int13_drive *drive,
+static int int13_read_sectors ( struct int13_drive *int13,
struct i386_all_regs *ix86 ) {
- DBG ( "Read: " );
- return int13_rw_sectors ( drive, ix86, drive->blockdev->op->read );
+ DBGC2 ( int13, "Read: " );
+ return int13_rw_sectors ( int13, ix86, block_read );
}
/**
* INT 13, 03 - Write sectors
*
- * @v drive Emulated drive
+ * @v int13 Emulated drive
* @v al Number of sectors to write (must be nonzero)
* @v ch Low bits of cylinder number
* @v cl (bits 7:6) High bits of cylinder number
@@ -207,16 +588,16 @@ static int int13_read_sectors ( struct int13_drive *drive,
* @ret status Status code
* @ret al Number of sectors written
*/
-static int int13_write_sectors ( struct int13_drive *drive,
+static int int13_write_sectors ( struct int13_drive *int13,
struct i386_all_regs *ix86 ) {
- DBG ( "Write: " );
- return int13_rw_sectors ( drive, ix86, drive->blockdev->op->write );
+ DBGC2 ( int13, "Write: " );
+ return int13_rw_sectors ( int13, ix86, block_write );
}
/**
* INT 13, 08 - Get drive parameters
*
- * @v drive Emulated drive
+ * @v int13 Emulated drive
* @ret status Status code
* @ret ch Low bits of maximum cylinder number
* @ret cl (bits 7:6) High bits of maximum cylinder number
@@ -224,13 +605,13 @@ static int int13_write_sectors ( struct int13_drive *drive,
* @ret dh Maximum head number
* @ret dl Number of drives
*/
-static int int13_get_parameters ( struct int13_drive *drive,
+static int int13_get_parameters ( struct int13_drive *int13,
struct i386_all_regs *ix86 ) {
- unsigned int max_cylinder = drive->cylinders - 1;
- unsigned int max_head = drive->heads - 1;
- unsigned int max_sector = drive->sectors_per_track; /* sic */
+ unsigned int max_cylinder = int13->cylinders - 1;
+ unsigned int max_head = int13->heads - 1;
+ unsigned int max_sector = int13->sectors_per_track; /* sic */
- DBG ( "Get drive parameters\n" );
+ DBGC2 ( int13, "Get drive parameters\n" );
ix86->regs.ch = ( max_cylinder & 0xff );
ix86->regs.cl = ( ( ( max_cylinder >> 8 ) << 6 ) | max_sector );
@@ -242,18 +623,18 @@ static int int13_get_parameters ( struct int13_drive *drive,
/**
* INT 13, 15 - Get disk type
*
- * @v drive Emulated drive
+ * @v int13 Emulated drive
* @ret ah Type code
* @ret cx:dx Sector count
* @ret status Status code / disk type
*/
-static int int13_get_disk_type ( struct int13_drive *drive,
+static int int13_get_disk_type ( struct int13_drive *int13,
struct i386_all_regs *ix86 ) {
uint32_t blocks;
- DBG ( "Get disk type\n" );
- blocks = ( ( drive->blockdev->blocks <= 0xffffffffUL ) ?
- drive->blockdev->blocks : 0xffffffffUL );
+ DBGC2 ( int13, "Get disk type\n" );
+ blocks = ( ( int13->capacity.blocks <= 0xffffffffUL ) ?
+ int13->capacity.blocks : 0xffffffffUL );
ix86->regs.cx = ( blocks >> 16 );
ix86->regs.dx = ( blocks & 0xffff );
return INT13_DISK_TYPE_HDD;
@@ -262,16 +643,16 @@ static int int13_get_disk_type ( struct int13_drive *drive,
/**
* INT 13, 41 - Extensions installation check
*
- * @v drive Emulated drive
+ * @v int13 Emulated drive
* @v bx 0x55aa
* @ret bx 0xaa55
* @ret cx Extensions API support bitmap
* @ret status Status code / API version
*/
-static int int13_extension_check ( struct int13_drive *drive __unused,
+static int int13_extension_check ( struct int13_drive *int13 __unused,
struct i386_all_regs *ix86 ) {
if ( ix86->regs.bx == 0x55aa ) {
- DBG ( "INT 13 extensions installation check\n" );
+ DBGC2 ( int13, "INT13 extensions installation check\n" );
ix86->regs.bx = 0xaa55;
ix86->regs.cx = INT13_EXTENSION_LINEAR;
return INT13_EXTENSION_VER_1_X;
@@ -283,18 +664,19 @@ static int int13_extension_check ( struct int13_drive *drive __unused,
/**
* Extended read / write
*
- * @v drive Emulated drive
+ * @v int13 Emulated drive
* @v ds:si Disk address packet
- * @v io Read / write method
+ * @v block_rw Block read/write method
* @ret status Status code
*/
-static int int13_extended_rw ( struct int13_drive *drive,
+static int int13_extended_rw ( struct int13_drive *int13,
struct i386_all_regs *ix86,
- int ( * io ) ( struct block_device *blockdev,
- uint64_t block,
- unsigned long count,
- userptr_t buffer ) ) {
- struct block_device *blockdev = drive->blockdev;
+ int ( * block_rw ) ( struct interface *control,
+ struct interface *data,
+ uint64_t lba,
+ unsigned int count,
+ userptr_t buffer,
+ size_t len ) ) {
struct int13_disk_address addr;
uint64_t lba;
unsigned long count;
@@ -307,12 +689,14 @@ static int int13_extended_rw ( struct int13_drive *drive,
count = addr.count;
buffer = real_to_user ( addr.buffer.segment, addr.buffer.offset );
- DBG ( "LBA %#llx <-> %04x:%04x (count %ld)\n", (unsigned long long)lba,
- addr.buffer.segment, addr.buffer.offset, count );
+ DBGC2 ( int13, "LBA %08llx <-> %04x:%04x (count %ld)\n",
+ ( ( unsigned long long ) lba ), addr.buffer.segment,
+ addr.buffer.offset, count );
/* Read from / write to block device */
- if ( ( rc = io ( blockdev, lba, count, buffer ) ) != 0 ) {
- DBG ( "INT 13 failed: %s\n", strerror ( rc ) );
+ if ( ( rc = int13_rw ( int13, lba, count, buffer, block_rw ) ) != 0 ) {
+ DBGC ( int13, "INT13 drive %02x extended I/O failed: %s\n",
+ int13->drive, strerror ( rc ) );
return -INT13_STATUS_READ_ERROR;
}
@@ -322,50 +706,50 @@ static int int13_extended_rw ( struct int13_drive *drive,
/**
* INT 13, 42 - Extended read
*
- * @v drive Emulated drive
+ * @v int13 Emulated drive
* @v ds:si Disk address packet
* @ret status Status code
*/
-static int int13_extended_read ( struct int13_drive *drive,
+static int int13_extended_read ( struct int13_drive *int13,
struct i386_all_regs *ix86 ) {
- DBG ( "Extended read: " );
- return int13_extended_rw ( drive, ix86, drive->blockdev->op->read );
+ DBGC2 ( int13, "Extended read: " );
+ return int13_extended_rw ( int13, ix86, block_read );
}
/**
* INT 13, 43 - Extended write
*
- * @v drive Emulated drive
+ * @v int13 Emulated drive
* @v ds:si Disk address packet
* @ret status Status code
*/
-static int int13_extended_write ( struct int13_drive *drive,
+static int int13_extended_write ( struct int13_drive *int13,
struct i386_all_regs *ix86 ) {
- DBG ( "Extended write: " );
- return int13_extended_rw ( drive, ix86, drive->blockdev->op->write );
+ DBGC2 ( int13, "Extended write: " );
+ return int13_extended_rw ( int13, ix86, block_write );
}
/**
* INT 13, 48 - Get extended parameters
*
- * @v drive Emulated drive
+ * @v int13 Emulated drive
* @v ds:si Drive parameter table
* @ret status Status code
*/
-static int int13_get_extended_parameters ( struct int13_drive *drive,
+static int int13_get_extended_parameters ( struct int13_drive *int13,
struct i386_all_regs *ix86 ) {
struct int13_disk_parameters params = {
.bufsize = sizeof ( params ),
.flags = INT13_FL_DMA_TRANSPARENT,
- .cylinders = drive->cylinders,
- .heads = drive->heads,
- .sectors_per_track = drive->sectors_per_track,
- .sectors = drive->blockdev->blocks,
- .sector_size = drive->blockdev->blksize,
+ .cylinders = int13->cylinders,
+ .heads = int13->heads,
+ .sectors_per_track = int13->sectors_per_track,
+ .sectors = int13->capacity.blocks,
+ .sector_size = int13->capacity.blksize,
};
- DBG ( "Get extended drive parameters to %04x:%04x\n",
- ix86->segs.ds, ix86->regs.si );
+ DBGC2 ( int13, "Get extended drive parameters to %04x:%04x\n",
+ ix86->segs.ds, ix86->regs.si );
copy_to_real ( ix86->segs.ds, ix86->regs.si, &params,
sizeof ( params ) );
@@ -379,72 +763,74 @@ static int int13_get_extended_parameters ( struct int13_drive *drive,
static __asmcall void int13 ( struct i386_all_regs *ix86 ) {
int command = ix86->regs.ah;
unsigned int bios_drive = ix86->regs.dl;
- struct int13_drive *drive;
+ struct int13_drive *int13;
int status;
/* Check BIOS hasn't killed off our drive */
int13_check_num_drives();
- list_for_each_entry ( drive, &drives, list ) {
+ list_for_each_entry ( int13, &int13s, list ) {
- if ( bios_drive != drive->drive ) {
+ if ( bios_drive != int13->drive ) {
/* Remap any accesses to this drive's natural number */
- if ( bios_drive == drive->natural_drive ) {
- DBG ( "INT 13,%04x (%02x) remapped to "
- "(%02x)\n", ix86->regs.ax,
- bios_drive, drive->drive );
- ix86->regs.dl = drive->drive;
+ if ( bios_drive == int13->natural_drive ) {
+ DBGC2 ( int13, "INT13,%02x (%02x) remapped to "
+ "(%02x)\n", ix86->regs.ah,
+ bios_drive, int13->drive );
+ ix86->regs.dl = int13->drive;
return;
}
continue;
}
- DBG ( "INT 13,%04x (%02x): ", ix86->regs.ax, drive->drive );
+ DBGC2 ( int13, "INT13,%02x (%02x): ",
+ ix86->regs.ah, int13->drive );
switch ( command ) {
case INT13_RESET:
- status = int13_reset ( drive, ix86 );
+ status = int13_reset ( int13, ix86 );
break;
case INT13_GET_LAST_STATUS:
- status = int13_get_last_status ( drive, ix86 );
+ status = int13_get_last_status ( int13, ix86 );
break;
case INT13_READ_SECTORS:
- status = int13_read_sectors ( drive, ix86 );
+ status = int13_read_sectors ( int13, ix86 );
break;
case INT13_WRITE_SECTORS:
- status = int13_write_sectors ( drive, ix86 );
+ status = int13_write_sectors ( int13, ix86 );
break;
case INT13_GET_PARAMETERS:
- status = int13_get_parameters ( drive, ix86 );
+ status = int13_get_parameters ( int13, ix86 );
break;
case INT13_GET_DISK_TYPE:
- status = int13_get_disk_type ( drive, ix86 );
+ status = int13_get_disk_type ( int13, ix86 );
break;
case INT13_EXTENSION_CHECK:
- status = int13_extension_check ( drive, ix86 );
+ status = int13_extension_check ( int13, ix86 );
break;
case INT13_EXTENDED_READ:
- status = int13_extended_read ( drive, ix86 );
+ status = int13_extended_read ( int13, ix86 );
break;
case INT13_EXTENDED_WRITE:
- status = int13_extended_write ( drive, ix86 );
+ status = int13_extended_write ( int13, ix86 );
break;
case INT13_GET_EXTENDED_PARAMETERS:
- status = int13_get_extended_parameters ( drive, ix86 );
+ status = int13_get_extended_parameters ( int13, ix86 );
break;
default:
- DBG ( "*** Unrecognised INT 13 ***\n" );
+ DBGC2 ( int13, "*** Unrecognised INT13 ***\n" );
status = -INT13_STATUS_INVALID;
break;
}
/* Store status for INT 13,01 */
- drive->last_status = status;
+ int13->last_status = status;
/* Negative status indicates an error */
if ( status < 0 ) {
status = -status;
- DBG ( "INT 13 returning failure status %x\n", status );
+ DBGC ( int13, "INT13,%02x (%02x) failed with status "
+ "%02x\n", ix86->regs.ah, int13->drive, status );
} else {
ix86->flags &= ~CF;
}
@@ -461,7 +847,7 @@ static __asmcall void int13 ( struct i386_all_regs *ix86 ) {
* Hook INT 13 handler
*
*/
-static void hook_int13 ( void ) {
+static void int13_hook_vector ( void ) {
/* 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()).
@@ -517,136 +903,188 @@ static void hook_int13 ( void ) {
/**
* Unhook INT 13 handler
*/
-static void unhook_int13 ( void ) {
+static void int13_unhook_vector ( void ) {
unhook_bios_interrupt ( 0x13, ( unsigned int ) int13_wrapper,
&int13_vector );
}
/**
- * Guess INT 13 drive geometry
+ * Handle INT 13 emulated drive underlying block device closing
*
- * @v drive Emulated drive
- *
- * Guesses the drive geometry by inspecting the partition table.
+ * @v int13 Emulated drive
+ * @v rc Reason for close
*/
-static void guess_int13_geometry ( struct int13_drive *drive ) {
- struct master_boot_record mbr;
- struct partition_table_entry *partition;
- unsigned int guessed_heads = 255;
- unsigned int guessed_sectors_per_track = 63;
- unsigned long blocks;
- unsigned long blocks_per_cyl;
- unsigned int i;
+static void int13_block_close ( struct int13_drive *int13, int rc ) {
- /* Don't even try when the blksize is invalid for C/H/S access */
- if ( drive->blockdev->blksize != INT13_BLKSIZE )
- return;
+ /* Any closing is an error from our point of view */
+ if ( rc == 0 )
+ rc = -ENOTCONN;
- /* Scan through partition table and modify guesses for heads
- * and sectors_per_track if we find any used partitions.
+ DBGC ( int13, "INT13 drive %02x went away: %s\n",
+ int13->drive, strerror ( rc ) );
+
+ /* Record block device error code */
+ int13->block_rc = rc;
+
+ /* Shut down interfaces */
+ intf_restart ( &int13->block, rc );
+
+ /* Further INT 13 calls will fail immediately. The caller may
+ * use INT 13,00 to reset the drive.
*/
- if ( drive->blockdev->op->read ( drive->blockdev, 0, 1,
- virt_to_user ( &mbr ) ) == 0 ) {
- for ( i = 0 ; i < 4 ; i++ ) {
- partition = &mbr.partitions[i];
- if ( ! partition->type )
- continue;
- guessed_heads =
- ( PART_HEAD ( partition->chs_end ) + 1 );
- guessed_sectors_per_track =
- PART_SECTOR ( partition->chs_end );
- DBG ( "Guessing C/H/S xx/%d/%d based on partition "
- "%d\n", guessed_heads,
- guessed_sectors_per_track, ( i + 1 ) );
- }
- } else {
- DBG ( "Could not read partition table to guess geometry\n" );
- }
+}
- /* Apply guesses if no geometry already specified */
- if ( ! drive->heads )
- drive->heads = guessed_heads;
- if ( ! drive->sectors_per_track )
- drive->sectors_per_track = guessed_sectors_per_track;
- if ( ! drive->cylinders ) {
- /* Avoid attempting a 64-bit divide on a 32-bit system */
- blocks = ( ( drive->blockdev->blocks <= ULONG_MAX ) ?
- drive->blockdev->blocks : ULONG_MAX );
- blocks_per_cyl = ( drive->heads * drive->sectors_per_track );
- assert ( blocks_per_cyl != 0 );
- drive->cylinders = ( blocks / blocks_per_cyl );
- if ( drive->cylinders > 1024 )
- drive->cylinders = 1024;
- }
+/** INT 13 drive interface operations */
+static struct interface_operation int13_block_op[] = {
+ INTF_OP ( intf_close, struct int13_drive *, int13_block_close ),
+};
+
+/** INT 13 drive interface descriptor */
+static struct interface_descriptor int13_block_desc =
+ INTF_DESC ( struct int13_drive, block, int13_block_op );
+
+/**
+ * Free INT 13 emulated drive
+ *
+ * @v refcnt Reference count
+ */
+static void int13_free ( struct refcnt *refcnt ) {
+ struct int13_drive *int13 =
+ container_of ( refcnt, struct int13_drive, refcnt );
+
+ uri_put ( int13->uri );
+ free ( int13 );
}
/**
- * Register INT 13 emulated drive
+ * Hook INT 13 emulated drive
*
- * @v drive Emulated drive
+ * @v uri URI
+ * @v drive Requested drive number
+ * @ret drive Assigned drive number, or negative error
*
* Registers the drive with the INT 13 emulation subsystem, and hooks
* the INT 13 interrupt vector (if not already hooked).
- *
- * The underlying block device must be valid. A drive number and
- * geometry will be assigned if left blank.
*/
-void register_int13_drive ( struct int13_drive *drive ) {
+static int int13_hook ( struct uri *uri, unsigned int drive ) {
+ struct int13_drive *int13;
uint8_t num_drives;
+ unsigned int natural_drive;
+ int rc;
- /* Give drive a default geometry if none specified */
- guess_int13_geometry ( drive );
-
- /* Assign natural drive number */
+ /* Calculate drive number */
get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
- drive->natural_drive = ( num_drives | 0x80 );
+ natural_drive = ( num_drives | 0x80 );
+ if ( drive == INT13_USE_NATURAL_DRIVE )
+ drive = natural_drive;
+ drive |= 0x80;
+
+ /* Check that drive number is not in use */
+ list_for_each_entry ( int13, &int13s, list ) {
+ if ( int13->drive == drive ) {
+ rc = -EADDRINUSE;
+ goto err_in_use;
+ }
+ }
- /* Assign drive number */
- if ( ( drive->drive & 0xff ) == 0xff ) {
- /* Drive number == -1 => use natural drive number */
- drive->drive = drive->natural_drive;
- } else {
- /* Use specified drive number (+0x80 if necessary) */
- drive->drive |= 0x80;
+ /* Allocate and initialise structure */
+ int13 = zalloc ( sizeof ( *int13 ) );
+ if ( ! int13 ) {
+ rc = -ENOMEM;
+ goto err_zalloc;
}
+ ref_init ( &int13->refcnt, int13_free );
+ intf_init ( &int13->block, &int13_block_desc, &int13->refcnt );
+ int13->uri = uri_get ( uri );
+ int13->drive = drive;
+ int13->natural_drive = natural_drive;
+
+ /* Open block device interface */
+ if ( ( rc = int13_reopen_block ( int13 ) ) != 0 )
+ goto err_reopen_block;
- DBG ( "Registered INT13 drive %02x (naturally %02x) with C/H/S "
- "geometry %d/%d/%d\n", drive->drive, drive->natural_drive,
- drive->cylinders, drive->heads, drive->sectors_per_track );
+ /* Give drive a default geometry */
+ if ( ( rc = int13_guess_geometry ( int13 ) ) != 0 )
+ goto err_guess_geometry;
+
+ DBGC ( int13, "INT13 drive %02x (naturally %02x) registered with C/H/S "
+ "geometry %d/%d/%d\n", int13->drive, int13->natural_drive,
+ int13->cylinders, int13->heads, int13->sectors_per_track );
/* Hook INT 13 vector if not already hooked */
- if ( list_empty ( &drives ) )
- hook_int13();
+ if ( list_empty ( &int13s ) )
+ int13_hook_vector();
/* Add to list of emulated drives */
- list_add ( &drive->list, &drives );
+ list_add ( &int13->list, &int13s );
/* Update BIOS drive count */
int13_set_num_drives();
+
+ return int13->drive;
+
+ err_guess_geometry:
+ err_reopen_block:
+ intf_shutdown ( &int13->block, rc );
+ ref_put ( &int13->refcnt );
+ err_zalloc:
+ err_in_use:
+ return rc;
}
/**
- * Unregister INT 13 emulated drive
+ * Find INT 13 emulated drive by drive number
*
- * @v drive Emulated drive
+ * @v drive Drive number
+ * @ret int13 Emulated drive, or NULL
+ */
+static struct int13_drive * int13_find ( unsigned int drive ) {
+ struct int13_drive *int13;
+
+ list_for_each_entry ( int13, &int13s, list ) {
+ if ( int13->drive == drive )
+ return int13;
+ }
+ return NULL;
+}
+
+/**
+ * Unhook INT 13 emulated drive
+ *
+ * @v drive Drive number
*
* Unregisters the drive from the INT 13 emulation subsystem. If this
* is the last emulated drive, the INT 13 vector is unhooked (if
* possible).
*/
-void unregister_int13_drive ( struct int13_drive *drive ) {
+static void int13_unhook ( unsigned int drive ) {
+ struct int13_drive *int13;
+
+ /* Find drive */
+ int13 = int13_find ( drive );
+ if ( ! int13 ) {
+ DBG ( "INT13 cannot find emulated drive %02x\n", drive );
+ return;
+ }
+
+ /* Shut down interfaces */
+ intf_shutdown ( &int13->block, 0 );
+
/* Remove from list of emulated drives */
- list_del ( &drive->list );
+ list_del ( &int13->list );
- /* Should adjust BIOS drive count, but it's difficult to do so
- * reliably.
+ /* Should adjust BIOS drive count, but it's difficult
+ * to do so reliably.
*/
- DBG ( "Unregistered INT13 drive %02x\n", drive->drive );
+ DBGC ( int13, "INT13 drive %02x unregsitered\n", int13->drive );
/* Unhook INT 13 vector if no more drives */
- if ( list_empty ( &drives ) )
- unhook_int13();
+ if ( list_empty ( &int13s ) )
+ int13_unhook_vector();
+
+ /* Drop list's reference to drive */
+ ref_put ( &int13->refcnt );
}
/**
@@ -662,13 +1100,13 @@ void unregister_int13_drive ( struct int13_drive *drive ) {
*
* Note that this function can never return success, by definition.
*/
-int int13_boot ( unsigned int drive ) {
+static int int13_boot ( unsigned int drive ) {
struct memory_map memmap;
int status, signature;
int discard_c, discard_d;
int rc;
- DBG ( "Booting from INT 13 drive %02x\n", drive );
+ DBG ( "INT13 drive %02x booting\n", drive );
/* Use INT 13 to read the boot sector */
__asm__ __volatile__ ( REAL_CODE ( "pushw %%es\n\t"
@@ -692,8 +1130,8 @@ int int13_boot ( unsigned int drive ) {
/* Check signature is correct */
if ( signature != be16_to_cpu ( 0x55aa ) ) {
- DBG ( "Invalid disk signature %#04x (should be 0x55aa)\n",
- cpu_to_be16 ( signature ) );
+ DBG ( "INT13 drive %02x invalid disk signature %#04x (should "
+ "be 0x55aa)\n", drive, cpu_to_be16 ( signature ) );
return -ENOEXEC;
}
@@ -706,10 +1144,74 @@ int int13_boot ( unsigned int drive ) {
/* Jump to boot sector */
if ( ( rc = call_bootsector ( 0x0, 0x7c00, drive ) ) != 0 ) {
- DBG ( "INT 13 drive %02x boot returned: %s\n",
+ DBG ( "INT13 drive %02x boot returned: %s\n",
drive, strerror ( rc ) );
return rc;
}
return -ECANCELED; /* -EIMPOSSIBLE */
}
+
+/** A boot firmware table generated by iPXE */
+union xbft_table {
+ /** ACPI header */
+ struct acpi_description_header acpi;
+ /** Padding */
+ char pad[768];
+};
+
+/** The boot firmware table generated by iPXE */
+static union xbft_table __bss16 ( xbftab ) __attribute__ (( aligned ( 16 ) ));
+#define xbftab __use_data16 ( xbftab )
+
+/**
+ * Describe INT 13 emulated drive for SAN-booted operating system
+ *
+ * @v drive Drive number
+ * @ret rc Return status code
+ */
+static int int13_describe ( unsigned int drive ) {
+ struct int13_drive *int13;
+ struct segoff xbft_address;
+ int rc;
+
+ /* Find drive */
+ int13 = int13_find ( drive );
+ if ( ! int13 ) {
+ DBG ( "INT13 cannot find emulated drive %02x\n", drive );
+ return -ENODEV;
+ }
+
+ /* Clear table */
+ memset ( &xbftab, 0, sizeof ( xbftab ) );
+
+ /* Fill in common parameters */
+ strncpy ( xbftab.acpi.oem_id, "FENSYS",
+ sizeof ( xbftab.acpi.oem_id ) );
+ strncpy ( xbftab.acpi.oem_table_id, "iPXE",
+ sizeof ( xbftab.acpi.oem_table_id ) );
+
+ /* Fill in remaining parameters */
+ if ( ( rc = acpi_describe ( &int13->block, &xbftab.acpi,
+ sizeof ( xbftab ) ) ) != 0 ) {
+ DBGC ( int13, "INT13 drive %02x could not create ACPI "
+ "description: %s\n", int13->drive, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Fix up ACPI checksum */
+ acpi_fix_checksum ( &xbftab.acpi );
+ xbft_address.segment = rm_ds;
+ xbft_address.offset = __from_data16 ( &xbftab );
+ DBGC ( int13, "INT13 drive %02x described using boot firmware "
+ "table:\n", int13->drive );
+ DBGC_HDA ( int13, xbft_address, &xbftab,
+ le32_to_cpu ( xbftab.acpi.length ) );
+
+ 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 );
diff --git a/src/arch/i386/interface/pcbios/iscsiboot.c b/src/arch/i386/interface/pcbios/iscsiboot.c
deleted file mode 100644
index 12c5566dc..000000000
--- a/src/arch/i386/interface/pcbios/iscsiboot.c
+++ /dev/null
@@ -1,75 +0,0 @@
-#include <stdint.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <ipxe/iscsi.h>
-#include <ipxe/netdevice.h>
-#include <ipxe/ibft.h>
-#include <ipxe/sanboot.h>
-#include <int13.h>
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-static int iscsiboot ( const char *root_path ) {
- struct scsi_device *scsi;
- struct int13_drive *drive;
- int rc;
-
- scsi = zalloc ( sizeof ( *scsi ) );
- if ( ! scsi ) {
- rc = -ENOMEM;
- goto err_alloc_scsi;
- }
- drive = zalloc ( sizeof ( *drive ) );
- if ( ! drive ) {
- rc = -ENOMEM;
- goto err_alloc_drive;
- }
-
- if ( ( rc = iscsi_attach ( scsi, root_path ) ) != 0 ) {
- printf ( "Could not attach iSCSI device: %s\n",
- strerror ( rc ) );
- goto err_attach;
- }
- if ( ( rc = init_scsidev ( scsi ) ) != 0 ) {
- printf ( "Could not initialise iSCSI device: %s\n",
- strerror ( rc ) );
- goto err_init;
- }
-
- drive->blockdev = &scsi->blockdev;
-
- /* FIXME: ugly, ugly hack */
- struct net_device *netdev = last_opened_netdev();
- struct iscsi_session *iscsi =
- container_of ( scsi->backend, struct iscsi_session, refcnt );
- ibft_fill_data ( netdev, iscsi );
-
- register_int13_drive ( drive );
- printf ( "Registered as BIOS drive %#02x\n", drive->drive );
- printf ( "Booting from BIOS drive %#02x\n", drive->drive );
- rc = int13_boot ( drive->drive );
- printf ( "Boot failed\n" );
-
- /* Leave drive registered, if instructed to do so */
- if ( keep_san() )
- return rc;
-
- printf ( "Unregistering BIOS drive %#02x\n", drive->drive );
- unregister_int13_drive ( drive );
-
- err_init:
- iscsi_detach ( scsi );
- err_attach:
- free ( drive );
- err_alloc_drive:
- free ( scsi );
- err_alloc_scsi:
- return rc;
-}
-
-struct sanboot_protocol iscsi_sanboot_protocol __sanboot_protocol = {
- .prefix = "iscsi:",
- .boot = iscsiboot,
-};
diff --git a/src/arch/i386/interface/pcbios/keepsan.c b/src/arch/i386/interface/pcbios/keepsan.c
deleted file mode 100644
index b2a931771..000000000
--- a/src/arch/i386/interface/pcbios/keepsan.c
+++ /dev/null
@@ -1,26 +0,0 @@
-#include <stdint.h>
-#include <stdio.h>
-#include <ipxe/settings.h>
-#include <ipxe/dhcp.h>
-#include <ipxe/init.h>
-#include <ipxe/sanboot.h>
-#include <usr/autoboot.h>
-
-struct setting keep_san_setting __setting = {
- .name = "keep-san",
- .description = "Preserve SAN connection",
- .tag = DHCP_EB_KEEP_SAN,
- .type = &setting_type_int8,
-};
-
-int keep_san ( void ) {
- int keep_san;
-
- keep_san = fetch_intz_setting ( NULL, &keep_san_setting );
- if ( ! keep_san )
- return 0;
-
- printf ( "Preserving connection to SAN disk\n" );
- shutdown_exit_flags |= SHUTDOWN_KEEP_DEVICES;
- return 1;
-}
diff --git a/src/arch/i386/interface/pcbios/sbft.c b/src/arch/i386/interface/pcbios/sbft.c
deleted file mode 100644
index 6d51020af..000000000
--- a/src/arch/i386/interface/pcbios/sbft.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-FILE_LICENCE ( BSD2 );
-
-/** @file
- *
- * SRP boot firmware table
- *
- */
-
-#include <assert.h>
-#include <realmode.h>
-#include <ipxe/srp.h>
-#include <ipxe/ib_srp.h>
-#include <ipxe/acpi.h>
-#include <ipxe/sbft.h>
-
-#define sbftab __use_data16 ( sbftab )
-/** The sBFT used by iPXE */
-struct ipxe_sbft __data16 ( sbftab ) = {
- /* Table header */
- .table = {
- /* ACPI header */
- .acpi = {
- .signature = SBFT_SIG,
- .length = sizeof ( sbftab ),
- .revision = 1,
- .oem_id = "FENSYS",
- .oem_table_id = "iPXE",
- },
- .scsi_offset = offsetof ( typeof ( sbftab ), scsi ),
- .srp_offset = offsetof ( typeof ( sbftab ), srp ),
- .ib_offset = offsetof ( typeof ( sbftab ), ib ),
- },
-};
-
-/**
- * Fill in all variable portions of sBFT
- *
- * @v srp SRP device
- * @ret rc Return status code
- */
-int sbft_fill_data ( struct srp_device *srp ) {
- struct sbft_scsi_subtable *sbft_scsi = &sbftab.scsi;
- struct sbft_srp_subtable *sbft_srp = &sbftab.srp;
- struct sbft_ib_subtable *sbft_ib = &sbftab.ib;
- struct ib_srp_parameters *ib_params;
- struct segoff rm_sbftab = {
- .segment = rm_ds,
- .offset = __from_data16 ( &sbftab ),
- };
-
- /* Fill in the SCSI subtable */
- memcpy ( &sbft_scsi->lun, &srp->lun, sizeof ( sbft_scsi->lun ) );
-
- /* Fill in the SRP subtable */
- memcpy ( &sbft_srp->port_ids, &srp->port_ids,
- sizeof ( sbft_srp->port_ids ) );
-
- /* Fill in the IB subtable */
- assert ( srp->transport == &ib_srp_transport );
- ib_params = ib_srp_params ( srp );
- memcpy ( &sbft_ib->sgid, &ib_params->sgid, sizeof ( sbft_ib->sgid ) );
- memcpy ( &sbft_ib->dgid, &ib_params->dgid, sizeof ( sbft_ib->dgid ) );
- memcpy ( &sbft_ib->service_id, &ib_params->service_id,
- sizeof ( sbft_ib->service_id ) );
- sbft_ib->pkey = ib_params->pkey;
-
- /* Update checksum */
- acpi_fix_checksum ( &sbftab.table.acpi );
-
- DBGC ( &sbftab, "SRP Boot Firmware Table at %04x:%04x:\n",
- rm_sbftab.segment, rm_sbftab.offset );
- DBGC_HDA ( &sbftab, rm_sbftab, &sbftab, sizeof ( sbftab ) );
-
- return 0;
-}
diff --git a/src/arch/x86_64/include/bits/sanboot.h b/src/arch/x86_64/include/bits/sanboot.h
new file mode 100644
index 000000000..d33d03cbe
--- /dev/null
+++ b/src/arch/x86_64/include/bits/sanboot.h
@@ -0,0 +1,12 @@
+#ifndef _BITS_SANBOOT_H
+#define _BITS_SANBOOT_H
+
+/** @file
+ *
+ * x86_64-specific sanboot API implementations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#endif /* _BITS_SANBOOT_H */