1 /** @file
2 
3   Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.<BR>
4   SPDX-License-Identifier: BSD-2-Clause-Patent
5 
6 **/
7 
8 #include "SecMain.h"
9 #include "SecFsp.h"
10 
11 EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI gSecTemporaryRamSupportPpi = {
12   SecTemporaryRamSupport
13 };
14 
15 EFI_PEI_PPI_DESCRIPTOR            mPeiSecPlatformInformationPpi[] = {
16   {
17     EFI_PEI_PPI_DESCRIPTOR_PPI,
18     &gFspInApiModePpiGuid,
19     NULL
20   },
21   {
22     (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
23     &gEfiTemporaryRamSupportPpiGuid,
24     &gSecTemporaryRamSupportPpi
25   }
26 };
27 
28 //
29 // These are IDT entries pointing to 08:FFFFFFE4h.
30 //
31 UINT64  mIdtEntryTemplate = 0xffff8e000008ffe4ULL;
32 
33 /**
34 
35   Entry point to the C language phase of SEC. After the SEC assembly
36   code has initialized some temporary memory and set up the stack,
37   the control is transferred to this function.
38 
39 
40   @param[in] SizeOfRam          Size of the temporary memory available for use.
41   @param[in] TempRamBase        Base address of temporary ram
42   @param[in] BootFirmwareVolume Base address of the Boot Firmware Volume.
43   @param[in] PeiCore            PeiCore entry point.
44   @param[in] BootLoaderStack    BootLoader stack.
45   @param[in] ApiIdx             the index of API.
46 
47   @return This function never returns.
48 
49 **/
50 VOID
51 EFIAPI
SecStartup(IN UINT32 SizeOfRam,IN UINT32 TempRamBase,IN VOID * BootFirmwareVolume,IN PEI_CORE_ENTRY PeiCore,IN UINT32 BootLoaderStack,IN UINT32 ApiIdx)52 SecStartup (
53   IN UINT32                   SizeOfRam,
54   IN UINT32                   TempRamBase,
55   IN VOID                    *BootFirmwareVolume,
56   IN PEI_CORE_ENTRY           PeiCore,
57   IN UINT32                   BootLoaderStack,
58   IN UINT32                   ApiIdx
59   )
60 {
61   EFI_SEC_PEI_HAND_OFF        SecCoreData;
62   IA32_DESCRIPTOR             IdtDescriptor;
63   SEC_IDT_TABLE               IdtTableInStack;
64   UINT32                      Index;
65   FSP_GLOBAL_DATA             PeiFspData;
66   UINT64                      ExceptionHandler;
67   UINTN                       IdtSize;
68 
69   //
70   // Process all libraries constructor function linked to SecCore.
71   //
72   ProcessLibraryConstructorList ();
73 
74   //
75   // Initialize floating point operating environment
76   // to be compliant with UEFI spec.
77   //
78   InitializeFloatingPointUnits ();
79 
80   //
81   // Scenario 1 memory map when running on bootloader stack
82   //
83   // |-------------------|---->
84   // |Idt Table          |
85   // |-------------------|
86   // |PeiService Pointer |
87   // |-------------------|
88   // |                   |
89   // |                   |
90   // |      Heap         |
91   // |                   |
92   // |                   |
93   // |-------------------|---->  TempRamBase
94   //
95   //
96   // |-------------------|
97   // |Bootloader stack   |----> somewhere in memory, FSP will share this stack.
98   // |-------------------|
99 
100   //
101   // Scenario 2 memory map when running FSP on a separate stack
102   //
103   // |-------------------|---->
104   // |Idt Table          |
105   // |-------------------|
106   // |PeiService Pointer |    PeiStackSize
107   // |-------------------|
108   // |                   |
109   // |      Stack        |
110   // |-------------------|---->
111   // |                   |
112   // |                   |
113   // |      Heap         |    PeiTemporayRamSize
114   // |                   |
115   // |                   |
116   // |-------------------|---->  TempRamBase
117   IdtTableInStack.PeiService  = NULL;
118   AsmReadIdtr (&IdtDescriptor);
119   if (IdtDescriptor.Base == 0) {
120     ExceptionHandler = FspGetExceptionHandler(mIdtEntryTemplate);
121     for (Index = 0; Index < FixedPcdGet8(PcdFspMaxInterruptSupported); Index ++) {
122       CopyMem ((VOID*)&IdtTableInStack.IdtTable[Index], (VOID*)&ExceptionHandler, sizeof (UINT64));
123     }
124     IdtSize = sizeof (IdtTableInStack.IdtTable);
125   } else {
126     IdtSize = IdtDescriptor.Limit + 1;
127     if (IdtSize > sizeof (IdtTableInStack.IdtTable)) {
128       //
129       // ERROR: IDT table size from boot loader is larger than FSP can support, DeadLoop here!
130       //
131       CpuDeadLoop();
132     } else {
133       CopyMem ((VOID *) (UINTN) &IdtTableInStack.IdtTable, (VOID *) IdtDescriptor.Base, IdtSize);
134     }
135   }
136   IdtDescriptor.Base  = (UINTN) &IdtTableInStack.IdtTable;
137   IdtDescriptor.Limit = (UINT16)(IdtSize - 1);
138 
139   AsmWriteIdtr (&IdtDescriptor);
140 
141   //
142   // Initialize the global FSP data region
143   //
144   FspGlobalDataInit (&PeiFspData, BootLoaderStack, (UINT8)ApiIdx);
145 
146   //
147   // Update the base address and length of Pei temporary memory
148   //
149   SecCoreData.DataSize               = sizeof (EFI_SEC_PEI_HAND_OFF);
150   SecCoreData.BootFirmwareVolumeBase = BootFirmwareVolume;
151   SecCoreData.BootFirmwareVolumeSize = (UINT32)((EFI_FIRMWARE_VOLUME_HEADER *)BootFirmwareVolume)->FvLength;
152 
153   SecCoreData.TemporaryRamBase       = (VOID*)(UINTN) TempRamBase;
154   if (PcdGet8 (PcdFspHeapSizePercentage) == 0) {
155     SecCoreData.TemporaryRamSize       = SizeOfRam; // stack size that is going to be copied to the permanent memory
156     SecCoreData.PeiTemporaryRamBase    = SecCoreData.TemporaryRamBase;
157     SecCoreData.PeiTemporaryRamSize    = SecCoreData.TemporaryRamSize;
158     SecCoreData.StackBase              = (VOID *)GetFspEntryStack(); // Share the same boot loader stack
159     SecCoreData.StackSize              = 0;
160   } else {
161     SecCoreData.TemporaryRamSize       = SizeOfRam;
162     SecCoreData.PeiTemporaryRamBase    = SecCoreData.TemporaryRamBase;
163     SecCoreData.PeiTemporaryRamSize    = SecCoreData.TemporaryRamSize * PcdGet8 (PcdFspHeapSizePercentage) / 100;
164     SecCoreData.StackBase              = (VOID*)(UINTN)((UINTN)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize);
165     SecCoreData.StackSize              = SecCoreData.TemporaryRamSize - SecCoreData.PeiTemporaryRamSize;
166   }
167 
168   DEBUG ((DEBUG_INFO, "Fsp BootFirmwareVolumeBase - 0x%x\n", SecCoreData.BootFirmwareVolumeBase));
169   DEBUG ((DEBUG_INFO, "Fsp BootFirmwareVolumeSize - 0x%x\n", SecCoreData.BootFirmwareVolumeSize));
170   DEBUG ((DEBUG_INFO, "Fsp TemporaryRamBase       - 0x%x\n", SecCoreData.TemporaryRamBase));
171   DEBUG ((DEBUG_INFO, "Fsp TemporaryRamSize       - 0x%x\n", SecCoreData.TemporaryRamSize));
172   DEBUG ((DEBUG_INFO, "Fsp PeiTemporaryRamBase    - 0x%x\n", SecCoreData.PeiTemporaryRamBase));
173   DEBUG ((DEBUG_INFO, "Fsp PeiTemporaryRamSize    - 0x%x\n", SecCoreData.PeiTemporaryRamSize));
174   DEBUG ((DEBUG_INFO, "Fsp StackBase              - 0x%x\n", SecCoreData.StackBase));
175   DEBUG ((DEBUG_INFO, "Fsp StackSize              - 0x%x\n", SecCoreData.StackSize));
176 
177   //
178   // Call PeiCore Entry
179   //
180   PeiCore (&SecCoreData, mPeiSecPlatformInformationPpi);
181 
182   //
183   // Should never be here
184   //
185   CpuDeadLoop ();
186 }
187 
188 /**
189   This service of the TEMPORARY_RAM_SUPPORT_PPI that migrates temporary RAM into
190   permanent memory.
191 
192   @param[in] PeiServices            Pointer to the PEI Services Table.
193   @param[in] TemporaryMemoryBase    Source Address in temporary memory from which the SEC or PEIM will copy the
194                                 Temporary RAM contents.
195   @param[in] PermanentMemoryBase    Destination Address in permanent memory into which the SEC or PEIM will copy the
196                                 Temporary RAM contents.
197   @param[in] CopySize               Amount of memory to migrate from temporary to permanent memory.
198 
199   @retval EFI_SUCCESS           The data was successfully returned.
200   @retval EFI_INVALID_PARAMETER PermanentMemoryBase + CopySize > TemporaryMemoryBase when
201                                 TemporaryMemoryBase > PermanentMemoryBase.
202 
203 **/
204 EFI_STATUS
205 EFIAPI
SecTemporaryRamSupport(IN CONST EFI_PEI_SERVICES ** PeiServices,IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,IN UINTN CopySize)206 SecTemporaryRamSupport (
207   IN CONST EFI_PEI_SERVICES   **PeiServices,
208   IN EFI_PHYSICAL_ADDRESS     TemporaryMemoryBase,
209   IN EFI_PHYSICAL_ADDRESS     PermanentMemoryBase,
210   IN UINTN                    CopySize
211   )
212 {
213   IA32_DESCRIPTOR   IdtDescriptor;
214   VOID*             OldHeap;
215   VOID*             NewHeap;
216   VOID*             OldStack;
217   VOID*             NewStack;
218   UINTN             HeapSize;
219   UINTN             StackSize;
220 
221   UINTN             CurrentStack;
222   UINTN             FspStackBase;
223 
224   if (PcdGet8 (PcdFspHeapSizePercentage) == 0) {
225 
226     CurrentStack = AsmReadEsp();
227     FspStackBase = (UINTN)GetFspEntryStack();
228 
229     StackSize = FspStackBase - CurrentStack;
230     HeapSize  = CopySize;
231 
232     OldHeap = (VOID*)(UINTN)TemporaryMemoryBase;
233     NewHeap = (VOID*)((UINTN)PermanentMemoryBase);
234 
235     OldStack = (VOID*)CurrentStack;
236     //
237     //The old stack is copied at the end of the stack region because stack grows down.
238     //
239     NewStack = (VOID*)((UINTN)PermanentMemoryBase - StackSize);
240 
241   } else {
242     HeapSize   = CopySize * PcdGet8 (PcdFspHeapSizePercentage) / 100 ;
243     StackSize  = CopySize - HeapSize;
244 
245     OldHeap = (VOID*)(UINTN)TemporaryMemoryBase;
246     NewHeap = (VOID*)((UINTN)PermanentMemoryBase + StackSize);
247 
248     OldStack = (VOID*)((UINTN)TemporaryMemoryBase + HeapSize);
249     NewStack = (VOID*)(UINTN)PermanentMemoryBase;
250 
251   }
252   //
253   // Migrate Heap
254   //
255   CopyMem (NewHeap, OldHeap, HeapSize);
256 
257   //
258   // Migrate Stack
259   //
260   CopyMem (NewStack, OldStack, StackSize);
261 
262 
263   //
264   // We need *not* fix the return address because currently,
265   // The PeiCore is executed in flash.
266   //
267 
268   //
269   // Rebase IDT table in permanent memory
270   //
271   AsmReadIdtr (&IdtDescriptor);
272   IdtDescriptor.Base = IdtDescriptor.Base - (UINTN)OldStack + (UINTN)NewStack;
273 
274   AsmWriteIdtr (&IdtDescriptor);
275 
276   //
277   // Fixed the FSP data pointer
278   //
279   FspDataPointerFixUp ((UINTN)NewStack - (UINTN)OldStack);
280 
281   //
282   // SecSwitchStack function must be invoked after the memory migration
283   // immediately, also we need fixup the stack change caused by new call into
284   // permanent memory.
285   //
286   SecSwitchStack (
287     (UINT32) (UINTN) OldStack,
288     (UINT32) (UINTN) NewStack
289     );
290 
291   return EFI_SUCCESS;
292 }
293