]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg/AcpiPlatformDxe: alloc blobs from 64-bit space unless restricted
authorLaszlo Ersek <lersek@redhat.com>
Sat, 3 Jun 2017 14:11:08 +0000 (16:11 +0200)
committerLaszlo Ersek <lersek@redhat.com>
Wed, 7 Jun 2017 22:49:02 +0000 (00:49 +0200)
... by narrower than 8-byte ADD_POINTER references.

Introduce the CollectAllocationsRestrictedTo32Bit() function, which
iterates over the linker/loader script, and collects the names of the
fw_cfg blobs that are referenced by QEMU_LOADER_ADD_POINTER.PointeeFile
fields, such that QEMU_LOADER_ADD_POINTER.PointerSize is less than 8. This
means that the pointee blob's address will have to be patched into a
narrower-than-8 byte pointer field, hence the pointee blob must not be
allocated from 64-bit address space.

In ProcessCmdAllocate(), consult these restrictions when setting the
maximum address for gBS->AllocatePages(). The default is now MAX_UINT64,
unless restricted like described above to the pre-patch MAX_UINT32 limit.

In combination with Ard's QEMU commit cb51ac2ffe36 ("hw/arm/virt: generate
64-bit addressable ACPI objects", 2017-04-10), this patch enables
OvmfPkg/AcpiPlatformDxe to work entirely above the 4GB mark.

