VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/OvmfPkg/Sec/SecMain.c

Last change on this file was 105670, checked in by vboxsync, 5 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette