summaryrefslogtreecommitdiffstats
path: root/src/interface/efi
diff options
context:
space:
mode:
authorMichael Brown2017-03-13 13:18:46 +0100
committerMichael Brown2017-03-13 13:18:46 +0100
commitfdcdc5203b230fef23fa721573fd30ad093679d1 (patch)
treeb62ac6aab25da69167d85a7394c29ae88a2fe074 /src/interface/efi
parent[efi] Add EFI_ACPI_TABLE_PROTOCOL header and GUID definition (diff)
downloadipxe-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.c69
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;
}