aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/OvmfPkg/Library/LoadLinuxLib
diff options
context:
space:
mode:
Diffstat (limited to 'roms/edk2/OvmfPkg/Library/LoadLinuxLib')
-rw-r--r--roms/edk2/OvmfPkg/Library/LoadLinuxLib/Ia32/JumpToKernel.nasm43
-rw-r--r--roms/edk2/OvmfPkg/Library/LoadLinuxLib/Linux.c664
-rw-r--r--roms/edk2/OvmfPkg/Library/LoadLinuxLib/LinuxGdt.c175
-rw-r--r--roms/edk2/OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.h53
-rw-r--r--roms/edk2/OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf43
-rw-r--r--roms/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.nasm87
6 files changed, 1065 insertions, 0 deletions
diff --git a/roms/edk2/OvmfPkg/Library/LoadLinuxLib/Ia32/JumpToKernel.nasm b/roms/edk2/OvmfPkg/Library/LoadLinuxLib/Ia32/JumpToKernel.nasm
new file mode 100644
index 000000000..ae5f5eb03
--- /dev/null
+++ b/roms/edk2/OvmfPkg/Library/LoadLinuxLib/Ia32/JumpToKernel.nasm
@@ -0,0 +1,43 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+;
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+ SECTION .text
+
+;------------------------------------------------------------------------------
+; VOID
+; EFIAPI
+; JumpToKernel (
+; VOID *KernelStart,
+; VOID *KernelBootParams
+; );
+;------------------------------------------------------------------------------
+global ASM_PFX(JumpToKernel)
+ASM_PFX(JumpToKernel):
+
+ mov esi, [esp + 8]
+ call DWORD [esp + 4]
+ ret
+
+;------------------------------------------------------------------------------
+; VOID
+; EFIAPI
+; JumpToUefiKernel (
+; EFI_HANDLE ImageHandle,
+; EFI_SYSTEM_TABLE *SystemTable,
+; VOID *KernelBootParams,
+; VOID *KernelStart
+; );
+;------------------------------------------------------------------------------
+global ASM_PFX(JumpToUefiKernel)
+ASM_PFX(JumpToUefiKernel):
+
+ mov eax, [esp + 12]
+ mov eax, [eax + 0x264]
+ add eax, [esp + 16]
+ jmp eax
+
diff --git a/roms/edk2/OvmfPkg/Library/LoadLinuxLib/Linux.c b/roms/edk2/OvmfPkg/Library/LoadLinuxLib/Linux.c
new file mode 100644
index 000000000..c5022f663
--- /dev/null
+++ b/roms/edk2/OvmfPkg/Library/LoadLinuxLib/Linux.c
@@ -0,0 +1,664 @@
+/** @file
+
+ Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "LoadLinuxLib.h"
+
+
+/**
+ A simple check of the kernel setup image
+
+ An assumption is made that the size of the data is at least the
+ size of struct boot_params.
+
+ @param[in] KernelSetup - The kernel setup image
+
+ @retval EFI_SUCCESS - The kernel setup looks valid and supported
+ @retval EFI_INVALID_PARAMETER - KernelSetup was NULL
+ @retval EFI_UNSUPPORTED - The kernel setup is not valid or supported
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+BasicKernelSetupCheck (
+ IN VOID *KernelSetup
+ )
+{
+ return LoadLinuxCheckKernelSetup(KernelSetup, sizeof (struct boot_params));
+}
+
+
+EFI_STATUS
+EFIAPI
+LoadLinuxCheckKernelSetup (
+ IN VOID *KernelSetup,
+ IN UINTN KernelSetupSize
+ )
+{
+ struct boot_params *Bp;
+
+ if (KernelSetup == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (KernelSetupSize < sizeof (*Bp)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Bp = (struct boot_params*) KernelSetup;
+
+ if ((Bp->hdr.signature != 0xAA55) || // Check boot sector signature
+ (Bp->hdr.header != SETUP_HDR) ||
+ (Bp->hdr.version < 0x205) || // We only support relocatable kernels
+ (!Bp->hdr.relocatable_kernel)
+ ) {
+ return EFI_UNSUPPORTED;
+ } else {
+ return EFI_SUCCESS;
+ }
+}
+
+
+UINTN
+EFIAPI
+LoadLinuxGetKernelSize (
+ IN VOID *KernelSetup,
+ IN UINTN KernelSize
+ )
+{
+ struct boot_params *Bp;
+
+ if (EFI_ERROR (BasicKernelSetupCheck (KernelSetup))) {
+ return 0;
+ }
+
+ Bp = (struct boot_params*) KernelSetup;
+
+ if (Bp->hdr.version > 0x20a) {
+ return Bp->hdr.init_size;
+ } else {
+ //
+ // Add extra size for kernel decompression
+ //
+ return 3 * KernelSize;
+ }
+}
+
+
+VOID*
+EFIAPI
+LoadLinuxAllocateKernelSetupPages (
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Address;
+
+ Address = BASE_1GB;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiLoaderData,
+ Pages,
+ &Address
+ );
+ if (!EFI_ERROR (Status)) {
+ return (VOID*)(UINTN) Address;
+ } else {
+ return NULL;
+ }
+}
+
+EFI_STATUS
+EFIAPI
+LoadLinuxInitializeKernelSetup (
+ IN VOID *KernelSetup
+ )
+{
+ EFI_STATUS Status;
+ UINTN SetupEnd;
+ struct boot_params *Bp;
+
+ Status = BasicKernelSetupCheck (KernelSetup);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Bp = (struct boot_params*) KernelSetup;
+
+ SetupEnd = 0x202 + (Bp->hdr.jump & 0xff);
+
+ //
+ // Clear all but the setup_header
+ //
+ ZeroMem (KernelSetup, 0x1f1);
+ ZeroMem (((UINT8 *)KernelSetup) + SetupEnd, 4096 - SetupEnd);
+ DEBUG ((DEBUG_INFO, "Cleared kernel setup 0-0x1f1, 0x%Lx-0x1000\n",
+ (UINT64)SetupEnd));
+
+ return EFI_SUCCESS;
+}
+
+VOID*
+EFIAPI
+LoadLinuxAllocateKernelPages (
+ IN VOID *KernelSetup,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS KernelAddress;
+ UINT32 Loop;
+ struct boot_params *Bp;
+
+ if (EFI_ERROR (BasicKernelSetupCheck (KernelSetup))) {
+ return NULL;
+ }
+
+ Bp = (struct boot_params*) KernelSetup;
+
+ for (Loop = 1; Loop < 512; Loop++) {
+ KernelAddress = MultU64x32 (
+ 2 * Bp->hdr.kernel_alignment,
+ Loop
+ );
+ Status = gBS->AllocatePages (
+ AllocateAddress,
+ EfiLoaderData,
+ Pages,
+ &KernelAddress
+ );
+ if (!EFI_ERROR (Status)) {
+ return (VOID*)(UINTN) KernelAddress;
+ }
+ }
+
+ return NULL;
+}
+
+
+VOID*
+EFIAPI
+LoadLinuxAllocateCommandLinePages (
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Address;
+
+ Address = 0xa0000;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiLoaderData,
+ Pages,
+ &Address
+ );
+ if (!EFI_ERROR (Status)) {
+ return (VOID*)(UINTN) Address;
+ } else {
+ return NULL;
+ }
+}
+
+
+VOID*
+EFIAPI
+LoadLinuxAllocateInitrdPages (
+ IN VOID *KernelSetup,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Address;
+
+ struct boot_params *Bp;
+
+ if (EFI_ERROR (BasicKernelSetupCheck (KernelSetup))) {
+ return NULL;
+ }
+
+ Bp = (struct boot_params*) KernelSetup;
+
+ Address = (EFI_PHYSICAL_ADDRESS)(UINTN) Bp->hdr.ramdisk_max;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiLoaderData,
+ Pages,
+ &Address
+ );
+ if (!EFI_ERROR (Status)) {
+ return (VOID*)(UINTN) Address;
+ } else {
+ return NULL;
+ }
+}
+
+
+STATIC
+VOID
+SetupLinuxMemmap (
+ IN OUT struct boot_params *Bp
+ )
+{
+ EFI_STATUS Status;
+ UINT8 TmpMemoryMap[1];
+ UINTN MapKey;
+ UINTN DescriptorSize;
+ UINT32 DescriptorVersion;
+ UINTN MemoryMapSize;
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapPtr;
+ UINTN Index;
+ struct efi_info *Efi;
+ struct e820_entry *LastE820;
+ struct e820_entry *E820;
+ UINTN E820EntryCount;
+ EFI_PHYSICAL_ADDRESS LastEndAddr;
+
+ //
+ // Get System MemoryMapSize
+ //
+ MemoryMapSize = sizeof (TmpMemoryMap);
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSize,
+ (EFI_MEMORY_DESCRIPTOR *)TmpMemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+ //
+ // Enlarge space here, because we will allocate pool now.
+ //
+ MemoryMapSize += EFI_PAGE_SIZE;
+ Status = gBS->AllocatePool (
+ EfiLoaderData,
+ MemoryMapSize,
+ (VOID **) &MemoryMap
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Get System MemoryMap
+ //
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ LastE820 = NULL;
+ E820 = &Bp->e820_map[0];
+ E820EntryCount = 0;
+ LastEndAddr = 0;
+ MemoryMapPtr = MemoryMap;
+ for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) {
+ UINTN E820Type = 0;
+
+ if (MemoryMap->NumberOfPages == 0) {
+ continue;
+ }
+
+ switch(MemoryMap->Type) {
+ case EfiReservedMemoryType:
+ case EfiRuntimeServicesCode:
+ case EfiRuntimeServicesData:
+ case EfiMemoryMappedIO:
+ case EfiMemoryMappedIOPortSpace:
+ case EfiPalCode:
+ E820Type = E820_RESERVED;
+ break;
+
+ case EfiUnusableMemory:
+ E820Type = E820_UNUSABLE;
+ break;
+
+ case EfiACPIReclaimMemory:
+ E820Type = E820_ACPI;
+ break;
+
+ case EfiLoaderCode:
+ case EfiLoaderData:
+ case EfiBootServicesCode:
+ case EfiBootServicesData:
+ case EfiConventionalMemory:
+ E820Type = E820_RAM;
+ break;
+
+ case EfiACPIMemoryNVS:
+ E820Type = E820_NVS;
+ break;
+
+ default:
+ DEBUG ((
+ DEBUG_ERROR,
+ "Invalid EFI memory descriptor type (0x%x)!\n",
+ MemoryMap->Type
+ ));
+ continue;
+ }
+
+ if ((LastE820 != NULL) &&
+ (LastE820->type == (UINT32) E820Type) &&
+ (MemoryMap->PhysicalStart == LastEndAddr)) {
+ LastE820->size += EFI_PAGES_TO_SIZE ((UINTN) MemoryMap->NumberOfPages);
+ LastEndAddr += EFI_PAGES_TO_SIZE ((UINTN) MemoryMap->NumberOfPages);
+ } else {
+ if (E820EntryCount >= ARRAY_SIZE (Bp->e820_map)) {
+ break;
+ }
+ E820->type = (UINT32) E820Type;
+ E820->addr = MemoryMap->PhysicalStart;
+ E820->size = EFI_PAGES_TO_SIZE ((UINTN) MemoryMap->NumberOfPages);
+ LastE820 = E820;
+ LastEndAddr = E820->addr + E820->size;
+ E820++;
+ E820EntryCount++;
+ }
+
+ //
+ // Get next item
+ //
+ MemoryMap = (EFI_MEMORY_DESCRIPTOR *)((UINTN)MemoryMap + DescriptorSize);
+ }
+ Bp->e820_entries = (UINT8) E820EntryCount;
+
+ Efi = &Bp->efi_info;
+ Efi->efi_systab = (UINT32)(UINTN) gST;
+ Efi->efi_memdesc_size = (UINT32) DescriptorSize;
+ Efi->efi_memdesc_version = DescriptorVersion;
+ Efi->efi_memmap = (UINT32)(UINTN) MemoryMapPtr;
+ Efi->efi_memmap_size = (UINT32) MemoryMapSize;
+#ifdef MDE_CPU_IA32
+ Efi->efi_loader_signature = SIGNATURE_32 ('E', 'L', '3', '2');
+#else
+ Efi->efi_systab_hi = (UINT32) (((UINT64)(UINTN) gST) >> 32);
+ Efi->efi_memmap_hi = (UINT32) (((UINT64)(UINTN) MemoryMapPtr) >> 32);
+ Efi->efi_loader_signature = SIGNATURE_32 ('E', 'L', '6', '4');
+#endif
+
+ gBS->ExitBootServices (gImageHandle, MapKey);
+}
+
+
+EFI_STATUS
+EFIAPI
+LoadLinuxSetCommandLine (
+ IN OUT VOID *KernelSetup,
+ IN CHAR8 *CommandLine
+ )
+{
+ EFI_STATUS Status;
+ struct boot_params *Bp;
+
+ Status = BasicKernelSetupCheck (KernelSetup);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Bp = (struct boot_params*) KernelSetup;
+
+ Bp->hdr.cmd_line_ptr = (UINT32)(UINTN) CommandLine;
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+LoadLinuxSetInitrd (
+ IN OUT VOID *KernelSetup,
+ IN VOID *Initrd,
+ IN UINTN InitrdSize
+ )
+{
+ EFI_STATUS Status;
+ struct boot_params *Bp;
+
+ Status = BasicKernelSetupCheck (KernelSetup);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Bp = (struct boot_params*) KernelSetup;
+
+ Bp->hdr.ramdisk_start = (UINT32)(UINTN) Initrd;
+ Bp->hdr.ramdisk_len = (UINT32) InitrdSize;
+
+ return EFI_SUCCESS;
+}
+
+
+STATIC VOID
+FindBits (
+ unsigned long Mask,
+ UINT8 *Pos,
+ UINT8 *Size
+ )
+{
+ UINT8 First, Len;
+
+ First = 0;
+ Len = 0;
+
+ if (Mask) {
+ while (!(Mask & 0x1)) {
+ Mask = Mask >> 1;
+ First++;
+ }
+
+ while (Mask & 0x1) {
+ Mask = Mask >> 1;
+ Len++;
+ }
+ }
+ *Pos = First;
+ *Size = Len;
+}
+
+
+STATIC
+EFI_STATUS
+SetupGraphicsFromGop (
+ struct screen_info *Si,
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop
+ )
+{
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+ EFI_STATUS Status;
+ UINTN Size;
+
+ Status = Gop->QueryMode(Gop, Gop->Mode->Mode, &Size, &Info);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ /* We found a GOP */
+
+ /* EFI framebuffer */
+ Si->orig_video_isVGA = 0x70;
+
+ Si->orig_x = 0;
+ Si->orig_y = 0;
+ Si->orig_video_page = 0;
+ Si->orig_video_mode = 0;
+ Si->orig_video_cols = 0;
+ Si->orig_video_lines = 0;
+ Si->orig_video_ega_bx = 0;
+ Si->orig_video_points = 0;
+
+ Si->lfb_base = (UINT32) Gop->Mode->FrameBufferBase;
+ Si->lfb_size = (UINT32) Gop->Mode->FrameBufferSize;
+ Si->lfb_width = (UINT16) Info->HorizontalResolution;
+ Si->lfb_height = (UINT16) Info->VerticalResolution;
+ Si->pages = 1;
+ Si->vesapm_seg = 0;
+ Si->vesapm_off = 0;
+
+ if (Info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) {
+ Si->lfb_depth = 32;
+ Si->red_size = 8;
+ Si->red_pos = 0;
+ Si->green_size = 8;
+ Si->green_pos = 8;
+ Si->blue_size = 8;
+ Si->blue_pos = 16;
+ Si->rsvd_size = 8;
+ Si->rsvd_pos = 24;
+ Si->lfb_linelength = (UINT16) (Info->PixelsPerScanLine * 4);
+
+ } else if (Info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) {
+ Si->lfb_depth = 32;
+ Si->red_size = 8;
+ Si->red_pos = 16;
+ Si->green_size = 8;
+ Si->green_pos = 8;
+ Si->blue_size = 8;
+ Si->blue_pos = 0;
+ Si->rsvd_size = 8;
+ Si->rsvd_pos = 24;
+ Si->lfb_linelength = (UINT16) (Info->PixelsPerScanLine * 4);
+ } else if (Info->PixelFormat == PixelBitMask) {
+ FindBits(Info->PixelInformation.RedMask,
+ &Si->red_pos, &Si->red_size);
+ FindBits(Info->PixelInformation.GreenMask,
+ &Si->green_pos, &Si->green_size);
+ FindBits(Info->PixelInformation.BlueMask,
+ &Si->blue_pos, &Si->blue_size);
+ FindBits(Info->PixelInformation.ReservedMask,
+ &Si->rsvd_pos, &Si->rsvd_size);
+ Si->lfb_depth = Si->red_size + Si->green_size +
+ Si->blue_size + Si->rsvd_size;
+ Si->lfb_linelength = (UINT16) ((Info->PixelsPerScanLine * Si->lfb_depth) / 8);
+ } else {
+ Si->lfb_depth = 4;
+ Si->red_size = 0;
+ Si->red_pos = 0;
+ Si->green_size = 0;
+ Si->green_pos = 0;
+ Si->blue_size = 0;
+ Si->blue_pos = 0;
+ Si->rsvd_size = 0;
+ Si->rsvd_pos = 0;
+ Si->lfb_linelength = Si->lfb_width / 2;
+ }
+
+ return Status;
+}
+
+
+STATIC
+EFI_STATUS
+SetupGraphics (
+ IN OUT struct boot_params *Bp
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
+
+ ZeroMem ((VOID*)&Bp->screen_info, sizeof(Bp->screen_info));
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiGraphicsOutputProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID*) &Gop
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = SetupGraphicsFromGop (&Bp->screen_info, Gop);
+ if (!EFI_ERROR (Status)) {
+ FreePool (HandleBuffer);
+ return EFI_SUCCESS;
+ }
+ }
+
+ FreePool (HandleBuffer);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+STATIC
+EFI_STATUS
+SetupLinuxBootParams (
+ IN OUT struct boot_params *Bp
+ )
+{
+ SetupGraphics (Bp);
+
+ SetupLinuxMemmap (Bp);
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+LoadLinux (
+ IN VOID *Kernel,
+ IN OUT VOID *KernelSetup
+ )
+{
+ EFI_STATUS Status;
+ struct boot_params *Bp;
+
+ Status = BasicKernelSetupCheck (KernelSetup);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Bp = (struct boot_params *) KernelSetup;
+
+ if (Bp->hdr.version < 0x205 || !Bp->hdr.relocatable_kernel) {
+ //
+ // We only support relocatable kernels
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ InitLinuxDescriptorTables ();
+
+ Bp->hdr.code32_start = (UINT32)(UINTN) Kernel;
+ if (Bp->hdr.version >= 0x20c && Bp->hdr.handover_offset &&
+ (Bp->hdr.xloadflags & (sizeof (UINTN) == 4 ? BIT2 : BIT3))) {
+ DEBUG ((DEBUG_INFO, "Jumping to kernel EFI handover point at ofs %x\n", Bp->hdr.handover_offset));
+
+ DisableInterrupts ();
+ JumpToUefiKernel ((VOID*) gImageHandle, (VOID*) gST, KernelSetup, Kernel);
+ }
+
+ //
+ // Old kernels without EFI handover protocol
+ //
+ SetupLinuxBootParams (KernelSetup);
+
+ DEBUG ((DEBUG_INFO, "Jumping to kernel\n"));
+ DisableInterrupts ();
+ SetLinuxDescriptorTables ();
+ JumpToKernel (Kernel, (VOID*) KernelSetup);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/OvmfPkg/Library/LoadLinuxLib/LinuxGdt.c b/roms/edk2/OvmfPkg/Library/LoadLinuxLib/LinuxGdt.c
new file mode 100644
index 000000000..d90e999d8
--- /dev/null
+++ b/roms/edk2/OvmfPkg/Library/LoadLinuxLib/LinuxGdt.c
@@ -0,0 +1,175 @@
+/** @file
+ Initialize GDT for Linux.
+
+ Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "LoadLinuxLib.h"
+
+
+//
+// Local structure definitions
+//
+
+#pragma pack (1)
+
+//
+// Global Descriptor Entry structures
+//
+
+typedef struct _GDT_ENTRY {
+ UINT16 Limit15_0;
+ UINT16 Base15_0;
+ UINT8 Base23_16;
+ UINT8 Type;
+ UINT8 Limit19_16_and_flags;
+ UINT8 Base31_24;
+} GDT_ENTRY;
+
+typedef
+struct _GDT_ENTRIES {
+ GDT_ENTRY Null;
+ GDT_ENTRY Null2;
+ GDT_ENTRY Linear;
+ GDT_ENTRY LinearCode;
+ GDT_ENTRY TaskSegment;
+ GDT_ENTRY Spare4;
+ GDT_ENTRY Spare5;
+} GDT_ENTRIES;
+
+#pragma pack ()
+
+STATIC GDT_ENTRIES *mGdt = NULL;
+
+//
+// Global descriptor table (GDT) Template
+//
+STATIC GDT_ENTRIES GdtTemplate = {
+ //
+ // Null
+ //
+ {
+ 0x0, // limit 15:0
+ 0x0, // base 15:0
+ 0x0, // base 23:16
+ 0x0, // type
+ 0x0, // limit 19:16, flags
+ 0x0, // base 31:24
+ },
+ //
+ // Null2
+ //
+ {
+ 0x0, // limit 15:0
+ 0x0, // base 15:0
+ 0x0, // base 23:16
+ 0x0, // type
+ 0x0, // limit 19:16, flags
+ 0x0, // base 31:24
+ },
+ //
+ // Linear
+ //
+ {
+ 0x0FFFF, // limit 0xFFFFF
+ 0x0, // base 0
+ 0x0,
+ 0x09A, // present, ring 0, data, expand-up, writable
+ 0x0CF, // page-granular, 32-bit
+ 0x0,
+ },
+ //
+ // LinearCode
+ //
+ {
+ 0x0FFFF, // limit 0xFFFFF
+ 0x0, // base 0
+ 0x0,
+ 0x092, // present, ring 0, data, expand-up, writable
+ 0x0CF, // page-granular, 32-bit
+ 0x0,
+ },
+ //
+ // TaskSegment
+ //
+ {
+ 0x0, // limit 0
+ 0x0, // base 0
+ 0x0,
+ 0x089, // ?
+ 0x080, // ?
+ 0x0,
+ },
+ //
+ // Spare4
+ //
+ {
+ 0x0, // limit 0
+ 0x0, // base 0
+ 0x0,
+ 0x0, // present, ring 0, data, expand-up, writable
+ 0x0, // page-granular, 32-bit
+ 0x0,
+ },
+ //
+ // Spare5
+ //
+ {
+ 0x0, // limit 0
+ 0x0, // base 0
+ 0x0,
+ 0x0, // present, ring 0, data, expand-up, writable
+ 0x0, // page-granular, 32-bit
+ 0x0,
+ },
+};
+
+/**
+ Initialize Global Descriptor Table.
+
+**/
+VOID
+InitLinuxDescriptorTables (
+ VOID
+ )
+{
+ //
+ // Allocate Runtime Data for the GDT
+ //
+ mGdt = AllocateRuntimePool (sizeof (GdtTemplate) + 8);
+ ASSERT (mGdt != NULL);
+ mGdt = ALIGN_POINTER (mGdt, 8);
+
+ //
+ // Initialize all GDT entries
+ //
+ CopyMem (mGdt, &GdtTemplate, sizeof (GdtTemplate));
+
+}
+
+/**
+ Initialize Global Descriptor Table.
+
+**/
+VOID
+SetLinuxDescriptorTables (
+ VOID
+ )
+{
+ IA32_DESCRIPTOR GdtPtr;
+ IA32_DESCRIPTOR IdtPtr;
+
+ //
+ // Write GDT register
+ //
+ GdtPtr.Base = (UINT32)(UINTN)(VOID*) mGdt;
+ GdtPtr.Limit = (UINT16) (sizeof (GdtTemplate) - 1);
+ AsmWriteGdtr (&GdtPtr);
+
+ IdtPtr.Base = (UINT32) 0;
+ IdtPtr.Limit = (UINT16) 0;
+ AsmWriteIdtr (&IdtPtr);
+}
+
diff --git a/roms/edk2/OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.h b/roms/edk2/OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.h
new file mode 100644
index 000000000..daaecb615
--- /dev/null
+++ b/roms/edk2/OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.h
@@ -0,0 +1,53 @@
+/** @file
+ Boot UEFI Linux.
+
+ Copyright (c) 2008 - 2013, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _LOAD_LINUX_LIB_INCLUDED_
+#define _LOAD_LINUX_LIB_INCLUDED_
+
+#include <Uefi.h>
+#include <Library/LoadLinuxLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include <IndustryStandard/LinuxBzimage.h>
+
+#include <Protocol/GraphicsOutput.h>
+
+VOID
+EFIAPI
+JumpToKernel (
+ VOID *KernelStart,
+ VOID *KernelBootParams
+ );
+
+VOID
+EFIAPI
+JumpToUefiKernel (
+ EFI_HANDLE ImageHandle,
+ EFI_SYSTEM_TABLE *SystemTable,
+ VOID *KernelBootParams,
+ VOID *KernelStart
+ );
+
+VOID
+InitLinuxDescriptorTables (
+ VOID
+ );
+
+VOID
+SetLinuxDescriptorTables (
+ VOID
+ );
+
+#endif
+
diff --git a/roms/edk2/OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf b/roms/edk2/OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
new file mode 100644
index 000000000..cc643373e
--- /dev/null
+++ b/roms/edk2/OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
@@ -0,0 +1,43 @@
+## @file
+#
+# Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LoadLinuxLib
+ FILE_GUID = eaec1915-65a0-43a9-bf0b-a76438da61db
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = LoadLinuxLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.common]
+ Linux.c
+ LinuxGdt.c
+ LoadLinuxLib.h
+
+[Sources.IA32]
+ Ia32/JumpToKernel.nasm
+
+[Sources.X64]
+ X64/JumpToKernel.nasm
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ MemoryAllocationLib
+ BaseMemoryLib
+
diff --git a/roms/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.nasm b/roms/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.nasm
new file mode 100644
index 000000000..6e37f21db
--- /dev/null
+++ b/roms/edk2/OvmfPkg/Library/LoadLinuxLib/X64/JumpToKernel.nasm
@@ -0,0 +1,87 @@
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+;
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+ DEFAULT REL
+ SECTION .text
+
+;------------------------------------------------------------------------------
+; VOID
+; EFIAPI
+; JumpToKernel (
+; VOID *KernelStart, // rcx
+; VOID *KernelBootParams // rdx
+; );
+;------------------------------------------------------------------------------
+global ASM_PFX(JumpToKernel)
+ASM_PFX(JumpToKernel):
+
+ ; Set up for executing kernel. BP in %esi, entry point on the stack
+ ; (64-bit when the 'ret' will use it as 32-bit, but we're little-endian)
+ mov rsi, rdx
+ push rcx
+
+ ; Jump into the compatibility mode CS
+ push 0x10
+ lea rax, [.0]
+ push rax
+ DB 0x48, 0xcb ; retfq
+
+.0:
+ ; Now in compatibility mode.
+
+ DB 0xb8, 0x18, 0x0, 0x0, 0x0 ; movl $0x18, %eax
+ DB 0x8e, 0xd8 ; movl %eax, %ds
+ DB 0x8e, 0xc0 ; movl %eax, %es
+ DB 0x8e, 0xe0 ; movl %eax, %fs
+ DB 0x8e, 0xe8 ; movl %eax, %gs
+ DB 0x8e, 0xd0 ; movl %eax, %ss
+
+ ; Disable paging
+ DB 0xf, 0x20, 0xc0 ; movl %cr0, %eax
+ DB 0xf, 0xba, 0xf8, 0x1f ; btcl $31, %eax
+ DB 0xf, 0x22, 0xc0 ; movl %eax, %cr0
+
+ ; Disable long mode in EFER
+ DB 0xb9, 0x80, 0x0, 0x0, 0xc0 ; movl $0x0c0000080, %ecx
+ DB 0xf, 0x32 ; rdmsr
+ DB 0xf, 0xba, 0xf8, 0x8 ; btcl $8, %eax
+ DB 0xf, 0x30 ; wrmsr
+
+ ; Disable PAE
+ DB 0xf, 0x20, 0xe0 ; movl %cr4, %eax
+ DB 0xf, 0xba, 0xf8, 0x5 ; btcl $5, %eax
+ DB 0xf, 0x22, 0xe0 ; movl %eax, %cr4
+
+ DB 0x31, 0xed ; xor %ebp, %ebp
+ DB 0x31, 0xff ; xor %edi, %edi
+ DB 0x31, 0xdb ; xor %ebx, %ebx
+ DB 0xc3 ; ret
+
+;------------------------------------------------------------------------------
+; VOID
+; EFIAPI
+; JumpToUefiKernel (
+; EFI_HANDLE ImageHandle, // rcx
+; EFI_SYSTEM_TABLE *SystemTable, // rdx
+; VOID *KernelBootParams // r8
+; VOID *KernelStart, // r9
+; );
+;------------------------------------------------------------------------------
+global ASM_PFX(JumpToUefiKernel)
+ASM_PFX(JumpToUefiKernel):
+
+ mov rdi, rcx
+ mov rsi, rdx
+ mov rdx, r8
+ xor rax, rax
+ mov eax, [r8 + 0x264]
+ add r9, rax
+ add r9, 0x200
+ call r9
+ ret
+