]> git.proxmox.com Git - mirror_edk2.git/blob - QuarkPlatformPkg/Acpi/Dxe/BootScriptExecutorDxe/ScriptExecute.c
QuarkPlatformPkg: Add new package for Galileo boards
[mirror_edk2.git] / QuarkPlatformPkg / Acpi / Dxe / BootScriptExecutorDxe / ScriptExecute.c
1 /** @file
2 This is the code for Boot Script Executer module.
3
4 This driver is dispatched by Dxe core and the driver will reload itself to ACPI NVS memory
5 in the entry point. The functionality is to interpret and restore the S3 boot script
6
7 Copyright (c) 2013-2015 Intel Corporation.
8
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
13
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16
17 **/
18
19 #include "ScriptExecute.h"
20
21 #pragma pack(1)
22 typedef union {
23 struct {
24 UINT32 LimitLow : 16;
25 UINT32 BaseLow : 16;
26 UINT32 BaseMid : 8;
27 UINT32 Type : 4;
28 UINT32 System : 1;
29 UINT32 Dpl : 2;
30 UINT32 Present : 1;
31 UINT32 LimitHigh : 4;
32 UINT32 Software : 1;
33 UINT32 Reserved : 1;
34 UINT32 DefaultSize : 1;
35 UINT32 Granularity : 1;
36 UINT32 BaseHigh : 8;
37 } Bits;
38 UINT64 Uint64;
39 } IA32_GDT;
40
41 #pragma pack()
42
43 EFI_GUID mBootScriptExecutorImageGuid = {
44 0x9a8d3433, 0x9fe8, 0x42b6, {0x87, 0xb, 0x1e, 0x31, 0xc8, 0x4e, 0xbe, 0x3b}
45 };
46
47 //
48 // Global Descriptor Table (GDT)
49 //
50 GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = {
51 /* selector { Global Segment Descriptor } */
52 /* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
53 /* 0x08 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
54 /* 0x10 */ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 0, 1, 1, 0}},
55 /* 0x18 */ {{0xFFFF, 0, 0, 0x3, 1, 0, 1, 0xF, 0, 0, 1, 1, 0}},
56 /* 0x20 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
57 /* 0x28 */ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 0, 0, 1, 0}},
58 /* 0x30 */ {{0xFFFF, 0, 0, 0x3, 1, 0, 1, 0xF, 0, 0, 0, 1, 0}},
59 /* 0x38 */ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 1, 0, 1, 0}},
60 /* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
61 };
62
63 //
64 // IA32 Gdt register
65 //
66 GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR mGdt = {
67 sizeof (mGdtEntries) - 1,
68 (UINTN) mGdtEntries
69 };
70
71 /**
72 Entry function of Boot script exector. This function will be executed in
73 S3 boot path.
74 This function should not return, because it is invoked by switch stack.
75
76 @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
77 @param PeiS3ResumeState a pointer to a structure of PEI_S3_RESUME_STATE
78
79 @retval EFI_INVALID_PARAMETER - OS waking vector not found
80 @retval EFI_UNSUPPORTED - something wrong when we resume to OS
81 **/
82 EFI_STATUS
83 EFIAPI
84 S3BootScriptExecutorEntryFunction (
85 IN ACPI_S3_CONTEXT *AcpiS3Context,
86 IN PEI_S3_RESUME_STATE *PeiS3ResumeState
87 )
88 {
89 EFI_STATUS Status;
90
91 //
92 // Disable interrupt of Debug timer, since new IDT table cannot handle it.
93 //
94 SaveAndSetDebugTimerInterrupt (FALSE);
95
96 //
97 // Restore IDT for debug
98 //
99 SetIdtEntry (AcpiS3Context);
100
101 //
102 // Initialize Debug Agent to support source level debug in S3 path.
103 //
104 InitializeDebugAgent (DEBUG_AGENT_INIT_S3, NULL, NULL);
105
106 //
107 // Because not install BootScriptExecute PPI(used just in this module), So just pass NULL
108 // for that parameter.
109 //
110 Status = S3BootScriptExecute ();
111
112 AsmWbinvd ();
113
114 //
115 // We need turn back to S3Resume - install boot script done ppi and report status code on S3resume.
116 //
117 if (PeiS3ResumeState != 0) {
118 //
119 // Need report status back to S3ResumePeim.
120 // If boot script execution is failed, S3ResumePeim wil report the error status code.
121 //
122 PeiS3ResumeState->ReturnStatus = (UINT64)(UINTN)Status;
123 //
124 // IA32 S3 Resume
125 //
126 DEBUG ((EFI_D_INFO, "Call SwitchStack() to return to S3 Resume in PEI Phase\n"));
127 PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)PlatformTransferControl16;
128
129 SwitchStack (
130 (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiS3ResumeState->ReturnEntryPoint,
131 (VOID *)(UINTN)AcpiS3Context,
132 (VOID *)(UINTN)PeiS3ResumeState,
133 (VOID *)(UINTN)PeiS3ResumeState->ReturnStackPointer
134 );
135
136 //
137 // Never run to here
138 //
139 CpuDeadLoop();
140 return EFI_UNSUPPORTED;
141 }
142
143 //
144 // Never run to here
145 //
146 CpuDeadLoop();
147 return EFI_UNSUPPORTED;
148 }
149 /**
150 Entrypoint of Boot script exector driver, this function will be executed in
151 normal boot phase and invoked by DXE dispatch.
152
153 @param[in] ImageHandle The firmware allocated handle for the EFI image.
154 @param[in] SystemTable A pointer to the EFI System Table.
155
156 @retval EFI_SUCCESS The entry point is executed successfully.
157 @retval other Some error occurs when executing this entry point.
158 **/
159 EFI_STATUS
160 EFIAPI
161 BootScriptExecutorEntryPoint (
162 IN EFI_HANDLE ImageHandle,
163 IN EFI_SYSTEM_TABLE *SystemTable
164 )
165 {
166 UINT8 *Buffer;
167 UINTN BufferSize;
168 UINTN Pages;
169 EFI_PHYSICAL_ADDRESS FfsBuffer;
170 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
171 BOOT_SCRIPT_EXECUTOR_VARIABLE *EfiBootScriptExecutorVariable;
172 EFI_PHYSICAL_ADDRESS BootScriptExecutorBuffer;
173 EFI_STATUS Status;
174 VOID *DevicePath;
175 EFI_HANDLE NewImageHandle;
176
177 //
178 // Test if the gEfiCallerIdGuid of this image is already installed. if not, the entry
179 // point is loaded by DXE code which is the first time loaded. or else, it is already
180 // be reloaded be itself.This is a work-around
181 //
182 Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &DevicePath);
183 if (EFI_ERROR (Status)) {
184
185 //
186 // This is the first-time loaded by DXE core. reload itself to NVS mem
187 //
188 //
189 // A workarouond: Here we install a dummy handle
190 //
191 NewImageHandle = NULL;
192 Status = gBS->InstallProtocolInterface (
193 &NewImageHandle,
194 &gEfiCallerIdGuid,
195 EFI_NATIVE_INTERFACE,
196 NULL
197 );
198
199 Status = GetSectionFromAnyFv (
200 &gEfiCallerIdGuid,
201 EFI_SECTION_PE32,
202 0,
203 (VOID **) &Buffer,
204 &BufferSize
205 );
206 ImageContext.Handle = Buffer;
207 ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
208 //
209 // Get information about the image being loaded
210 //
211 Status = PeCoffLoaderGetImageInfo (&ImageContext);
212 if (EFI_ERROR (Status)) {
213 return Status;
214 }
215 Pages = EFI_SIZE_TO_PAGES(BufferSize + ImageContext.SectionAlignment);
216 FfsBuffer = 0xFFFFFFFF;
217 Status = gBS->AllocatePages (
218 AllocateMaxAddress,
219 EfiACPIMemoryNVS,
220 Pages,
221 &FfsBuffer
222 );
223 if (EFI_ERROR (Status)) {
224 return EFI_OUT_OF_RESOURCES;
225 }
226 ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer;
227 //
228 // Align buffer on section boundry
229 //
230 ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
231 ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);
232 //
233 // Load the image to our new buffer
234 //
235 Status = PeCoffLoaderLoadImage (&ImageContext);
236 if (EFI_ERROR (Status)) {
237 gBS->FreePages (FfsBuffer, Pages);
238 return Status;
239 }
240
241 //
242 // Relocate the image in our new buffer
243 //
244 Status = PeCoffLoaderRelocateImage (&ImageContext);
245
246 if (EFI_ERROR (Status)) {
247 PeCoffLoaderUnloadImage (&ImageContext);
248 gBS->FreePages (FfsBuffer, Pages);
249 return Status;
250 }
251 //
252 // Flush the instruction cache so the image data is written before we execute it
253 //
254 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
255 Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable);
256 if (EFI_ERROR (Status)) {
257 gBS->FreePages (FfsBuffer, Pages);
258 return Status;
259 }
260 //
261 // Additional step for BootScript integrity
262 // Save BootScriptExecutor image
263 //
264 Status = SaveLockBox (
265 &mBootScriptExecutorImageGuid,
266 (VOID *)(UINTN)ImageContext.ImageAddress,
267 (UINTN)ImageContext.ImageSize
268 );
269 ASSERT_EFI_ERROR (Status);
270
271 Status = SetLockBoxAttributes (&mBootScriptExecutorImageGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
272 ASSERT_EFI_ERROR (Status);
273
274 } else {
275 //
276 // the entry point is invoked after reloading. following code only run in ACPI NVS
277 //
278 BufferSize = sizeof (BOOT_SCRIPT_EXECUTOR_VARIABLE);
279
280 BootScriptExecutorBuffer = 0xFFFFFFFF;
281 Pages = EFI_SIZE_TO_PAGES(BufferSize);
282 Status = gBS->AllocatePages (
283 AllocateMaxAddress,
284 EfiACPIMemoryNVS,
285 Pages,
286 &BootScriptExecutorBuffer
287 );
288 if (EFI_ERROR (Status)) {
289 return EFI_OUT_OF_RESOURCES;
290 }
291
292 EfiBootScriptExecutorVariable = (BOOT_SCRIPT_EXECUTOR_VARIABLE *)(UINTN)BootScriptExecutorBuffer;
293 EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint = (UINTN) S3BootScriptExecutorEntryFunction ;
294
295 Status = SaveLockBox (
296 &gEfiBootScriptExecutorVariableGuid,
297 &BootScriptExecutorBuffer,
298 sizeof(BootScriptExecutorBuffer)
299 );
300 ASSERT_EFI_ERROR (Status);
301
302 //
303 // Additional step for BootScript integrity
304 // Save BootScriptExecutor context
305 //
306 Status = SaveLockBox (
307 &gEfiBootScriptExecutorContextGuid,
308 EfiBootScriptExecutorVariable,
309 sizeof(*EfiBootScriptExecutorVariable)
310 );
311 ASSERT_EFI_ERROR (Status);
312
313 Status = SetLockBoxAttributes (&gEfiBootScriptExecutorContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
314 ASSERT_EFI_ERROR (Status);
315
316 }
317
318 return EFI_SUCCESS;
319 }
320
321 /**
322 Platform specific mechanism to transfer control to 16bit OS waking vector
323
324 @param[in] AcpiWakingVector The 16bit OS waking vector
325 @param[in] AcpiLowMemoryBase A buffer under 1M which could be used during the transfer
326
327 **/
328 VOID
329 PlatformTransferControl16 (
330 IN UINT32 AcpiWakingVector,
331 IN UINT32 AcpiLowMemoryBase
332 )
333 {
334 UINT32 NewValue;
335 UINT64 BaseAddress;
336 UINT64 SmramLength;
337 UINTN Index;
338
339 DEBUG (( EFI_D_INFO, "PlatformTransferControl - Entry\r\n"));
340
341 //
342 // Need to make sure the GDT is loaded with values that support long mode and real mode.
343 //
344 AsmWriteGdtr (&mGdt);
345
346 //
347 // Disable eSram block (this will also clear/zero eSRAM)
348 // We only use eSRAM in the PEI phase. Disable now that we are resuming the OS
349 //
350 NewValue = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_ESRAMPGCTRL_BLOCK);
351 NewValue |= BLOCK_DISABLE_PG;
352 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_ESRAMPGCTRL_BLOCK, NewValue);
353
354 //
355 // Update HMBOUND to top of DDR3 memory and LOCK
356 // We disabled eSRAM so now we move HMBOUND down to top of DDR3
357 //
358 QNCGetTSEGMemoryRange (&BaseAddress, &SmramLength);
359 NewValue = (UINT32)(BaseAddress + SmramLength);
360 DEBUG ((EFI_D_INFO,"Locking HMBOUND at: = 0x%8x\n",NewValue));
361 QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HMBOUND_REG, (NewValue | HMBOUND_LOCK));
362
363 //
364 // Lock all IMR regions now that HMBOUND is locked
365 //
366 for (Index = (QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXL); Index <= (QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXL); Index += 4) {
367 NewValue = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, Index);
368 NewValue |= IMR_LOCK;
369 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, Index, NewValue);
370 }
371
372 //
373 // Call ASM routine to switch to real mode and jump to 16bit OS waking vector
374 //
375 AsmTransferControl(AcpiWakingVector, 0);
376
377 //
378 // Never run to here
379 //
380 CpuDeadLoop();
381 }
382
383
384
385