OvmfPkg: AcpiPlatformDxe: don't rely on unstable QEMU interface

The fw_cfg file "etc/acpi/tables" is not a stable guest interface -- QEMU
could rename it in the future, and/or introduce additional fw_cfg files
with ACPI payload. Only the higher-level "etc/table-loader" file is
considered stable, which contains a sequence of commands to assist
firmware with reading QEMU ACPI tables from the FwCfg interface.

Because edk2 provides publishing support for ACPI tables, OVMF only uses
the Allocate command to find the names of FwCfg files to read and publish
as ACPI tables.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15574 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Laszlo Ersek 2014-06-19 06:13:29 +00:00 committed by jljusten
parent 374df8fc59
commit a618eaa1f4
2 changed files with 139 additions and 5 deletions

View File

@ -16,6 +16,7 @@
**/ **/
#include "AcpiPlatform.h" #include "AcpiPlatform.h"
#include "QemuLoader.h"
#include <Library/BaseMemoryLib.h> #include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h> #include <Library/MemoryAllocationLib.h>
#include <Library/QemuFwCfgLib.h> #include <Library/QemuFwCfgLib.h>
@ -795,8 +796,7 @@ InstallQemuLinkedTables (
@retval EFI_OUT_OF_RESOURCES Memory allocation failed, or more than @retval EFI_OUT_OF_RESOURCES Memory allocation failed, or more than
INSTALLED_TABLES_MAX tables found. INSTALLED_TABLES_MAX tables found.
@retval EFI_PROTOCOL_ERROR Found truncated or invalid ACPI table header @retval EFI_PROTOCOL_ERROR Found invalid fw_cfg contents.
in the fw_cfg contents.
@return Status codes returned by @return Status codes returned by
AcpiProtocol->InstallAcpiTable(). AcpiProtocol->InstallAcpiTable().
@ -812,6 +812,10 @@ InstallAllQemuLinkedTables (
UINTN *InstalledKey; UINTN *InstalledKey;
INT32 Installed; INT32 Installed;
EFI_STATUS Status; EFI_STATUS Status;
FIRMWARE_CONFIG_ITEM LoaderItem;
UINTN LoaderSize;
UINT8 *Loader;
QEMU_LOADER_ENTRY *Entry, *End;
InstalledKey = AllocatePool (INSTALLED_TABLES_MAX * sizeof *InstalledKey); InstalledKey = AllocatePool (INSTALLED_TABLES_MAX * sizeof *InstalledKey);
if (InstalledKey == NULL) { if (InstalledKey == NULL) {
@ -819,10 +823,49 @@ InstallAllQemuLinkedTables (
} }
Installed = 0; Installed = 0;
Status = InstallQemuLinkedTables ("etc/acpi/tables", AcpiProtocol, 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); InstalledKey, &Installed);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
ASSERT (Status != EFI_INVALID_PARAMETER); ASSERT (Status != EFI_INVALID_PARAMETER);
break;
}
}
++Entry;
}
FreePool (Loader);
if (EFI_ERROR (Status)) {
// //
// Roll back partial installation. // Roll back partial installation.
// //
@ -834,6 +877,7 @@ InstallAllQemuLinkedTables (
DEBUG ((EFI_D_INFO, "%a: installed %d tables\n", __FUNCTION__, Installed)); DEBUG ((EFI_D_INFO, "%a: installed %d tables\n", __FUNCTION__, Installed));
} }
FreeInstalledKey:
FreePool (InstalledKey); FreePool (InstalledKey);
return Status; return Status;
} }

View File

@ -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/Base.h>
#include <Library/QemuFwCfgLib.h>
//
// 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