summaryrefslogtreecommitdiffstats
path: root/OvmfPkg/AcpiPlatformDxe
diff options
context:
space:
mode:
authorLaszlo Ersek <lersek@redhat.com>2017-06-03 16:11:08 +0200
committerLaszlo Ersek <lersek@redhat.com>2017-06-08 00:49:02 +0200
commit4275f38507a4a44260555495dfb6da1d8a307307 (patch)
treeca28ee3db541319cfcfa621f453a501bf230a9c0 /OvmfPkg/AcpiPlatformDxe
parentb941c34ef859971e29683ffb57c309e24e6a96be (diff)
downloadedk2-4275f38507a4a44260555495dfb6da1d8a307307.tar.gz
edk2-4275f38507a4a44260555495dfb6da1d8a307307.tar.bz2
edk2-4275f38507a4a44260555495dfb6da1d8a307307.zip
OvmfPkg/AcpiPlatformDxe: alloc blobs from 64-bit space unless restricted
... 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>
Diffstat (limited to 'OvmfPkg/AcpiPlatformDxe')
-rw-r--r--OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c197
1 files changed, 190 insertions, 7 deletions
diff --git a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c
index 1bc5fe297a..98be36c64b 100644
--- a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c
+++ b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c
@@ -133,12 +133,171 @@ PointerCompare (
/**
+ Comparator function for two ASCII strings. Can be used as both Key and
+ UserStruct comparator.
+
+ This function exists solely so we can avoid casting &AsciiStrCmp to
+ ORDERED_COLLECTION_USER_COMPARE and ORDERED_COLLECTION_KEY_COMPARE.
+
+ @param[in] AsciiString1 Pointer to the first ASCII string.
+
+ @param[in] AsciiString2 Pointer to the second ASCII string.
+
+ @return The return value of AsciiStrCmp (AsciiString1, AsciiString2).
+**/
+STATIC
+INTN
+EFIAPI
+AsciiStringCompare (
+ IN CONST VOID *AsciiString1,
+ IN CONST VOID *AsciiString2
+ )
+{
+ return AsciiStrCmp (AsciiString1, AsciiString2);
+}
+
+
+/**
+ Release the ORDERED_COLLECTION structure populated by
+ CollectAllocationsRestrictedTo32Bit() (below).
+
+ This function may be called by CollectAllocationsRestrictedTo32Bit() itself,
+ on the error path.
+
+ @param[in] AllocationsRestrictedTo32Bit The ORDERED_COLLECTION structure to
+ release.
+**/
+STATIC
+VOID
+ReleaseAllocationsRestrictedTo32Bit (
+ IN ORDERED_COLLECTION *AllocationsRestrictedTo32Bit
+)
+{
+ ORDERED_COLLECTION_ENTRY *Entry, *Entry2;
+
+ for (Entry = OrderedCollectionMin (AllocationsRestrictedTo32Bit);
+ Entry != NULL;
+ Entry = Entry2) {
+ Entry2 = OrderedCollectionNext (Entry);
+ OrderedCollectionDelete (AllocationsRestrictedTo32Bit, Entry, NULL);
+ }
+ OrderedCollectionUninit (AllocationsRestrictedTo32Bit);
+}
+
+
+/**
+ Iterate over the linker/loader script, and collect 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.
+
+ @param[out] AllocationsRestrictedTo32Bit The ORDERED_COLLECTION structure
+ linking (not copying / owning) such
+ QEMU_LOADER_ADD_POINTER.PointeeFile
+ fields that name the blobs
+ restricted from 64-bit allocation.
+
+ @param[in] LoaderStart Points to the first entry in the
+ linker/loader script.
+
+ @param[in] LoaderEnd Points one past the last entry in
+ the linker/loader script.
+
+ @retval EFI_SUCCESS AllocationsRestrictedTo32Bit has been
+ populated.
+
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+
+ @retval EFI_PROTOCOL_ERROR Invalid linker/loader script contents.
+**/
+STATIC
+EFI_STATUS
+CollectAllocationsRestrictedTo32Bit (
+ OUT ORDERED_COLLECTION **AllocationsRestrictedTo32Bit,
+ IN CONST QEMU_LOADER_ENTRY *LoaderStart,
+ IN CONST QEMU_LOADER_ENTRY *LoaderEnd
+)
+{
+ ORDERED_COLLECTION *Collection;
+ CONST QEMU_LOADER_ENTRY *LoaderEntry;
+ EFI_STATUS Status;
+
+ Collection = OrderedCollectionInit (AsciiStringCompare, AsciiStringCompare);
+ if (Collection == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (LoaderEntry = LoaderStart; LoaderEntry < LoaderEnd; ++LoaderEntry) {
+ CONST QEMU_LOADER_ADD_POINTER *AddPointer;
+
+ if (LoaderEntry->Type != QemuLoaderCmdAddPointer) {
+ continue;
+ }
+ AddPointer = &LoaderEntry->Command.AddPointer;
+
+ if (AddPointer->PointerSize >= 8) {
+ continue;
+ }
+
+ if (AddPointer->PointeeFile[QEMU_LOADER_FNAME_SIZE - 1] != '\0') {
+ DEBUG ((DEBUG_ERROR, "%a: malformed file name\n", __FUNCTION__));
+ Status = EFI_PROTOCOL_ERROR;
+ goto RollBack;
+ }
+
+ Status = OrderedCollectionInsert (
+ Collection,
+ NULL, // Entry
+ (VOID *)AddPointer->PointeeFile
+ );
+ switch (Status) {
+ case EFI_SUCCESS:
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: restricting blob \"%a\" from 64-bit allocation\n",
+ __FUNCTION__,
+ AddPointer->PointeeFile
+ ));
+ break;
+ case EFI_ALREADY_STARTED:
+ //
+ // The restriction has been recorded already.
+ //
+ break;
+ case EFI_OUT_OF_RESOURCES:
+ goto RollBack;
+ default:
+ ASSERT (FALSE);
+ }
+ }
+
+ *AllocationsRestrictedTo32Bit = Collection;
+ return EFI_SUCCESS;
+
+RollBack:
+ ReleaseAllocationsRestrictedTo32Bit (Collection);
+ return Status;
+}
+
+
+/**
Process a QEMU_LOADER_ALLOCATE command.
- @param[in] Allocate The QEMU_LOADER_ALLOCATE command to process.
+ @param[in] Allocate The QEMU_LOADER_ALLOCATE command to
+ process.
- @param[in,out] Tracker The ORDERED_COLLECTION tracking the BLOB user
- structures created thus far.
+ @param[in,out] Tracker The ORDERED_COLLECTION tracking the
+ BLOB user structures created thus
+ far.
+
+ @param[in] AllocationsRestrictedTo32Bit The ORDERED_COLLECTION populated by
+ the function
+ CollectAllocationsRestrictedTo32Bit,
+ naming the fw_cfg blobs that must
+ not be allocated from 64-bit address
+ space.
@retval EFI_SUCCESS An area of whole AcpiNVS pages has been
allocated for the blob contents, and the
@@ -164,7 +323,8 @@ EFI_STATUS
EFIAPI
ProcessCmdAllocate (
IN CONST QEMU_LOADER_ALLOCATE *Allocate,
- IN OUT ORDERED_COLLECTION *Tracker
+ IN OUT ORDERED_COLLECTION *Tracker,
+ IN ORDERED_COLLECTION *AllocationsRestrictedTo32Bit
)
{
FIRMWARE_CONFIG_ITEM FwCfgItem;
@@ -193,7 +353,13 @@ ProcessCmdAllocate (
}
NumPages = EFI_SIZE_TO_PAGES (FwCfgSize);
- Address = 0xFFFFFFFF;
+ Address = MAX_UINT64;
+ if (OrderedCollectionFind (
+ AllocationsRestrictedTo32Bit,
+ Allocate->File
+ ) != NULL) {
+ Address = MAX_UINT32;
+ }
Status = gBS->AllocatePages (AllocateMaxAddress, EfiACPIMemoryNVS, NumPages,
&Address);
if (EFI_ERROR (Status)) {
@@ -806,6 +972,7 @@ InstallQemuFwCfgTables (
CONST QEMU_LOADER_ENTRY *WritePointerSubsetEnd;
ORIGINAL_ATTRIBUTES *OriginalPciAttributes;
UINTN OriginalPciAttributesCount;
+ ORDERED_COLLECTION *AllocationsRestrictedTo32Bit;
S3_CONTEXT *S3Context;
ORDERED_COLLECTION *Tracker;
UINTN *InstalledKey;
@@ -834,6 +1001,15 @@ InstallQemuFwCfgTables (
RestorePciDecoding (OriginalPciAttributes, OriginalPciAttributesCount);
LoaderEnd = LoaderStart + FwCfgSize / sizeof *LoaderEntry;
+ Status = CollectAllocationsRestrictedTo32Bit (
+ &AllocationsRestrictedTo32Bit,
+ LoaderStart,
+ LoaderEnd
+ );
+ if (EFI_ERROR (Status)) {
+ goto FreeLoader;
+ }
+
S3Context = NULL;
if (QemuFwCfgS3Enabled ()) {
//
@@ -842,7 +1018,7 @@ InstallQemuFwCfgTables (
//
Status = AllocateS3Context (&S3Context, LoaderEnd - LoaderStart);
if (EFI_ERROR (Status)) {
- goto FreeLoader;
+ goto FreeAllocationsRestrictedTo32Bit;
}
}
@@ -863,7 +1039,11 @@ InstallQemuFwCfgTables (
for (LoaderEntry = LoaderStart; LoaderEntry < LoaderEnd; ++LoaderEntry) {
switch (LoaderEntry->Type) {
case QemuLoaderCmdAllocate:
- Status = ProcessCmdAllocate (&LoaderEntry->Command.Allocate, Tracker);
+ Status = ProcessCmdAllocate (
+ &LoaderEntry->Command.Allocate,
+ Tracker,
+ AllocationsRestrictedTo32Bit
+ );
break;
case QemuLoaderCmdAddPointer:
@@ -1010,6 +1190,9 @@ FreeS3Context:
ReleaseS3Context (S3Context);
}
+FreeAllocationsRestrictedTo32Bit:
+ ReleaseAllocationsRestrictedTo32Bit (AllocationsRestrictedTo32Bit);
+
FreeLoader:
FreePool (LoaderStart);