comments in-line
On 10/29/12 01:01, Jordan Justen wrote:
> [Note: This patch depends on my previous QEMU -kernel patch series.]
>
> If QEMU's -kernel is used with a UEFI executable, then it will
> be launched as a standard UEFI image, and not treated as a
> Linux kernel image.
>
> So, for example, even though we build the older EFI shell into
> OVMF by default, you can use a command such at this to launch
> OVMF and run the new UEFI shell:
> OvmfPkg/build.sh qemu -kernel ShellBinPkg/UefiShell/X64/Shell.efi
>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Jordan Justen <[email protected]>
> ---
> OvmfPkg/Library/PlatformBdsLib/PlatformBdsLib.inf | 3 +-
> OvmfPkg/Library/PlatformBdsLib/QemuKernel.c | 275
> ++++++++++++++++++---
> 2 files changed, 238 insertions(+), 40 deletions(-)
>
> diff --git a/OvmfPkg/Library/PlatformBdsLib/PlatformBdsLib.inf
> b/OvmfPkg/Library/PlatformBdsLib/PlatformBdsLib.inf
> index 7f7f473..a293b30 100644
> --- a/OvmfPkg/Library/PlatformBdsLib/PlatformBdsLib.inf
> +++ b/OvmfPkg/Library/PlatformBdsLib/PlatformBdsLib.inf
> @@ -63,4 +63,5 @@
>
> [Protocols]
> gEfiDecompressProtocolGuid
> -
> + gEfiDevicePathProtocolGuid
> + gEfiLoadedImageProtocolGuid
> diff --git a/OvmfPkg/Library/PlatformBdsLib/QemuKernel.c
> b/OvmfPkg/Library/PlatformBdsLib/QemuKernel.c
> index fa8bcbc..09684a0 100644
> --- a/OvmfPkg/Library/PlatformBdsLib/QemuKernel.c
> +++ b/OvmfPkg/Library/PlatformBdsLib/QemuKernel.c
> @@ -13,32 +13,205 @@
>
> #include <Uefi.h>
>
> +#include <IndustryStandard/PeImage.h>
> +
> #include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> #include <Library/DebugLib.h>
> +#include <Library/DevicePathLib.h>
> #include <Library/LoadLinuxLib.h>
> #include <Library/MemoryAllocationLib.h>
> #include <Library/QemuFwCfgLib.h>
> #include <Library/UefiBootServicesTableLib.h>
>
>
> +typedef struct {
> + MEMMAP_DEVICE_PATH MemMapDevPath;
> + EFI_DEVICE_PATH_PROTOCOL EndDevPath;
> +} MEMMAP_IMAGE_DEVICE_PATH;
> +
> +MEMMAP_IMAGE_DEVICE_PATH mMemmapImageDevicePathTemplate = {
> + {
> + {
> + HARDWARE_DEVICE_PATH,
> + HW_MEMMAP_DP,
> + {
> + (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
> + (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
> + }
> + },
> + EfiBootServicesData,
> + (EFI_PHYSICAL_ADDRESS) 0,
> + (EFI_PHYSICAL_ADDRESS) 0,
> + },
> + {
> + END_DEVICE_PATH_TYPE,
> + END_ENTIRE_DEVICE_PATH_SUBTYPE,
> + {
> + END_DEVICE_PATH_LENGTH,
> + 0
It doesn't matter much, but for readability I'd suggest
"END_DEVICE_PATH_LENGTH >> 8".
> + }
> + }
> +};
> +
> +/**
> + Determines if a buffer looks like a PE/COFF image.
> +
> + @param Buffer The buffer containing a potential PE/COFF image.
> + @param Size The size of the buffer
[in] qualifiers missing, but they may not be that important
> +
> + @retval TRUE The buffer appears to be a PE/COFF image
> + @retval FALSE The buffer does not appear to be a PE/COFF image
> +
> +**/
> +BOOLEAN
> +LooksLikeAPeCoffImage (
> + IN VOID *Buffer,
> + IN UINTN Size
> + )
> +{
> + EFI_IMAGE_DOS_HEADER *DosHdr;
> + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
> +
> + ASSERT (Buffer != NULL);
extraneous whitespace
> +
> + DosHdr = (EFI_IMAGE_DOS_HEADER *)Buffer;
I'm not familiar with the headers you're checking here and I'll have to
look them up, but I think we should make sure
Size >= sizeof (EFI_IMAGE_DOS_HEADER)
(also for the other headers) before converting the pointer.
> + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
> + //
> + // DOS image header is present, so read the PE header after the DOS
> image header.
> + //
> + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Buffer + (UINTN)
> ((DosHdr->e_lfanew) & 0x0ffff));
(a) why not just 0xffff?
(b) the expression relies on the following, thus I'd suggest checking it
explicitly:
Size >= ((DosHdr->e_lfanew & 0xffff) +
sizeof (EFI_IMAGE_NT_HEADERS32))
(The addition on the right side can't overflow on either supported
platform.)
> + } else {
> + //
> + // DOS image header is not present, so PE header is at the image base.
> + //
> + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) Buffer;
Size >= sizeof (EFI_IMAGE_NT_HEADERS32)
> + }
> +
> + //
> + // Does the signature show a PE32 or TE image?
> + //
> + if ((Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) ||
> + (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE)) {
After the additional checks suggested above, dereferencing Hdr.Pe32
should be OK. However EFI_TE_IMAGE_HEADER could be bigger than
EFI_IMAGE_NT_HEADERS32 (it seems to be the case in fact), for which case
we have to redo the same checks.
> + return TRUE;
> + } else {
> + return FALSE;
> + }
> +}
I suggest rewriting the function like this:
BOOLEAN
LooksLikeAPeCoffImage (
IN VOID *Buffer,
IN UINTN Size
)
{
EFI_IMAGE_DOS_HEADER *DosHdr;
UINTN Offset;
EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
ASSERT (Buffer != NULL);
if (Size < sizeof (EFI_IMAGE_DOS_HEADER)) {
return FALSE;
}
DosHdr = (EFI_IMAGE_DOS_HEADER *) Buffer;
//
// If DOS image header is present, search for the PE header after the DOS
// image.
//
Offset = (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) ?
(DosHdr->e_lfanew) & 0xffff :
0;
//
// The following check is for a sufficient (not necessary) condition, but in
// practice it should never refuse a valid image.
// The addition on the RHS never overflows.
//
if (Size < Offset + sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION)) {
return FALSE;
}
Hdr.Union = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) Buffer + Offset);
//
// Does the signature show a PE32 or TE image?
//
if ((Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) ||
(Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE)) {
return TRUE;
} else {
return FALSE;
}
}
Review to be continued -- apologies for the inconvenience.
Thanks,
Laszlo
> +
> +
> +STATIC
> EFI_STATUS
> -TryRunningQemuKernel (
> - VOID
> +TryRunningPeCoffImage (
> + IN VOID *SetupBuf,
> + IN UINTN SetupSize,
> + IN UINTN KernelSize
> + )
> +{
> + EFI_STATUS Status;
> + UINTN PeImageSize;
> + VOID *PeImageData;
> + EFI_HANDLE ImageHandle;
> + EFI_HANDLE DevicePathHandle;
> + MEMMAP_IMAGE_DEVICE_PATH DevicePath;
> +
> + PeImageData = NULL;
> + PeImageSize = 0;
> + Status = EFI_SUCCESS;
> +
> + //
> + // The first part of the PE/COFF image was loaded from the 'kernel setup'
> + // area. QEMU will put the remaining portion in the 'kernel data' area.
> + //
> + // We combine these two items into a single buffer to retrieve the original
> + // PE/COFF image.
> + //
> + PeImageSize = SetupSize + KernelSize;
> + PeImageData = AllocatePages (EFI_SIZE_TO_PAGES (PeImageSize));
> + if (PeImageData == NULL) {
> + Status = EFI_OUT_OF_RESOURCES;
> + goto FreeAndReturn;
> + }
> + CopyMem (PeImageData, SetupBuf, SetupSize);
> +
> + DEBUG ((EFI_D_INFO, "Remaining PE/COFF image size: 0x%x\n", (UINT32)
> KernelSize));
> + DEBUG ((EFI_D_INFO, "Reading PE/COFF image ..."));
> + QemuFwCfgSelectItem (QemuFwCfgItemKernelData);
> + QemuFwCfgReadBytes (KernelSize, ((UINT8*) PeImageData) + SetupSize);
> + DEBUG ((EFI_D_INFO, " [done]\n"));
> +
> + //
> + // Create a device path for the image
> + //
> + CopyMem ((VOID*) &DevicePath,
> + (VOID*) &mMemmapImageDevicePathTemplate,
> + sizeof (DevicePath));
> + DevicePath.MemMapDevPath.StartingAddress = (UINTN) PeImageData;
> + DevicePath.MemMapDevPath.EndingAddress =
> + DevicePath.MemMapDevPath.StartingAddress + PeImageSize;
> + DevicePathHandle = NULL;
> + Status = gBS->InstallProtocolInterface (
> + &DevicePathHandle,
> + &gEfiDevicePathProtocolGuid,
> + EFI_NATIVE_INTERFACE,
> + (VOID*) &DevicePath
> + );
> +
> + //
> + // Load and start the PE/COFF image
> + //
> + ImageHandle = NULL;
> + Status = gBS->LoadImage (
> + FALSE,
> + gImageHandle,
> + (VOID*) &DevicePath,
> + PeImageData,
> + PeImageSize,
> + &ImageHandle
> + );
> + DEBUG ((EFI_D_INFO, "Loading PE/COFF image -> %r\n", Status));
> +
> + if (!EFI_ERROR (Status)) {
> + DEBUG ((EFI_D_INFO, "Starting PE/COFF image ...\n"));
> + Status = gBS->StartImage (ImageHandle, NULL, NULL);
> + DEBUG ((EFI_D_INFO, "PE/COFF image exited -> %r\n", Status));
> + }
> +
> + //
> + // Uninstall the device path for the image
> + //
> + Status = gBS->UninstallProtocolInterface (
> + DevicePathHandle,
> + &gEfiDevicePathProtocolGuid,
> + (VOID*) &DevicePath
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> +FreeAndReturn:
> + if (PeImageData != NULL) {
> + FreePages (PeImageData, EFI_SIZE_TO_PAGES (PeImageSize));
> + }
> +
> + return Status;
> +}
> +
> +
> +STATIC
> +EFI_STATUS
> +TryRunningKernelImage (
> + IN VOID *SetupBuf,
> + IN UINTN SetupSize,
> + IN UINTN KernelSize
> )
> {
> EFI_STATUS Status;
> - UINTN KernelSize;
> - UINTN KernelInitialSize;
> - VOID *KernelBuf;
> - UINTN SetupSize;
> - VOID *SetupBuf;
> UINTN CommandLineSize;
> CHAR8 *CommandLine;
> + UINTN KernelInitialSize;
> + VOID *KernelBuf;
> UINTN InitrdSize;
> VOID* InitrdData;
>
> - SetupBuf = NULL;
> - SetupSize = 0;
> KernelBuf = NULL;
> KernelInitialSize = 0;
> CommandLine = NULL;
> @@ -46,33 +219,6 @@ TryRunningQemuKernel (
> InitrdData = NULL;
> InitrdSize = 0;
>
> - if (!QemuFwCfgIsAvailable ()) {
> - return EFI_NOT_FOUND;
> - }
> -
> - QemuFwCfgSelectItem (QemuFwCfgItemKernelSize);
> - KernelSize = (UINTN) QemuFwCfgRead64 ();
> -
> - QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupSize);
> - SetupSize = (UINTN) QemuFwCfgRead64 ();
> -
> - if (KernelSize == 0 || SetupSize == 0) {
> - DEBUG ((EFI_D_INFO, "qemu -kernel was not used.\n"));
> - return EFI_NOT_FOUND;
> - }
> -
> - SetupBuf = LoadLinuxAllocateKernelSetupPages (EFI_SIZE_TO_PAGES
> (SetupSize));
> - if (SetupBuf == NULL) {
> - DEBUG ((EFI_D_ERROR, "Unable to allocate memory for kernel setup!\n"));
> - return EFI_OUT_OF_RESOURCES;
> - }
> -
> - DEBUG ((EFI_D_INFO, "Setup size: 0x%x\n", (UINT32) SetupSize));
> - DEBUG ((EFI_D_INFO, "Reading kernel setup image ..."));
> - QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupData);
> - QemuFwCfgReadBytes (SetupSize, SetupBuf);
> - DEBUG ((EFI_D_INFO, " [done]\n"));
> -
> Status = LoadLinuxCheckKernelSetup (SetupBuf, SetupSize);
> if (EFI_ERROR (Status)) {
> goto FreeAndReturn;
> @@ -141,9 +287,6 @@ TryRunningQemuKernel (
> Status = LoadLinux (KernelBuf, SetupBuf);
>
> FreeAndReturn:
> - if (SetupBuf != NULL) {
> - FreePages (SetupBuf, EFI_SIZE_TO_PAGES (SetupSize));
> - }
> if (KernelBuf != NULL) {
> FreePages (KernelBuf, EFI_SIZE_TO_PAGES (KernelInitialSize));
> }
> @@ -157,3 +300,57 @@ FreeAndReturn:
> return Status;
> }
>
> +
> +EFI_STATUS
> +TryRunningQemuKernel (
> + VOID
> + )
> +{
> + EFI_STATUS Status;
> + UINTN SetupSize;
> + VOID *SetupBuf;
> + UINTN KernelSize;
> +
> + SetupBuf = NULL;
> + SetupSize = 0;
> +
> + if (!QemuFwCfgIsAvailable ()) {
> + return EFI_NOT_FOUND;
> + }
> +
> + QemuFwCfgSelectItem (QemuFwCfgItemKernelSize);
> + KernelSize = (UINTN) QemuFwCfgRead64 ();
> +
> + QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupSize);
> + SetupSize = (UINTN) QemuFwCfgRead64 ();
> +
> + if (KernelSize == 0 || SetupSize == 0) {
> + DEBUG ((EFI_D_INFO, "qemu -kernel was not used.\n"));
> + return EFI_NOT_FOUND;
> + }
> +
> + SetupBuf = LoadLinuxAllocateKernelSetupPages (EFI_SIZE_TO_PAGES
> (SetupSize));
> + if (SetupBuf == NULL) {
> + DEBUG ((EFI_D_ERROR, "Unable to allocate memory for kernel setup!\n"));
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + DEBUG ((EFI_D_INFO, "Setup size: 0x%x\n", (UINT32) SetupSize));
> + DEBUG ((EFI_D_INFO, "Reading kernel setup image ..."));
> + QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupData);
> + QemuFwCfgReadBytes (SetupSize, SetupBuf);
> + DEBUG ((EFI_D_INFO, " [done]\n"));
> +
> + if (LooksLikeAPeCoffImage (SetupBuf, SetupSize)) {
> + Status = TryRunningPeCoffImage (SetupBuf, SetupSize, KernelSize);
> + } else {
> + Status = TryRunningKernelImage (SetupBuf, SetupSize, KernelSize);
> + }
> +
> + if (SetupBuf != NULL) {
> + FreePages (SetupBuf, EFI_SIZE_TO_PAGES (SetupSize));
> + }
> +
> + return Status;
> +}
> +
------------------------------------------------------------------------------
Monitor your physical, virtual and cloud infrastructure from a single
web console. Get in-depth insight into apps, servers, databases, vmware,
SAP, cloud infrastructure, etc. Download 30-day Free Trial.
Pricing starts from $795 for 25 servers or applications!
http://p.sf.net/sfu/zoho_dev2dev_nov
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/edk2-devel