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