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