+++ /dev/null
-/** @file\r
-This is the driver that implements the QNC S3 Support protocol\r
-\r
-Copyright (c) 2013-2016 Intel Corporation.\r
-\r
-SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-#include "QncS3Support.h"\r
-\r
-//\r
-// Global Variables\r
-//\r
-EFI_QNC_S3_SUPPORT_PROTOCOL mQncS3SupportProtocol;\r
-QNC_S3_PARAMETER_HEADER *mS3Parameter;\r
-UINT32 mQncS3ImageEntryPoint;\r
-VOID *mQncS3ImageAddress;\r
-UINTN mQncS3ImageSize;\r
-\r
-extern EFI_GUID gQncS3CodeInLockBoxGuid;\r
-extern EFI_GUID gQncS3ContextInLockBoxGuid;\r
-\r
-/**\r
-\r
- Create a buffer that is used to store context information for use with\r
- dispatch functions.\r
-\r
- @retval EFI_SUCCESS - Buffer allocated and initialized.\r
-\r
-**/\r
-EFI_STATUS\r
-CreateContextBuffer (\r
- VOID\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_PHYSICAL_ADDRESS Address;\r
- UINT32 ContextStoreSize;\r
-\r
- ContextStoreSize = EFI_PAGE_SIZE;\r
-\r
- //\r
- // Allcoate <4G EfiReservedMemory\r
- //\r
- Address = 0xFFFFFFFF;\r
- Status = gBS->AllocatePages (AllocateMaxAddress, EfiReservedMemoryType, EFI_SIZE_TO_PAGES (ContextStoreSize), &Address);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- mS3Parameter = (QNC_S3_PARAMETER_HEADER *) (UINTN) Address;\r
-\r
- //\r
- // Determine the maximum number of context entries that can be stored in this\r
- // table.\r
- //\r
- mS3Parameter->MaxContexts = ((ContextStoreSize - sizeof(QNC_S3_PARAMETER_HEADER)) / sizeof(EFI_DISPATCH_CONTEXT_UNION)) + 1;\r
- mS3Parameter->StorePosition = 0;\r
-\r
- return Status;\r
-}\r
-\r
-//\r
-// Functions\r
-//\r
-EFI_STATUS\r
-EFIAPI\r
-QncS3SupportEntryPoint (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-/*++\r
-\r
- Routine Description:\r
-\r
- QNC S3 support driver entry point\r
-\r
- Arguments:\r
-\r
- ImageHandle - Handle for the image of this driver\r
- SystemTable - Pointer to the EFI System Table\r
-\r
- Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- EFI_STATUS Status;\r
- VOID *TmpPtr;\r
- EFI_EVENT Event;\r
-\r
- //\r
- // If the protocol is found execution is happening in ACPI NVS memory. If it\r
- // is not found copy the driver into ACPI NVS memory and pass control to it.\r
- //\r
- Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &TmpPtr);\r
-\r
- //\r
- // Load the QNC S3 image\r
- //\r
- if (EFI_ERROR (Status)) {\r
- Status = LoadQncS3Image (SystemTable);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- } else {\r
- DEBUG ((DEBUG_INFO, "QncS3SupportEntryPoint() in reserved memory - Begin\n"));\r
- //\r
- // Allocate and initialize context buffer.\r
- //\r
- Status = CreateContextBuffer ();\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // Install the QNC S3 Support protocol\r
- //\r
- mQncS3SupportProtocol.SetDispatchItem = QncS3SetDispatchItem;\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- &ImageHandle,\r
- &gEfiQncS3SupportProtocolGuid,\r
- &mQncS3SupportProtocol,\r
- NULL\r
- );\r
-\r
- mQncS3ImageAddress = (VOID *)(UINTN)PcdGet64(PcdQncS3CodeInLockBoxAddress);\r
- mQncS3ImageSize = (UINTN)PcdGet64(PcdQncS3CodeInLockBoxSize);\r
- DEBUG ((DEBUG_INFO, "QncS3SupportEntry Code = %08x, Size = %08x\n", (UINTN)mQncS3ImageAddress, mQncS3ImageSize));\r
- DEBUG ((DEBUG_INFO, "QncS3SupportEntry Contex = %08x, Size = %08x\n", (UINTN)mS3Parameter, EFI_PAGE_SIZE));\r
- ASSERT (mQncS3ImageAddress != 0);\r
-\r
- //\r
- // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.\r
- //\r
- Status = gBS->CreateEventEx (\r
- EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
- QncS3BootEvent,\r
- NULL,\r
- &gEfiEndOfDxeEventGroupGuid,\r
- &Event\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- DEBUG ((DEBUG_INFO, "QncS3SupportEntryPoint() in reserved memory - End\n"));\r
- }\r
-\r
-\r
-\r
- return Status;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-QncS3SetDispatchItem (\r
- IN EFI_QNC_S3_SUPPORT_PROTOCOL *This,\r
- IN EFI_QNC_S3_DISPATCH_ITEM *DispatchItem,\r
- OUT VOID **S3DispatchEntryPoint,\r
- OUT VOID **Context\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Set an item to be dispatched at S3 resume time. At the same time, the entry point\r
- of the QNC S3 support image is returned to be used in subsequent boot script save\r
- call\r
-\r
-Arguments:\r
-\r
- This - Pointer to the protocol instance.\r
- DispatchItem - The item to be dispatched.\r
- S3DispatchEntryPoint - The entry point of the QNC S3 support image.\r
-\r
-Returns:\r
-\r
- EFI_STATUS - Successfully completed.\r
- EFI_OUT_OF_RESOURCES - Out of resources.\r
-\r
---*/\r
-{\r
-\r
- DEBUG ((DEBUG_INFO, "QncS3SetDispatchItem() Start\n"));\r
-\r
- //\r
- // Set default values.\r
- //\r
- *S3DispatchEntryPoint = NULL;\r
- *Context = NULL;\r
-\r
- //\r
- // Determine if this entry will fit.\r
- //\r
- if (mS3Parameter->StorePosition >= mS3Parameter->MaxContexts) {\r
- DEBUG ((DEBUG_INFO, "QncS3SetDispatchItem exceeds max length - 0x%08x\n", (UINTN)mS3Parameter->MaxContexts));\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- //\r
- // Calculate the size required;\r
- // ** Always round up to be 8 byte aligned\r
- //\r
- switch (DispatchItem->Type) {\r
- case QncS3ItemTypeInitPcieRootPortDownstream:\r
- *S3DispatchEntryPoint = (VOID*) (UINTN)QncS3InitPcieRootPortDownstream;\r
- *Context = &mS3Parameter->Contexts[mS3Parameter->StorePosition];\r
- CopyMem (&mS3Parameter->Contexts[mS3Parameter->StorePosition], DispatchItem->Parameter, sizeof(UINT32));\r
- DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream @ 0x%08x - context 0x%08x\n", (UINTN)*S3DispatchEntryPoint, (UINTN)*Context));\r
- break;\r
-\r
- default:\r
- return EFI_UNSUPPORTED;\r
-\r
- }\r
-\r
- mS3Parameter->StorePosition ++;\r
- DEBUG ((DEBUG_INFO, "QncS3SetDispatchItem() End\n"));\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-LoadQncS3Image (\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Load the QNC S3 Image into Efi Reserved Memory below 4G.\r
-\r
-Arguments:\r
-\r
- ImageEntryPoint the ImageEntryPoint after success loading\r
-\r
-Returns:\r
-\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- EFI_STATUS Status;\r
- UINT8 *Buffer;\r
- UINTN BufferSize;\r
- VOID *FfsBuffer;\r
- PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
- EFI_HANDLE NewImageHandle;\r
-\r
- //\r
- // Install NULL protocol on module file handle to indicate that the entry point\r
- // has been called for the first time.\r
- //\r
- NewImageHandle = NULL;\r
- Status = gBS->InstallProtocolInterface (\r
- &NewImageHandle,\r
- &gEfiCallerIdGuid,\r
- EFI_NATIVE_INTERFACE,\r
- NULL\r
- );\r
-\r
-\r
- //\r
- // Find this module so it can be loaded again.\r
- //\r
- Status = GetSectionFromAnyFv (\r
- &gEfiCallerIdGuid,\r
- EFI_SECTION_PE32,\r
- 0,\r
- (VOID**) &Buffer,\r
- &BufferSize\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
-\r
- //\r
- // Get information about the image being loaded.\r
- //\r
- ImageContext.Handle = Buffer;\r
- ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
-\r
- //\r
- // Get information about the image being loaded\r
- //\r
- Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
- ASSERT_EFI_ERROR (Status);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- Status = gBS->AllocatePool (\r
- EfiReservedMemoryType,\r
- BufferSize + ImageContext.SectionAlignment,\r
- &FfsBuffer\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((DEBUG_INFO, "LoadQncS3Image failed for no enough space! \n"));\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- mQncS3ImageAddress = FfsBuffer;\r
- mQncS3ImageSize = BufferSize + ImageContext.SectionAlignment;\r
- Status = PcdSet64S (PcdQncS3CodeInLockBoxAddress, (UINT64)(UINTN)mQncS3ImageAddress);\r
- ASSERT_EFI_ERROR (Status);\r
- Status = PcdSet64S (PcdQncS3CodeInLockBoxSize, (UINT64)mQncS3ImageSize);\r
- ASSERT_EFI_ERROR (Status);\r
- //\r
- // Align buffer on section boundary\r
- //\r
- ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer;\r
- if (ImageContext.SectionAlignment != 0) {\r
- ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;\r
- ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);\r
- }\r
-\r
- //\r
- // Load the image to our new buffer\r
- //\r
- Status = PeCoffLoaderLoadImage (&ImageContext);\r
- if (EFI_ERROR (Status)) {\r
- gBS->FreePool (FfsBuffer);\r
- DEBUG ((DEBUG_INFO, "LoadQncS3Image failed for PeCoffLoaderLoadImage failure! \n"));\r
- return Status;\r
- }\r
-\r
- //\r
- // Relocate the image in our new buffer\r
- //\r
- Status = PeCoffLoaderRelocateImage (&ImageContext);\r
- if (EFI_ERROR (Status)) {\r
- PeCoffLoaderUnloadImage (&ImageContext);\r
- gBS->FreePool (FfsBuffer);\r
- DEBUG ((DEBUG_INFO, "LoadQncS3Image failed for PeCoffLoaderRelocateImage failure! \n"));\r
- return Status;\r
- }\r
-\r
- //\r
- // Invalidate instruction cache and pass control to the image. This will perform\r
- // the initialization of the module and publish the supporting protocols.\r
- //\r
- InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);\r
- Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable);\r
- if (EFI_ERROR (Status)) {\r
- gBS->FreePool (FfsBuffer);\r
- return Status;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-\r
-}\r
-\r
-EFI_STATUS\r
-QncS3InitPcieRootPortDownstream (\r
- IN EFI_HANDLE ImageHandle,\r
- IN VOID *Context\r
- )\r
-/*++\r
-\r
- Routine Description:\r
- Perform Init Root Port Downstream devices on S3 resume\r
-\r
- Arguments:\r
- Parameter Parameters passed in from DXE\r
-\r
- Returns:\r
- EFI_STATUS\r
-\r
---*/\r
-{\r
- EFI_STATUS Status;\r
-\r
- DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream() Begin\n"));\r
-\r
- //\r
- // Initialize the device behind the root port.\r
- //\r
- Status = PciExpressInit ();\r
-\r
- //\r
- // Not checking the error status here - downstream device not present does not\r
- // mean an error of this root port. Our return status of EFI_SUCCESS means this\r
- // port is enabled and outer function depends on this return status to do\r
- // subsequent initializations.\r
- //\r
-\r
- if (Status != EFI_SUCCESS){\r
- DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream() failed\n"));\r
- }\r
-\r
- DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream() End\n"));\r
- return Status;\r
-}\r
-\r
-VOID\r
-EFIAPI\r
-QncS3BootEvent (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- //\r
- // These 2 boxes will be restored by RestoreAllLockBoxInPlace in S3Resume automatically\r
- //\r
- DEBUG ((DEBUG_INFO, "SaveLockBox QncS3Code = %08x, Size = %08x\n", (UINTN)mQncS3ImageAddress, mQncS3ImageSize));\r
- SaveLockBox(&gQncS3CodeInLockBoxGuid, mQncS3ImageAddress, mQncS3ImageSize);\r
- Status = SetLockBoxAttributes (&gQncS3CodeInLockBoxGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- DEBUG ((DEBUG_INFO, "SaveLockBox QncS3Context = %08x, Size = %08x\n", (UINTN)mS3Parameter, EFI_PAGE_SIZE));\r
- SaveLockBox(&gQncS3ContextInLockBoxGuid, (VOID *)mS3Parameter, EFI_PAGE_SIZE);\r
- Status = SetLockBoxAttributes (&gQncS3ContextInLockBoxGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
- ASSERT_EFI_ERROR (Status);\r
-}\r
-\r