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