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