]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/PeilessStartupLib/DxeLoad.c
6e79c30846725c7a8a13139693f5e92ade2e0e1b
[mirror_edk2.git] / OvmfPkg / Library / PeilessStartupLib / DxeLoad.c
1 /** @file
2 Responsibility of this file is to load the DXE Core from a Firmware Volume.
3
4 Copyright (c) 2016 HP Development Company, L.P.
5 Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "PeilessStartupInternal.h"
11 #include <Library/DebugLib.h>
12 #include <Library/BaseLib.h>
13 #include <Library/BaseMemoryLib.h>
14 #include <Library/MemoryAllocationLib.h>
15 #include <Library/PcdLib.h>
16 #include <Guid/MemoryTypeInformation.h>
17 #include <Guid/MemoryAllocationHob.h>
18 #include <Guid/PcdDataBaseSignatureGuid.h>
19 #include <Register/Intel/Cpuid.h>
20 #include <Library/PrePiLib.h>
21 #include "X64/PageTables.h"
22 #include <Library/ReportStatusCodeLib.h>
23
24 #define STACK_SIZE 0x20000
25
26 /**
27 Transfers control to DxeCore.
28
29 This function performs a CPU architecture specific operations to execute
30 the entry point of DxeCore
31
32 @param DxeCoreEntryPoint The entry point of DxeCore.
33
34 **/
35 VOID
36 HandOffToDxeCore (
37 IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint
38 )
39 {
40 VOID *BaseOfStack;
41 VOID *TopOfStack;
42 UINTN PageTables;
43
44 //
45 // Clear page 0 and mark it as allocated if NULL pointer detection is enabled.
46 //
47 if (IsNullDetectionEnabled ()) {
48 ClearFirst4KPage (GetHobList ());
49 BuildMemoryAllocationHob (0, EFI_PAGES_TO_SIZE (1), EfiBootServicesData);
50 }
51
52 //
53 // Allocate 128KB for the Stack
54 //
55 BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (STACK_SIZE));
56 ASSERT (BaseOfStack != NULL);
57
58 //
59 // Compute the top of the stack we were allocated. Pre-allocate a UINTN
60 // for safety.
61 //
62 TopOfStack = (VOID *)((UINTN)BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT);
63 TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
64
65 DEBUG ((DEBUG_INFO, "BaseOfStack=0x%x, TopOfStack=0x%x\n", BaseOfStack, TopOfStack));
66
67 //
68 // Create page table and save PageMapLevel4 to CR3
69 //
70 PageTables = CreateIdentityMappingPageTables (
71 (EFI_PHYSICAL_ADDRESS)(UINTN)BaseOfStack,
72 STACK_SIZE
73 );
74 if (PageTables == 0) {
75 DEBUG ((DEBUG_ERROR, "Failed to create idnetity mapping page tables.\n"));
76 CpuDeadLoop ();
77 }
78
79 AsmWriteCr3 (PageTables);
80
81 //
82 // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.
83 //
84 UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN)BaseOfStack, STACK_SIZE);
85
86 DEBUG ((DEBUG_INFO, "SwitchStack then Jump to DxeCore\n"));
87 //
88 // Transfer the control to the entry point of DxeCore.
89 //
90 SwitchStack (
91 (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,
92 GetHobList (),
93 NULL,
94 TopOfStack
95 );
96 }
97
98 /**
99 Searches DxeCore in all firmware Volumes and loads the first
100 instance that contains DxeCore.
101
102 @return FileHandle of DxeCore to load DxeCore.
103
104 **/
105 EFI_STATUS
106 FindDxeCore (
107 IN INTN FvInstance,
108 IN OUT EFI_PEI_FILE_HANDLE *FileHandle
109 )
110 {
111 EFI_STATUS Status;
112 EFI_PEI_FV_HANDLE VolumeHandle;
113
114 if (FileHandle == NULL) {
115 ASSERT (FALSE);
116 return EFI_INVALID_PARAMETER;
117 }
118
119 *FileHandle = NULL;
120
121 //
122 // Caller passed in a specific FV to try, so only try that one
123 //
124 Status = FfsFindNextVolume (FvInstance, &VolumeHandle);
125 if (!EFI_ERROR (Status)) {
126 Status = FfsFindNextFile (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, VolumeHandle, FileHandle);
127 if (*FileHandle) {
128 // Assume the FV that contains multiple compressed FVs.
129 // So decompress the compressed FVs
130 Status = FfsProcessFvFile (*FileHandle);
131 ASSERT_EFI_ERROR (Status);
132 Status = FfsAnyFvFindFirstFile (EFI_FV_FILETYPE_DXE_CORE, &VolumeHandle, FileHandle);
133 }
134 }
135
136 return Status;
137 }
138
139 /**
140 This function finds DXE Core in the firmware volume and transfer the control to
141 DXE core.
142
143 @return EFI_SUCCESS DXE core was successfully loaded.
144 @return EFI_OUT_OF_RESOURCES There are not enough resources to load DXE core.
145
146 **/
147 EFI_STATUS
148 EFIAPI
149 DxeLoadCore (
150 IN INTN FvInstance
151 )
152 {
153 EFI_STATUS Status;
154 EFI_FV_FILE_INFO DxeCoreFileInfo;
155 EFI_PHYSICAL_ADDRESS DxeCoreAddress;
156 UINT64 DxeCoreSize;
157 EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint;
158 EFI_PEI_FILE_HANDLE FileHandle;
159 VOID *PeCoffImage;
160
161 //
162 // Look in all the FVs present and find the DXE Core FileHandle
163 //
164 Status = FindDxeCore (FvInstance, &FileHandle);
165
166 if (EFI_ERROR (Status)) {
167 ASSERT (FALSE);
168 return Status;
169 }
170
171 //
172 // Load the DXE Core from a Firmware Volume.
173 //
174 Status = FfsFindSectionData (EFI_SECTION_PE32, FileHandle, &PeCoffImage);
175 if (EFI_ERROR (Status)) {
176 return Status;
177 }
178
179 Status = LoadPeCoffImage (PeCoffImage, &DxeCoreAddress, &DxeCoreSize, &DxeCoreEntryPoint);
180 ASSERT_EFI_ERROR (Status);
181
182 //
183 // Extract the DxeCore GUID file name.
184 //
185 Status = FfsGetFileInfo (FileHandle, &DxeCoreFileInfo);
186 ASSERT_EFI_ERROR (Status);
187
188 //
189 // Add HOB for the DXE Core
190 //
191 BuildModuleHob (
192 &DxeCoreFileInfo.FileName,
193 DxeCoreAddress,
194 ALIGN_VALUE (DxeCoreSize, EFI_PAGE_SIZE),
195 DxeCoreEntryPoint
196 );
197
198 DEBUG ((
199 DEBUG_INFO | DEBUG_LOAD,
200 "Loading DXE CORE at 0x%11p EntryPoint=0x%11p\n",
201 (VOID *)(UINTN)DxeCoreAddress,
202 FUNCTION_ENTRY_POINT (DxeCoreEntryPoint)
203 ));
204
205 // Transfer control to the DXE Core
206 // The hand off state is simply a pointer to the HOB list
207 //
208 HandOffToDxeCore (DxeCoreEntryPoint);
209
210 //
211 // If we get here, then the DXE Core returned. This is an error
212 // DxeCore should not return.
213 //
214 ASSERT (FALSE);
215 CpuDeadLoop ();
216
217 return EFI_OUT_OF_RESOURCES;
218 }