From fdcdc5203b230fef23fa721573fd30ad093679d1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 13 Mar 2017 12:18:46 +0000 Subject: [PATCH] [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 Signed-off-by: Michael Brown --- src/interface/efi/efi_block.c | 69 +++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) 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 #include #include +#include #include #include #include +#include #include #include #include #include #include +/** 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; }