]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Sec/SecMain.c
OvmfPkg: Sec: assert the build-time calculated end of the scratch buffer
[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
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include <PiPei.h>
17
18 #include <Library/PeimEntryPoint.h>
19 #include <Library/BaseLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/BaseMemoryLib.h>
22 #include <Library/PeiServicesLib.h>
23 #include <Library/PcdLib.h>
24 #include <Library/UefiCpuLib.h>
25 #include <Library/DebugAgentLib.h>
26 #include <Library/IoLib.h>
27 #include <Library/PeCoffLib.h>
28 #include <Library/PeCoffGetEntryPointLib.h>
29 #include <Library/PeCoffExtraActionLib.h>
30 #include <Library/ExtractGuidedSectionLib.h>
31 #include <Library/LocalApicLib.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 ((EFI_D_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 = *(UINT32*) File->Size & 0xffffff;
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_FIRMWARE_VOLUME_IMAGE_SECTION *FvSection;
336 EFI_FIRMWARE_VOLUME_HEADER *PeiMemFv;
337 EFI_FIRMWARE_VOLUME_HEADER *DxeMemFv;
338
339 FvSection = (EFI_FIRMWARE_VOLUME_IMAGE_SECTION*) NULL;
340
341 Status = FindFfsFileAndSection (
342 *Fv,
343 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
344 EFI_SECTION_GUID_DEFINED,
345 (EFI_COMMON_SECTION_HEADER**) &Section
346 );
347 if (EFI_ERROR (Status)) {
348 DEBUG ((EFI_D_ERROR, "Unable to find GUID defined section\n"));
349 return Status;
350 }
351
352 Status = ExtractGuidedSectionGetInfo (
353 Section,
354 &OutputBufferSize,
355 &ScratchBufferSize,
356 &SectionAttribute
357 );
358 if (EFI_ERROR (Status)) {
359 DEBUG ((EFI_D_ERROR, "Unable to GetInfo for GUIDed section\n"));
360 return Status;
361 }
362
363 OutputBuffer = (VOID*) ((UINT8*)(UINTN) PcdGet32 (PcdOvmfDxeMemFvBase) + SIZE_1MB);
364 ScratchBuffer = ALIGN_POINTER ((UINT8*) OutputBuffer + OutputBufferSize, SIZE_1MB);
365
366 DEBUG ((EFI_D_VERBOSE, "%a: OutputBuffer@%p+0x%x ScratchBuffer@%p+0x%x "
367 "PcdOvmfDecompressionScratchEnd=0x%x\n", __FUNCTION__, OutputBuffer,
368 OutputBufferSize, ScratchBuffer, ScratchBufferSize,
369 PcdGet32 (PcdOvmfDecompressionScratchEnd)));
370 ASSERT ((UINTN)ScratchBuffer + ScratchBufferSize ==
371 PcdGet32 (PcdOvmfDecompressionScratchEnd));
372
373 Status = ExtractGuidedSectionDecode (
374 Section,
375 &OutputBuffer,
376 ScratchBuffer,
377 &AuthenticationStatus
378 );
379 if (EFI_ERROR (Status)) {
380 DEBUG ((EFI_D_ERROR, "Error during GUID section decode\n"));
381 return Status;
382 }
383
384 Status = FindFfsSectionInstance (
385 OutputBuffer,
386 OutputBufferSize,
387 EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
388 0,
389 (EFI_COMMON_SECTION_HEADER**) &FvSection
390 );
391 if (EFI_ERROR (Status)) {
392 DEBUG ((EFI_D_ERROR, "Unable to find PEI FV section\n"));
393 return Status;
394 }
395
396 ASSERT (SECTION_SIZE (FvSection) ==
397 (PcdGet32 (PcdOvmfPeiMemFvSize) + sizeof (*FvSection)));
398 ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE);
399
400 PeiMemFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfPeiMemFvBase);
401 CopyMem (PeiMemFv, (VOID*) (FvSection + 1), PcdGet32 (PcdOvmfPeiMemFvSize));
402
403 if (PeiMemFv->Signature != EFI_FVH_SIGNATURE) {
404 DEBUG ((EFI_D_ERROR, "Extracted FV at %p does not have FV header signature\n", PeiMemFv));
405 CpuDeadLoop ();
406 return EFI_VOLUME_CORRUPTED;
407 }
408
409 Status = FindFfsSectionInstance (
410 OutputBuffer,
411 OutputBufferSize,
412 EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
413 1,
414 (EFI_COMMON_SECTION_HEADER**) &FvSection
415 );
416 if (EFI_ERROR (Status)) {
417 DEBUG ((EFI_D_ERROR, "Unable to find DXE FV section\n"));
418 return Status;
419 }
420
421 ASSERT (FvSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE);
422 ASSERT (SECTION_SIZE (FvSection) ==
423 (PcdGet32 (PcdOvmfDxeMemFvSize) + sizeof (*FvSection)));
424
425 DxeMemFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfDxeMemFvBase);
426 CopyMem (DxeMemFv, (VOID*) (FvSection + 1), PcdGet32 (PcdOvmfDxeMemFvSize));
427
428 if (DxeMemFv->Signature != EFI_FVH_SIGNATURE) {
429 DEBUG ((EFI_D_ERROR, "Extracted FV at %p does not have FV header signature\n", DxeMemFv));
430 CpuDeadLoop ();
431 return EFI_VOLUME_CORRUPTED;
432 }
433
434 *Fv = PeiMemFv;
435 return EFI_SUCCESS;
436 }
437
438 /**
439 Locates the PEI Core entry point address
440
441 @param[in] Fv The firmware volume to search
442 @param[out] PeiCoreEntryPoint The entry point of the PEI Core image
443
444 @retval EFI_SUCCESS The file and section was found
445 @retval EFI_NOT_FOUND The file and section was not found
446 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
447
448 **/
449 EFI_STATUS
450 FindPeiCoreImageBaseInFv (
451 IN EFI_FIRMWARE_VOLUME_HEADER *Fv,
452 OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase
453 )
454 {
455 EFI_STATUS Status;
456 EFI_COMMON_SECTION_HEADER *Section;
457
458 Status = FindFfsFileAndSection (
459 Fv,
460 EFI_FV_FILETYPE_PEI_CORE,
461 EFI_SECTION_PE32,
462 &Section
463 );
464 if (EFI_ERROR (Status)) {
465 Status = FindFfsFileAndSection (
466 Fv,
467 EFI_FV_FILETYPE_PEI_CORE,
468 EFI_SECTION_TE,
469 &Section
470 );
471 if (EFI_ERROR (Status)) {
472 DEBUG ((EFI_D_ERROR, "Unable to find PEI Core image\n"));
473 return Status;
474 }
475 }
476
477 *PeiCoreImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(Section + 1);
478 return EFI_SUCCESS;
479 }
480
481
482 /**
483 Reads 8-bits of CMOS data.
484
485 Reads the 8-bits of CMOS data at the location specified by Index.
486 The 8-bit read value is returned.
487
488 @param Index The CMOS location to read.
489
490 @return The value read.
491
492 **/
493 STATIC
494 UINT8
495 CmosRead8 (
496 IN UINTN Index
497 )
498 {
499 IoWrite8 (0x70, (UINT8) Index);
500 return IoRead8 (0x71);
501 }
502
503
504 STATIC
505 BOOLEAN
506 IsS3Resume (
507 VOID
508 )
509 {
510 return (CmosRead8 (0xF) == 0xFE);
511 }
512
513
514 STATIC
515 EFI_STATUS
516 GetS3ResumePeiFv (
517 IN OUT EFI_FIRMWARE_VOLUME_HEADER **PeiFv
518 )
519 {
520 *PeiFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfPeiMemFvBase);
521 return EFI_SUCCESS;
522 }
523
524
525 /**
526 Locates the PEI Core entry point address
527
528 @param[in,out] Fv The firmware volume to search
529 @param[out] PeiCoreEntryPoint The entry point of the PEI Core image
530
531 @retval EFI_SUCCESS The file and section was found
532 @retval EFI_NOT_FOUND The file and section was not found
533 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
534
535 **/
536 VOID
537 FindPeiCoreImageBase (
538 IN OUT EFI_FIRMWARE_VOLUME_HEADER **BootFv,
539 OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase
540 )
541 {
542 *PeiCoreImageBase = 0;
543
544 if (IsS3Resume ()) {
545 DEBUG ((EFI_D_VERBOSE, "SEC: S3 resume\n"));
546 GetS3ResumePeiFv (BootFv);
547 } else {
548 DEBUG ((EFI_D_VERBOSE, "SEC: Normal boot\n"));
549 FindMainFv (BootFv);
550
551 DecompressMemFvs (BootFv);
552 }
553
554 FindPeiCoreImageBaseInFv (*BootFv, PeiCoreImageBase);
555 }
556
557 /**
558 Find core image base.
559
560 **/
561 EFI_STATUS
562 FindImageBase (
563 IN EFI_FIRMWARE_VOLUME_HEADER *BootFirmwareVolumePtr,
564 OUT EFI_PHYSICAL_ADDRESS *SecCoreImageBase
565 )
566 {
567 EFI_PHYSICAL_ADDRESS CurrentAddress;
568 EFI_PHYSICAL_ADDRESS EndOfFirmwareVolume;
569 EFI_FFS_FILE_HEADER *File;
570 UINT32 Size;
571 EFI_PHYSICAL_ADDRESS EndOfFile;
572 EFI_COMMON_SECTION_HEADER *Section;
573 EFI_PHYSICAL_ADDRESS EndOfSection;
574
575 *SecCoreImageBase = 0;
576
577 CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) BootFirmwareVolumePtr;
578 EndOfFirmwareVolume = CurrentAddress + BootFirmwareVolumePtr->FvLength;
579
580 //
581 // Loop through the FFS files in the Boot Firmware Volume
582 //
583 for (EndOfFile = CurrentAddress + BootFirmwareVolumePtr->HeaderLength; ; ) {
584
585 CurrentAddress = (EndOfFile + 7) & 0xfffffffffffffff8ULL;
586 if (CurrentAddress > EndOfFirmwareVolume) {
587 return EFI_NOT_FOUND;
588 }
589
590 File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
591 Size = *(UINT32*) File->Size & 0xffffff;
592 if (Size < sizeof (*File)) {
593 return EFI_NOT_FOUND;
594 }
595
596 EndOfFile = CurrentAddress + Size;
597 if (EndOfFile > EndOfFirmwareVolume) {
598 return EFI_NOT_FOUND;
599 }
600
601 //
602 // Look for SEC Core
603 //
604 if (File->Type != EFI_FV_FILETYPE_SECURITY_CORE) {
605 continue;
606 }
607
608 //
609 // Loop through the FFS file sections within the FFS file
610 //
611 EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) (File + 1);
612 for (;;) {
613 CurrentAddress = (EndOfSection + 3) & 0xfffffffffffffffcULL;
614 Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
615
616 Size = *(UINT32*) Section->Size & 0xffffff;
617 if (Size < sizeof (*Section)) {
618 return EFI_NOT_FOUND;
619 }
620
621 EndOfSection = CurrentAddress + Size;
622 if (EndOfSection > EndOfFile) {
623 return EFI_NOT_FOUND;
624 }
625
626 //
627 // Look for executable sections
628 //
629 if (Section->Type == EFI_SECTION_PE32 || Section->Type == EFI_SECTION_TE) {
630 if (File->Type == EFI_FV_FILETYPE_SECURITY_CORE) {
631 *SecCoreImageBase = (PHYSICAL_ADDRESS) (UINTN) (Section + 1);
632 }
633 break;
634 }
635 }
636
637 //
638 // SEC Core image found
639 //
640 if (*SecCoreImageBase != 0) {
641 return EFI_SUCCESS;
642 }
643 }
644 }
645
646 /*
647 Find and return Pei Core entry point.
648
649 It also find SEC and PEI Core file debug inforamtion. It will report them if
650 remote debug is enabled.
651
652 **/
653 VOID
654 FindAndReportEntryPoints (
655 IN EFI_FIRMWARE_VOLUME_HEADER **BootFirmwareVolumePtr,
656 OUT EFI_PEI_CORE_ENTRY_POINT *PeiCoreEntryPoint
657 )
658 {
659 EFI_STATUS Status;
660 EFI_PHYSICAL_ADDRESS SecCoreImageBase;
661 EFI_PHYSICAL_ADDRESS PeiCoreImageBase;
662 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
663
664 //
665 // Find SEC Core and PEI Core image base
666 //
667 Status = FindImageBase (*BootFirmwareVolumePtr, &SecCoreImageBase);
668 ASSERT_EFI_ERROR (Status);
669
670 FindPeiCoreImageBase (BootFirmwareVolumePtr, &PeiCoreImageBase);
671
672 ZeroMem ((VOID *) &ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
673 //
674 // Report SEC Core debug information when remote debug is enabled
675 //
676 ImageContext.ImageAddress = SecCoreImageBase;
677 ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress);
678 PeCoffLoaderRelocateImageExtraAction (&ImageContext);
679
680 //
681 // Report PEI Core debug information when remote debug is enabled
682 //
683 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiCoreImageBase;
684 ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress);
685 PeCoffLoaderRelocateImageExtraAction (&ImageContext);
686
687 //
688 // Find PEI Core entry point
689 //
690 Status = PeCoffLoaderGetEntryPoint ((VOID *) (UINTN) PeiCoreImageBase, (VOID**) PeiCoreEntryPoint);
691 if (EFI_ERROR (Status)) {
692 *PeiCoreEntryPoint = 0;
693 }
694
695 return;
696 }
697
698 VOID
699 EFIAPI
700 SecCoreStartupWithStack (
701 IN EFI_FIRMWARE_VOLUME_HEADER *BootFv,
702 IN VOID *TopOfCurrentStack
703 )
704 {
705 EFI_SEC_PEI_HAND_OFF SecCoreData;
706 SEC_IDT_TABLE IdtTableInStack;
707 IA32_DESCRIPTOR IdtDescriptor;
708 UINT32 Index;
709 volatile UINT8 *Table;
710
711 //
712 // To ensure SMM can't be compromised on S3 resume, we must force re-init of
713 // the BaseExtractGuidedSectionLib. Since this is before library contructors
714 // are called, we must use a loop rather than SetMem.
715 //
716 Table = (UINT8*)(UINTN)FixedPcdGet64 (PcdGuidedExtractHandlerTableAddress);
717 for (Index = 0;
718 Index < FixedPcdGet32 (PcdGuidedExtractHandlerTableSize);
719 ++Index) {
720 Table[Index] = 0;
721 }
722
723 ProcessLibraryConstructorList (NULL, NULL);
724
725 DEBUG ((EFI_D_INFO,
726 "SecCoreStartupWithStack(0x%x, 0x%x)\n",
727 (UINT32)(UINTN)BootFv,
728 (UINT32)(UINTN)TopOfCurrentStack
729 ));
730
731 //
732 // Initialize floating point operating environment
733 // to be compliant with UEFI spec.
734 //
735 InitializeFloatingPointUnits ();
736
737 //
738 // Initialize IDT
739 //
740 IdtTableInStack.PeiService = NULL;
741 for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index ++) {
742 CopyMem (&IdtTableInStack.IdtTable[Index], &mIdtEntryTemplate, sizeof (mIdtEntryTemplate));
743 }
744
745 IdtDescriptor.Base = (UINTN)&IdtTableInStack.IdtTable;
746 IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);
747
748 AsmWriteIdtr (&IdtDescriptor);
749
750 #if defined (MDE_CPU_X64)
751 //
752 // ASSERT that the Page Tables were set by the reset vector code to
753 // the address we expect.
754 //
755 ASSERT (AsmReadCr3 () == (UINTN) PcdGet32 (PcdOvmfSecPageTablesBase));
756 #endif
757
758 //
759 // |-------------| <-- TopOfCurrentStack
760 // | Stack | 32k
761 // |-------------|
762 // | Heap | 32k
763 // |-------------| <-- SecCoreData.TemporaryRamBase
764 //
765
766 ASSERT ((UINTN) (PcdGet32 (PcdOvmfSecPeiTempRamBase) +
767 PcdGet32 (PcdOvmfSecPeiTempRamSize)) ==
768 (UINTN) TopOfCurrentStack);
769
770 //
771 // Initialize SEC hand-off state
772 //
773 SecCoreData.DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);
774
775 SecCoreData.TemporaryRamSize = (UINTN) PcdGet32 (PcdOvmfSecPeiTempRamSize);
776 SecCoreData.TemporaryRamBase = (VOID*)((UINT8 *)TopOfCurrentStack - SecCoreData.TemporaryRamSize);
777
778 SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase;
779 SecCoreData.PeiTemporaryRamSize = SecCoreData.TemporaryRamSize >> 1;
780
781 SecCoreData.StackBase = (UINT8 *)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize;
782 SecCoreData.StackSize = SecCoreData.TemporaryRamSize >> 1;
783
784 SecCoreData.BootFirmwareVolumeBase = BootFv;
785 SecCoreData.BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;
786
787 //
788 // Make sure the 8259 is masked before initializing the Debug Agent and the debug timer is enabled
789 //
790 IoWrite8 (0x21, 0xff);
791 IoWrite8 (0xA1, 0xff);
792
793 //
794 // Initialize Local APIC Timer hardware and disable Local APIC Timer
795 // interrupts before initializing the Debug Agent and the debug timer is
796 // enabled.
797 //
798 InitializeApicTimer (0, MAX_UINT32, TRUE, 5);
799 DisableApicTimerInterrupt ();
800
801 //
802 // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.
803 //
804 InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, &SecCoreData, SecStartupPhase2);
805 }
806
807 /**
808 Caller provided function to be invoked at the end of InitializeDebugAgent().
809
810 Entry point to the C language phase of SEC. After the SEC assembly
811 code has initialized some temporary memory and set up the stack,
812 the control is transferred to this function.
813
814 @param[in] Context The first input parameter of InitializeDebugAgent().
815
816 **/
817 VOID
818 EFIAPI
819 SecStartupPhase2(
820 IN VOID *Context
821 )
822 {
823 EFI_SEC_PEI_HAND_OFF *SecCoreData;
824 EFI_FIRMWARE_VOLUME_HEADER *BootFv;
825 EFI_PEI_CORE_ENTRY_POINT PeiCoreEntryPoint;
826
827 SecCoreData = (EFI_SEC_PEI_HAND_OFF *) Context;
828
829 //
830 // Find PEI Core entry point. It will report SEC and Pei Core debug information if remote debug
831 // is enabled.
832 //
833 BootFv = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
834 FindAndReportEntryPoints (&BootFv, &PeiCoreEntryPoint);
835 SecCoreData->BootFirmwareVolumeBase = BootFv;
836 SecCoreData->BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;
837
838 //
839 // Transfer the control to the PEI core
840 //
841 (*PeiCoreEntryPoint) (SecCoreData, (EFI_PEI_PPI_DESCRIPTOR *)&mPrivateDispatchTable);
842
843 //
844 // If we get here then the PEI Core returned, which is not recoverable.
845 //
846 ASSERT (FALSE);
847 CpuDeadLoop ();
848 }
849
850 EFI_STATUS
851 EFIAPI
852 TemporaryRamMigration (
853 IN CONST EFI_PEI_SERVICES **PeiServices,
854 IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
855 IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
856 IN UINTN CopySize
857 )
858 {
859 IA32_DESCRIPTOR IdtDescriptor;
860 VOID *OldHeap;
861 VOID *NewHeap;
862 VOID *OldStack;
863 VOID *NewStack;
864 DEBUG_AGENT_CONTEXT_POSTMEM_SEC DebugAgentContext;
865 BOOLEAN OldStatus;
866 BASE_LIBRARY_JUMP_BUFFER JumpBuffer;
867
868 DEBUG ((EFI_D_INFO,
869 "TemporaryRamMigration(0x%Lx, 0x%Lx, 0x%Lx)\n",
870 TemporaryMemoryBase,
871 PermanentMemoryBase,
872 (UINT64)CopySize
873 ));
874
875 OldHeap = (VOID*)(UINTN)TemporaryMemoryBase;
876 NewHeap = (VOID*)((UINTN)PermanentMemoryBase + (CopySize >> 1));
877
878 OldStack = (VOID*)((UINTN)TemporaryMemoryBase + (CopySize >> 1));
879 NewStack = (VOID*)(UINTN)PermanentMemoryBase;
880
881 DebugAgentContext.HeapMigrateOffset = (UINTN)NewHeap - (UINTN)OldHeap;
882 DebugAgentContext.StackMigrateOffset = (UINTN)NewStack - (UINTN)OldStack;
883
884 OldStatus = SaveAndSetDebugTimerInterrupt (FALSE);
885 InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, (VOID *) &DebugAgentContext, NULL);
886
887 //
888 // Migrate Heap
889 //
890 CopyMem (NewHeap, OldHeap, CopySize >> 1);
891
892 //
893 // Migrate Stack
894 //
895 CopyMem (NewStack, OldStack, CopySize >> 1);
896
897 //
898 // Rebase IDT table in permanent memory
899 //
900 AsmReadIdtr (&IdtDescriptor);
901 IdtDescriptor.Base = IdtDescriptor.Base - (UINTN)OldStack + (UINTN)NewStack;
902
903 AsmWriteIdtr (&IdtDescriptor);
904
905 //
906 // Use SetJump()/LongJump() to switch to a new stack.
907 //
908 if (SetJump (&JumpBuffer) == 0) {
909 #if defined (MDE_CPU_IA32)
910 JumpBuffer.Esp = JumpBuffer.Esp + DebugAgentContext.StackMigrateOffset;
911 #endif
912 #if defined (MDE_CPU_X64)
913 JumpBuffer.Rsp = JumpBuffer.Rsp + DebugAgentContext.StackMigrateOffset;
914 #endif
915 LongJump (&JumpBuffer, (UINTN)-1);
916 }
917
918 SaveAndSetDebugTimerInterrupt (OldStatus);
919
920 return EFI_SUCCESS;
921 }
922