Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jordan Justen <jordan.l.justen@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16171 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			670 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			670 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
 | 
						|
  Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
 | 
						|
 | 
						|
  This program and the accompanying materials
 | 
						|
  are licensed and made available under the terms and conditions of the BSD License
 | 
						|
  which accompanies this distribution.  The full text of the license may be found at
 | 
						|
  http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#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 ((EFI_D_INFO, "Cleared kernel setup 0-0x1f1, 0x%x-0x1000\n", 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 ((
 | 
						|
        EFI_D_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 >= (sizeof (Bp->e820_map) / sizeof (Bp->e820_map[0]))) {
 | 
						|
        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 ((EFI_D_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 ((EFI_D_INFO, "Jumping to kernel\n"));
 | 
						|
  DisableInterrupts ();
 | 
						|
  SetLinuxDescriptorTables ();
 | 
						|
  JumpToKernel (Kernel, (VOID*) KernelSetup);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 |