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