(An upcoming / planned aarch64 QEMU machine type will have no RAM under
4GB at all. Plus, moving the allocations higher is beneficial to the
current "virt" machine type as well; in Ard's words: "having all firmware
allocations inside the same 1 GB (or 512 MB for 64k pages) frame reduces
the TLB footprint".)

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Suggested-by: Igor Mammedov <imammedo@redhat.com>
Suggested-by: Gerd Hoffmann <kraxel@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c

index 1bc5fe297a96e5b6dd3a2855e2474cac09286a87..98be36c64b436f07abdb66eae5792a9ca0bed424 100644 (file)
@@ -132,13 +132,172 @@ PointerCompare (
 }\r
 \r
 \r
+/**\r
+  Comparator function for two ASCII strings. Can be used as both Key and\r
+  UserStruct comparator.\r
+\r
+  This function exists solely so we can avoid casting &AsciiStrCmp to\r
+  ORDERED_COLLECTION_USER_COMPARE and ORDERED_COLLECTION_KEY_COMPARE.\r
+\r
+  @param[in] AsciiString1  Pointer to the first ASCII string.\r
+\r
+  @param[in] AsciiString2  Pointer to the second ASCII string.\r
+\r
+  @return  The return value of AsciiStrCmp (AsciiString1, AsciiString2).\r
+**/\r
+STATIC\r
+INTN\r
+EFIAPI\r
+AsciiStringCompare (\r
+  IN CONST VOID *AsciiString1,\r
+  IN CONST VOID *AsciiString2\r
+  )\r
+{\r
+  return AsciiStrCmp (AsciiString1, AsciiString2);\r
+}\r
+\r
+\r
+/**\r
+  Release the ORDERED_COLLECTION structure populated by\r
+  CollectAllocationsRestrictedTo32Bit() (below).\r
+\r
+  This function may be called by CollectAllocationsRestrictedTo32Bit() itself,\r
+  on the error path.\r
+\r
+  @param[in] AllocationsRestrictedTo32Bit  The ORDERED_COLLECTION structure to\r
+                                           release.\r
+**/\r
+STATIC\r
+VOID\r
+ReleaseAllocationsRestrictedTo32Bit (\r
+  IN ORDERED_COLLECTION *AllocationsRestrictedTo32Bit\r
+)\r
+{\r
+  ORDERED_COLLECTION_ENTRY *Entry, *Entry2;\r
+\r
+  for (Entry = OrderedCollectionMin (AllocationsRestrictedTo32Bit);\r
+       Entry != NULL;\r
+       Entry = Entry2) {\r
+    Entry2 = OrderedCollectionNext (Entry);\r
+    OrderedCollectionDelete (AllocationsRestrictedTo32Bit, Entry, NULL);\r
+  }\r
+  OrderedCollectionUninit (AllocationsRestrictedTo32Bit);\r
+}\r
+\r
+\r
+/**\r
+  Iterate over the linker/loader script, and collect the names of the fw_cfg\r
+  blobs that are referenced by QEMU_LOADER_ADD_POINTER.PointeeFile fields, such\r
+  that QEMU_LOADER_ADD_POINTER.PointerSize is less than 8. This means that the\r
+  pointee blob's address will have to be patched into a narrower-than-8 byte\r
+  pointer field, hence the pointee blob must not be allocated from 64-bit\r
+  address space.\r
+\r
+  @param[out] AllocationsRestrictedTo32Bit  The ORDERED_COLLECTION structure\r
+                                            linking (not copying / owning) such\r
+                                            QEMU_LOADER_ADD_POINTER.PointeeFile\r
+                                            fields that name the blobs\r
+                                            restricted from 64-bit allocation.\r
+\r
+  @param[in] LoaderStart                    Points to the first entry in the\r
+                                            linker/loader script.\r
+\r
+  @param[in] LoaderEnd                      Points one past the last entry in\r
+                                            the linker/loader script.\r
+\r
+  @retval EFI_SUCCESS           AllocationsRestrictedTo32Bit has been\r
+                                populated.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.\r
+\r
+  @retval EFI_PROTOCOL_ERROR    Invalid linker/loader script contents.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+CollectAllocationsRestrictedTo32Bit (\r
+  OUT ORDERED_COLLECTION     **AllocationsRestrictedTo32Bit,\r
+  IN CONST QEMU_LOADER_ENTRY *LoaderStart,\r
+  IN CONST QEMU_LOADER_ENTRY *LoaderEnd\r
+)\r
+{\r
+  ORDERED_COLLECTION      *Collection;\r
+  CONST QEMU_LOADER_ENTRY *LoaderEntry;\r
+  EFI_STATUS              Status;\r
+\r
+  Collection = OrderedCollectionInit (AsciiStringCompare, AsciiStringCompare);\r
+  if (Collection == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  for (LoaderEntry = LoaderStart; LoaderEntry < LoaderEnd; ++LoaderEntry) {\r
+    CONST QEMU_LOADER_ADD_POINTER *AddPointer;\r
+\r
+    if (LoaderEntry->Type != QemuLoaderCmdAddPointer) {\r
+      continue;\r
+    }\r
+    AddPointer = &LoaderEntry->Command.AddPointer;\r
+\r
+    if (AddPointer->PointerSize >= 8) {\r
+      continue;\r
+    }\r
+\r
+    if (AddPointer->PointeeFile[QEMU_LOADER_FNAME_SIZE - 1] != '\0') {\r
+      DEBUG ((DEBUG_ERROR, "%a: malformed file name\n", __FUNCTION__));\r
+      Status = EFI_PROTOCOL_ERROR;\r
+      goto RollBack;\r
+    }\r
+\r
+    Status = OrderedCollectionInsert (\r
+               Collection,\r
+               NULL,                           // Entry\r
+               (VOID *)AddPointer->PointeeFile\r
+               );\r
+    switch (Status) {\r
+    case EFI_SUCCESS:\r
+      DEBUG ((\r
+        DEBUG_VERBOSE,\r
+        "%a: restricting blob \"%a\" from 64-bit allocation\n",\r
+        __FUNCTION__,\r
+        AddPointer->PointeeFile\r
+        ));\r
+      break;\r
+    case EFI_ALREADY_STARTED:\r
+      //\r
+      // The restriction has been recorded already.\r
+      //\r
+      break;\r
+    case EFI_OUT_OF_RESOURCES:\r
+      goto RollBack;\r
+    default:\r
+      ASSERT (FALSE);\r
+    }\r
+  }\r
+\r
+  *AllocationsRestrictedTo32Bit = Collection;\r
+  return EFI_SUCCESS;\r
+\r
+RollBack:\r
+  ReleaseAllocationsRestrictedTo32Bit (Collection);\r
+  return Status;\r
+}\r
+\r
+\r
 /**\r
   Process a QEMU_LOADER_ALLOCATE command.\r
 \r
-  @param[in] Allocate     The QEMU_LOADER_ALLOCATE command to process.\r
+  @param[in] Allocate                      The QEMU_LOADER_ALLOCATE command to\r
+                                           process.\r
 \r
-  @param[in,out] Tracker  The ORDERED_COLLECTION tracking the BLOB user\r
-                          structures created thus far.\r
+  @param[in,out] Tracker                   The ORDERED_COLLECTION tracking the\r
+                                           BLOB user structures created thus\r
+                                           far.\r
+\r
+  @param[in] AllocationsRestrictedTo32Bit  The ORDERED_COLLECTION populated by\r
+                                           the function\r
+                                           CollectAllocationsRestrictedTo32Bit,\r
+                                           naming the fw_cfg blobs that must\r
+                                           not be allocated from 64-bit address\r
+                                           space.\r
 \r
   @retval EFI_SUCCESS           An area of whole AcpiNVS pages has been\r
                                 allocated for the blob contents, and the\r
@@ -164,7 +323,8 @@ EFI_STATUS
 EFIAPI\r
 ProcessCmdAllocate (\r
   IN CONST QEMU_LOADER_ALLOCATE *Allocate,\r
-  IN OUT ORDERED_COLLECTION     *Tracker\r
+  IN OUT ORDERED_COLLECTION     *Tracker,\r
+  IN ORDERED_COLLECTION         *AllocationsRestrictedTo32Bit\r
   )\r
 {\r
   FIRMWARE_CONFIG_ITEM FwCfgItem;\r
@@ -193,7 +353,13 @@ ProcessCmdAllocate (
   }\r
 \r
   NumPages = EFI_SIZE_TO_PAGES (FwCfgSize);\r
-  Address = 0xFFFFFFFF;\r
+  Address = MAX_UINT64;\r
+  if (OrderedCollectionFind (\r
+        AllocationsRestrictedTo32Bit,\r
+        Allocate->File\r
+        ) != NULL) {\r
+    Address = MAX_UINT32;\r
+  }\r
   Status = gBS->AllocatePages (AllocateMaxAddress, EfiACPIMemoryNVS, NumPages,\r
                   &Address);\r
   if (EFI_ERROR (Status)) {\r
@@ -806,6 +972,7 @@ InstallQemuFwCfgTables (
   CONST QEMU_LOADER_ENTRY  *WritePointerSubsetEnd;\r
   ORIGINAL_ATTRIBUTES      *OriginalPciAttributes;\r
   UINTN                    OriginalPciAttributesCount;\r
+  ORDERED_COLLECTION       *AllocationsRestrictedTo32Bit;\r
   S3_CONTEXT               *S3Context;\r
   ORDERED_COLLECTION       *Tracker;\r
   UINTN                    *InstalledKey;\r
@@ -834,6 +1001,15 @@ InstallQemuFwCfgTables (
   RestorePciDecoding (OriginalPciAttributes, OriginalPciAttributesCount);\r
   LoaderEnd = LoaderStart + FwCfgSize / sizeof *LoaderEntry;\r
 \r
+  Status = CollectAllocationsRestrictedTo32Bit (\r
+             &AllocationsRestrictedTo32Bit,\r
+             LoaderStart,\r
+             LoaderEnd\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto FreeLoader;\r
+  }\r
+\r
   S3Context = NULL;\r
   if (QemuFwCfgS3Enabled ()) {\r
     //\r
@@ -842,7 +1018,7 @@ InstallQemuFwCfgTables (
     //\r
     Status = AllocateS3Context (&S3Context, LoaderEnd - LoaderStart);\r
     if (EFI_ERROR (Status)) {\r
-      goto FreeLoader;\r
+      goto FreeAllocationsRestrictedTo32Bit;\r
     }\r
   }\r
 \r
@@ -863,7 +1039,11 @@ InstallQemuFwCfgTables (
   for (LoaderEntry = LoaderStart; LoaderEntry < LoaderEnd; ++LoaderEntry) {\r
     switch (LoaderEntry->Type) {\r
     case QemuLoaderCmdAllocate:\r
-      Status = ProcessCmdAllocate (&LoaderEntry->Command.Allocate, Tracker);\r
+      Status = ProcessCmdAllocate (\r
+                 &LoaderEntry->Command.Allocate,\r
+                 Tracker,\r
+                 AllocationsRestrictedTo32Bit\r
+                 );\r
       break;\r
 \r
     case QemuLoaderCmdAddPointer:\r
@@ -1010,6 +1190,9 @@ FreeS3Context:
     ReleaseS3Context (S3Context);\r
   }\r
 \r
+FreeAllocationsRestrictedTo32Bit:\r
+  ReleaseAllocationsRestrictedTo32Bit (AllocationsRestrictedTo32Bit);\r
+\r
 FreeLoader:\r
   FreePool (LoaderStart);\r
 \r