diff mbox

[seabios,1/2] romfile_loader: alloc: cope with the UEFI-oriented NOACPI content hint

Message ID 20170602160210.1868-2-lersek@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Laszlo Ersek June 2, 2017, 4:02 p.m. UTC
OvmfPkg/AcpiPlatformDxe, which implements the client for QEMU's
linker/loader in the OVMF and ArmVirtQemu virtual UEFI firmwares,
currently relies on a 2nd pass processing of the ADD_POINTER commands, to
identify potential ACPI tables in the pointed-to blobs. The reason for
this is that ACPI tables must be individually passed to
EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() for installation.

In order to tell apart ACPI tables from other operation region-like areas
within pointed-to blobs, OvmfPkg/AcpiPlatformDxe employs a heuristic
called "ACPI SDT header probe" at the target locations of the ADD_POINTER
commands. While all ACPI tables generated by QEMU satisfy this check
(i.e., there are no false negatives), blob content that is *not* an ACPI
table has a very slight chance to pass the test as well (i.e., there is a
small chance for false positives).

In order to suppress this small chance, in QEMU we've historically
formatted opregion-like areas in blobs with a fixed size zero prefix (see
e.g. "docs/specs/vmgenid.txt"), which guarantees that the probe in
OvmfPkg/AcpiPlatformDxe will fail. However, this "suppressor prefix" has
had to be taken into account explicitly in generated AML code -- the
prefix size has had to be added to the patched integer object in AML, at
runtime --, leading to awkwardness.

QEMU is introducing a new hint for the ALLOC command, as the most
significant bit of the uint8_t "zone" field, for disabling the ACPI SDT
header probe in OvmfPkg/AcpiPlatformDxe, for all the pointers that point
into the blob downloaded with the ALLOC command. When the bit is set, the
blob is guaranteed to contain no ACPI tables. When the bit is clear, the
behavior is left unchanged.

For SeaBIOS, this bit is irrelevant, thus mask it out.

Cc: "Kevin O'Connor" <kevin@koconnor.net>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Ben Warren <ben@skyportsystems.com>
Cc: Dongjiu Geng <gengdongjiu@huawei.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Shannon Zhao <zhaoshenglong@huawei.com>
Cc: Stefan Berger <stefanb@linux.vnet.ibm.com>
Cc: Xiao Guangrong <guangrong.xiao@linux.intel.com>
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 src/fw/romfile_loader.h | 7 +++++++
 src/fw/romfile_loader.c | 5 ++++-
 2 files changed, 11 insertions(+), 1 deletion(-)
diff mbox

Patch

diff --git a/src/fw/romfile_loader.h b/src/fw/romfile_loader.h
index fcd4ab236b61..d90c3db24331 100644
--- a/src/fw/romfile_loader.h
+++ b/src/fw/romfile_loader.h
@@ -12,10 +12,12 @@  struct romfile_loader_entry_s {
     union {
         /*
          * COMMAND_ALLOCATE - allocate a table from @alloc.file
          * subject to @alloc.align alignment (must be power of 2)
          * and @alloc.zone (can be HIGH or FSEG) requirements.
+         * The most significant bit (bit 7) of @alloc.zone is used as a content
+         * hint for UEFI guest firmware, see ROMFILE_LOADER_ALLOC_CONTENT_*.
          *
          * Must appear exactly once for each file, and before
          * this file is referenced by any other command.
          */
         struct {
@@ -82,10 +84,15 @@  enum {
 enum {
     ROMFILE_LOADER_ALLOC_ZONE_HIGH = 0x1,
     ROMFILE_LOADER_ALLOC_ZONE_FSEG = 0x2,
 };
 
+enum {
+    ROMFILE_LOADER_ALLOC_CONTENT_MIXED  = 0x00,
+    ROMFILE_LOADER_ALLOC_CONTENT_NOACPI = 0x80,
+};
+
 int romfile_loader_execute(const char *name);
 
 void romfile_fw_cfg_resume(void);
 
 #endif
diff --git a/src/fw/romfile_loader.c b/src/fw/romfile_loader.c
index 18476e2075e3..6a457902a36a 100644
--- a/src/fw/romfile_loader.c
+++ b/src/fw/romfile_loader.c
@@ -55,19 +55,22 @@  void romfile_fw_cfg_resume(void)
 
 static void romfile_loader_allocate(struct romfile_loader_entry_s *entry,
                                     struct romfile_loader_files *files)
 {
     struct zone_s *zone;
+    unsigned zone_req;
     struct romfile_loader_file *file = &files->files[files->nfiles];
     void *data;
     int ret;
     unsigned alloc_align = le32_to_cpu(entry->alloc.align);
 
     if (alloc_align & (alloc_align - 1))
         goto err;
 
-    switch (entry->alloc.zone) {
+    zone_req = entry->alloc.zone;
+    zone_req &= ~(unsigned)ROMFILE_LOADER_ALLOC_CONTENT_NOACPI;
+    switch (zone_req) {
         case ROMFILE_LOADER_ALLOC_ZONE_HIGH:
             zone = &ZoneHigh;
             break;
         case ROMFILE_LOADER_ALLOC_ZONE_FSEG:
             zone = &ZoneFSeg;