From: Laszlo Ersek <lersek@redhat.com>
To: edk2-devel-01 <edk2-devel@lists.01.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>,
Gerd Hoffmann <kraxel@redhat.com>,
Igor Mammedov <imammedo@redhat.com>,
Jordan Justen <jordan.l.justen@intel.com>
Subject: [PATCH 1/1] OvmfPkg/AcpiPlatformDxe: alloc blobs from 64-bit space unless restricted
Date: Sat, 3 Jun 2017 17:42:03 +0200 [thread overview]
Message-ID: <20170603154203.29907-2-lersek@redhat.com> (raw)
In-Reply-To: <20170603154203.29907-1-lersek@redhat.com>
... by narrower than 8-byte ADD_POINTER references.
Introduce the CollectRestrictedAllocations() 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>
---
OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c | 190 +++++++++++++++++++-
1 file changed, 183 insertions(+), 7 deletions(-)
diff --git a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c
index 1bc5fe297a96..7aeb6472188b 100644
--- a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c
+++ b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c
@@ -132,14 +132,169 @@ 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
+ CollectRestrictedAllocations() (below).
+
+ This function may be called by CollectRestrictedAllocations() itself, on
+ the error path.
+
+ @param[in] RestrictedAllocations The ORDERED_COLLECTION structure to
+ release.
+**/
+STATIC
+VOID
+ReleaseRestrictedAllocations (
+ IN ORDERED_COLLECTION *RestrictedAllocations
+)
+{
+ ORDERED_COLLECTION_ENTRY *Entry, *Entry2;
+
+ for (Entry = OrderedCollectionMin (RestrictedAllocations);
+ Entry != NULL;
+ Entry = Entry2) {
+ Entry2 = OrderedCollectionNext (Entry);
+ OrderedCollectionDelete (RestrictedAllocations, Entry, NULL);
+ }
+ OrderedCollectionUninit (RestrictedAllocations);
+}
+
+
+/**
+ 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] RestrictedAllocations 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 RestrictedAllocations has been populated.
+
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+
+ @retval EFI_PROTOCOL_ERROR Invalid linker/loader script contents.
+**/
+STATIC
+EFI_STATUS
+CollectRestrictedAllocations (
+ OUT ORDERED_COLLECTION **RestrictedAllocations,
+ 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);
+ }
+ }
+
+ *RestrictedAllocations = Collection;
+ return EFI_SUCCESS;
+
+RollBack:
+ ReleaseRestrictedAllocations (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] RestrictedAllocations The ORDERED_COLLECTION populated by
+ CollectRestrictedAllocations(), 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
contents have been saved. A BLOB object (user
@@ -163,9 +318,10 @@ STATIC
EFI_STATUS
EFIAPI
ProcessCmdAllocate (
IN CONST QEMU_LOADER_ALLOCATE *Allocate,
- IN OUT ORDERED_COLLECTION *Tracker
+ IN OUT ORDERED_COLLECTION *Tracker,
+ IN ORDERED_COLLECTION *RestrictedAllocations
)
{
FIRMWARE_CONFIG_ITEM FwCfgItem;
UINTN FwCfgSize;
@@ -192,9 +348,12 @@ ProcessCmdAllocate (
return Status;
}
NumPages = EFI_SIZE_TO_PAGES (FwCfgSize);
- Address = 0xFFFFFFFF;
+ Address = MAX_UINT64;
+ if (OrderedCollectionFind (RestrictedAllocations, Allocate->File) != NULL) {
+ Address = MAX_UINT32;
+ }
Status = gBS->AllocatePages (AllocateMaxAddress, EfiACPIMemoryNVS, NumPages,
&Address);
if (EFI_ERROR (Status)) {
return Status;
@@ -805,8 +964,9 @@ InstallQemuFwCfgTables (
CONST QEMU_LOADER_ENTRY *LoaderEntry, *LoaderEnd;
CONST QEMU_LOADER_ENTRY *WritePointerSubsetEnd;
ORIGINAL_ATTRIBUTES *OriginalPciAttributes;
UINTN OriginalPciAttributesCount;
+ ORDERED_COLLECTION *RestrictedAllocations;
S3_CONTEXT *S3Context;
ORDERED_COLLECTION *Tracker;
UINTN *InstalledKey;
INT32 Installed;
@@ -833,17 +993,26 @@ InstallQemuFwCfgTables (
QemuFwCfgReadBytes (FwCfgSize, LoaderStart);
RestorePciDecoding (OriginalPciAttributes, OriginalPciAttributesCount);
LoaderEnd = LoaderStart + FwCfgSize / sizeof *LoaderEntry;
+ Status = CollectRestrictedAllocations (
+ &RestrictedAllocations,
+ LoaderStart,
+ LoaderEnd
+ );
+ if (EFI_ERROR (Status)) {
+ goto FreeLoader;
+ }
+
S3Context = NULL;
if (QemuFwCfgS3Enabled ()) {
//
// Size the allocation pessimistically, assuming that all commands in the
// script are QEMU_LOADER_WRITE_POINTER commands.
//
Status = AllocateS3Context (&S3Context, LoaderEnd - LoaderStart);
if (EFI_ERROR (Status)) {
- goto FreeLoader;
+ goto FreeRestrictedAllocations;
}
}
Tracker = OrderedCollectionInit (BlobCompare, BlobKeyCompare);
@@ -862,9 +1031,13 @@ InstallQemuFwCfgTables (
WritePointerSubsetEnd = LoaderStart;
for (LoaderEntry = LoaderStart; LoaderEntry < LoaderEnd; ++LoaderEntry) {
switch (LoaderEntry->Type) {
case QemuLoaderCmdAllocate:
- Status = ProcessCmdAllocate (&LoaderEntry->Command.Allocate, Tracker);
+ Status = ProcessCmdAllocate (
+ &LoaderEntry->Command.Allocate,
+ Tracker,
+ RestrictedAllocations
+ );
break;
case QemuLoaderCmdAddPointer:
Status = ProcessCmdAddPointer (&LoaderEntry->Command.AddPointer,
@@ -1009,8 +1182,11 @@ FreeS3Context:
if (S3Context != NULL) {
ReleaseS3Context (S3Context);
}
+FreeRestrictedAllocations:
+ ReleaseRestrictedAllocations (RestrictedAllocations);
+
FreeLoader:
FreePool (LoaderStart);
return Status;
--
2.9.3
next prev parent reply other threads:[~2017-06-03 15:41 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-06-03 15:42 [PATCH 0/1] OvmfPkg/AcpiPlatformDxe: alloc blobs from 64-bit space unless restricted Laszlo Ersek
2017-06-03 15:42 ` Laszlo Ersek [this message]
2017-06-03 18:33 ` [PATCH 1/1] " Ard Biesheuvel
2017-06-05 17:47 ` Jordan Justen
2017-06-06 18:16 ` Laszlo Ersek
2017-06-07 23:10 ` Laszlo Ersek
2017-06-08 10:11 ` Ard Biesheuvel
2017-06-08 18:40 ` Laszlo Ersek
2017-06-08 19:05 ` Ard Biesheuvel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170603154203.29907-2-lersek@redhat.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox