2 This is the driver that implements the QNC S3 Support protocol
4 Copyright (c) 2013-2016 Intel Corporation.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "QncS3Support.h"
14 EFI_QNC_S3_SUPPORT_PROTOCOL mQncS3SupportProtocol
;
15 QNC_S3_PARAMETER_HEADER
*mS3Parameter
;
16 UINT32 mQncS3ImageEntryPoint
;
17 VOID
*mQncS3ImageAddress
;
18 UINTN mQncS3ImageSize
;
20 extern EFI_GUID gQncS3CodeInLockBoxGuid
;
21 extern EFI_GUID gQncS3ContextInLockBoxGuid
;
25 Create a buffer that is used to store context information for use with
28 @retval EFI_SUCCESS - Buffer allocated and initialized.
37 EFI_PHYSICAL_ADDRESS Address
;
38 UINT32 ContextStoreSize
;
40 ContextStoreSize
= EFI_PAGE_SIZE
;
43 // Allcoate <4G EfiReservedMemory
46 Status
= gBS
->AllocatePages (AllocateMaxAddress
, EfiReservedMemoryType
, EFI_SIZE_TO_PAGES (ContextStoreSize
), &Address
);
47 if (EFI_ERROR (Status
)) {
50 mS3Parameter
= (QNC_S3_PARAMETER_HEADER
*) (UINTN
) Address
;
53 // Determine the maximum number of context entries that can be stored in this
56 mS3Parameter
->MaxContexts
= ((ContextStoreSize
- sizeof(QNC_S3_PARAMETER_HEADER
)) / sizeof(EFI_DISPATCH_CONTEXT_UNION
)) + 1;
57 mS3Parameter
->StorePosition
= 0;
67 QncS3SupportEntryPoint (
68 IN EFI_HANDLE ImageHandle
,
69 IN EFI_SYSTEM_TABLE
*SystemTable
75 QNC S3 support driver entry point
79 ImageHandle - Handle for the image of this driver
80 SystemTable - Pointer to the EFI System Table
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.
96 Status
= gBS
->LocateProtocol (&gEfiCallerIdGuid
, NULL
, &TmpPtr
);
99 // Load the QNC S3 image
101 if (EFI_ERROR (Status
)) {
102 Status
= LoadQncS3Image (SystemTable
);
103 ASSERT_EFI_ERROR (Status
);
106 DEBUG ((DEBUG_INFO
, "QncS3SupportEntryPoint() in reserved memory - Begin\n"));
108 // Allocate and initialize context buffer.
110 Status
= CreateContextBuffer ();
112 if (EFI_ERROR (Status
)) {
116 // Install the QNC S3 Support protocol
118 mQncS3SupportProtocol
.SetDispatchItem
= QncS3SetDispatchItem
;
119 Status
= gBS
->InstallMultipleProtocolInterfaces (
121 &gEfiQncS3SupportProtocolGuid
,
122 &mQncS3SupportProtocol
,
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);
133 // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
135 Status
= gBS
->CreateEventEx (
140 &gEfiEndOfDxeEventGroupGuid
,
143 ASSERT_EFI_ERROR (Status
);
145 DEBUG ((DEBUG_INFO
, "QncS3SupportEntryPoint() in reserved memory - End\n"));
155 QncS3SetDispatchItem (
156 IN EFI_QNC_S3_SUPPORT_PROTOCOL
*This
,
157 IN EFI_QNC_S3_DISPATCH_ITEM
*DispatchItem
,
158 OUT VOID
**S3DispatchEntryPoint
,
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
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.
177 EFI_STATUS - Successfully completed.
178 EFI_OUT_OF_RESOURCES - Out of resources.
183 DEBUG ((DEBUG_INFO
, "QncS3SetDispatchItem() Start\n"));
186 // Set default values.
188 *S3DispatchEntryPoint
= NULL
;
192 // Determine if this entry will fit.
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
;
199 // Calculate the size required;
200 // ** Always round up to be 8 byte aligned
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
));
211 return EFI_UNSUPPORTED
;
215 mS3Parameter
->StorePosition
++;
216 DEBUG ((DEBUG_INFO
, "QncS3SetDispatchItem() End\n"));
223 IN EFI_SYSTEM_TABLE
*SystemTable
229 Load the QNC S3 Image into Efi Reserved Memory below 4G.
233 ImageEntryPoint the ImageEntryPoint after success loading
245 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
246 EFI_HANDLE NewImageHandle
;
249 // Install NULL protocol on module file handle to indicate that the entry point
250 // has been called for the first time.
252 NewImageHandle
= NULL
;
253 Status
= gBS
->InstallProtocolInterface (
256 EFI_NATIVE_INTERFACE
,
262 // Find this module so it can be loaded again.
264 Status
= GetSectionFromAnyFv (
271 if (EFI_ERROR (Status
)) {
277 // Get information about the image being loaded.
279 ImageContext
.Handle
= Buffer
;
280 ImageContext
.ImageRead
= PeCoffLoaderImageReadFromMemory
;
283 // Get information about the image being loaded
285 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
286 ASSERT_EFI_ERROR (Status
);
287 if (EFI_ERROR (Status
)) {
291 Status
= gBS
->AllocatePool (
292 EfiReservedMemoryType
,
293 BufferSize
+ ImageContext
.SectionAlignment
,
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
;
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
);
309 // Align buffer on section boundary
311 ImageContext
.ImageAddress
= (PHYSICAL_ADDRESS
)(UINTN
)FfsBuffer
;
312 if (ImageContext
.SectionAlignment
!= 0) {
313 ImageContext
.ImageAddress
+= ImageContext
.SectionAlignment
- 1;
314 ImageContext
.ImageAddress
&= ~(ImageContext
.SectionAlignment
- 1);
318 // Load the image to our new buffer
320 Status
= PeCoffLoaderLoadImage (&ImageContext
);
321 if (EFI_ERROR (Status
)) {
322 gBS
->FreePool (FfsBuffer
);
323 DEBUG ((DEBUG_INFO
, "LoadQncS3Image failed for PeCoffLoaderLoadImage failure! \n"));
328 // Relocate the image in our new buffer
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"));
339 // Invalidate instruction cache and pass control to the image. This will perform
340 // the initialization of the module and publish the supporting protocols.
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
);
354 QncS3InitPcieRootPortDownstream (
355 IN EFI_HANDLE ImageHandle
,
361 Perform Init Root Port Downstream devices on S3 resume
364 Parameter Parameters passed in from DXE
373 DEBUG ((DEBUG_INFO
, "QncS3InitPcieRootPortDownstream() Begin\n"));
376 // Initialize the device behind the root port.
378 Status
= PciExpressInit ();
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.
387 if (Status
!= EFI_SUCCESS
){
388 DEBUG ((DEBUG_INFO
, "QncS3InitPcieRootPortDownstream() failed\n"));
391 DEBUG ((DEBUG_INFO
, "QncS3InitPcieRootPortDownstream() End\n"));
405 // These 2 boxes will be restored by RestoreAllLockBoxInPlace in S3Resume automatically
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
);
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
);