1 /** @file
2
3 Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
4
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "UefiPayloadEntry.h"
10
11 /**
12 Allocate pages for code.
13
14 @param[in] Pages Number of pages to be allocated.
15
16 @return Allocated memory.
17 **/
18 VOID*
AllocateCodePages(IN UINTN Pages)19 AllocateCodePages (
20 IN UINTN Pages
21 )
22 {
23 VOID *Alloc;
24 EFI_PEI_HOB_POINTERS Hob;
25
26 Alloc = AllocatePages (Pages);
27 if (Alloc == NULL) {
28 return NULL;
29 }
30
31 // find the HOB we just created, and change the type to EfiBootServicesCode
32 Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION);
33 while (Hob.Raw != NULL) {
34 if (Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress == (UINTN)Alloc) {
35 Hob.MemoryAllocation->AllocDescriptor.MemoryType = EfiBootServicesCode;
36 return Alloc;
37 }
38 Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, GET_NEXT_HOB (Hob));
39 }
40
41 ASSERT (FALSE);
42
43 FreePages (Alloc, Pages);
44 return NULL;
45 }
46
47
48 /**
49 Loads and relocates a PE/COFF image
50
51 @param[in] PeCoffImage Point to a Pe/Coff image.
52 @param[out] ImageAddress The image memory address after relocation.
53 @param[out] ImageSize The image size.
54 @param[out] EntryPoint The image entry point.
55
56 @return EFI_SUCCESS If the image is loaded and relocated successfully.
57 @return Others If the image failed to load or relocate.
58 **/
59 EFI_STATUS
LoadPeCoffImage(IN VOID * PeCoffImage,OUT EFI_PHYSICAL_ADDRESS * ImageAddress,OUT UINT64 * ImageSize,OUT EFI_PHYSICAL_ADDRESS * EntryPoint)60 LoadPeCoffImage (
61 IN VOID *PeCoffImage,
62 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
63 OUT UINT64 *ImageSize,
64 OUT EFI_PHYSICAL_ADDRESS *EntryPoint
65 )
66 {
67 RETURN_STATUS Status;
68 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
69 VOID *Buffer;
70
71 ZeroMem (&ImageContext, sizeof (ImageContext));
72
73 ImageContext.Handle = PeCoffImage;
74 ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
75
76 Status = PeCoffLoaderGetImageInfo (&ImageContext);
77 if (EFI_ERROR (Status)) {
78 ASSERT_EFI_ERROR (Status);
79 return Status;
80 }
81
82 //
83 // Allocate Memory for the image
84 //
85 Buffer = AllocateCodePages (EFI_SIZE_TO_PAGES((UINT32)ImageContext.ImageSize));
86 if (Buffer == NULL) {
87 return EFI_OUT_OF_RESOURCES;
88 }
89 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
90
91 //
92 // Load the image to our new buffer
93 //
94 Status = PeCoffLoaderLoadImage (&ImageContext);
95 if (EFI_ERROR (Status)) {
96 ASSERT_EFI_ERROR (Status);
97 return Status;
98 }
99
100 //
101 // Relocate the image in our new buffer
102 //
103 Status = PeCoffLoaderRelocateImage (&ImageContext);
104 if (EFI_ERROR (Status)) {
105 ASSERT_EFI_ERROR (Status);
106 return Status;
107 }
108
109 *ImageAddress = ImageContext.ImageAddress;
110 *ImageSize = ImageContext.ImageSize;
111 *EntryPoint = ImageContext.EntryPoint;
112
113 return EFI_SUCCESS;
114 }
115
116 /**
117 This function searchs a given file type within a valid FV.
118
119 @param FvHeader A pointer to firmware volume header that contains the set of files
120 to be searched.
121 @param FileType File type to be searched.
122 @param FileHeader A pointer to the discovered file, if successful.
123
124 @retval EFI_SUCCESS Successfully found FileType
125 @retval EFI_NOT_FOUND File type can't be found.
126 **/
127 EFI_STATUS
FvFindFile(IN EFI_FIRMWARE_VOLUME_HEADER * FvHeader,IN EFI_FV_FILETYPE FileType,OUT EFI_FFS_FILE_HEADER ** FileHeader)128 FvFindFile (
129 IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader,
130 IN EFI_FV_FILETYPE FileType,
131 OUT EFI_FFS_FILE_HEADER **FileHeader
132 )
133 {
134 EFI_PHYSICAL_ADDRESS CurrentAddress;
135 EFI_PHYSICAL_ADDRESS EndOfFirmwareVolume;
136 EFI_FFS_FILE_HEADER *File;
137 UINT32 Size;
138 EFI_PHYSICAL_ADDRESS EndOfFile;
139
140 CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) FvHeader;
141 EndOfFirmwareVolume = CurrentAddress + FvHeader->FvLength;
142
143 //
144 // Loop through the FFS files
145 //
146 for (EndOfFile = CurrentAddress + FvHeader->HeaderLength; ; ) {
147 CurrentAddress = (EndOfFile + 7) & 0xfffffffffffffff8ULL;
148 if (CurrentAddress > EndOfFirmwareVolume) {
149 break;
150 }
151
152 File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
153 if (IS_FFS_FILE2 (File)) {
154 Size = FFS_FILE2_SIZE (File);
155 if (Size <= 0x00FFFFFF) {
156 break;
157 }
158 } else {
159 Size = FFS_FILE_SIZE (File);
160 if (Size < sizeof (EFI_FFS_FILE_HEADER)) {
161 break;
162 }
163 }
164
165 EndOfFile = CurrentAddress + Size;
166 if (EndOfFile > EndOfFirmwareVolume) {
167 break;
168 }
169
170 //
171 // Look for file type
172 //
173 if (File->Type == FileType) {
174 *FileHeader = File;
175 return EFI_SUCCESS;
176 }
177 }
178
179 return EFI_NOT_FOUND;
180 }
181
182
183 /**
184 This function searchs a given section type within a valid FFS file.
185
186 @param FileHeader A pointer to the file header that contains the set of sections to
187 be searched.
188 @param SearchType The value of the section type to search.
189 @param SectionData A pointer to the discovered section, if successful.
190
191 @retval EFI_SUCCESS The section was found.
192 @retval EFI_NOT_FOUND The section was not found.
193
194 **/
195 EFI_STATUS
FileFindSection(IN EFI_FFS_FILE_HEADER * FileHeader,IN EFI_SECTION_TYPE SectionType,OUT VOID ** SectionData)196 FileFindSection (
197 IN EFI_FFS_FILE_HEADER *FileHeader,
198 IN EFI_SECTION_TYPE SectionType,
199 OUT VOID **SectionData
200 )
201 {
202 UINT32 FileSize;
203 EFI_COMMON_SECTION_HEADER *Section;
204 UINT32 SectionSize;
205 UINT32 Index;
206
207 if (IS_FFS_FILE2 (FileHeader)) {
208 FileSize = FFS_FILE2_SIZE (FileHeader);
209 } else {
210 FileSize = FFS_FILE_SIZE (FileHeader);
211 }
212 FileSize -= sizeof (EFI_FFS_FILE_HEADER);
213
214 Section = (EFI_COMMON_SECTION_HEADER *)(FileHeader + 1);
215 Index = 0;
216 while (Index < FileSize) {
217 if (Section->Type == SectionType) {
218 if (IS_SECTION2 (Section)) {
219 *SectionData = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2));
220 } else {
221 *SectionData = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER));
222 }
223 return EFI_SUCCESS;
224 }
225
226 if (IS_SECTION2 (Section)) {
227 SectionSize = SECTION2_SIZE (Section);
228 } else {
229 SectionSize = SECTION_SIZE (Section);
230 }
231
232 SectionSize = GET_OCCUPIED_SIZE (SectionSize, 4);
233 ASSERT (SectionSize != 0);
234 Index += SectionSize;
235
236 Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionSize);
237 }
238
239 return EFI_NOT_FOUND;
240 }
241
242
243 /**
244 Find DXE core from FV and build DXE core HOBs.
245
246 @param[out] DxeCoreEntryPoint DXE core entry point
247
248 @retval EFI_SUCCESS If it completed successfully.
249 @retval EFI_NOT_FOUND If it failed to load DXE FV.
250 **/
251 EFI_STATUS
LoadDxeCore(OUT PHYSICAL_ADDRESS * DxeCoreEntryPoint)252 LoadDxeCore (
253 OUT PHYSICAL_ADDRESS *DxeCoreEntryPoint
254 )
255 {
256 EFI_STATUS Status;
257 EFI_FIRMWARE_VOLUME_HEADER *PayloadFv;
258 EFI_FIRMWARE_VOLUME_HEADER *DxeCoreFv;
259 EFI_FFS_FILE_HEADER *FileHeader;
260 VOID *PeCoffImage;
261 EFI_PHYSICAL_ADDRESS ImageAddress;
262 UINT64 ImageSize;
263
264 PayloadFv = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PcdGet32 (PcdPayloadFdMemBase);
265
266 //
267 // DXE FV is inside Payload FV. Here find DXE FV from Payload FV
268 //
269 Status = FvFindFile (PayloadFv, EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, &FileHeader);
270 if (EFI_ERROR (Status)) {
271 return Status;
272 }
273 Status = FileFindSection (FileHeader, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, (VOID **)&DxeCoreFv);
274 if (EFI_ERROR (Status)) {
275 return Status;
276 }
277
278 //
279 // Report DXE FV to DXE core
280 //
281 BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) DxeCoreFv, DxeCoreFv->FvLength);
282
283 //
284 // Find DXE core file from DXE FV
285 //
286 Status = FvFindFile (DxeCoreFv, EFI_FV_FILETYPE_DXE_CORE, &FileHeader);
287 if (EFI_ERROR (Status)) {
288 return Status;
289 }
290
291 Status = FileFindSection (FileHeader, EFI_SECTION_PE32, (VOID **)&PeCoffImage);
292 if (EFI_ERROR (Status)) {
293 return Status;
294 }
295
296 //
297 // Get DXE core info
298 //
299 Status = LoadPeCoffImage (PeCoffImage, &ImageAddress, &ImageSize, DxeCoreEntryPoint);
300 if (EFI_ERROR (Status)) {
301 return Status;
302 }
303
304 BuildModuleHob (&FileHeader->Name, ImageAddress, EFI_SIZE_TO_PAGES ((UINT32) ImageSize) * EFI_PAGE_SIZE, *DxeCoreEntryPoint);
305
306 return EFI_SUCCESS;
307 }
308