OsLoader - Container Type Cleanup (#1816)

* Add Name field to IMAGE_DATA structure

Add a name field to the structure to be used by container parsing
functions. It will be useful to determine the name of the container
component when dealing with special files like ACPI blobs.

Signed-off-by: Atharva Lele <atharva.lele@intel.com>

* OsLoader: save the name of the component when creating array of components

Saving the name will help us deal with special files like ACPI blobs
more easily

Signed-off-by: Atharva Lele <atharva.lele@intel.com>

* OsLoader: streamline container types

Update container functionality to streamline container types:
- Normal: PE32, FV, ELF images. Supports ACPI table update.
- Classic (Linux): Used for a traditional Linux boot setup.
  (cmdline, bzImage, initrd). Additionally supports ACPI table update.
- Multiboot: Used for Multiboot/Multiboot-2 compliant ELF images.
  Supports ACPI table update.

Signed-off-by: Atharva Lele <atharva.lele@intel.com>

* Rename CLASSIC container to CLASSIC_LINUX

This type of container is to be used for a traditional Linux
boot setup consisting of a cmdline, bzImage, initrd(optional),
and other binary blobs or ACPI blobs.

Rename it to CLASSIC_LINUX to make the purpose of the container
clearer.

Signed-off-by: Atharva Lele <atharva.lele@intel.com>

* OsLoader: copy Linux ExtraBlobs to reserved mem and add to cmdline

Until now, SBL loaded the Extra blobs with the Linux kernel
into memory. However, there was no way for the OS to know where
these blobs resided in memory. The blobs were also loaded in
memory that was not marked as reserved.

This patch copies the blobs to reserved memory and adds the
blob addresses into an expected placeholder in the Linux cmdline.
If the placeholder is not present, nothing related to that blob
will be added to the cmdline.

Signed-off-by: Atharva Lele <atharva.lele@intel.com>

---------

Signed-off-by: Atharva Lele <atharva.lele@intel.com>
This commit is contained in:
Atharva Lele 2023-02-02 09:19:31 -08:00 committed by GitHub
parent 401228a7db
commit 82769186dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 121 additions and 15 deletions

View File

@ -42,7 +42,7 @@ typedef UINT8 AUTH_TYPE;
// Container Image types
#define CONTAINER_TYPE_NORMAL 0x0 // Used for boot images in FV, regular ELF, PE32, etc. formats
#define CONTAINER_TYPE_CLASSIC 0x3 // Used for booting Linux with bzImage, cmdline, initrd, etc.
#define CONTAINER_TYPE_CLASSIC_LINUX 0x3 // Used for booting Linux with bzImage, cmdline, initrd, etc.
#define CONTAINER_TYPE_MULTIBOOT 0x4 // Multiboot compliant ELF images
// Max images per container

View File

@ -1,7 +1,7 @@
/** @file
This file defines IAS File structures.
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@ -66,6 +66,7 @@ typedef struct { /* a file (sub-image) inside a boot image */
VOID *Addr;
UINT32 Size;
IMAGE_ALLOCATE_TYPE AllocType;
UINT32 Name; // Name specified for the component when building the container
} IMAGE_DATA;
//

View File

