diff options
Diffstat (limited to 'src/arch')
| -rw-r--r-- | src/arch/i386/image/eltorito.c | 336 | ||||
| -rw-r--r-- | src/arch/i386/include/bits/eltorito.h | 3 | ||||
| -rw-r--r-- | src/arch/i386/include/bits/sanboot.h | 14 | ||||
| -rw-r--r-- | src/arch/i386/include/int13.h | 61 | ||||
| -rw-r--r-- | src/arch/i386/include/ipxe/abft.h | 37 | ||||
| -rw-r--r-- | src/arch/i386/include/ipxe/bios_sanboot.h | 18 | ||||
| -rw-r--r-- | src/arch/i386/include/ipxe/ibft.h | 302 | ||||
| -rw-r--r-- | src/arch/i386/include/ipxe/sbft.h | 125 | ||||
| -rw-r--r-- | src/arch/i386/interface/pcbios/abft.c | 62 | ||||
| -rw-r--r-- | src/arch/i386/interface/pcbios/aoeboot.c | 78 | ||||
| -rw-r--r-- | src/arch/i386/interface/pcbios/ib_srpboot.c | 73 | ||||
| -rw-r--r-- | src/arch/i386/interface/pcbios/ibft.c | 451 | ||||
| -rw-r--r-- | src/arch/i386/interface/pcbios/int13.c | 890 | ||||
| -rw-r--r-- | src/arch/i386/interface/pcbios/iscsiboot.c | 75 | ||||
| -rw-r--r-- | src/arch/i386/interface/pcbios/keepsan.c | 26 | ||||
| -rw-r--r-- | src/arch/i386/interface/pcbios/sbft.c | 105 | ||||
| -rw-r--r-- | src/arch/x86_64/include/bits/sanboot.h | 12 |
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, ¶ms, 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 */ |
