+++ /dev/null
-/*++\r
-\r
-Copyright (c) 2006, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-Module Name:\r
-\r
- Runtime.c\r
-\r
-Abstract:\r
-\r
- Runtime Architectural Protocol as defined in the DXE CIS\r
-\r
- This code is used to produce the EFI runtime virtual switch over\r
-\r
- THIS IS VERY DANGEROUS CODE BE VERY CAREFUL IF YOU CHANGE IT\r
-\r
- The transition for calling EFI Runtime functions in physical mode to calling\r
- them in virtual mode is very very complex. Every pointer in needs to be\r
- converted from physical mode to virtual mode. Be very careful walking linked\r
- lists! Then to make it really hard the code it's self needs be relocated into\r
- the new virtual address space.\r
-\r
- So here is the concept. The code in this module will never ever be called in\r
- virtual mode. This is the code that collects the information needed to convert\r
- to virtual mode (DXE core registers runtime stuff with this code). Since this\r
- code is used to fixup all runtime images, it CAN NOT fix it's self up. So some\r
- code has to stay behind and that is us.\r
-\r
- Also you need to be careful about when you allocate memory, as once we are in\r
- runtime (including our EVT_SIGNAL_EXIT_BOOT_SERVICES event) you can no longer\r
- allocate memory.\r
-\r
- Any runtime driver that gets loaded before us will not be callable in virtual\r
- mode. This is due to the fact that the DXE core can not register the info\r
- needed with us. This is good, since it keeps the code in this file from\r
- getting registered.\r
-\r
-\r
-Revision History:\r
-\r
- - Move the CalculateCrc32 function from Runtime Arch Protocol to Boot Service.\r
- Runtime Arch Protocol definition no longer contains CalculateCrc32. Boot Service\r
- Table now contains an item named CalculateCrc32.\r
-\r
---*/\r
-\r
-\r
-#include "Runtime.h"\r
-\r
-//\r
-// Global Variables\r
-//\r
-EFI_MEMORY_DESCRIPTOR *mVirtualMap = NULL;\r
-UINTN mVirtualMapDescriptorSize;\r
-UINTN mVirtualMapMaxIndex;\r
-VOID *mMyImageBase;\r
-\r
-//\r
-// The handle onto which the Runtime Architectural Protocol instance is installed\r
-//\r
-EFI_HANDLE mRuntimeHandle = NULL;\r
-\r
-//\r
-// The Runtime Architectural Protocol instance produced by this driver\r
-//\r
-EFI_RUNTIME_ARCH_PROTOCOL mRuntime = {\r
- INITIALIZE_LIST_HEAD_VARIABLE (mRuntime.ImageHead),\r
- INITIALIZE_LIST_HEAD_VARIABLE (mRuntime.EventHead),\r
-\r
- //\r
- // Make sure Size != sizeof (EFI_MEMORY_DESCRIPTOR). This will\r
- // prevent people from having pointer math bugs in their code.\r
- // now you have to use *DescriptorSize to make things work.\r
- //\r
- sizeof (EFI_MEMORY_DESCRIPTOR) + sizeof (UINT64) - (sizeof (EFI_MEMORY_DESCRIPTOR) % sizeof (UINT64)),\r
- EFI_MEMORY_DESCRIPTOR_VERSION,\r
- 0,\r
- NULL,\r
- NULL,\r
- FALSE,\r
- FALSE\r
-};\r
-\r
-//\r
-// Worker Functions\r
-//\r
-STATIC\r
-VOID\r
-RuntimeDriverCalculateEfiHdrCrc (\r
- IN OUT EFI_TABLE_HEADER *Hdr\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Calcualte the 32-bit CRC in a EFI table using the Runtime Drivers\r
- internal function. The EFI Boot Services Table can not be used because\r
- the EFI Boot Services Table was destroyed at ExitBootServices()\r
-\r
-Arguments:\r
-\r
- Hdr - Pointer to an EFI standard header\r
-\r
-Returns:\r
-\r
- None\r
-\r
---*/\r
-{\r
- UINT32 Crc;\r
-\r
- Hdr->CRC32 = 0;\r
-\r
- Crc = 0;\r
- RuntimeDriverCalculateCrc32 ((UINT8 *) Hdr, Hdr->HeaderSize, &Crc);\r
- Hdr->CRC32 = Crc;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-RuntimeDriverConvertPointer (\r
- IN UINTN DebugDisposition,\r
- IN OUT VOID **ConvertAddress\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Determines the new virtual address that is to be used on subsequent memory accesses.\r
-\r
-Arguments:\r
-\r
- DebugDisposition - Supplies type information for the pointer being converted.\r
- ConvertAddress - A pointer to a pointer that is to be fixed to be the value needed\r
- for the new virtual address mappings being applied.\r
-\r
-Returns:\r
-\r
- EFI_SUCCESS - The pointer pointed to by Address was modified.\r
- EFI_NOT_FOUND - The pointer pointed to by Address was not found to be part\r
- of the current memory map. This is normally fatal.\r
- EFI_INVALID_PARAMETER - One of the parameters has an invalid value.\r
-\r
---*/\r
-{\r
- UINTN Address;\r
- VOID *PlabelConvertAddress;\r
- UINT64 VirtEndOfRange;\r
- EFI_MEMORY_DESCRIPTOR *VirtEntry;\r
- UINTN Index;\r
-\r
- //\r
- // Make sure ConvertAddress is a valid pointer\r
- //\r
- if (ConvertAddress == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- //\r
- // Get the address to convert\r
- //\r
- Address = (UINTN) *ConvertAddress;\r
-\r
- //\r
- // If this is a null pointer, return if it's allowed\r
- //\r
- if (Address == 0) {\r
- if (DebugDisposition & EFI_OPTIONAL_POINTER) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- PlabelConvertAddress = NULL;\r
- VirtEntry = mVirtualMap;\r
- for (Index = 0; Index < mVirtualMapMaxIndex; Index++) {\r
- //\r
- // To prevent the inclusion of 64-bit math functions a UINTN was placed in\r
- // front of VirtEntry->NumberOfPages to cast it to a 32-bit thing on IA-32\r
- // platforms. If you get this ASSERT remove the UINTN and do a 64-bit\r
- // multiply.\r
- //\r
- ASSERT (((UINTN) VirtEntry->NumberOfPages < 0xffffffff) || (sizeof (UINTN) > 4));\r
-\r
- if ((VirtEntry->Attribute & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {\r
- if (Address >= VirtEntry->PhysicalStart) {\r
- VirtEndOfRange = VirtEntry->PhysicalStart + (((UINTN) VirtEntry->NumberOfPages) * EFI_PAGE_SIZE);\r
- if (Address < VirtEndOfRange) {\r
- //\r
- // Compute new address\r
- //\r
- *ConvertAddress = (VOID *) (Address - (UINTN) VirtEntry->PhysicalStart + (UINTN) VirtEntry->VirtualStart);\r
- return EFI_SUCCESS;\r
- } else if (Address < (VirtEndOfRange + 0x200000)) {\r
- //\r
- // On Itanium GP defines a window +/- 2 MB inside an image.\r
- // The compiler may asign a GP value outside of the image. Thus\r
- // it could fall out side of any of our valid regions\r
- //\r
- PlabelConvertAddress = (VOID *) (Address - (UINTN) VirtEntry->PhysicalStart + (UINTN) VirtEntry->VirtualStart);\r
- }\r
- }\r
- }\r
-\r
- VirtEntry = NextMemoryDescriptor (VirtEntry, mVirtualMapDescriptorSize);\r
- }\r
-\r
- if (DebugDisposition & EFI_IPF_GP_POINTER) {\r
- //\r
- // If it's an IPF GP and the GP was outside the image handle that case.\r
- //\r
- if (PlabelConvertAddress != NULL) {\r
- *ConvertAddress = PlabelConvertAddress;\r
- return EFI_SUCCESS;\r
- }\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
-}\r
-\r
-STATIC\r
-EFI_STATUS\r
-RuntimeDriverConvertInternalPointer (\r
- IN OUT VOID **ConvertAddress\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Determines the new virtual address that is to be used on subsequent memory accesses\r
- for internal pointers.\r
-\r
-Arguments:\r
-\r
- ConvertAddress - A pointer to a pointer that is to be fixed to be the value needed\r
- for the new virtual address mappings being applied.\r
-\r
-Returns:\r
-\r
- EFI_SUCCESS - The pointer pointed to by Address was modified.\r
- EFI_NOT_FOUND - The pointer pointed to by Address was not found to be part\r
- of the current memory map. This is normally fatal.\r
- EFI_INVALID_PARAMETER - One of the parameters has an invalid value.\r
-\r
---*/\r
-{\r
- return RuntimeDriverConvertPointer (0x0, ConvertAddress);\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-RuntimeDriverSetVirtualAddressMap (\r
- IN UINTN MemoryMapSize,\r
- IN UINTN DescriptorSize,\r
- IN UINT32 DescriptorVersion,\r
- IN EFI_MEMORY_DESCRIPTOR *VirtualMap\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Changes the runtime addressing mode of EFI firmware from physical to virtual.\r
-\r
-Arguments:\r
-\r
- MemoryMapSize - The size in bytes of VirtualMap.\r
- DescriptorSize - The size in bytes of an entry in the VirtualMap.\r
- DescriptorVersion - The version of the structure entries in VirtualMap.\r
- VirtualMap - An array of memory descriptors which contain new virtual\r
- address mapping information for all runtime ranges.\r
-\r
-Returns:\r
-\r
- EFI_SUCCESS - The virtual address map has been applied.\r
- EFI_UNSUPPORTED - EFI firmware is not at runtime, or the EFI firmware is already in\r
- virtual address mapped mode.\r
- EFI_INVALID_PARAMETER - DescriptorSize or DescriptorVersion is invalid.\r
- EFI_NO_MAPPING - A virtual address was not supplied for a range in the memory\r
- map that requires a mapping.\r
- EFI_NOT_FOUND - A virtual address was supplied for an address that is not found\r
- in the memory map.\r
-\r
---*/\r
-{\r
- EFI_STATUS Status;\r
- EFI_RUNTIME_EVENT_ENTRY *RuntimeEvent;\r
- EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage;\r
- LIST_ENTRY *Link;\r
- UINTN Index;\r
- UINTN Index1;\r
- EFI_DRIVER_OS_HANDOFF_HEADER *DriverOsHandoffHeader;\r
- EFI_DRIVER_OS_HANDOFF *DriverOsHandoff;\r
- EFI_PHYSICAL_ADDRESS VirtImageBase;\r
- EFI_CAPSULE_TABLE *CapsuleTable;\r
-\r
- //\r
- // Can only switch to virtual addresses once the memory map is locked down,\r
- // and can only set it once\r
- //\r
- if (!mRuntime.AtRuntime || mRuntime.VirtualMode) {\r
- return EFI_UNSUPPORTED;\r
- }\r
- //\r
- // Only understand the original descriptor format\r
- //\r
- if (DescriptorVersion != EFI_MEMORY_DESCRIPTOR_VERSION || DescriptorSize < sizeof (EFI_MEMORY_DESCRIPTOR)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- //\r
- // We are now committed to go to virtual mode, so lets get to it!\r
- //\r
- mRuntime.VirtualMode = TRUE;\r
-\r
- //\r
- // ConvertPointer() needs this mVirtualMap to do the conversion. So set up\r
- // globals we need to parse the virtual address map.\r
- //\r
- mVirtualMapDescriptorSize = DescriptorSize;\r
- mVirtualMapMaxIndex = MemoryMapSize / DescriptorSize;\r
- mVirtualMap = VirtualMap;\r
-\r
- //\r
- // Currently the bug in StatusCode/RuntimeLib has been fixed, it will\r
- // check whether in Runtime or not (this is judged by looking at\r
- // mEfiAtRuntime global So this ReportStatusCode will work\r
- //\r
- REPORT_STATUS_CODE (\r
- EFI_PROGRESS_CODE,\r
- (EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_RS_PC_SET_VIRTUAL_ADDRESS_MAP)\r
- );\r
-\r
- //\r
- // Signal all the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE events.\r
- // All runtime events are stored in a list in Runtime AP.\r
- //\r
- for (Link = mRuntime.EventHead.ForwardLink; Link != &mRuntime.EventHead; Link = Link->ForwardLink) {\r
- RuntimeEvent = _CR (Link, EFI_RUNTIME_EVENT_ENTRY, Link);\r
- if ((RuntimeEvent->Type & EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {\r
- RuntimeEvent->NotifyFunction (\r
- RuntimeEvent->Event,\r
- RuntimeEvent->NotifyContext\r
- );\r
- }\r
- }\r
-\r
- //\r
- // Relocate runtime images. All runtime images are stored in a list in Runtime AP.\r
- //\r
- for (Link = mRuntime.ImageHead.ForwardLink; Link != &mRuntime.ImageHead; Link = Link->ForwardLink) {\r
- RuntimeImage = _CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link);\r
- //\r
- // We don't want to relocate our selves, as we only run in physical mode.\r
- //\r
- if (mMyImageBase != RuntimeImage->ImageBase) {\r
-\r
- VirtImageBase = (EFI_PHYSICAL_ADDRESS) (UINTN) RuntimeImage->ImageBase;\r
- Status = RuntimeDriverConvertPointer (0, (VOID **) &VirtImageBase);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- PeCoffLoaderRelocateImageForRuntime (\r
- (EFI_PHYSICAL_ADDRESS) (UINTN) RuntimeImage->ImageBase,\r
- VirtImageBase,\r
- (UINTN) RuntimeImage->ImageSize,\r
- RuntimeImage->RelocationData\r
- );\r
-\r
- InvalidateInstructionCacheRange (RuntimeImage->ImageBase, (UINTN)RuntimeImage->ImageSize);\r
- }\r
- }\r
-\r
- //\r
- // Convert all the Runtime Services except ConvertPointer() and SetVirtualAddressMap()\r
- // and recompute the CRC-32\r
- //\r
- RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetTime);\r
- RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetTime);\r
- RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetWakeupTime);\r
- RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetWakeupTime);\r
- RuntimeDriverConvertInternalPointer ((VOID **) &gRT->ResetSystem);\r
- RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetNextHighMonotonicCount);\r
- RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetVariable);\r
- RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetVariable);\r
- RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetNextVariableName);\r
- RuntimeDriverConvertInternalPointer ((VOID **) &gRT->QueryVariableInfo);\r
- RuntimeDriverConvertInternalPointer ((VOID **) &gRT->UpdateCapsule);\r
- RuntimeDriverConvertInternalPointer ((VOID **) &gRT->QueryCapsuleCapabilities);\r
- RuntimeDriverCalculateEfiHdrCrc (&gRT->Hdr);\r
-\r
- //\r
- // Convert the UGA OS Handoff Table if it is present in the Configuration Table\r
- //\r
- for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {\r
- if (CompareGuid (&gEfiUgaIoProtocolGuid, &(gST->ConfigurationTable[Index].VendorGuid))) {\r
- DriverOsHandoffHeader = gST->ConfigurationTable[Index].VendorTable;\r
- for (Index1 = 0; Index1 < DriverOsHandoffHeader->NumberOfEntries; Index1++) {\r
- DriverOsHandoff = (EFI_DRIVER_OS_HANDOFF *)\r
- (\r
- (UINTN) DriverOsHandoffHeader +\r
- DriverOsHandoffHeader->HeaderSize +\r
- Index1 *\r
- DriverOsHandoffHeader->SizeOfEntries\r
- );\r
- RuntimeDriverConvertPointer (EFI_OPTIONAL_POINTER, (VOID **) &DriverOsHandoff->DevicePath);\r
- RuntimeDriverConvertPointer (EFI_OPTIONAL_POINTER, (VOID **) &DriverOsHandoff->PciRomImage);\r
- }\r
-\r
- RuntimeDriverConvertPointer (EFI_OPTIONAL_POINTER, (VOID **) &(gST->ConfigurationTable[Index].VendorTable));\r
- }\r
-\r
- if (CompareGuid (&gEfiCapsuleGuid, &(gST->ConfigurationTable[Index].VendorGuid))) {\r
- CapsuleTable = gST->ConfigurationTable[Index].VendorTable;\r
- for (Index1 = 0; Index1 < CapsuleTable->CapsuleArrayNumber; Index1++) {\r
- RuntimeDriverConvertPointer (EFI_OPTIONAL_POINTER, (VOID **) &CapsuleTable->CapsulePtr[Index1]);\r
- }\r
- RuntimeDriverConvertPointer (EFI_OPTIONAL_POINTER, (VOID **) &(gST->ConfigurationTable[Index].VendorTable));\r
- }\r
- }\r
- //\r
- // Convert the runtime fields of the EFI System Table and recompute the CRC-32\r
- //\r
- RuntimeDriverConvertInternalPointer ((VOID **) &gST->FirmwareVendor);\r
- RuntimeDriverConvertInternalPointer ((VOID **) &gST->ConfigurationTable);\r
- RuntimeDriverConvertInternalPointer ((VOID **) &gST->RuntimeServices);\r
- RuntimeDriverCalculateEfiHdrCrc (&gST->Hdr);\r
-\r
- //\r
- // At this point, gRT and gST are physical pointers, but the contents of these tables\r
- // have been converted to runtime.\r
- //\r
- //\r
- // mVirtualMap is only valid during SetVirtualAddressMap() call\r
- //\r
- mVirtualMap = NULL;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-RuntimeDriverInitialize (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-/*++\r
-\r
-Routine Description:\r
- Install Runtime AP. This code includes the EfiDriverLib, but it functions at\r
- RT in physical mode. The only Lib services are gBS, gRT, and the DEBUG and\r
- ASSERT macros (they do ReportStatusCode).\r
-\r
-Arguments:\r
- (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)\r
-\r
-Returns:\r
-\r
- EFI_SUCEESS - Runtime Driver Architectural Protocol Installed\r
-\r
- Other - Return value from gBS->InstallMultipleProtocolInterfaces\r
-\r
---*/\r
-{\r
- EFI_STATUS Status;\r
- EFI_LOADED_IMAGE_PROTOCOL *MyLoadedImage;\r
-\r
- //\r
- // This image needs to be exclued from relocation for virtual mode, so cache\r
- // a copy of the Loaded Image protocol to test later.\r
- //\r
- Status = gBS->HandleProtocol (\r
- ImageHandle,\r
- &gEfiLoadedImageProtocolGuid,\r
- (VOID**)&MyLoadedImage\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- mMyImageBase = MyLoadedImage->ImageBase;\r
-\r
- //\r
- // Initialize the table used to compute 32-bit CRCs\r
- //\r
- RuntimeDriverInitializeCrc32Table ();\r
-\r
- //\r
- // Fill in the entries of the EFI Boot Services and EFI Runtime Services Tables\r
- //\r
- gBS->CalculateCrc32 = RuntimeDriverCalculateCrc32;\r
- gRT->SetVirtualAddressMap = RuntimeDriverSetVirtualAddressMap;\r
- gRT->ConvertPointer = RuntimeDriverConvertPointer;\r
-\r
- //\r
- // Install the Runtime Architectural Protocol onto a new handle\r
- //\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- &mRuntimeHandle,\r
- &gEfiRuntimeArchProtocolGuid,\r
- &mRuntime,\r
- NULL\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- return EFI_SUCCESS;\r
-}\r