]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[efi] Provide ACPI table description for SAN devices
authorMichael Brown <mcb30@ipxe.org>
Mon, 13 Mar 2017 12:18:46 +0000 (12:18 +0000)
committerMichael Brown <mcb30@ipxe.org>
Mon, 13 Mar 2017 12:18:46 +0000 (12:18 +0000)
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>
src/interface/efi/efi_block.c

index 8eb300a1a22ea53fc25492f63044b82fe54078a8..10504f6a8f7a1246ea7e6d74ab6510eddfa7cc1f 100644 (file)
@@ -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;
 }