2 This is the driver that implements the QNC S3 Support protocol
4 Copyright (c) 2013-2015 Intel Corporation.
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "QncS3Support.h"
20 EFI_QNC_S3_SUPPORT_PROTOCOL mQncS3SupportProtocol
;
21 QNC_S3_PARAMETER_HEADER
*mS3Parameter
;
22 UINT32 mQncS3ImageEntryPoint
;
23 VOID
*mQncS3ImageAddress
;
24 UINTN mQncS3ImageSize
;
26 extern EFI_GUID gQncS3CodeInLockBoxGuid
;
27 extern EFI_GUID gQncS3ContextInLockBoxGuid
;
31 Create a buffer that is used to store context information for use with
34 @retval EFI_SUCCESS - Buffer allocated and initialized.
43 EFI_PHYSICAL_ADDRESS Address
;
44 UINT32 ContextStoreSize
;
46 ContextStoreSize
= EFI_PAGE_SIZE
;
49 // Allcoate <4G EfiReservedMemory
52 Status
= gBS
->AllocatePages (AllocateMaxAddress
, EfiReservedMemoryType
, EFI_SIZE_TO_PAGES (ContextStoreSize
), &Address
);
53 if (EFI_ERROR (Status
)) {
56 mS3Parameter
= (QNC_S3_PARAMETER_HEADER
*) (UINTN
) Address
;
59 // Determine the maximum number of context entries that can be stored in this
62 mS3Parameter
->MaxContexts
= ((ContextStoreSize
- sizeof(QNC_S3_PARAMETER_HEADER
)) / sizeof(EFI_DISPATCH_CONTEXT_UNION
)) + 1;
63 mS3Parameter
->StorePosition
= 0;
73 QncS3SupportEntryPoint (
74 IN EFI_HANDLE ImageHandle
,
75 IN EFI_SYSTEM_TABLE
*SystemTable
81 QNC S3 support driver entry point
85 ImageHandle - Handle for the image of this driver
86 SystemTable - Pointer to the EFI System Table
99 // If the protocol is found execution is happening in ACPI NVS memory. If it
100 // is not found copy the driver into ACPI NVS memory and pass control to it.
102 Status
= gBS
->LocateProtocol (&gEfiCallerIdGuid
, NULL
, &TmpPtr
);
105 // Load the QNC S3 image
107 if (EFI_ERROR (Status
)) {
108 Status
= LoadQncS3Image (SystemTable
);
109 ASSERT_EFI_ERROR (Status
);
112 DEBUG ((DEBUG_INFO
, "QncS3SupportEntryPoint() in reserved memory - Begin\n"));
114 // Allocate and initialize context buffer.
116 Status
= CreateContextBuffer ();
118 if (EFI_ERROR (Status
)) {
122 // Install the QNC S3 Support protocol
124 mQncS3SupportProtocol
.SetDispatchItem
= QncS3SetDispatchItem
;
125 Status
= gBS
->InstallMultipleProtocolInterfaces (
127 &gEfiQncS3SupportProtocolGuid
,
128 &mQncS3SupportProtocol
,
132 mQncS3ImageAddress
= (VOID
*)(UINTN
)PcdGet64(PcdQncS3CodeInLockBoxAddress
);
133 mQncS3ImageSize
= (UINTN
)PcdGet64(PcdQncS3CodeInLockBoxSize
);
134 DEBUG ((DEBUG_INFO
, "QncS3SupportEntry Code = %08x, Size = %08x\n", (UINTN
)mQncS3ImageAddress
, mQncS3ImageSize
));
135 DEBUG ((DEBUG_INFO
, "QncS3SupportEntry Contex = %08x, Size = %08x\n", (UINTN
)mS3Parameter
, EFI_PAGE_SIZE
));
136 ASSERT (mQncS3ImageAddress
!= 0);
139 // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
141 Status
= gBS
->CreateEventEx (
146 &gEfiEndOfDxeEventGroupGuid
,
149 ASSERT_EFI_ERROR (Status
);
151 DEBUG ((DEBUG_INFO
, "QncS3SupportEntryPoint() in reserved memory - End\n"));
161 QncS3SetDispatchItem (
162 IN EFI_QNC_S3_SUPPORT_PROTOCOL
*This
,
163 IN EFI_QNC_S3_DISPATCH_ITEM
*DispatchItem
,
164 OUT VOID
**S3DispatchEntryPoint
,
171 Set an item to be dispatched at S3 resume time. At the same time, the entry point
172 of the QNC S3 support image is returned to be used in subsequent boot script save
177 This - Pointer to the protocol instance.
178 DispatchItem - The item to be dispatched.
179 S3DispatchEntryPoint - The entry point of the QNC S3 support image.
183 EFI_STATUS - Successfully completed.
184 EFI_OUT_OF_RESOURCES - Out of resources.
189 DEBUG ((DEBUG_INFO
, "QncS3SetDispatchItem() Start\n"));
192 // Set default values.
194 *S3DispatchEntryPoint
= NULL
;
198 // Determine if this entry will fit.
200 if (mS3Parameter
->StorePosition
>= mS3Parameter
->MaxContexts
) {
201 DEBUG ((DEBUG_INFO
, "QncS3SetDispatchItem exceeds max length - 0x%08x\n", (UINTN
)mS3Parameter
->MaxContexts
));
202 return EFI_OUT_OF_RESOURCES
;
205 // Calculate the size required;
206 // ** Always round up to be 8 byte aligned
208 switch (DispatchItem
->Type
) {
209 case QncS3ItemTypeInitPcieRootPortDownstream
:
210 *S3DispatchEntryPoint
= (VOID
*) (UINTN
)QncS3InitPcieRootPortDownstream
;
211 *Context
= &mS3Parameter
->Contexts
[mS3Parameter
->StorePosition
];
212 CopyMem (&mS3Parameter
->Contexts
[mS3Parameter
->StorePosition
], DispatchItem
->Parameter
, sizeof(UINT32
));
213 DEBUG ((DEBUG_INFO
, "QncS3InitPcieRootPortDownstream @ 0x%08x - context 0x%08x\n", (UINTN
)*S3DispatchEntryPoint
, (UINTN
)*Context
));
217 return EFI_UNSUPPORTED
;
221 mS3Parameter
->StorePosition
++;
222 DEBUG ((DEBUG_INFO
, "QncS3SetDispatchItem() End\n"));
229 IN EFI_SYSTEM_TABLE
*SystemTable
235 Load the QNC S3 Image into Efi Reserved Memory below 4G.
239 ImageEntryPoint the ImageEntryPoint after success loading
251 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
252 EFI_HANDLE NewImageHandle
;
255 // Install NULL protocol on module file handle to indicate that the entry point
256 // has been called for the first time.
258 NewImageHandle
= NULL
;
259 Status
= gBS
->InstallProtocolInterface (
262 EFI_NATIVE_INTERFACE
,
268 // Find this module so it can be loaded again.
270 Status
= GetSectionFromAnyFv (
277 if (EFI_ERROR (Status
)) {
283 // Get information about the image being loaded.
285 ImageContext
.Handle
= Buffer
;
286 ImageContext
.ImageRead
= PeCoffLoaderImageReadFromMemory
;
289 // Get information about the image being loaded
291 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
292 ASSERT_EFI_ERROR (Status
);
293 if (EFI_ERROR (Status
)) {
297 Status
= gBS
->AllocatePool (
298 EfiReservedMemoryType
,
299 BufferSize
+ ImageContext
.SectionAlignment
,
302 ASSERT_EFI_ERROR (Status
);
303 if (EFI_ERROR (Status
)) {
304 DEBUG ((DEBUG_INFO
, "LoadQncS3Image failed for no enough space! \n"));
305 return EFI_OUT_OF_RESOURCES
;
308 mQncS3ImageAddress
= FfsBuffer
;
309 mQncS3ImageSize
= BufferSize
+ ImageContext
.SectionAlignment
;
310 Status
= PcdSet64S (PcdQncS3CodeInLockBoxAddress
, (UINT64
)(UINTN
)mQncS3ImageAddress
);
311 ASSERT_EFI_ERROR (Status
);
312 Status
= PcdSet64S (PcdQncS3CodeInLockBoxSize
, (UINT64
)mQncS3ImageSize
);
313 ASSERT_EFI_ERROR (Status
);
315 // Align buffer on section boundry
317 ImageContext
.ImageAddress
= (PHYSICAL_ADDRESS
)(UINTN
)FfsBuffer
;
318 if (ImageContext
.SectionAlignment
!= 0) {
319 ImageContext
.ImageAddress
+= ImageContext
.SectionAlignment
- 1;
320 ImageContext
.ImageAddress
&= ~(ImageContext
.SectionAlignment
- 1);
324 // Load the image to our new buffer
326 Status
= PeCoffLoaderLoadImage (&ImageContext
);
327 if (EFI_ERROR (Status
)) {
328 gBS
->FreePool (FfsBuffer
);
329 DEBUG ((DEBUG_INFO
, "LoadQncS3Image failed for PeCoffLoaderLoadImage failure! \n"));
334 // Relocate the image in our new buffer
336 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
337 if (EFI_ERROR (Status
)) {
338 PeCoffLoaderUnloadImage (&ImageContext
);
339 gBS
->FreePool (FfsBuffer
);
340 DEBUG ((DEBUG_INFO
, "LoadQncS3Image failed for PeCoffLoaderRelocateImage failure! \n"));
345 // Invalidate instruction cache and pass control to the image. This will perform
346 // the initialization of the module and publish the supporting protocols.
348 InvalidateInstructionCacheRange ((VOID
*)(UINTN
)ImageContext
.ImageAddress
, (UINTN
)ImageContext
.ImageSize
);
349 Status
= ((EFI_IMAGE_ENTRY_POINT
)(UINTN
)(ImageContext
.EntryPoint
)) (NewImageHandle
, SystemTable
);
350 if (EFI_ERROR (Status
)) {
351 gBS
->FreePool (FfsBuffer
);
360 QncS3InitPcieRootPortDownstream (
361 IN EFI_HANDLE ImageHandle
,
367 Perform Init Root Port Downstream devices on S3 resume
370 Parameter Parameters passed in from DXE
379 DEBUG ((DEBUG_INFO
, "QncS3InitPcieRootPortDownstream() Begin\n"));
382 // Initialize the device behind the root port.
384 Status
= PciExpressInit ();
387 // Not checking the error status here - downstream device not present does not
388 // mean an error of this root port. Our return status of EFI_SUCCESS means this
389 // port is enabled and outer function depends on this return status to do
390 // subsequent initializations.
393 if (Status
!= EFI_SUCCESS
){
394 DEBUG ((DEBUG_INFO
, "QncS3InitPcieRootPortDownstream() failed\n"));
397 DEBUG ((DEBUG_INFO
, "QncS3InitPcieRootPortDownstream() End\n"));
411 // These 2 boxes will be restored by RestoreAllLockBoxInPlace in S3Resume automatically
413 DEBUG ((DEBUG_INFO
, "SaveLockBox QncS3Code = %08x, Size = %08x\n", (UINTN
)mQncS3ImageAddress
, mQncS3ImageSize
));
414 SaveLockBox(&gQncS3CodeInLockBoxGuid
, mQncS3ImageAddress
, mQncS3ImageSize
);
415 Status
= SetLockBoxAttributes (&gQncS3CodeInLockBoxGuid
, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE
);
416 ASSERT_EFI_ERROR (Status
);
418 DEBUG ((DEBUG_INFO
, "SaveLockBox QncS3Context = %08x, Size = %08x\n", (UINTN
)mS3Parameter
, EFI_PAGE_SIZE
));
419 SaveLockBox(&gQncS3ContextInLockBoxGuid
, (VOID
*)mS3Parameter
, EFI_PAGE_SIZE
);
420 Status
= SetLockBoxAttributes (&gQncS3ContextInLockBoxGuid
, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE
);
421 ASSERT_EFI_ERROR (Status
);