@ -1,6 +1,6 @@
/** @file
Copyright (c) 2017 - 2022, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2017 - 2023, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@ -64,22 +64,22 @@ UpdateLoadedImage (
COMMON_IMAGE *CommonImage;
PLATFORM_SERVICE *PlatformService;
CHAR8 *TypeStr;
CHAR8 BlobName[5]; // 4 character component name + null termination
CHAR8 BlobAddr[17]; // 64-bit address in ASCII hex + null termination
CHAR8 *BlobPos; // Pointer to a character in the kernel cmdline string
CHAR8 BlobSearchStr[28]; // ASCII string in the expected format: SBL.XXXX=0x0000000000000000
VOID *BlobReservedBuf; // Pointer to allocated reserved memory
PlatformService = NULL;
Status = EFI_SUCCESS;
if (ImageType == CONTAINER_TYPE_NORMAL) {
// Image can be of type: Multiboot, PE, FV, bzImage, or ELF
// Image can be of type: PE, FV, bzImage, or ELF
// Container can contain additional ACPI binary blobs
// Assuming that the first image in the container is used for booting
CommonImage = &LoadedImage->Image.Common;
CopyMem (&CommonImage->BootFile, &File[0], sizeof (IMAGE_DATA));
if (IsMultiboot (File[0].Addr)) {
LoadedImage->Flags |= LOADED_IMAGE_MULTIBOOT;
TypeStr = "Multiboot";
} else if (IsMultiboot2 (File[0].Addr)) {
LoadedImage->Flags |= LOADED_IMAGE_MULTIBOOT2;
TypeStr = "Multiboot-2";
} else if (IsTePe32Image (File[0].Addr, NULL) && \
if (IsTePe32Image (File[0].Addr, NULL) && \
(* (UINT32 *)File[0].Addr == EFI_IMAGE_DOS_SIGNATURE)) {
// Add extra check to ensure it is a PE32 image generated from payload build.
// Please note vmlinuxz is also following PE32 format, but it should
@ -101,10 +101,31 @@ UpdateLoadedImage (
}
DEBUG ((DEBUG_INFO, "One %a file in boot image file .... \n", TypeStr));
// If there are more files, check for ACPI blobs and update ACPI tables accordingly
if (NumFiles > 1) {
Index = 1;
while (Index < NumFiles) {
// Update ACPI tables if we encounter an ACPI blob
if (File[Index].Name == SIGNATURE_32('A', 'C', 'P', 'I')) {
DEBUG ((DEBUG_INFO, "Loading boot image ACPI tables...\n"));
PlatformService = (PLATFORM_SERVICE *) GetServiceBySignature (PLATFORM_SERVICE_SIGNATURE);
if ((PlatformService != NULL) && (PlatformService->AcpiTableUpdate != NULL)) {
Status = PlatformService->AcpiTableUpdate (File[Index].Addr, File[Index].Size);
DEBUG ((DEBUG_INFO, "Updating ACPI table with boot image %d - %r\n", Index, Status));
}
FreeImageData (&File[Index]);
continue;
}
Index++;
}
}
return EFI_SUCCESS;
} else if (ImageType == CONTAINER_TYPE_CLASSIC) {
// Files: cmdline, bzImage, initrd, acpi, firmware1, firmware2, ...
// The file order mentioned above is fixed and needs to be followed
} else if (ImageType == CONTAINER_TYPE_CLASSIC_LINUX) {
// Files: cmdline, bzImage, initrd, other optional files (acpi, firmware1, firmware2, ...)
// The file order for the first three files mentioned above is fixed. The rest are optional and can be in any order.
// Container can contain additional ACPI binary blobs
// Make sure that the boot file (File[1]) is present
if (NumFiles < 2) {
@ -136,14 +157,91 @@ UpdateLoadedImage (
// Save other binary blobs
Index = 3;
while ((Index < MAX_MULTIBOOT_MODULE_NUMBER) && (Index < NumFiles)) {
while ((Index < MAX_EXTRA_FILE_NUMBER) && (Index < NumFiles)) {
// Update ACPI tables if we encounter an ACPI blob
if (File[Index].Name == SIGNATURE_32('A', 'C', 'P', 'I')) {
DEBUG ((DEBUG_INFO, "Loading boot image ACPI tables...\n"));
PlatformService = (PLATFORM_SERVICE *) GetServiceBySignature (PLATFORM_SERVICE_SIGNATURE);
if ((PlatformService != NULL) && (PlatformService->AcpiTableUpdate != NULL)) {
Status = PlatformService->AcpiTableUpdate (File[Index].Addr, File[Index].Size);
DEBUG ((DEBUG_INFO, "Updating ACPI table with boot image %d - %r\n", Index, Status));
}
FreeImageData (&File[Index]);
Index++;
continue;
}
CopyMem (&LinuxImage->ExtraBlob[Index - 3], &File[Index], sizeof (IMAGE_DATA));
//
// Update the blob's address in the kernel command line so that the OS knows where it resides
// We also copy the blob into a reserved memory address so that the OS does not overwrite it
//
// Get the blob name
CopyMem(BlobName, &File[Index].Name, 4);
BlobName[4] = '\0';
// Copy the extra blob into reserved memory
BlobReservedBuf = AllocateReservedPages(EFI_SIZE_TO_PAGES(File[Index].Size));
if (BlobReservedBuf == NULL) {
return EFI_OUT_OF_RESOURCES;
}
CopyMem(BlobReservedBuf, File[Index].Addr, File[Index].Size);
DEBUG ((DEBUG_INFO, "Copied %a to reserved memory @ 0x%016X\n", BlobName, BlobReservedBuf));
// Generate the search string: SBL.XXXX=0x0000000000000000
AsciiSPrint(BlobSearchStr, 28, "SBL.%a=0x0000000000000000", BlobName);
DEBUG ((DEBUG_INFO, "Searching for \"%a\" blob placeholder string in cmdline: %a... ", BlobName, BlobSearchStr));
// Find the location of the placeholder string
BlobPos = AsciiStrStr(LinuxImage->CmdFile.Addr, BlobSearchStr);
if (BlobPos != NULL) {
// Move the pointer to where we get to the actual adress (part after 0x)
// e.g. SBL.ABCD=0x0000000000000000
// AsciiStrStr will get us a pointer to 'S'. Adding 11 will get us to the address
BlobPos += 11;
// Get the blob's address into a string
// AsciiSPrint(BlobAddr, 17, "%016X", File[Index].Addr);
AsciiSPrint(BlobAddr, 17, "%016X", BlobReservedBuf);
// Copy the actual address at the placeholder location
AsciiStrCpyS(BlobPos, 17, BlobAddr);
// Replace the copied string's last character with a space for all files except the last one
// We don't do this for the last one since the kernel expects a null-terminated cmdline
if (Index != NumFiles) {
BlobPos += 16;
*BlobPos = ' ';
}
DEBUG ((DEBUG_INFO, "Found and patched address!\n"));
} else {
DEBUG ((DEBUG_INFO, "Could not find cmdline placeholder\n"));
}
// Move to the next file
Index++;
}
LinuxImage->ExtraBlobNumber = Index;
} else if (ImageType == CONTAINER_TYPE_MULTIBOOT) {
// Files: cmdline1, elf1, cmdline2, elf2, ...
// Container can contain additional ACPI binary blobs
// Assume the first elf file is the one to boot
if (IsMultiboot (File[1].Addr)) {
LoadedImage->Flags |= LOADED_IMAGE_MULTIBOOT;
TypeStr = "Multiboot";
} else if (IsMultiboot2 (File[1].Addr)) {
LoadedImage->Flags |= LOADED_IMAGE_MULTIBOOT2;
TypeStr = "Multiboot-2";
} else {
DEBUG ((DEBUG_ERROR, "\"Multiboot\" container type used for a non-multiboot image!"));
return EFI_UNSUPPORTED;
}
DEBUG ((DEBUG_INFO, "%a file in boot image file .... \n", TypeStr));
MultiBoot = &LoadedImage->Image.MultiBoot;
LoadedImage->Flags |= LOADED_IMAGE_MULTIBOOT;
CopyMem (&MultiBoot->CmdFile, &File[0], sizeof (IMAGE_DATA));
@ -153,6 +251,10 @@ UpdateLoadedImage (
ModuleIndex = 0;
for (Index = 2; Index < NumFiles; Index += 2) {
if (Index < MAX_MULTIBOOT_MODULE_NUMBER) {
// Multiboot modules are in a cmdline-ELF pair according to the spec.
// So to accomodate for that, ACPI binary blobs should be preceded by
// a corresponding dummy cmdline file that contains the MULTIBOOT_SPECIAL_MODULE_MAGIC
// string to indicate that the paired file is the ACPI binary blob
if (* (UINT32 *) File[Index].Addr == MULTIBOOT_SPECIAL_MODULE_MAGIC) {
DEBUG ((DEBUG_INFO, "Loading boot image ACPI tables...\n"));
PlatformService = (PLATFORM_SERVICE *) GetServiceBySignature (PLATFORM_SERVICE_SIGNATURE);
@ -261,6 +363,9 @@ ParseContainerImage (
}
}
// Save the name of the component
File[Index].Name = (UINT32) ComponentName;
Index++;
} while ((Status == EFI_SUCCESS) && (Index < ARRAY_SIZE (File)));