mirror of https://github.com/acidanthera/audk.git
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>
This commit is contained in:
parent
b941c34ef8
commit
4275f38507
|
@ -132,13 +132,172 @@ 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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue