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