CompatImageLoaderDxe.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /** @file
  2. * PE/COFF emulator protocol implementation to start Linux kernel
  3. * images from non-native firmware
  4. *
  5. * Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
  6. *
  7. * SPDX-License-Identifier: BSD-2-Clause-Patent
  8. *
  9. */
  10. #include <PiDxe.h>
  11. #include <Library/BaseMemoryLib.h>
  12. #include <Library/DebugLib.h>
  13. #include <Library/PeCoffLib.h>
  14. #include <Library/UefiBootServicesTableLib.h>
  15. #include <Protocol/PeCoffImageEmulator.h>
  16. #pragma pack (1)
  17. typedef struct {
  18. UINT8 Type;
  19. UINT8 Size;
  20. UINT16 MachineType;
  21. UINT32 EntryPoint;
  22. } PE_COMPAT_TYPE1;
  23. #pragma pack ()
  24. STATIC
  25. BOOLEAN
  26. EFIAPI
  27. IsImageSupported (
  28. IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
  29. IN UINT16 ImageType,
  30. IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL
  31. )
  32. {
  33. return ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;
  34. }
  35. STATIC
  36. EFI_IMAGE_ENTRY_POINT
  37. EFIAPI
  38. GetCompatEntryPoint (
  39. IN EFI_PHYSICAL_ADDRESS ImageBase
  40. )
  41. {
  42. EFI_IMAGE_DOS_HEADER *DosHdr;
  43. UINTN PeCoffHeaderOffset;
  44. EFI_IMAGE_NT_HEADERS32 *Pe32;
  45. EFI_IMAGE_SECTION_HEADER *Section;
  46. UINTN NumberOfSections;
  47. PE_COMPAT_TYPE1 *PeCompat;
  48. UINTN PeCompatEnd;
  49. DosHdr = (EFI_IMAGE_DOS_HEADER *)(UINTN)ImageBase;
  50. if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
  51. return NULL;
  52. }
  53. PeCoffHeaderOffset = DosHdr->e_lfanew;
  54. Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageBase + PeCoffHeaderOffset);
  55. Section = (EFI_IMAGE_SECTION_HEADER *)((UINTN)&Pe32->OptionalHeader +
  56. Pe32->FileHeader.SizeOfOptionalHeader);
  57. NumberOfSections = (UINTN)Pe32->FileHeader.NumberOfSections;
  58. while (NumberOfSections--) {
  59. if (!CompareMem (Section->Name, ".compat", sizeof (Section->Name))) {
  60. //
  61. // Dereference the section contents to find the mixed mode entry point
  62. //
  63. PeCompat = (PE_COMPAT_TYPE1 *)((UINTN)ImageBase + Section->VirtualAddress);
  64. PeCompatEnd = (UINTN)(VOID *)PeCompat + Section->Misc.VirtualSize;
  65. while (PeCompat->Type != 0 && (UINTN)(VOID *)PeCompat < PeCompatEnd) {
  66. if ((PeCompat->Type == 1) &&
  67. (PeCompat->Size >= sizeof (PE_COMPAT_TYPE1)) &&
  68. EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCompat->MachineType))
  69. {
  70. return (EFI_IMAGE_ENTRY_POINT)((UINTN)ImageBase + PeCompat->EntryPoint);
  71. }
  72. PeCompat = (PE_COMPAT_TYPE1 *)((UINTN)PeCompat + PeCompat->Size);
  73. ASSERT ((UINTN)(VOID *)PeCompat < PeCompatEnd);
  74. }
  75. }
  76. Section++;
  77. }
  78. return NULL;
  79. }
  80. STATIC
  81. EFI_STATUS
  82. EFIAPI
  83. RegisterImage (
  84. IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
  85. IN EFI_PHYSICAL_ADDRESS ImageBase,
  86. IN UINT64 ImageSize,
  87. IN OUT EFI_IMAGE_ENTRY_POINT *EntryPoint
  88. )
  89. {
  90. EFI_IMAGE_ENTRY_POINT CompatEntryPoint;
  91. CompatEntryPoint = GetCompatEntryPoint (ImageBase);
  92. if (CompatEntryPoint == NULL) {
  93. return EFI_UNSUPPORTED;
  94. }
  95. *EntryPoint = CompatEntryPoint;
  96. return EFI_SUCCESS;
  97. }
  98. STATIC
  99. EFI_STATUS
  100. EFIAPI
  101. UnregisterImage (
  102. IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
  103. IN EFI_PHYSICAL_ADDRESS ImageBase
  104. )
  105. {
  106. return EFI_SUCCESS;
  107. }
  108. STATIC EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL mCompatLoaderPeCoffEmuProtocol = {
  109. IsImageSupported,
  110. RegisterImage,
  111. UnregisterImage,
  112. EDKII_PECOFF_IMAGE_EMULATOR_VERSION,
  113. EFI_IMAGE_MACHINE_X64
  114. };
  115. EFI_STATUS
  116. EFIAPI
  117. CompatImageLoaderDxeEntryPoint (
  118. IN EFI_HANDLE ImageHandle,
  119. IN EFI_SYSTEM_TABLE *SystemTable
  120. )
  121. {
  122. return gBS->InstallProtocolInterface (
  123. &ImageHandle,
  124. &gEdkiiPeCoffImageEmulatorProtocolGuid,
  125. EFI_NATIVE_INTERFACE,
  126. &mCompatLoaderPeCoffEmuProtocol
  127. );
  128. }