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.
|
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
|
@param[in,out] Tracker The ORDERED_COLLECTION tracking the
|
||||||
structures created thus far.
|
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
|
@retval EFI_SUCCESS An area of whole AcpiNVS pages has been
|
||||||
allocated for the blob contents, and the
|
allocated for the blob contents, and the
|
||||||
|
@ -164,7 +323,8 @@ EFI_STATUS
|
||||||
EFIAPI
|
EFIAPI
|
||||||
ProcessCmdAllocate (
|
ProcessCmdAllocate (
|
||||||
IN CONST QEMU_LOADER_ALLOCATE *Allocate,
|
IN CONST QEMU_LOADER_ALLOCATE *Allocate,
|
||||||
IN OUT ORDERED_COLLECTION *Tracker
|
IN OUT ORDERED_COLLECTION *Tracker,
|
||||||
|
IN ORDERED_COLLECTION *AllocationsRestrictedTo32Bit
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
FIRMWARE_CONFIG_ITEM FwCfgItem;
|
FIRMWARE_CONFIG_ITEM FwCfgItem;
|
||||||
|
@ -193,7 +353,13 @@ ProcessCmdAllocate (
|
||||||
}
|
}
|
||||||
|
|
||||||
NumPages = EFI_SIZE_TO_PAGES (FwCfgSize);
|
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,
|
Status = gBS->AllocatePages (AllocateMaxAddress, EfiACPIMemoryNVS, NumPages,
|
||||||
&Address);
|
&Address);
|
||||||
if (EFI_ERROR (Status)) {
|
if (EFI_ERROR (Status)) {
|
||||||
|
@ -806,6 +972,7 @@ InstallQemuFwCfgTables (
|
||||||
CONST QEMU_LOADER_ENTRY *WritePointerSubsetEnd;
|
CONST QEMU_LOADER_ENTRY *WritePointerSubsetEnd;
|
||||||
ORIGINAL_ATTRIBUTES *OriginalPciAttributes;
|
ORIGINAL_ATTRIBUTES *OriginalPciAttributes;
|
||||||
UINTN OriginalPciAttributesCount;
|
UINTN OriginalPciAttributesCount;
|
||||||
|
ORDERED_COLLECTION *AllocationsRestrictedTo32Bit;
|
||||||
S3_CONTEXT *S3Context;
|
S3_CONTEXT *S3Context;
|
||||||
ORDERED_COLLECTION *Tracker;
|
ORDERED_COLLECTION *Tracker;
|
||||||
UINTN *InstalledKey;
|
UINTN *InstalledKey;
|
||||||
|
@ -834,6 +1001,15 @@ InstallQemuFwCfgTables (
|
||||||
RestorePciDecoding (OriginalPciAttributes, OriginalPciAttributesCount);
|
RestorePciDecoding (OriginalPciAttributes, OriginalPciAttributesCount);
|
||||||
LoaderEnd = LoaderStart + FwCfgSize / sizeof *LoaderEntry;
|
LoaderEnd = LoaderStart + FwCfgSize / sizeof *LoaderEntry;
|
||||||
|
|
||||||
|
Status = CollectAllocationsRestrictedTo32Bit (
|
||||||
|
&AllocationsRestrictedTo32Bit,
|
||||||
|
LoaderStart,
|
||||||
|
LoaderEnd
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto FreeLoader;
|
||||||
|
}
|
||||||
|
|
||||||
S3Context = NULL;
|
S3Context = NULL;
|
||||||
if (QemuFwCfgS3Enabled ()) {
|
if (QemuFwCfgS3Enabled ()) {
|
||||||
//
|
//
|
||||||
|
@ -842,7 +1018,7 @@ InstallQemuFwCfgTables (
|
||||||
//
|
//
|
||||||
Status = AllocateS3Context (&S3Context, LoaderEnd - LoaderStart);
|
Status = AllocateS3Context (&S3Context, LoaderEnd - LoaderStart);
|
||||||
if (EFI_ERROR (Status)) {
|
if (EFI_ERROR (Status)) {
|
||||||
goto FreeLoader;
|
goto FreeAllocationsRestrictedTo32Bit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -863,7 +1039,11 @@ InstallQemuFwCfgTables (
|
||||||
for (LoaderEntry = LoaderStart; LoaderEntry < LoaderEnd; ++LoaderEntry) {
|
for (LoaderEntry = LoaderStart; LoaderEntry < LoaderEnd; ++LoaderEntry) {
|
||||||
switch (LoaderEntry->Type) {
|
switch (LoaderEntry->Type) {
|
||||||
case QemuLoaderCmdAllocate:
|
case QemuLoaderCmdAllocate:
|
||||||
Status = ProcessCmdAllocate (&LoaderEntry->Command.Allocate, Tracker);
|
Status = ProcessCmdAllocate (
|
||||||
|
&LoaderEntry->Command.Allocate,
|
||||||
|
Tracker,
|
||||||
|
AllocationsRestrictedTo32Bit
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QemuLoaderCmdAddPointer:
|
case QemuLoaderCmdAddPointer:
|
||||||
|
@ -1010,6 +1190,9 @@ FreeS3Context:
|
||||||
ReleaseS3Context (S3Context);
|
ReleaseS3Context (S3Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FreeAllocationsRestrictedTo32Bit:
|
||||||
|
ReleaseAllocationsRestrictedTo32Bit (AllocationsRestrictedTo32Bit);
|
||||||
|
|
||||||
FreeLoader:
|
FreeLoader:
|
||||||
FreePool (LoaderStart);
|
FreePool (LoaderStart);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue