[ipxe-devel] [PATCH 1/1 WIP] [efi] setup ibft tables in uefi sanboot mode

Vishvananda Ishaya vishvananda at gmail.com
Mon Dec 12 20:39:05 UTC 2016


With the other change, windows boots, so I think this doesn't need to be
considered WIP. I have another version which also sets the OemId and
OemTableId values to match what is provided by the firmware, which is how
edk2 does it. It makes the code a bit more complicated though, so I'll
leave that patch be unless someone feels strongly about matching the id.

Vish



On Thu, Dec 8, 2016 at 6:25 PM Vishvananda Ishaya Abrams <
vish.ishaya at oracle.com> wrote:

> This uses efi functions to register the ibft table when sanbooting in
> uefi mode. It mirrors similar functionality in the int13 bios code
> path. The AcpiTable.h code is pulled over from the edk2 source.
> ---
>  src/include/ipxe/efi/Protocol/AcpiTable.h | 127
> ++++++++++++++++++++++++++++++
>  src/interface/efi/efi_block.c             |  92 ++++++++++++++++++++++
>  2 files changed, 219 insertions(+)
>  create mode 100644 src/include/ipxe/efi/Protocol/AcpiTable.h
>
> diff --git a/src/include/ipxe/efi/Protocol/AcpiTable.h
> b/src/include/ipxe/efi/Protocol/AcpiTable.h
> new file mode 100644
> index 0000000..6149b7e
> --- /dev/null
> +++ b/src/include/ipxe/efi/Protocol/AcpiTable.h
> @@ -0,0 +1,127 @@
> +/** @file
> +  The file provides the protocol to install or remove an ACPI
> +  table from a platform.
> +
> +  Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may
> be found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR
> IMPLIED.
> +
> +**/
> +
> +#ifndef __ACPI_TABLE_H___
> +#define __ACPI_TABLE_H___
> +
> +#define EFI_ACPI_TABLE_PROTOCOL_GUID \
> +  { 0xffe06bdd, 0x6107, 0x46a6, { 0x7b, 0xb2, 0x5a, 0x9c, 0x7e, 0xc5,
> 0x27, 0x5c }}
> +
> +
> +typedef struct _EFI_ACPI_TABLE_PROTOCOL EFI_ACPI_TABLE_PROTOCOL;
> +
> +/**
> +
> +  The InstallAcpiTable() function allows a caller to install an
> +  ACPI table. When successful, the table will be linked by the
> +  RSDT/XSDT. AcpiTableBuffer specifies the table to be installed.
> +  InstallAcpiTable() will make a copy of the table and insert the
> +  copy into the RSDT/XSDT. InstallAcpiTable() must insert the new
> +  table at the end of the RSDT/XSDT. To prevent namespace
> +  collision, ACPI tables may be created using UEFI ACPI table
> +  format. If this protocol is used to install a table with a
> +  signature already present in the system, the new table will not
> +  replace the existing table. It is a platform implementation
> +  decision to add a new table with a signature matching an
> +  existing table or disallow duplicate table signatures and
> +  return EFI_ACCESS_DENIED. On successful output, TableKey is
> +  initialized with a unique key. Its value may be used in a
> +  subsequent call to UninstallAcpiTable to remove an ACPI table.
> +  If an EFI application is running at the time of this call, the
> +  relevant EFI_CONFIGURATION_TABLE pointer to the RSDT is no
> +  longer considered valid.
> +
> +
> +  @param This                 A pointer to a EFI_ACPI_TABLE_PROTOCOL.
> +
> +  @param AcpiTableBuffer      A pointer to a buffer containing the
> +                              ACPI table to be installed.
> +
> +  @param AcpiTableBufferSize  Specifies the size, in bytes, of
> +                              the AcpiTableBuffer buffer.
> +
> +
> +  @param TableKey             Returns a key to refer to the ACPI table.
> +
> +  @retval EFI_SUCCESS           The table was successfully inserted
> +
> +  @retval EFI_INVALID_PARAMETER Either AcpiTableBuffer is NULL,
> +                                TableKey is NULL, or
> +                                AcpiTableBufferSize and the size
> +                                field embedded in the ACPI table
> +                                pointed to by AcpiTableBuffer
> +                                are not in sync.
> +
> +  @retval EFI_OUT_OF_RESOURCES  Insufficient resources exist to
> +                                complete the request.
> +  @retval EFI_ACCESS_DENIED     The table signature matches a table
> already
> +                                present in the system and platform policy
> +                                does not allow duplicate tables of this
> type.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EFI_ACPI_TABLE_INSTALL_ACPI_TABLE)(
> +  IN   EFI_ACPI_TABLE_PROTOCOL       *This,
> +  IN   VOID                          *AcpiTableBuffer,
> +  IN   UINTN                         AcpiTableBufferSize,
> +  OUT  UINTN                         *TableKey
> +);
> +
> +
> +/**
> +
> +  The UninstallAcpiTable() function allows a caller to remove an
> +  ACPI table. The routine will remove its reference from the
> +  RSDT/XSDT. A table is referenced by the TableKey parameter
> +  returned from a prior call to InstallAcpiTable(). If an EFI
> +  application is running at the time of this call, the relevant
> +  EFI_CONFIGURATION_TABLE pointer to the RSDT is no longer
> +  considered valid.
> +
> +  @param This                   A pointer to a EFI_ACPI_TABLE_PROTOCOL.
> +
> +  @param TableKey               Specifies the table to uninstall. The key
> was
> +                                returned from InstallAcpiTable().
> +
> +  @retval EFI_SUCCESS           The table was successfully inserted
> +
> +  @retval EFI_NOT_FOUND         TableKey does not refer to a valid key
> +                                for a table entry.
> +
> +  @retval EFI_OUT_OF_RESOURCES  Insufficient resources exist to
> +                                complete the request.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EFI_ACPI_TABLE_UNINSTALL_ACPI_TABLE)(
> +  IN  EFI_ACPI_TABLE_PROTOCOL       *This,
> +  IN  UINTN                         TableKey
> +);
> +
> +///
> +/// The EFI_ACPI_TABLE_PROTOCOL provides the ability for a component
> +/// to install and uninstall ACPI tables from a platform.
> +///
> +struct _EFI_ACPI_TABLE_PROTOCOL {
> +  EFI_ACPI_TABLE_INSTALL_ACPI_TABLE   InstallAcpiTable;
> +  EFI_ACPI_TABLE_UNINSTALL_ACPI_TABLE UninstallAcpiTable;
> +};
> +
> +extern EFI_GUID gEfiAcpiTableProtocolGuid;
> +
> +#endif
> +
> diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c
> index 6240c9b..0609029 100644
> --- a/src/interface/efi/efi_block.c
> +++ b/src/interface/efi/efi_block.c
> @@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
>   *
>   */
>
> +#include <registers.h>
>  #include <stddef.h>
>  #include <stdio.h>
>  #include <stdlib.h>
> @@ -44,11 +45,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
>  #include <ipxe/open.h>
>  #include <ipxe/retry.h>
>  #include <ipxe/timer.h>
> +#include <ipxe/acpi.h>
>  #include <ipxe/process.h>
>  #include <ipxe/sanboot.h>
>  #include <ipxe/iso9660.h>
>  #include <ipxe/settings.h>
>  #include <ipxe/efi/efi.h>
> +#include <ipxe/efi/Protocol/AcpiTable.h>
>  #include <ipxe/efi/Protocol/BlockIo.h>
>  #include <ipxe/efi/Protocol/SimpleFileSystem.h>
>  #include <ipxe/efi/efi_driver.h>
> @@ -892,6 +895,25 @@ static void efi_block_unhook ( unsigned int drive ) {
>         ref_put ( &block->refcnt );
>  }
>
> +/** 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 )
> +
> +/** BOFM1 protocol GUID */
> +static EFI_GUID acpi_table_protocol_guid =
> +       EFI_ACPI_TABLE_PROTOCOL_GUID;
> +
> +static BOOLEAN table_installed;
> +static UINTN table_key;
> +
>  /**
>   * Describe EFI block device
>   *
> @@ -899,7 +921,15 @@ static void efi_block_unhook ( unsigned int drive ) {
>   * @ret rc             Return status code
>   */
>  static int efi_block_describe ( unsigned int drive ) {
> +       EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
>         struct efi_block *block;
> +       struct segoff xbft_address;
> +       union {
> +               EFI_ACPI_TABLE_PROTOCOL *acpi;
> +               void *interface;
> +       } acpi;
> +       EFI_STATUS efirc;
> +       int rc;
>
>         /* Find block device */
>         block = efi_block_find ( drive );
> @@ -908,6 +938,68 @@ static int efi_block_describe ( unsigned int drive ) {
>                 return -ENODEV;
>         }
>
> +       /* Locate  protocol */
> +       if ( ( efirc = bs->LocateProtocol ( &acpi_table_protocol_guid,
> NULL,
> +                                           &acpi.interface ) ) != 0 ) {
> +               rc = -EEFI ( efirc );
> +               DBGC ( block, "EFIBLK %02x cannot find ACPI TABLE
> protocol\n",
> +                      block->drive );
> +               return rc;
> +       }
> +
> +       /* Uninstall existing table */
> +       if (table_installed) {
> +               /* Install table */
> +               if ( ( efirc = acpi.acpi->UninstallAcpiTable ( acpi.acpi,
> +                                                   table_key ) ) != 0 ) {
> +                       rc = -EEFI ( efirc );
> +                       DBGC ( block, "EFIBLK %02x cannot uninstall
> table\n",
> +                                                block->drive );
> +                       return rc;
> +               }
> +               table_installed = FALSE;
> +       }
> +
> +       /* 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 ( &block->intf, &xbftab.acpi,
> +                                   sizeof ( xbftab ) ) ) != 0 ) {
> +               DBGC ( block, "EFIBLK %02x could not create ACPI "
> +                      "description: %s\n", block->drive, strerror ( rc )
> );
> +               return rc;
> +       }
> +
> +       /* Fix up ACPI checksum */
> +       acpi_fix_checksum ( &xbftab.acpi );
> +
> +       /* Install table */
> +       if ( ( efirc = acpi.acpi->InstallAcpiTable ( acpi.acpi,
> &xbftab.acpi,
> +                                           xbftab.acpi.length, &table_key
> ) ) != 0 ) {
> +               rc = -EEFI ( efirc );
> +               DBGC ( block, "EFIBLK %02x cannot install table\n",
> +                      block->drive );
> +               return rc;
> +       }
> +       table_installed = TRUE;
> +
> +       DBGC ( block, "EFIBLK %02x described using boot firmware "
> +              "table:\n", block->drive );
> +
> +       /* The xbft_address isn't necessary for the uefi registration,
> +        * but we use it to print out the table in debug mode */
> +       xbft_address.segment = rm_ds;
> +       xbft_address.offset = __from_data16 ( &xbftab );
> +       DBGC_HDA ( block, xbft_address, &xbftab,
> +                  le32_to_cpu ( xbftab.acpi.length ) );
> +
>         return 0;
>  }
>
> --
> 2.5.0
>
> _______________________________________________
> ipxe-devel mailing list
> ipxe-devel at lists.ipxe.org
> https://lists.ipxe.org/mailman/listinfo.cgi/ipxe-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ipxe.org/pipermail/ipxe-devel/attachments/20161212/34f67997/attachment.htm>


More information about the ipxe-devel mailing list