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