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