diff --git a/OvmfPkg/AcpiPlatformDxe/Qemu.c b/OvmfPkg/AcpiPlatformDxe/Qemu.c index 5a96d76a1f..70f3ff6426 100644 --- a/OvmfPkg/AcpiPlatformDxe/Qemu.c +++ b/OvmfPkg/AcpiPlatformDxe/Qemu.c @@ -16,6 +16,7 @@ **/ #include "AcpiPlatform.h" +#include "QemuLoader.h" #include #include #include @@ -795,8 +796,7 @@ InstallQemuLinkedTables ( @retval EFI_OUT_OF_RESOURCES Memory allocation failed, or more than INSTALLED_TABLES_MAX tables found. - @retval EFI_PROTOCOL_ERROR Found truncated or invalid ACPI table header - in the fw_cfg contents. + @retval EFI_PROTOCOL_ERROR Found invalid fw_cfg contents. @return Status codes returned by AcpiProtocol->InstallAcpiTable(). @@ -812,6 +812,10 @@ InstallAllQemuLinkedTables ( UINTN *InstalledKey; INT32 Installed; EFI_STATUS Status; + FIRMWARE_CONFIG_ITEM LoaderItem; + UINTN LoaderSize; + UINT8 *Loader; + QEMU_LOADER_ENTRY *Entry, *End; InstalledKey = AllocatePool (INSTALLED_TABLES_MAX * sizeof *InstalledKey); if (InstalledKey == NULL) { @@ -819,10 +823,49 @@ InstallAllQemuLinkedTables ( } Installed = 0; - Status = InstallQemuLinkedTables ("etc/acpi/tables", AcpiProtocol, - InstalledKey, &Installed); + Status = QemuFwCfgFindFile ("etc/table-loader", &LoaderItem, &LoaderSize); + if (EFI_ERROR (Status)) { + goto FreeInstalledKey; + } + if (LoaderSize % sizeof *Entry != 0) { + Status = EFI_PROTOCOL_ERROR; + goto FreeInstalledKey; + } + + Loader = AllocatePool (LoaderSize); + if (Loader == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeInstalledKey; + } + + QemuFwCfgSelectItem (LoaderItem); + QemuFwCfgReadBytes (LoaderSize, Loader); + + Entry = (QEMU_LOADER_ENTRY *)Loader; + End = (QEMU_LOADER_ENTRY *)(Loader + LoaderSize); + while (Entry < End) { + if (Entry->Type == QemuLoaderCmdAllocate) { + QEMU_LOADER_ALLOCATE *Allocate; + + Allocate = &Entry->Command.Allocate; + if (Allocate->File[sizeof Allocate->File - 1] != '\0') { + Status = EFI_PROTOCOL_ERROR; + break; + } + + Status = InstallQemuLinkedTables ((CHAR8 *)Allocate->File, AcpiProtocol, + InstalledKey, &Installed); + if (EFI_ERROR (Status)) { + ASSERT (Status != EFI_INVALID_PARAMETER); + break; + } + } + ++Entry; + } + + FreePool (Loader); + if (EFI_ERROR (Status)) { - ASSERT (Status != EFI_INVALID_PARAMETER); // // Roll back partial installation. // @@ -834,6 +877,7 @@ InstallAllQemuLinkedTables ( DEBUG ((EFI_D_INFO, "%a: installed %d tables\n", __FUNCTION__, Installed)); } +FreeInstalledKey: FreePool (InstalledKey); return Status; } diff --git a/OvmfPkg/AcpiPlatformDxe/QemuLoader.h b/OvmfPkg/AcpiPlatformDxe/QemuLoader.h new file mode 100644 index 0000000000..b8f6147ceb --- /dev/null +++ b/OvmfPkg/AcpiPlatformDxe/QemuLoader.h @@ -0,0 +1,90 @@ +/** @file + Command structures for the QEMU FwCfg table loader interface. + + Copyright (C) 2014, Red Hat, Inc. + + 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 __QEMU_LOADER_H__ +#define __QEMU_LOADER_H__ + +#include +#include + +// +// The types and the documentation reflects the SeaBIOS interface. In OVMF we +// use a minimal subset of it. +// +#define QEMU_LOADER_FNAME_SIZE QEMU_FW_CFG_FNAME_SIZE + +// +// We only look at the Allocate command, and only to get FwCfg filenames. +// +typedef enum { + QemuLoaderCmdAllocate = 1, + QemuLoaderCmdAddPointer, + QemuLoaderCmdAddChecksum +} QEMU_LOADER_COMMAND_TYPE; + +typedef enum { + QemuLoaderAllocHigh = 1, + QemuLoaderAllocFSeg +} QEMU_LOADER_ALLOC_ZONE; + +#pragma pack (1) +// +// QemuLoaderCmdAllocate: download the fw_cfg file named File, to a buffer +// allocated in the zone specified by Zone, aligned at a multiple of Alignment. +// +typedef struct { + UINT8 File[QEMU_LOADER_FNAME_SIZE]; // NUL-terminated + UINT32 Alignment; // power of two + UINT8 Zone; // QEMU_LOADER_ALLOC_ZONE values +} QEMU_LOADER_ALLOCATE; + +// +// QemuLoaderCmdAddPointer: the bytes at +// [PointerOffset..PointerOffset+PointerSize) in the file PointerFile contain a +// relative pointer (an offset) into PointeeFile. Increment the relative +// pointer's value by the base address of where PointeeFile's contents have +// been placed (when QemuLoaderCmdAllocate has been executed for PointeeFile). +// +typedef struct { + UINT8 PointerFile[QEMU_LOADER_FNAME_SIZE]; // NUL-terminated + UINT8 PointeeFile[QEMU_LOADER_FNAME_SIZE]; // NUL-terminated + UINT32 PointerOffset; + UINT8 PointerSize; // one of 1, 2, 4, 8 +} QEMU_LOADER_ADD_POINTER; + +// +// QemuLoaderCmdAddChecksum: calculate the UINT8 checksum (as per +// CalculateChecksum8()) of the range [Start..Start+Length) in File. Store the +// UINT8 result at ResultOffset in the same File. +// +typedef struct { + UINT8 File[QEMU_LOADER_FNAME_SIZE]; // NUL-terminated + UINT32 ResultOffset; + UINT32 Start; + UINT32 Length; +} QEMU_LOADER_ADD_CHECKSUM; + +typedef struct { + UINT32 Type; // QEMU_LOADER_COMMAND_TYPE values + union { + QEMU_LOADER_ALLOCATE Allocate; + QEMU_LOADER_ADD_POINTER AddPointer; + QEMU_LOADER_ADD_CHECKSUM AddChecksum; + UINT8 Padding[124]; + } Command; +} QEMU_LOADER_ENTRY; +#pragma pack () + +#endif