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