diff options
author | Michael Brown | 2017-03-13 13:18:46 +0100 |
---|---|---|
committer | Michael Brown | 2017-03-13 13:18:46 +0100 |
commit | fdcdc5203b230fef23fa721573fd30ad093679d1 (patch) | |
tree | b62ac6aab25da69167d85a7394c29ae88a2fe074 /src/interface/efi | |
parent | [efi] Add EFI_ACPI_TABLE_PROTOCOL header and GUID definition (diff) | |
download | ipxe-fdcdc5203b230fef23fa721573fd30ad093679d1.tar.gz ipxe-fdcdc5203b230fef23fa721573fd30ad093679d1.tar.xz ipxe-fdcdc5203b230fef23fa721573fd30ad093679d1.zip |
[efi] Provide ACPI table description for SAN devices
Provide a basic proof of concept ACPI table description (e.g. iBFT for
iSCSI) for SAN devices in a UEFI environment, using a control flow
that is functionally identical to that used in a BIOS environment.
Originally-implemented-by: Vishvananda Ishaya Abrams <vish.ishaya@oracle.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/interface/efi')
-rw-r--r-- | src/interface/efi/efi_block.c | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c index 8eb300a1..10504f6a 100644 --- a/src/interface/efi/efi_block.c +++ b/src/interface/efi/efi_block.c @@ -46,15 +46,21 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/process.h> #include <ipxe/sanboot.h> #include <ipxe/iso9660.h> +#include <ipxe/acpi.h> #include <ipxe/efi/efi.h> #include <ipxe/efi/Protocol/BlockIo.h> #include <ipxe/efi/Protocol/SimpleFileSystem.h> +#include <ipxe/efi/Protocol/AcpiTable.h> #include <ipxe/efi/efi_driver.h> #include <ipxe/efi/efi_strings.h> #include <ipxe/efi/efi_snp.h> #include <ipxe/efi/efi_utils.h> #include <ipxe/efi/efi_block.h> +/** ACPI table protocol protocol */ +static EFI_ACPI_TABLE_PROTOCOL *acpi; +EFI_REQUEST_PROTOCOL ( EFI_ACPI_TABLE_PROTOCOL, &acpi ); + /** Boot filename */ static wchar_t efi_block_boot_filename[] = EFI_REMOVABLE_MEDIA_FILE_NAME; @@ -399,7 +405,17 @@ static void efi_block_unhook ( unsigned int drive ) { * @ret rc Return status code */ static int efi_block_describe ( unsigned int drive ) { + static union { + /** ACPI header */ + struct acpi_description_header acpi; + /** Padding */ + char pad[768]; + } xbftab; + static UINTN key; struct san_device *sandev; + size_t len; + EFI_STATUS efirc; + int rc; /* Find SAN device */ sandev = sandev_find ( drive ); @@ -408,6 +424,59 @@ static int efi_block_describe ( unsigned int drive ) { return -ENODEV; } + /* Sanity check */ + if ( ! acpi ) { + DBGC ( sandev, "EFIBLK %#02x has no ACPI table protocol\n", + sandev->drive ); + return -ENOTSUP; + } + + /* Remove existing table, if any */ + if ( key ) { + if ( ( efirc = acpi->UninstallAcpiTable ( acpi, key ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( sandev, "EFIBLK %#02x could not uninstall ACPI " + "table: %s\n", sandev->drive, strerror ( rc ) ); + /* Continue anyway */ + } + key = 0; + } + + /* Reopen block device if necessary */ + if ( sandev_needs_reopen ( sandev ) && + ( ( rc = sandev_reopen ( sandev ) ) != 0 ) ) + return rc; + + /* 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 ( &sandev->block, &xbftab.acpi, + sizeof ( xbftab ) ) ) != 0 ) { + DBGC ( sandev, "EFIBLK %#02x could not create ACPI " + "description: %s\n", sandev->drive, strerror ( rc ) ); + return rc; + } + len = le32_to_cpu ( xbftab.acpi.length ); + + /* Fix up ACPI checksum */ + acpi_fix_checksum ( &xbftab.acpi ); + + /* Install table */ + if ( ( efirc = acpi->InstallAcpiTable ( acpi, &xbftab, len, + &key ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( sandev, "EFIBLK %#02x could not install ACPI table: " + "%s\n", sandev->drive, strerror ( rc ) ); + return rc; + } + return 0; } |