OvmfPkg/Sec: Don't decompress the FV on S3 resume
[mirror_edk2.git] / OvmfPkg / Sec / SecMain.c
CommitLineData
bb4aa855
JJ
1/** @file\r
2 Main SEC phase code. Transitions to PEI.\r
3\r
c67178b7 4 Copyright (c) 2008 - 2013, Intel Corporation. All rights reserved.<BR>\r
bb4aa855
JJ
5\r
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include <PiPei.h>\r
17\r
18#include <Library/PeimEntryPoint.h>\r
19#include <Library/BaseLib.h>\r
20#include <Library/DebugLib.h>\r
21#include <Library/BaseMemoryLib.h>\r
22#include <Library/PeiServicesLib.h>\r
23#include <Library/PcdLib.h>\r
24#include <Library/UefiCpuLib.h>\r
25#include <Library/DebugAgentLib.h>\r
26#include <Library/IoLib.h>\r
27#include <Library/PeCoffLib.h>\r
28#include <Library/PeCoffGetEntryPointLib.h>\r
29#include <Library/PeCoffExtraActionLib.h>\r
30#include <Library/ExtractGuidedSectionLib.h>\r
31\r
32#include <Ppi/TemporaryRamSupport.h>\r
33\r
34#define SEC_IDT_ENTRY_COUNT 34\r
35\r
36typedef struct _SEC_IDT_TABLE {\r
37 EFI_PEI_SERVICES *PeiService;\r
38 IA32_IDT_GATE_DESCRIPTOR IdtTable[SEC_IDT_ENTRY_COUNT];\r
39} SEC_IDT_TABLE;\r
40\r
41VOID\r
42EFIAPI\r
43SecStartupPhase2 (\r
44 IN VOID *Context\r
45 );\r
46\r
47EFI_STATUS\r
48EFIAPI\r
49TemporaryRamMigration (\r
50 IN CONST EFI_PEI_SERVICES **PeiServices,\r
51 IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,\r
52 IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,\r
53 IN UINTN CopySize\r
54 );\r
55\r
56//\r
57//\r
58// \r
59EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI mTemporaryRamSupportPpi = {\r
60 TemporaryRamMigration\r
61};\r
62\r
63EFI_PEI_PPI_DESCRIPTOR mPrivateDispatchTable[] = {\r
64 {\r
65 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
66 &gEfiTemporaryRamSupportPpiGuid,\r
67 &mTemporaryRamSupportPpi\r
68 },\r
69};\r
70\r
71//\r
72// Template of an IDT entry pointing to 10:FFFFFFE4h.\r
73//\r
74IA32_IDT_GATE_DESCRIPTOR mIdtEntryTemplate = {\r
75 { // Bits\r
76 0xffe4, // OffsetLow\r
77 0x10, // Selector\r
78 0x0, // Reserved_0\r
79 IA32_IDT_GATE_TYPE_INTERRUPT_32, // GateType\r
80 0xffff // OffsetHigh\r
81 } \r
82};\r
83\r
84/**\r
85 Locates the main boot firmware volume.\r
86\r
87 @param[in,out] BootFv On input, the base of the BootFv\r
88 On output, the decompressed main firmware volume\r
89\r
90 @retval EFI_SUCCESS The main firmware volume was located and decompressed\r
91 @retval EFI_NOT_FOUND The main firmware volume was not found\r
92\r
93**/\r
94EFI_STATUS\r
95FindMainFv (\r
96 IN OUT EFI_FIRMWARE_VOLUME_HEADER **BootFv\r
97 )\r
98{\r
99 EFI_FIRMWARE_VOLUME_HEADER *Fv;\r
100 UINTN Distance;\r
101\r
102 ASSERT (((UINTN) *BootFv & EFI_PAGE_MASK) == 0);\r
103\r
104 Fv = *BootFv;\r
105 Distance = (UINTN) (*BootFv)->FvLength;\r
106 do {\r
107 Fv = (EFI_FIRMWARE_VOLUME_HEADER*) ((UINT8*) Fv - EFI_PAGE_SIZE);\r
108 Distance += EFI_PAGE_SIZE;\r
109 if (Distance > SIZE_32MB) {\r
110 return EFI_NOT_FOUND;\r
111 }\r
112\r
113 if (Fv->Signature != EFI_FVH_SIGNATURE) {\r
114 continue;\r
115 }\r
116\r
117 if ((UINTN) Fv->FvLength > Distance) {\r
118 continue;\r
119 }\r
120\r
121 *BootFv = Fv;\r
122 return EFI_SUCCESS;\r
123\r
124 } while (TRUE);\r
125}\r
126\r
127/**\r
128 Locates a section within a series of sections\r
129 with the specified section type.\r
130\r
4b4b783d
JJ
131 The Instance parameter indicates which instance of the section\r
132 type to return. (0 is first instance, 1 is second...)\r
133\r
bb4aa855
JJ
134 @param[in] Sections The sections to search\r
135 @param[in] SizeOfSections Total size of all sections\r
136 @param[in] SectionType The section type to locate\r
4b4b783d 137 @param[in] Instance The section instance number\r
bb4aa855
JJ
138 @param[out] FoundSection The FFS section if found\r
139\r
140 @retval EFI_SUCCESS The file and section was found\r
141 @retval EFI_NOT_FOUND The file and section was not found\r
142 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted\r
143\r
144**/\r
145EFI_STATUS\r
4b4b783d 146FindFfsSectionInstance (\r
bb4aa855
JJ
147 IN VOID *Sections,\r
148 IN UINTN SizeOfSections,\r
149 IN EFI_SECTION_TYPE SectionType,\r
4b4b783d 150 IN UINTN Instance,\r
bb4aa855
JJ
151 OUT EFI_COMMON_SECTION_HEADER **FoundSection\r
152 )\r
153{\r
154 EFI_PHYSICAL_ADDRESS CurrentAddress;\r
155 UINT32 Size;\r
156 EFI_PHYSICAL_ADDRESS EndOfSections;\r
157 EFI_COMMON_SECTION_HEADER *Section;\r
158 EFI_PHYSICAL_ADDRESS EndOfSection;\r
159\r
160 //\r
161 // Loop through the FFS file sections within the PEI Core FFS file\r
162 //\r
163 EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) Sections;\r
164 EndOfSections = EndOfSection + SizeOfSections;\r
165 for (;;) {\r
166 if (EndOfSection == EndOfSections) {\r
167 break;\r
168 }\r
169 CurrentAddress = (EndOfSection + 3) & ~(3ULL);\r
170 if (CurrentAddress >= EndOfSections) {\r
171 return EFI_VOLUME_CORRUPTED;\r
172 }\r
173\r
174 Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;\r
bb4aa855
JJ
175\r
176 Size = SECTION_SIZE (Section);\r
177 if (Size < sizeof (*Section)) {\r
178 return EFI_VOLUME_CORRUPTED;\r
179 }\r
180\r
181 EndOfSection = CurrentAddress + Size;\r
182 if (EndOfSection > EndOfSections) {\r
183 return EFI_VOLUME_CORRUPTED;\r
184 }\r
185\r
186 //\r
187 // Look for the requested section type\r
188 //\r
189 if (Section->Type == SectionType) {\r
4b4b783d
JJ
190 if (Instance == 0) {\r
191 *FoundSection = Section;\r
192 return EFI_SUCCESS;\r
193 } else {\r
194 Instance--;\r
195 }\r
bb4aa855 196 }\r
bb4aa855
JJ
197 }\r
198\r
199 return EFI_NOT_FOUND;\r
200}\r
201\r
4b4b783d
JJ
202/**\r
203 Locates a section within a series of sections\r
204 with the specified section type.\r
205\r
206 @param[in] Sections The sections to search\r
207 @param[in] SizeOfSections Total size of all sections\r
208 @param[in] SectionType The section type to locate\r
209 @param[out] FoundSection The FFS section if found\r
210\r
211 @retval EFI_SUCCESS The file and section was found\r
212 @retval EFI_NOT_FOUND The file and section was not found\r
213 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted\r
214\r
215**/\r
216EFI_STATUS\r
217FindFfsSectionInSections (\r
218 IN VOID *Sections,\r
219 IN UINTN SizeOfSections,\r
220 IN EFI_SECTION_TYPE SectionType,\r
221 OUT EFI_COMMON_SECTION_HEADER **FoundSection\r
222 )\r
223{\r
224 return FindFfsSectionInstance (\r
225 Sections,\r
226 SizeOfSections,\r
227 SectionType,\r
228 0,\r
229 FoundSection\r
230 );\r
231}\r
232\r
bb4aa855
JJ
233/**\r
234 Locates a FFS file with the specified file type and a section\r
235 within that file with the specified section type.\r
236\r
237 @param[in] Fv The firmware volume to search\r
238 @param[in] FileType The file type to locate\r
239 @param[in] SectionType The section type to locate\r
240 @param[out] FoundSection The FFS section if found\r
241\r
242 @retval EFI_SUCCESS The file and section was found\r
243 @retval EFI_NOT_FOUND The file and section was not found\r
244 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted\r
245\r
246**/\r
247EFI_STATUS\r
bb4aa855
JJ
248FindFfsFileAndSection (\r
249 IN EFI_FIRMWARE_VOLUME_HEADER *Fv,\r
250 IN EFI_FV_FILETYPE FileType,\r
251 IN EFI_SECTION_TYPE SectionType,\r
252 OUT EFI_COMMON_SECTION_HEADER **FoundSection\r
253 )\r
254{\r
255 EFI_STATUS Status;\r
256 EFI_PHYSICAL_ADDRESS CurrentAddress;\r
257 EFI_PHYSICAL_ADDRESS EndOfFirmwareVolume;\r
258 EFI_FFS_FILE_HEADER *File;\r
259 UINT32 Size;\r
260 EFI_PHYSICAL_ADDRESS EndOfFile;\r
261\r
262 if (Fv->Signature != EFI_FVH_SIGNATURE) {\r
c67178b7 263 DEBUG ((EFI_D_ERROR, "FV at %p does not have FV header signature\n", Fv));\r
bb4aa855
JJ
264 return EFI_VOLUME_CORRUPTED;\r
265 }\r
266\r
267 CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Fv;\r
268 EndOfFirmwareVolume = CurrentAddress + Fv->FvLength;\r
269\r
270 //\r
271 // Loop through the FFS files in the Boot Firmware Volume\r
272 //\r
273 for (EndOfFile = CurrentAddress + Fv->HeaderLength; ; ) {\r
274\r
275 CurrentAddress = (EndOfFile + 7) & ~(7ULL);\r
276 if (CurrentAddress > EndOfFirmwareVolume) {\r
277 return EFI_VOLUME_CORRUPTED;\r
278 }\r
279\r
280 File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;\r
281 Size = *(UINT32*) File->Size & 0xffffff;\r
282 if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {\r
283 return EFI_VOLUME_CORRUPTED;\r
284 }\r
bb4aa855
JJ
285\r
286 EndOfFile = CurrentAddress + Size;\r
287 if (EndOfFile > EndOfFirmwareVolume) {\r
288 return EFI_VOLUME_CORRUPTED;\r
289 }\r
290\r
291 //\r
292 // Look for the request file type\r
293 //\r
294 if (File->Type != FileType) {\r
bb4aa855
JJ
295 continue;\r
296 }\r
297\r
298 Status = FindFfsSectionInSections (\r
299 (VOID*) (File + 1),\r
300 (UINTN) EndOfFile - (UINTN) (File + 1),\r
301 SectionType,\r
302 FoundSection\r
303 );\r
304 if (!EFI_ERROR (Status) || (Status == EFI_VOLUME_CORRUPTED)) {\r
305 return Status;\r
306 }\r
307 }\r
308}\r
309\r
310/**\r
311 Locates the compressed main firmware volume and decompresses it.\r
312\r
313 @param[in,out] Fv On input, the firmware volume to search\r
b36f701d 314 On output, the decompressed BOOT/PEI FV\r
bb4aa855
JJ
315\r
316 @retval EFI_SUCCESS The file and section was found\r
317 @retval EFI_NOT_FOUND The file and section was not found\r
318 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted\r
319\r
320**/\r
321EFI_STATUS\r
b36f701d 322DecompressMemFvs (\r
bb4aa855
JJ
323 IN OUT EFI_FIRMWARE_VOLUME_HEADER **Fv\r
324 )\r
325{\r
326 EFI_STATUS Status;\r
327 EFI_GUID_DEFINED_SECTION *Section;\r
328 UINT32 OutputBufferSize;\r
329 UINT32 ScratchBufferSize;\r
330 UINT16 SectionAttribute;\r
331 UINT32 AuthenticationStatus;\r
332 VOID *OutputBuffer;\r
333 VOID *ScratchBuffer;\r
b36f701d
JJ
334 EFI_FIRMWARE_VOLUME_IMAGE_SECTION *FvSection;\r
335 EFI_FIRMWARE_VOLUME_HEADER *PeiMemFv;\r
336 EFI_FIRMWARE_VOLUME_HEADER *DxeMemFv;\r
bb4aa855 337\r
b36f701d 338 FvSection = (EFI_FIRMWARE_VOLUME_IMAGE_SECTION*) NULL;\r
bb4aa855
JJ
339\r
340 Status = FindFfsFileAndSection (\r
341 *Fv,\r
342 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,\r
343 EFI_SECTION_GUID_DEFINED,\r
344 (EFI_COMMON_SECTION_HEADER**) &Section\r
345 );\r
346 if (EFI_ERROR (Status)) {\r
347 DEBUG ((EFI_D_ERROR, "Unable to find GUID defined section\n"));\r
348 return Status;\r
349 }\r
350\r
351 Status = ExtractGuidedSectionGetInfo (\r
352 Section,\r
353 &OutputBufferSize,\r
354 &ScratchBufferSize,\r
355 &SectionAttribute\r
356 );\r
357 if (EFI_ERROR (Status)) {\r
358 DEBUG ((EFI_D_ERROR, "Unable to GetInfo for GUIDed section\n"));\r
359 return Status;\r
360 }\r
361\r
b36f701d 362 OutputBuffer = (VOID*) ((UINT8*)(UINTN) PcdGet32 (PcdOvmfDxeMemFvBase) + SIZE_1MB);\r
bb4aa855
JJ
363 ScratchBuffer = ALIGN_POINTER ((UINT8*) OutputBuffer + OutputBufferSize, SIZE_1MB);\r
364 Status = ExtractGuidedSectionDecode (\r
365 Section,\r
366 &OutputBuffer,\r
367 ScratchBuffer,\r
368 &AuthenticationStatus\r
369 );\r
370 if (EFI_ERROR (Status)) {\r
371 DEBUG ((EFI_D_ERROR, "Error during GUID section decode\n"));\r
372 return Status;\r
373 }\r
374\r
b36f701d 375 Status = FindFfsSectionInstance (\r
bb4aa855
JJ
376 OutputBuffer,\r
377 OutputBufferSize,\r
378 EFI_SECTION_FIRMWARE_VOLUME_IMAGE,\r
b36f701d
JJ
379 0,\r
380 (EFI_COMMON_SECTION_HEADER**) &FvSection\r
bb4aa855
JJ
381 );\r
382 if (EFI_ERROR (Status)) {\r
b36f701d 383 DEBUG ((EFI_D_ERROR, "Unable to find PEI FV section\n"));\r
bb4aa855
JJ
384 return Status;\r
385 }\r
386\r
b36f701d
JJ
387 ASSERT (SECTION_SIZE (FvSection) ==\r
388 (PcdGet32 (PcdOvmfPeiMemFvSize) + sizeof (*FvSection)));\r
389 ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE);\r
bb4aa855 390\r
b36f701d
JJ
391 PeiMemFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfPeiMemFvBase);\r
392 CopyMem (PeiMemFv, (VOID*) (FvSection + 1), PcdGet32 (PcdOvmfPeiMemFvSize));\r
393\r
394 if (PeiMemFv->Signature != EFI_FVH_SIGNATURE) {\r
395 DEBUG ((EFI_D_ERROR, "Extracted FV at %p does not have FV header signature\n", PeiMemFv));\r
396 CpuDeadLoop ();\r
397 return EFI_VOLUME_CORRUPTED;\r
398 }\r
399\r
400 Status = FindFfsSectionInstance (\r
401 OutputBuffer,\r
402 OutputBufferSize,\r
403 EFI_SECTION_FIRMWARE_VOLUME_IMAGE,\r
404 1,\r
405 (EFI_COMMON_SECTION_HEADER**) &FvSection\r
406 );\r
407 if (EFI_ERROR (Status)) {\r
408 DEBUG ((EFI_D_ERROR, "Unable to find DXE FV section\n"));\r
409 return Status;\r
410 }\r
411\r
412 ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE);\r
413 ASSERT (SECTION_SIZE (FvSection) ==\r
414 (PcdGet32 (PcdOvmfDxeMemFvSize) + sizeof (*FvSection)));\r
415\r
416 DxeMemFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfDxeMemFvBase);\r
417 CopyMem (DxeMemFv, (VOID*) (FvSection + 1), PcdGet32 (PcdOvmfDxeMemFvSize));\r
418\r
419 if (DxeMemFv->Signature != EFI_FVH_SIGNATURE) {\r
420 DEBUG ((EFI_D_ERROR, "Extracted FV at %p does not have FV header signature\n", DxeMemFv));\r
bb4aa855
JJ
421 CpuDeadLoop ();\r
422 return EFI_VOLUME_CORRUPTED;\r
423 }\r
424\r
b36f701d 425 *Fv = PeiMemFv;\r
bb4aa855
JJ
426 return EFI_SUCCESS;\r
427}\r
428\r
429/**\r
430 Locates the PEI Core entry point address\r
431\r
432 @param[in] Fv The firmware volume to search\r
433 @param[out] PeiCoreEntryPoint The entry point of the PEI Core image\r
434\r
435 @retval EFI_SUCCESS The file and section was found\r
436 @retval EFI_NOT_FOUND The file and section was not found\r
437 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted\r
438\r
439**/\r
440EFI_STATUS\r
bb4aa855
JJ
441FindPeiCoreImageBaseInFv (\r
442 IN EFI_FIRMWARE_VOLUME_HEADER *Fv,\r
443 OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase\r
444 )\r
445{\r
446 EFI_STATUS Status;\r
447 EFI_COMMON_SECTION_HEADER *Section;\r
448\r
449 Status = FindFfsFileAndSection (\r
450 Fv,\r
451 EFI_FV_FILETYPE_PEI_CORE,\r
452 EFI_SECTION_PE32,\r
453 &Section\r
454 );\r
455 if (EFI_ERROR (Status)) {\r
456 Status = FindFfsFileAndSection (\r
457 Fv,\r
458 EFI_FV_FILETYPE_PEI_CORE,\r
459 EFI_SECTION_TE,\r
460 &Section\r
461 );\r
462 if (EFI_ERROR (Status)) {\r
463 DEBUG ((EFI_D_ERROR, "Unable to find PEI Core image\n"));\r
464 return Status;\r
465 }\r
466 }\r
467\r
468 *PeiCoreImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(Section + 1);\r
469 return EFI_SUCCESS;\r
470}\r
471\r
a781f709
JJ
472\r
473/**\r
474 Reads 8-bits of CMOS data.\r
475\r
476 Reads the 8-bits of CMOS data at the location specified by Index.\r
477 The 8-bit read value is returned.\r
478\r
479 @param Index The CMOS location to read.\r
480\r
481 @return The value read.\r
482\r
483**/\r
484STATIC\r
485UINT8\r
486CmosRead8 (\r
487 IN UINTN Index\r
488 )\r
489{\r
490 IoWrite8 (0x70, (UINT8) Index);\r
491 return IoRead8 (0x71);\r
492}\r
493\r
494\r
495STATIC\r
496BOOLEAN\r
497IsS3Resume (\r
498 VOID\r
499 )\r
500{\r
501 return (CmosRead8 (0xF) == 0xFE);\r
502}\r
503\r
504\r
505STATIC\r
506EFI_STATUS\r
507GetS3ResumePeiFv (\r
508 IN OUT EFI_FIRMWARE_VOLUME_HEADER **PeiFv\r
509 )\r
510{\r
511 *PeiFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfPeiMemFvBase);\r
512 return EFI_SUCCESS;\r
513}\r
514\r
515\r
bb4aa855
JJ
516/**\r
517 Locates the PEI Core entry point address\r
518\r
519 @param[in,out] Fv The firmware volume to search\r
520 @param[out] PeiCoreEntryPoint The entry point of the PEI Core image\r
521\r
522 @retval EFI_SUCCESS The file and section was found\r
523 @retval EFI_NOT_FOUND The file and section was not found\r
524 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted\r
525\r
526**/\r
527VOID\r
bb4aa855
JJ
528FindPeiCoreImageBase (\r
529 IN OUT EFI_FIRMWARE_VOLUME_HEADER **BootFv,\r
530 OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase\r
531 )\r
532{\r
533 *PeiCoreImageBase = 0;\r
534\r
a781f709
JJ
535 if (IsS3Resume ()) {\r
536 DEBUG ((EFI_D_VERBOSE, "SEC: S3 resume\n"));\r
537 GetS3ResumePeiFv (BootFv);\r
538 } else {\r
539 DEBUG ((EFI_D_VERBOSE, "SEC: Normal boot\n"));\r
540 FindMainFv (BootFv);\r
bb4aa855 541\r
a781f709
JJ
542 DecompressMemFvs (BootFv);\r
543 }\r
bb4aa855
JJ
544\r
545 FindPeiCoreImageBaseInFv (*BootFv, PeiCoreImageBase);\r
546}\r
547\r
548/**\r
549 Find core image base.\r
550\r
551**/\r
552EFI_STATUS\r
bb4aa855
JJ
553FindImageBase (\r
554 IN EFI_FIRMWARE_VOLUME_HEADER *BootFirmwareVolumePtr,\r
555 OUT EFI_PHYSICAL_ADDRESS *SecCoreImageBase\r
556 )\r
557{\r
558 EFI_PHYSICAL_ADDRESS CurrentAddress;\r
559 EFI_PHYSICAL_ADDRESS EndOfFirmwareVolume;\r
560 EFI_FFS_FILE_HEADER *File;\r
561 UINT32 Size;\r
562 EFI_PHYSICAL_ADDRESS EndOfFile;\r
563 EFI_COMMON_SECTION_HEADER *Section;\r
564 EFI_PHYSICAL_ADDRESS EndOfSection;\r
565\r
566 *SecCoreImageBase = 0;\r
567\r
568 CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) BootFirmwareVolumePtr;\r
569 EndOfFirmwareVolume = CurrentAddress + BootFirmwareVolumePtr->FvLength;\r
570\r
571 //\r
572 // Loop through the FFS files in the Boot Firmware Volume\r
573 //\r
574 for (EndOfFile = CurrentAddress + BootFirmwareVolumePtr->HeaderLength; ; ) {\r
575\r
576 CurrentAddress = (EndOfFile + 7) & 0xfffffffffffffff8ULL;\r
577 if (CurrentAddress > EndOfFirmwareVolume) {\r
578 return EFI_NOT_FOUND;\r
579 }\r
580\r
581 File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;\r
582 Size = *(UINT32*) File->Size & 0xffffff;\r
583 if (Size < sizeof (*File)) {\r
584 return EFI_NOT_FOUND;\r
585 }\r
586\r
587 EndOfFile = CurrentAddress + Size;\r
588 if (EndOfFile > EndOfFirmwareVolume) {\r
589 return EFI_NOT_FOUND;\r
590 }\r
591\r
592 //\r
593 // Look for SEC Core\r
594 //\r
595 if (File->Type != EFI_FV_FILETYPE_SECURITY_CORE) {\r
596 continue;\r
597 }\r
598\r
599 //\r
600 // Loop through the FFS file sections within the FFS file\r
601 //\r
602 EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) (File + 1);\r
603 for (;;) {\r
604 CurrentAddress = (EndOfSection + 3) & 0xfffffffffffffffcULL;\r
605 Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;\r
606\r
607 Size = *(UINT32*) Section->Size & 0xffffff;\r
608 if (Size < sizeof (*Section)) {\r
609 return EFI_NOT_FOUND;\r
610 }\r
611\r
612 EndOfSection = CurrentAddress + Size;\r
613 if (EndOfSection > EndOfFile) {\r
614 return EFI_NOT_FOUND;\r
615 }\r
616\r
617 //\r
618 // Look for executable sections\r
619 //\r
620 if (Section->Type == EFI_SECTION_PE32 || Section->Type == EFI_SECTION_TE) {\r
621 if (File->Type == EFI_FV_FILETYPE_SECURITY_CORE) {\r
622 *SecCoreImageBase = (PHYSICAL_ADDRESS) (UINTN) (Section + 1);\r
623 }\r
624 break;\r
625 }\r
626 }\r
627\r
628 //\r
629 // SEC Core image found\r
630 //\r
631 if (*SecCoreImageBase != 0) {\r
632 return EFI_SUCCESS;\r
633 }\r
634 }\r
635}\r
636\r
637/*\r
638 Find and return Pei Core entry point.\r
639\r
640 It also find SEC and PEI Core file debug inforamtion. It will report them if\r
641 remote debug is enabled.\r
642\r
643**/\r
644VOID\r
bb4aa855
JJ
645FindAndReportEntryPoints (\r
646 IN EFI_FIRMWARE_VOLUME_HEADER **BootFirmwareVolumePtr,\r
647 OUT EFI_PEI_CORE_ENTRY_POINT *PeiCoreEntryPoint\r
648 )\r
649{\r
650 EFI_STATUS Status;\r
651 EFI_PHYSICAL_ADDRESS SecCoreImageBase;\r
652 EFI_PHYSICAL_ADDRESS PeiCoreImageBase;\r
653 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
654\r
655 //\r
656 // Find SEC Core and PEI Core image base\r
657 //\r
658 Status = FindImageBase (*BootFirmwareVolumePtr, &SecCoreImageBase);\r
659 ASSERT_EFI_ERROR (Status);\r
660\r
661 FindPeiCoreImageBase (BootFirmwareVolumePtr, &PeiCoreImageBase);\r
662 \r
663 ZeroMem ((VOID *) &ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));\r
664 //\r
665 // Report SEC Core debug information when remote debug is enabled\r
666 //\r
667 ImageContext.ImageAddress = SecCoreImageBase;\r
668 ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress);\r
669 PeCoffLoaderRelocateImageExtraAction (&ImageContext);\r
670\r
671 //\r
672 // Report PEI Core debug information when remote debug is enabled\r
673 //\r
674 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiCoreImageBase;\r
675 ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress);\r
676 PeCoffLoaderRelocateImageExtraAction (&ImageContext);\r
677\r
678 //\r
679 // Find PEI Core entry point\r
680 //\r
681 Status = PeCoffLoaderGetEntryPoint ((VOID *) (UINTN) PeiCoreImageBase, (VOID**) PeiCoreEntryPoint);\r
682 if (EFI_ERROR (Status)) {\r
683 *PeiCoreEntryPoint = 0;\r
684 }\r
685\r
686 return;\r
687}\r
688\r
689VOID\r
690EFIAPI\r
691SecCoreStartupWithStack (\r
692 IN EFI_FIRMWARE_VOLUME_HEADER *BootFv,\r
693 IN VOID *TopOfCurrentStack\r
694 )\r
695{\r
696 EFI_SEC_PEI_HAND_OFF SecCoreData;\r
697 SEC_IDT_TABLE IdtTableInStack;\r
698 IA32_DESCRIPTOR IdtDescriptor;\r
699 UINT32 Index;\r
700\r
701 ProcessLibraryConstructorList (NULL, NULL);\r
702\r
c67178b7 703 DEBUG ((EFI_D_INFO,\r
bb4aa855
JJ
704 "SecCoreStartupWithStack(0x%x, 0x%x)\n",\r
705 (UINT32)(UINTN)BootFv,\r
706 (UINT32)(UINTN)TopOfCurrentStack\r
707 ));\r
708\r
709 //\r
710 // Initialize floating point operating environment\r
711 // to be compliant with UEFI spec.\r
712 //\r
713 InitializeFloatingPointUnits ();\r
714\r
715 //\r
716 // Initialize IDT\r
717 // \r
718 IdtTableInStack.PeiService = NULL;\r
719 for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index ++) {\r
720 CopyMem (&IdtTableInStack.IdtTable[Index], &mIdtEntryTemplate, sizeof (mIdtEntryTemplate));\r
721 }\r
722\r
723 IdtDescriptor.Base = (UINTN)&IdtTableInStack.IdtTable;\r
724 IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);\r
725\r
726 AsmWriteIdtr (&IdtDescriptor);\r
727\r
b382ede3
JJ
728#if defined (MDE_CPU_X64)\r
729 //\r
730 // ASSERT that the Page Tables were set by the reset vector code to\r
731 // the address we expect.\r
732 //\r
733 ASSERT (AsmReadCr3 () == (UINTN) PcdGet32 (PcdOvmfSecPageTablesBase));\r
734#endif\r
735\r
bb4aa855
JJ
736 //\r
737 // |-------------| <-- TopOfCurrentStack\r
738 // | Stack | 32k\r
739 // |-------------|\r
740 // | Heap | 32k\r
741 // |-------------| <-- SecCoreData.TemporaryRamBase\r
742 //\r
743\r
7cb6b0e0
JJ
744 ASSERT ((UINTN) (PcdGet32 (PcdOvmfSecPeiTempRamBase) +\r
745 PcdGet32 (PcdOvmfSecPeiTempRamSize)) ==\r
746 (UINTN) TopOfCurrentStack);\r
747\r
bb4aa855
JJ
748 //\r
749 // Initialize SEC hand-off state\r
750 //\r
751 SecCoreData.DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);\r
752\r
7cb6b0e0 753 SecCoreData.TemporaryRamSize = (UINTN) PcdGet32 (PcdOvmfSecPeiTempRamSize);\r
bb4aa855
JJ
754 SecCoreData.TemporaryRamBase = (VOID*)((UINT8 *)TopOfCurrentStack - SecCoreData.TemporaryRamSize);\r
755\r
756 SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase;\r
757 SecCoreData.PeiTemporaryRamSize = SecCoreData.TemporaryRamSize >> 1;\r
758\r
759 SecCoreData.StackBase = (UINT8 *)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize;\r
760 SecCoreData.StackSize = SecCoreData.TemporaryRamSize >> 1;\r
761\r
762 SecCoreData.BootFirmwareVolumeBase = BootFv;\r
763 SecCoreData.BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;\r
764\r
765 //\r
766 // Make sure the 8259 is masked before initializing the Debug Agent and the debug timer is enabled\r
767 //\r
768 IoWrite8 (0x21, 0xff);\r
769 IoWrite8 (0xA1, 0xff);\r
770 \r
771 //\r
772 // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.\r
773 //\r
774 InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, &SecCoreData, SecStartupPhase2);\r
775}\r
776 \r
777/**\r
778 Caller provided function to be invoked at the end of InitializeDebugAgent().\r
779\r
780 Entry point to the C language phase of SEC. After the SEC assembly\r
781 code has initialized some temporary memory and set up the stack,\r
782 the control is transferred to this function.\r
783\r
784 @param[in] Context The first input parameter of InitializeDebugAgent().\r
785\r
786**/\r
787VOID\r
788EFIAPI\r
789SecStartupPhase2(\r
790 IN VOID *Context\r
791 )\r
792{\r
793 EFI_SEC_PEI_HAND_OFF *SecCoreData;\r
794 EFI_FIRMWARE_VOLUME_HEADER *BootFv;\r
795 EFI_PEI_CORE_ENTRY_POINT PeiCoreEntryPoint;\r
796 \r
797 SecCoreData = (EFI_SEC_PEI_HAND_OFF *) Context;\r
798 \r
799 //\r
800 // Find PEI Core entry point. It will report SEC and Pei Core debug information if remote debug\r
801 // is enabled.\r
802 //\r
803 BootFv = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;\r
804 FindAndReportEntryPoints (&BootFv, &PeiCoreEntryPoint);\r
805 SecCoreData->BootFirmwareVolumeBase = BootFv;\r
806 SecCoreData->BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;\r
807\r
808 //\r
809 // Transfer the control to the PEI core\r
810 //\r
811 (*PeiCoreEntryPoint) (SecCoreData, (EFI_PEI_PPI_DESCRIPTOR *)&mPrivateDispatchTable);\r
812 \r
813 //\r
814 // If we get here then the PEI Core returned, which is not recoverable.\r
815 //\r
816 ASSERT (FALSE);\r
817 CpuDeadLoop ();\r
818}\r
819\r
820EFI_STATUS\r
821EFIAPI\r
822TemporaryRamMigration (\r
823 IN CONST EFI_PEI_SERVICES **PeiServices,\r
824 IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,\r
825 IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,\r
826 IN UINTN CopySize\r
827 )\r
828{\r
829 IA32_DESCRIPTOR IdtDescriptor;\r
830 VOID *OldHeap;\r
831 VOID *NewHeap;\r
832 VOID *OldStack;\r
833 VOID *NewStack;\r
834 DEBUG_AGENT_CONTEXT_POSTMEM_SEC DebugAgentContext;\r
835 BOOLEAN OldStatus;\r
836 BASE_LIBRARY_JUMP_BUFFER JumpBuffer;\r
837 \r
c67178b7
JJ
838 DEBUG ((EFI_D_INFO,\r
839 "TemporaryRamMigration(0x%x, 0x%x, 0x%x)\n",\r
840 (UINTN) TemporaryMemoryBase,\r
841 (UINTN) PermanentMemoryBase,\r
842 CopySize\r
843 ));\r
bb4aa855
JJ
844 \r
845 OldHeap = (VOID*)(UINTN)TemporaryMemoryBase;\r
846 NewHeap = (VOID*)((UINTN)PermanentMemoryBase + (CopySize >> 1));\r
847 \r
848 OldStack = (VOID*)((UINTN)TemporaryMemoryBase + (CopySize >> 1));\r
849 NewStack = (VOID*)(UINTN)PermanentMemoryBase;\r
850\r
851 DebugAgentContext.HeapMigrateOffset = (UINTN)NewHeap - (UINTN)OldHeap;\r
852 DebugAgentContext.StackMigrateOffset = (UINTN)NewStack - (UINTN)OldStack;\r
853 \r
854 OldStatus = SaveAndSetDebugTimerInterrupt (FALSE);\r
855 InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, (VOID *) &DebugAgentContext, NULL);\r
856\r
857 //\r
858 // Migrate Heap\r
859 //\r
860 CopyMem (NewHeap, OldHeap, CopySize >> 1);\r
861\r
862 //\r
863 // Migrate Stack\r
864 //\r
865 CopyMem (NewStack, OldStack, CopySize >> 1);\r
866 \r
867 //\r
868 // Rebase IDT table in permanent memory\r
869 //\r
870 AsmReadIdtr (&IdtDescriptor);\r
871 IdtDescriptor.Base = IdtDescriptor.Base - (UINTN)OldStack + (UINTN)NewStack;\r
872\r
873 AsmWriteIdtr (&IdtDescriptor);\r
874\r
875 //\r
876 // Use SetJump()/LongJump() to switch to a new stack.\r
877 // \r
878 if (SetJump (&JumpBuffer) == 0) {\r
879#if defined (MDE_CPU_IA32)\r
880 JumpBuffer.Esp = JumpBuffer.Esp + DebugAgentContext.StackMigrateOffset;\r
881#endif \r
882#if defined (MDE_CPU_X64)\r
883 JumpBuffer.Rsp = JumpBuffer.Rsp + DebugAgentContext.StackMigrateOffset;\r
884#endif \r
885 LongJump (&JumpBuffer, (UINTN)-1);\r
886 }\r
887\r
888 SaveAndSetDebugTimerInterrupt (OldStatus);\r
889\r
890 return EFI_SUCCESS;\r
891}\r
892\r