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