]> git.proxmox.com Git - mirror_edk2.git/blame - QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.c
QuarkSocPkg: Fix typos in comments
[mirror_edk2.git] / QuarkSocPkg / QuarkNorthCluster / S3Support / Dxe / QncS3Support.c
CommitLineData
9b6bbcdb
MK
1/** @file\r
2This is the driver that implements the QNC S3 Support protocol\r
3\r
74c6a103 4Copyright (c) 2013-2016 Intel Corporation.\r
9b6bbcdb
MK
5\r
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15#include "QncS3Support.h"\r
16\r
17//\r
18// Global Variables\r
19//\r
20EFI_QNC_S3_SUPPORT_PROTOCOL mQncS3SupportProtocol;\r
21QNC_S3_PARAMETER_HEADER *mS3Parameter;\r
22UINT32 mQncS3ImageEntryPoint;\r
23VOID *mQncS3ImageAddress;\r
24UINTN mQncS3ImageSize;\r
25\r
26extern EFI_GUID gQncS3CodeInLockBoxGuid;\r
27extern EFI_GUID gQncS3ContextInLockBoxGuid;\r
28\r
29/**\r
30\r
31 Create a buffer that is used to store context information for use with\r
32 dispatch functions.\r
33\r
34 @retval EFI_SUCCESS - Buffer allocated and initialized.\r
35\r
36**/\r
37EFI_STATUS\r
38CreateContextBuffer (\r
39 VOID\r
40 )\r
41{\r
42 EFI_STATUS Status;\r
43 EFI_PHYSICAL_ADDRESS Address;\r
44 UINT32 ContextStoreSize;\r
45\r
46 ContextStoreSize = EFI_PAGE_SIZE;\r
47\r
48 //\r
49 // Allcoate <4G EfiReservedMemory\r
50 //\r
51 Address = 0xFFFFFFFF;\r
52 Status = gBS->AllocatePages (AllocateMaxAddress, EfiReservedMemoryType, EFI_SIZE_TO_PAGES (ContextStoreSize), &Address);\r
53 if (EFI_ERROR (Status)) {\r
54 return Status;\r
55 }\r
56 mS3Parameter = (QNC_S3_PARAMETER_HEADER *) (UINTN) Address;\r
57\r
58 //\r
59 // Determine the maximum number of context entries that can be stored in this\r
60 // table.\r
61 //\r
62 mS3Parameter->MaxContexts = ((ContextStoreSize - sizeof(QNC_S3_PARAMETER_HEADER)) / sizeof(EFI_DISPATCH_CONTEXT_UNION)) + 1;\r
63 mS3Parameter->StorePosition = 0;\r
64\r
65 return Status;\r
66}\r
67\r
68//\r
69// Functions\r
70//\r
71EFI_STATUS\r
72EFIAPI\r
73QncS3SupportEntryPoint (\r
74 IN EFI_HANDLE ImageHandle,\r
75 IN EFI_SYSTEM_TABLE *SystemTable\r
76 )\r
77/*++\r
78\r
79 Routine Description:\r
80\r
81 QNC S3 support driver entry point\r
82\r
83 Arguments:\r
84\r
85 ImageHandle - Handle for the image of this driver\r
86 SystemTable - Pointer to the EFI System Table\r
87\r
88 Returns:\r
89\r
90 EFI_STATUS\r
91\r
92--*/\r
93{\r
94 EFI_STATUS Status;\r
95 VOID *TmpPtr;\r
96 EFI_EVENT Event;\r
97\r
98 //\r
99 // If the protocol is found execution is happening in ACPI NVS memory. If it\r
100 // is not found copy the driver into ACPI NVS memory and pass control to it.\r
101 //\r
102 Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &TmpPtr);\r
103\r
104 //\r
105 // Load the QNC S3 image\r
106 //\r
107 if (EFI_ERROR (Status)) {\r
108 Status = LoadQncS3Image (SystemTable);\r
109 ASSERT_EFI_ERROR (Status);\r
110\r
111 } else {\r
112 DEBUG ((DEBUG_INFO, "QncS3SupportEntryPoint() in reserved memory - Begin\n"));\r
113 //\r
114 // Allocate and initialize context buffer.\r
115 //\r
116 Status = CreateContextBuffer ();\r
117\r
118 if (EFI_ERROR (Status)) {\r
119 return Status;\r
120 }\r
121 //\r
122 // Install the QNC S3 Support protocol\r
123 //\r
124 mQncS3SupportProtocol.SetDispatchItem = QncS3SetDispatchItem;\r
125 Status = gBS->InstallMultipleProtocolInterfaces (\r
126 &ImageHandle,\r
127 &gEfiQncS3SupportProtocolGuid,\r
128 &mQncS3SupportProtocol,\r
129 NULL\r
130 );\r
131\r
132 mQncS3ImageAddress = (VOID *)(UINTN)PcdGet64(PcdQncS3CodeInLockBoxAddress);\r
133 mQncS3ImageSize = (UINTN)PcdGet64(PcdQncS3CodeInLockBoxSize);\r
134 DEBUG ((DEBUG_INFO, "QncS3SupportEntry Code = %08x, Size = %08x\n", (UINTN)mQncS3ImageAddress, mQncS3ImageSize));\r
135 DEBUG ((DEBUG_INFO, "QncS3SupportEntry Contex = %08x, Size = %08x\n", (UINTN)mS3Parameter, EFI_PAGE_SIZE));\r
136 ASSERT (mQncS3ImageAddress != 0);\r
137\r
138 //\r
139 // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.\r
140 //\r
141 Status = gBS->CreateEventEx (\r
142 EVT_NOTIFY_SIGNAL,\r
143 TPL_CALLBACK,\r
144 QncS3BootEvent,\r
145 NULL,\r
146 &gEfiEndOfDxeEventGroupGuid,\r
147 &Event\r
148 );\r
149 ASSERT_EFI_ERROR (Status);\r
150\r
151 DEBUG ((DEBUG_INFO, "QncS3SupportEntryPoint() in reserved memory - End\n"));\r
152 }\r
153\r
154\r
155\r
156 return Status;\r
157}\r
158\r
159EFI_STATUS\r
160EFIAPI\r
161QncS3SetDispatchItem (\r
162 IN EFI_QNC_S3_SUPPORT_PROTOCOL *This,\r
163 IN EFI_QNC_S3_DISPATCH_ITEM *DispatchItem,\r
164 OUT VOID **S3DispatchEntryPoint,\r
165 OUT VOID **Context\r
166 )\r
167/*++\r
168\r
169Routine Description:\r
170\r
171 Set an item to be dispatched at S3 resume time. At the same time, the entry point\r
172 of the QNC S3 support image is returned to be used in subsequent boot script save\r
173 call\r
174\r
175Arguments:\r
176\r
177 This - Pointer to the protocol instance.\r
178 DispatchItem - The item to be dispatched.\r
179 S3DispatchEntryPoint - The entry point of the QNC S3 support image.\r
180\r
181Returns:\r
182\r
183 EFI_STATUS - Successfully completed.\r
184 EFI_OUT_OF_RESOURCES - Out of resources.\r
185\r
186--*/\r
187{\r
188\r
189 DEBUG ((DEBUG_INFO, "QncS3SetDispatchItem() Start\n"));\r
190\r
191 //\r
192 // Set default values.\r
193 //\r
194 *S3DispatchEntryPoint = NULL;\r
195 *Context = NULL;\r
196\r
197 //\r
198 // Determine if this entry will fit.\r
199 //\r
200 if (mS3Parameter->StorePosition >= mS3Parameter->MaxContexts) {\r
201 DEBUG ((DEBUG_INFO, "QncS3SetDispatchItem exceeds max length - 0x%08x\n", (UINTN)mS3Parameter->MaxContexts));\r
202 return EFI_OUT_OF_RESOURCES;\r
203 }\r
204 //\r
205 // Calculate the size required;\r
206 // ** Always round up to be 8 byte aligned\r
207 //\r
208 switch (DispatchItem->Type) {\r
209 case QncS3ItemTypeInitPcieRootPortDownstream:\r
210 *S3DispatchEntryPoint = (VOID*) (UINTN)QncS3InitPcieRootPortDownstream;\r
211 *Context = &mS3Parameter->Contexts[mS3Parameter->StorePosition];\r
212 CopyMem (&mS3Parameter->Contexts[mS3Parameter->StorePosition], DispatchItem->Parameter, sizeof(UINT32));\r
213 DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream @ 0x%08x - context 0x%08x\n", (UINTN)*S3DispatchEntryPoint, (UINTN)*Context));\r
214 break;\r
215\r
216 default:\r
217 return EFI_UNSUPPORTED;\r
218\r
219 }\r
220\r
221 mS3Parameter->StorePosition ++;\r
222 DEBUG ((DEBUG_INFO, "QncS3SetDispatchItem() End\n"));\r
223\r
224 return EFI_SUCCESS;\r
225}\r
226\r
227EFI_STATUS\r
228LoadQncS3Image (\r
229 IN EFI_SYSTEM_TABLE *SystemTable\r
230 )\r
231/*++\r
232\r
233Routine Description:\r
234\r
235 Load the QNC S3 Image into Efi Reserved Memory below 4G.\r
236\r
237Arguments:\r
238\r
239 ImageEntryPoint the ImageEntryPoint after success loading\r
240\r
241Returns:\r
242\r
243 EFI_STATUS\r
244\r
245--*/\r
246{\r
247 EFI_STATUS Status;\r
248 UINT8 *Buffer;\r
249 UINTN BufferSize;\r
250 VOID *FfsBuffer;\r
251 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
252 EFI_HANDLE NewImageHandle;\r
253\r
254 //\r
255 // Install NULL protocol on module file handle to indicate that the entry point\r
256 // has been called for the first time.\r
257 //\r
258 NewImageHandle = NULL;\r
259 Status = gBS->InstallProtocolInterface (\r
260 &NewImageHandle,\r
261 &gEfiCallerIdGuid,\r
262 EFI_NATIVE_INTERFACE,\r
263 NULL\r
264 );\r
265\r
266\r
267 //\r
268 // Find this module so it can be loaded again.\r
269 //\r
270 Status = GetSectionFromAnyFv (\r
271 &gEfiCallerIdGuid,\r
272 EFI_SECTION_PE32,\r
273 0,\r
274 (VOID**) &Buffer,\r
275 &BufferSize\r
276 );\r
277 if (EFI_ERROR (Status)) {\r
278 return Status;\r
279 }\r
280\r
281\r
282 //\r
283 // Get information about the image being loaded.\r
284 //\r
285 ImageContext.Handle = Buffer;\r
286 ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
287\r
288 //\r
289 // Get information about the image being loaded\r
290 //\r
291 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
292 ASSERT_EFI_ERROR (Status);\r
293 if (EFI_ERROR (Status)) {\r
294 return Status;\r
295 }\r
296\r
297 Status = gBS->AllocatePool (\r
298 EfiReservedMemoryType,\r
299 BufferSize + ImageContext.SectionAlignment,\r
300 &FfsBuffer\r
301 );\r
302 ASSERT_EFI_ERROR (Status);\r
303 if (EFI_ERROR (Status)) {\r
304 DEBUG ((DEBUG_INFO, "LoadQncS3Image failed for no enough space! \n"));\r
305 return EFI_OUT_OF_RESOURCES;\r
306 }\r
307\r
308 mQncS3ImageAddress = FfsBuffer;\r
309 mQncS3ImageSize = BufferSize + ImageContext.SectionAlignment;\r
310 Status = PcdSet64S (PcdQncS3CodeInLockBoxAddress, (UINT64)(UINTN)mQncS3ImageAddress);\r
311 ASSERT_EFI_ERROR (Status);\r
312 Status = PcdSet64S (PcdQncS3CodeInLockBoxSize, (UINT64)mQncS3ImageSize);\r
313 ASSERT_EFI_ERROR (Status);\r
314 //\r
74c6a103 315 // Align buffer on section boundary\r
9b6bbcdb
MK
316 //\r
317 ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer;\r
318 if (ImageContext.SectionAlignment != 0) {\r
319 ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;\r
320 ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);\r
321 }\r
322\r
323 //\r
324 // Load the image to our new buffer\r
325 //\r
326 Status = PeCoffLoaderLoadImage (&ImageContext);\r
327 if (EFI_ERROR (Status)) {\r
328 gBS->FreePool (FfsBuffer);\r
329 DEBUG ((DEBUG_INFO, "LoadQncS3Image failed for PeCoffLoaderLoadImage failure! \n"));\r
330 return Status;\r
331 }\r
332\r
333 //\r
334 // Relocate the image in our new buffer\r
335 //\r
336 Status = PeCoffLoaderRelocateImage (&ImageContext);\r
337 if (EFI_ERROR (Status)) {\r
338 PeCoffLoaderUnloadImage (&ImageContext);\r
339 gBS->FreePool (FfsBuffer);\r
340 DEBUG ((DEBUG_INFO, "LoadQncS3Image failed for PeCoffLoaderRelocateImage failure! \n"));\r
341 return Status;\r
342 }\r
343\r
344 //\r
345 // Invalidate instruction cache and pass control to the image. This will perform\r
346 // the initialization of the module and publish the supporting protocols.\r
347 //\r
348 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);\r
349 Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable);\r
350 if (EFI_ERROR (Status)) {\r
351 gBS->FreePool (FfsBuffer);\r
352 return Status;\r
353 }\r
354\r
355 return EFI_SUCCESS;\r
356\r
357}\r
358\r
359EFI_STATUS\r
360QncS3InitPcieRootPortDownstream (\r
361 IN EFI_HANDLE ImageHandle,\r
362 IN VOID *Context\r
363 )\r
364/*++\r
365\r
366 Routine Description:\r
367 Perform Init Root Port Downstream devices on S3 resume\r
368\r
369 Arguments:\r
370 Parameter Parameters passed in from DXE\r
371\r
372 Returns:\r
373 EFI_STATUS\r
374\r
375--*/\r
376{\r
377 EFI_STATUS Status;\r
378\r
379 DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream() Begin\n"));\r
380\r
381 //\r
382 // Initialize the device behind the root port.\r
383 //\r
384 Status = PciExpressInit ();\r
385\r
386 //\r
387 // Not checking the error status here - downstream device not present does not\r
388 // mean an error of this root port. Our return status of EFI_SUCCESS means this\r
389 // port is enabled and outer function depends on this return status to do\r
390 // subsequent initializations.\r
391 //\r
392\r
393 if (Status != EFI_SUCCESS){\r
394 DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream() failed\n"));\r
395 }\r
396\r
397 DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream() End\n"));\r
398 return Status;\r
399}\r
400\r
401VOID\r
402EFIAPI\r
403QncS3BootEvent (\r
404 IN EFI_EVENT Event,\r
405 IN VOID *Context\r
406 )\r
407{\r
408 EFI_STATUS Status;\r
409\r
410 //\r
411 // These 2 boxes will be restored by RestoreAllLockBoxInPlace in S3Resume automatically\r
412 //\r
413 DEBUG ((DEBUG_INFO, "SaveLockBox QncS3Code = %08x, Size = %08x\n", (UINTN)mQncS3ImageAddress, mQncS3ImageSize));\r
414 SaveLockBox(&gQncS3CodeInLockBoxGuid, mQncS3ImageAddress, mQncS3ImageSize);\r
415 Status = SetLockBoxAttributes (&gQncS3CodeInLockBoxGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
416 ASSERT_EFI_ERROR (Status);\r
417\r
418 DEBUG ((DEBUG_INFO, "SaveLockBox QncS3Context = %08x, Size = %08x\n", (UINTN)mS3Parameter, EFI_PAGE_SIZE));\r
419 SaveLockBox(&gQncS3ContextInLockBoxGuid, (VOID *)mS3Parameter, EFI_PAGE_SIZE);\r
420 Status = SetLockBoxAttributes (&gQncS3ContextInLockBoxGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
421 ASSERT_EFI_ERROR (Status);\r
422}\r
423\r