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
FindMainFv(IN OUT EFI_FIRMWARE_VOLUME_HEADER ** BootFv)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
FindFfsSectionInstance(IN VOID * Sections,IN UINTN SizeOfSections,IN EFI_SECTION_TYPE SectionType,IN UINTN Instance,OUT EFI_COMMON_SECTION_HEADER ** FoundSection)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
FindFfsSectionInSections(IN VOID * Sections,IN UINTN SizeOfSections,IN EFI_SECTION_TYPE SectionType,OUT EFI_COMMON_SECTION_HEADER ** FoundSection)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
FindFfsFileAndSection(IN EFI_FIRMWARE_VOLUME_HEADER * Fv,IN EFI_FV_FILETYPE FileType,IN EFI_SECTION_TYPE SectionType,OUT EFI_COMMON_SECTION_HEADER ** FoundSection)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
DecompressMemFvs(IN OUT EFI_FIRMWARE_VOLUME_HEADER ** Fv)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
FindPeiCoreImageBaseInFv(IN EFI_FIRMWARE_VOLUME_HEADER * Fv,OUT EFI_PHYSICAL_ADDRESS * PeiCoreImageBase)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
CmosRead8(IN UINTN Index)495 CmosRead8 (
496   IN      UINTN                     Index
497   )
498 {
499   IoWrite8 (0x70, (UINT8) Index);
500   return IoRead8 (0x71);
501 }
502 
503 
504 STATIC
505 BOOLEAN
IsS3Resume(VOID)506 IsS3Resume (
507   VOID
508   )
509 {
510   return (CmosRead8 (0xF) == 0xFE);
511 }
512 
513 
514 STATIC
515 EFI_STATUS
GetS3ResumePeiFv(IN OUT EFI_FIRMWARE_VOLUME_HEADER ** PeiFv)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
FindPeiCoreImageBase(IN OUT EFI_FIRMWARE_VOLUME_HEADER ** BootFv,OUT EFI_PHYSICAL_ADDRESS * PeiCoreImageBase)537 FindPeiCoreImageBase (
538   IN OUT  EFI_FIRMWARE_VOLUME_HEADER       **BootFv,
539      OUT  EFI_PHYSICAL_ADDRESS             *PeiCoreImageBase
540   )
541 {
542   BOOLEAN S3Resume;
543 
544   *PeiCoreImageBase = 0;
545 
546   S3Resume = IsS3Resume ();
547   if (S3Resume && !FeaturePcdGet (PcdSmmSmramRequire)) {
548     //
549     // A malicious runtime OS may have injected something into our previously
550     // decoded PEI FV, but we don't care about that unless SMM/SMRAM is required.
551     //
552     DEBUG ((EFI_D_VERBOSE, "SEC: S3 resume\n"));
553     GetS3ResumePeiFv (BootFv);
554   } else {
555     //
556     // We're either not resuming, or resuming "securely" -- we'll decompress
557     // both PEI FV and DXE FV from pristine flash.
558     //
559     DEBUG ((EFI_D_VERBOSE, "SEC: %a\n",
560       S3Resume ? "S3 resume (with PEI decompression)" : "Normal boot"));
561     FindMainFv (BootFv);
562 
563     DecompressMemFvs (BootFv);
564   }
565 
566   FindPeiCoreImageBaseInFv (*BootFv, PeiCoreImageBase);
567 }
568 
569 /**
570   Find core image base.
571 
572 **/
573 EFI_STATUS
FindImageBase(IN EFI_FIRMWARE_VOLUME_HEADER * BootFirmwareVolumePtr,OUT EFI_PHYSICAL_ADDRESS * SecCoreImageBase)574 FindImageBase (
575   IN  EFI_FIRMWARE_VOLUME_HEADER       *BootFirmwareVolumePtr,
576   OUT EFI_PHYSICAL_ADDRESS             *SecCoreImageBase
577   )
578 {
579   EFI_PHYSICAL_ADDRESS        CurrentAddress;
580   EFI_PHYSICAL_ADDRESS        EndOfFirmwareVolume;
581   EFI_FFS_FILE_HEADER         *File;
582   UINT32                      Size;
583   EFI_PHYSICAL_ADDRESS        EndOfFile;
584   EFI_COMMON_SECTION_HEADER   *Section;
585   EFI_PHYSICAL_ADDRESS        EndOfSection;
586 
587   *SecCoreImageBase = 0;
588 
589   CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) BootFirmwareVolumePtr;
590   EndOfFirmwareVolume = CurrentAddress + BootFirmwareVolumePtr->FvLength;
591 
592   //
593   // Loop through the FFS files in the Boot Firmware Volume
594   //
595   for (EndOfFile = CurrentAddress + BootFirmwareVolumePtr->HeaderLength; ; ) {
596 
597     CurrentAddress = (EndOfFile + 7) & 0xfffffffffffffff8ULL;
598     if (CurrentAddress > EndOfFirmwareVolume) {
599       return EFI_NOT_FOUND;
600     }
601 
602     File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
603     Size = *(UINT32*) File->Size & 0xffffff;
604     if (Size < sizeof (*File)) {
605       return EFI_NOT_FOUND;
606     }
607 
608     EndOfFile = CurrentAddress + Size;
609     if (EndOfFile > EndOfFirmwareVolume) {
610       return EFI_NOT_FOUND;
611     }
612 
613     //
614     // Look for SEC Core
615     //
616     if (File->Type != EFI_FV_FILETYPE_SECURITY_CORE) {
617       continue;
618     }
619 
620     //
621     // Loop through the FFS file sections within the FFS file
622     //
623     EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) (File + 1);
624     for (;;) {
625       CurrentAddress = (EndOfSection + 3) & 0xfffffffffffffffcULL;
626       Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
627 
628       Size = *(UINT32*) Section->Size & 0xffffff;
629       if (Size < sizeof (*Section)) {
630         return EFI_NOT_FOUND;
631       }
632 
633       EndOfSection = CurrentAddress + Size;
634       if (EndOfSection > EndOfFile) {
635         return EFI_NOT_FOUND;
636       }
637 
638       //
639       // Look for executable sections
640       //
641       if (Section->Type == EFI_SECTION_PE32 || Section->Type == EFI_SECTION_TE) {
642         if (File->Type == EFI_FV_FILETYPE_SECURITY_CORE) {
643           *SecCoreImageBase = (PHYSICAL_ADDRESS) (UINTN) (Section + 1);
644         }
645         break;
646       }
647     }
648 
649     //
650     // SEC Core image found
651     //
652     if (*SecCoreImageBase != 0) {
653       return EFI_SUCCESS;
654     }
655   }
656 }
657 
658 /*
659   Find and return Pei Core entry point.
660 
661   It also find SEC and PEI Core file debug inforamtion. It will report them if
662   remote debug is enabled.
663 
664 **/
665 VOID
FindAndReportEntryPoints(IN EFI_FIRMWARE_VOLUME_HEADER ** BootFirmwareVolumePtr,OUT EFI_PEI_CORE_ENTRY_POINT * PeiCoreEntryPoint)666 FindAndReportEntryPoints (
667   IN  EFI_FIRMWARE_VOLUME_HEADER       **BootFirmwareVolumePtr,
668   OUT EFI_PEI_CORE_ENTRY_POINT         *PeiCoreEntryPoint
669   )
670 {
671   EFI_STATUS                       Status;
672   EFI_PHYSICAL_ADDRESS             SecCoreImageBase;
673   EFI_PHYSICAL_ADDRESS             PeiCoreImageBase;
674   PE_COFF_LOADER_IMAGE_CONTEXT     ImageContext;
675 
676   //
677   // Find SEC Core and PEI Core image base
678    //
679   Status = FindImageBase (*BootFirmwareVolumePtr, &SecCoreImageBase);
680   ASSERT_EFI_ERROR (Status);
681 
682   FindPeiCoreImageBase (BootFirmwareVolumePtr, &PeiCoreImageBase);
683 
684   ZeroMem ((VOID *) &ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
685   //
686   // Report SEC Core debug information when remote debug is enabled
687   //
688   ImageContext.ImageAddress = SecCoreImageBase;
689   ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress);
690   PeCoffLoaderRelocateImageExtraAction (&ImageContext);
691 
692   //
693   // Report PEI Core debug information when remote debug is enabled
694   //
695   ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiCoreImageBase;
696   ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress);
697   PeCoffLoaderRelocateImageExtraAction (&ImageContext);
698 
699   //
700   // Find PEI Core entry point
701   //
702   Status = PeCoffLoaderGetEntryPoint ((VOID *) (UINTN) PeiCoreImageBase, (VOID**) PeiCoreEntryPoint);
703   if (EFI_ERROR (Status)) {
704     *PeiCoreEntryPoint = 0;
705   }
706 
707   return;
708 }
709 
710 VOID
711 EFIAPI
SecCoreStartupWithStack(IN EFI_FIRMWARE_VOLUME_HEADER * BootFv,IN VOID * TopOfCurrentStack)712 SecCoreStartupWithStack (
713   IN EFI_FIRMWARE_VOLUME_HEADER       *BootFv,
714   IN VOID                             *TopOfCurrentStack
715   )
716 {
717   EFI_SEC_PEI_HAND_OFF        SecCoreData;
718   SEC_IDT_TABLE               IdtTableInStack;
719   IA32_DESCRIPTOR             IdtDescriptor;
720   UINT32                      Index;
721   volatile UINT8              *Table;
722 
723   //
724   // To ensure SMM can't be compromised on S3 resume, we must force re-init of
725   // the BaseExtractGuidedSectionLib. Since this is before library contructors
726   // are called, we must use a loop rather than SetMem.
727   //
728   Table = (UINT8*)(UINTN)FixedPcdGet64 (PcdGuidedExtractHandlerTableAddress);
729   for (Index = 0;
730        Index < FixedPcdGet32 (PcdGuidedExtractHandlerTableSize);
731        ++Index) {
732     Table[Index] = 0;
733   }
734 
735   ProcessLibraryConstructorList (NULL, NULL);
736 
737   DEBUG ((EFI_D_INFO,
738     "SecCoreStartupWithStack(0x%x, 0x%x)\n",
739     (UINT32)(UINTN)BootFv,
740     (UINT32)(UINTN)TopOfCurrentStack
741     ));
742 
743   //
744   // Initialize floating point operating environment
745   // to be compliant with UEFI spec.
746   //
747   InitializeFloatingPointUnits ();
748 
749   //
750   // Initialize IDT
751   //
752   IdtTableInStack.PeiService = NULL;
753   for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index ++) {
754     CopyMem (&IdtTableInStack.IdtTable[Index], &mIdtEntryTemplate, sizeof (mIdtEntryTemplate));
755   }
756 
757   IdtDescriptor.Base  = (UINTN)&IdtTableInStack.IdtTable;
758   IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);
759 
760   AsmWriteIdtr (&IdtDescriptor);
761 
762 #if defined (MDE_CPU_X64)
763   //
764   // ASSERT that the Page Tables were set by the reset vector code to
765   // the address we expect.
766   //
767   ASSERT (AsmReadCr3 () == (UINTN) PcdGet32 (PcdOvmfSecPageTablesBase));
768 #endif
769 
770   //
771   // |-------------|       <-- TopOfCurrentStack
772   // |   Stack     | 32k
773   // |-------------|
774   // |    Heap     | 32k
775   // |-------------|       <-- SecCoreData.TemporaryRamBase
776   //
777 
778   ASSERT ((UINTN) (PcdGet32 (PcdOvmfSecPeiTempRamBase) +
779                    PcdGet32 (PcdOvmfSecPeiTempRamSize)) ==
780           (UINTN) TopOfCurrentStack);
781 
782   //
783   // Initialize SEC hand-off state
784   //
785   SecCoreData.DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);
786 
787   SecCoreData.TemporaryRamSize       = (UINTN) PcdGet32 (PcdOvmfSecPeiTempRamSize);
788   SecCoreData.TemporaryRamBase       = (VOID*)((UINT8 *)TopOfCurrentStack - SecCoreData.TemporaryRamSize);
789 
790   SecCoreData.PeiTemporaryRamBase    = SecCoreData.TemporaryRamBase;
791   SecCoreData.PeiTemporaryRamSize    = SecCoreData.TemporaryRamSize >> 1;
792 
793   SecCoreData.StackBase              = (UINT8 *)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize;
794   SecCoreData.StackSize              = SecCoreData.TemporaryRamSize >> 1;
795 
796   SecCoreData.BootFirmwareVolumeBase = BootFv;
797   SecCoreData.BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;
798 
799   //
800   // Make sure the 8259 is masked before initializing the Debug Agent and the debug timer is enabled
801   //
802   IoWrite8 (0x21, 0xff);
803   IoWrite8 (0xA1, 0xff);
804 
805   //
806   // Initialize Local APIC Timer hardware and disable Local APIC Timer
807   // interrupts before initializing the Debug Agent and the debug timer is
808   // enabled.
809   //
810   InitializeApicTimer (0, MAX_UINT32, TRUE, 5);
811   DisableApicTimerInterrupt ();
812 
813   //
814   // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.
815   //
816   InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, &SecCoreData, SecStartupPhase2);
817 }
818 
819 /**
820   Caller provided function to be invoked at the end of InitializeDebugAgent().
821 
822   Entry point to the C language phase of SEC. After the SEC assembly
823   code has initialized some temporary memory and set up the stack,
824   the control is transferred to this function.
825 
826   @param[in] Context    The first input parameter of InitializeDebugAgent().
827 
828 **/
829 VOID
830 EFIAPI
SecStartupPhase2(IN VOID * Context)831 SecStartupPhase2(
832   IN VOID                     *Context
833   )
834 {
835   EFI_SEC_PEI_HAND_OFF        *SecCoreData;
836   EFI_FIRMWARE_VOLUME_HEADER  *BootFv;
837   EFI_PEI_CORE_ENTRY_POINT    PeiCoreEntryPoint;
838 
839   SecCoreData = (EFI_SEC_PEI_HAND_OFF *) Context;
840 
841   //
842   // Find PEI Core entry point. It will report SEC and Pei Core debug information if remote debug
843   // is enabled.
844   //
845   BootFv = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
846   FindAndReportEntryPoints (&BootFv, &PeiCoreEntryPoint);
847   SecCoreData->BootFirmwareVolumeBase = BootFv;
848   SecCoreData->BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;
849 
850   //
851   // Transfer the control to the PEI core
852   //
853   (*PeiCoreEntryPoint) (SecCoreData, (EFI_PEI_PPI_DESCRIPTOR *)&mPrivateDispatchTable);
854 
855   //
856   // If we get here then the PEI Core returned, which is not recoverable.
857   //
858   ASSERT (FALSE);
859   CpuDeadLoop ();
860 }
861 
862 EFI_STATUS
863 EFIAPI
TemporaryRamMigration(IN CONST EFI_PEI_SERVICES ** PeiServices,IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,IN UINTN CopySize)864 TemporaryRamMigration (
865   IN CONST EFI_PEI_SERVICES   **PeiServices,
866   IN EFI_PHYSICAL_ADDRESS     TemporaryMemoryBase,
867   IN EFI_PHYSICAL_ADDRESS     PermanentMemoryBase,
868   IN UINTN                    CopySize
869   )
870 {
871   IA32_DESCRIPTOR                  IdtDescriptor;
872   VOID                             *OldHeap;
873   VOID                             *NewHeap;
874   VOID                             *OldStack;
875   VOID                             *NewStack;
876   DEBUG_AGENT_CONTEXT_POSTMEM_SEC  DebugAgentContext;
877   BOOLEAN                          OldStatus;
878   BASE_LIBRARY_JUMP_BUFFER         JumpBuffer;
879 
880   DEBUG ((EFI_D_INFO,
881     "TemporaryRamMigration(0x%Lx, 0x%Lx, 0x%Lx)\n",
882     TemporaryMemoryBase,
883     PermanentMemoryBase,
884     (UINT64)CopySize
885     ));
886 
887   OldHeap = (VOID*)(UINTN)TemporaryMemoryBase;
888   NewHeap = (VOID*)((UINTN)PermanentMemoryBase + (CopySize >> 1));
889 
890   OldStack = (VOID*)((UINTN)TemporaryMemoryBase + (CopySize >> 1));
891   NewStack = (VOID*)(UINTN)PermanentMemoryBase;
892 
893   DebugAgentContext.HeapMigrateOffset = (UINTN)NewHeap - (UINTN)OldHeap;
894   DebugAgentContext.StackMigrateOffset = (UINTN)NewStack - (UINTN)OldStack;
895 
896   OldStatus = SaveAndSetDebugTimerInterrupt (FALSE);
897   InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, (VOID *) &DebugAgentContext, NULL);
898 
899   //
900   // Migrate Heap
901   //
902   CopyMem (NewHeap, OldHeap, CopySize >> 1);
903 
904   //
905   // Migrate Stack
906   //
907   CopyMem (NewStack, OldStack, CopySize >> 1);
908 
909   //
910   // Rebase IDT table in permanent memory
911   //
912   AsmReadIdtr (&IdtDescriptor);
913   IdtDescriptor.Base = IdtDescriptor.Base - (UINTN)OldStack + (UINTN)NewStack;
914 
915   AsmWriteIdtr (&IdtDescriptor);
916 
917   //
918   // Use SetJump()/LongJump() to switch to a new stack.
919   //
920   if (SetJump (&JumpBuffer) == 0) {
921 #if defined (MDE_CPU_IA32)
922     JumpBuffer.Esp = JumpBuffer.Esp + DebugAgentContext.StackMigrateOffset;
923 #endif
924 #if defined (MDE_CPU_X64)
925     JumpBuffer.Rsp = JumpBuffer.Rsp + DebugAgentContext.StackMigrateOffset;
926 #endif
927     LongJump (&JumpBuffer, (UINTN)-1);
928   }
929 
930   SaveAndSetDebugTimerInterrupt (OldStatus);
931 
932   return EFI_SUCCESS;
933 }
934 
935