LoadBelow4G.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /** @file
  2. Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
  3. SPDX-License-Identifier: BSD-2-Clause-Patent
  4. **/
  5. #include <Uefi.h>
  6. #include <Library/BaseLib.h>
  7. #include <Library/UefiDriverEntryPoint.h>
  8. #include <Library/BaseMemoryLib.h>
  9. #include <Library/DebugLib.h>
  10. #include <Library/PeCoffLib.h>
  11. #include <Library/UefiBootServicesTableLib.h>
  12. #include <Library/DxeServicesLib.h>
  13. #include <Library/CacheMaintenanceLib.h>
  14. #include <Library/UefiLib.h>
  15. /**
  16. Relocate this image under 4G memory.
  17. @param ImageHandle Handle of driver image.
  18. @param SystemTable Pointer to system table.
  19. @retval EFI_SUCCESS Image successfully relocated.
  20. @retval EFI_ABORTED Failed to relocate image.
  21. **/
  22. EFI_STATUS
  23. RelocateImageUnder4GIfNeeded (
  24. IN EFI_HANDLE ImageHandle,
  25. IN EFI_SYSTEM_TABLE *SystemTable
  26. )
  27. {
  28. EFI_STATUS Status;
  29. UINT8 *Buffer;
  30. UINTN BufferSize;
  31. EFI_HANDLE NewImageHandle;
  32. UINTN Pages;
  33. EFI_PHYSICAL_ADDRESS FfsBuffer;
  34. PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
  35. VOID *Interface;
  36. //
  37. // If it is already <4G, no need do relocate
  38. //
  39. if ((UINTN)RelocateImageUnder4GIfNeeded < 0xFFFFFFFF) {
  40. return EFI_SUCCESS;
  41. }
  42. //
  43. // If locate gEfiCallerIdGuid success, it means 2nd entry.
  44. //
  45. Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &Interface);
  46. if (!EFI_ERROR (Status)) {
  47. DEBUG ((DEBUG_INFO, "FspNotifyDxe - 2nd entry\n"));
  48. return EFI_SUCCESS;
  49. }
  50. DEBUG ((DEBUG_INFO, "FspNotifyDxe - 1st entry\n"));
  51. //
  52. // Here we install a dummy handle
  53. //
  54. NewImageHandle = NULL;
  55. Status = gBS->InstallProtocolInterface (
  56. &NewImageHandle,
  57. &gEfiCallerIdGuid,
  58. EFI_NATIVE_INTERFACE,
  59. NULL
  60. );
  61. ASSERT_EFI_ERROR (Status);
  62. //
  63. // Reload image itself to <4G mem
  64. //
  65. Status = GetSectionFromAnyFv (
  66. &gEfiCallerIdGuid,
  67. EFI_SECTION_PE32,
  68. 0,
  69. (VOID **)&Buffer,
  70. &BufferSize
  71. );
  72. ASSERT_EFI_ERROR (Status);
  73. ImageContext.Handle = Buffer;
  74. ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
  75. //
  76. // Get information about the image being loaded
  77. //
  78. Status = PeCoffLoaderGetImageInfo (&ImageContext);
  79. ASSERT_EFI_ERROR (Status);
  80. if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
  81. Pages = EFI_SIZE_TO_PAGES ((UINTN)(ImageContext.ImageSize + ImageContext.SectionAlignment));
  82. } else {
  83. Pages = EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize);
  84. }
  85. FfsBuffer = 0xFFFFFFFF;
  86. Status = gBS->AllocatePages (
  87. AllocateMaxAddress,
  88. EfiBootServicesCode,
  89. Pages,
  90. &FfsBuffer
  91. );
  92. ASSERT_EFI_ERROR (Status);
  93. ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer;
  94. //
  95. // Align buffer on section boundary
  96. //
  97. ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
  98. ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
  99. //
  100. // Load the image to our new buffer
  101. //
  102. Status = PeCoffLoaderLoadImage (&ImageContext);
  103. ASSERT_EFI_ERROR (Status);
  104. //
  105. // Relocate the image in our new buffer
  106. //
  107. Status = PeCoffLoaderRelocateImage (&ImageContext);
  108. ASSERT_EFI_ERROR (Status);
  109. //
  110. // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer
  111. //
  112. gBS->FreePool (Buffer);
  113. //
  114. // Flush the instruction cache so the image data is written before we execute it
  115. //
  116. InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
  117. DEBUG ((DEBUG_INFO, "Loading driver at 0x%08x EntryPoint=0x%08x\n", (UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.EntryPoint));
  118. Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint))(NewImageHandle, gST);
  119. if (EFI_ERROR (Status)) {
  120. DEBUG ((DEBUG_ERROR, "Error: Image at 0x%08x start failed: %r\n", ImageContext.ImageAddress, Status));
  121. gBS->FreePages (FfsBuffer, Pages);
  122. }
  123. //
  124. // return error to unload >4G copy, if we already relocate itself to <4G.
  125. //
  126. return EFI_ALREADY_STARTED;
  127. }