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
38typedef struct _SEC_IDT_TABLE {
39  EFI_PEI_SERVICES          *PeiService;
40  IA32_IDT_GATE_DESCRIPTOR  IdtTable[SEC_IDT_ENTRY_COUNT];
41} SEC_IDT_TABLE;
42
43VOID
44EFIAPI
45SecStartupPhase2 (
46  IN VOID                     *Context
47  );
48
49EFI_STATUS
50EFIAPI
51TemporaryRamMigration (
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//
61EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI mTemporaryRamSupportPpi = {
62  TemporaryRamMigration
63};
64
65EFI_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//
76IA32_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**/
96EFI_STATUS
97FindMainFv (
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**/
147EFI_STATUS
148FindFfsSectionInstance (
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**/
218EFI_STATUS
219FindFfsSectionInSections (
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**/
249EFI_STATUS
250FindFfsFileAndSection (
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**/
323EFI_STATUS
324DecompressMemFvs (
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**/
460EFI_STATUS
461FindPeiCoreImageBaseInFv (
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**/
504STATIC
505UINT8
506CmosRead8 (
507  IN      UINTN                     Index
508  )
509{
510  IoWrite8 (0x70, (UINT8) Index);
511  return IoRead8 (0x71);
512}
513
514
515STATIC
516BOOLEAN
517IsS3Resume (
518  VOID
519  )
520{
521  return (CmosRead8 (0xF) == 0xFE);
522}
523
524
525STATIC
526EFI_STATUS
527GetS3ResumePeiFv (
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**/
547VOID
548FindPeiCoreImageBase (
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**/
584EFI_STATUS
585FindImageBase (
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**/
676VOID
677FindAndReportEntryPoints (
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
721VOID
722EFIAPI
723SecCoreStartupWithStack (
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**/
840VOID
841EFIAPI
842SecStartupPhase2(
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
873EFI_STATUS
874EFIAPI
875TemporaryRamMigration (
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