mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-11-04 05:25:45 +01:00 
			
		
		
		
	git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10420 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			423 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			423 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  This file implements Runtime Architectural Protocol as defined in the
 | 
						|
  Platform Initialization specification 1.0 VOLUME 2 DXE Core Interface.
 | 
						|
 | 
						|
  This code is used to produce the EFI runtime virtual switch over
 | 
						|
 | 
						|
  THIS IS VERY DANGEROUS CODE BE VERY CAREFUL IF YOU CHANGE IT
 | 
						|
 | 
						|
  The transition for calling EFI Runtime functions in physical mode to calling
 | 
						|
  them in virtual mode is very very complex. Every pointer in needs to be
 | 
						|
  converted from physical mode to virtual mode. Be very careful walking linked
 | 
						|
  lists! Then to make it really hard the code it's self needs be relocated into
 | 
						|
  the new virtual address space.
 | 
						|
 | 
						|
  So here is the concept. The code in this module will never ever be called in
 | 
						|
  virtual mode. This is the code that collects the information needed to convert
 | 
						|
  to virtual mode (DXE core registers runtime stuff with this code). Since this
 | 
						|
  code is used to fix up all runtime images, it CAN NOT fix it's self up. So some
 | 
						|
  code has to stay behind and that is us.
 | 
						|
 | 
						|
  Also you need to be careful about when you allocate memory, as once we are in
 | 
						|
  runtime (including our EVT_SIGNAL_EXIT_BOOT_SERVICES event) you can no longer
 | 
						|
  allocate memory.
 | 
						|
 | 
						|
  Any runtime driver that gets loaded before us will not be callable in virtual
 | 
						|
  mode. This is due to the fact that the DXE core can not register the info
 | 
						|
  needed with us. This is good, since it keeps the code in this file from
 | 
						|
  getting registered.
 | 
						|
 | 
						|
 | 
						|
Revision History:
 | 
						|
 | 
						|
  - Move the CalculateCrc32 function from Runtime Arch Protocol to Boot Service.
 | 
						|
  Runtime Arch Protocol definition no longer contains CalculateCrc32. Boot Service
 | 
						|
  Table now contains an item named CalculateCrc32.
 | 
						|
 | 
						|
 | 
						|
Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
 | 
						|
This program and the accompanying materials
 | 
						|
are licensed and made available under the terms and conditions of the BSD License
 | 
						|
which accompanies this distribution.  The full text of the license may be found at
 | 
						|
http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "Runtime.h"
 | 
						|
 | 
						|
//
 | 
						|
// Global Variables
 | 
						|
//
 | 
						|
EFI_MEMORY_DESCRIPTOR         *mVirtualMap                = NULL;
 | 
						|
UINTN                         mVirtualMapDescriptorSize;
 | 
						|
UINTN                         mVirtualMapMaxIndex;
 | 
						|
VOID                          *mMyImageBase;
 | 
						|
 | 
						|
//
 | 
						|
// The handle onto which the Runtime Architectural Protocol instance is installed
 | 
						|
//
 | 
						|
EFI_HANDLE                    mRuntimeHandle = NULL;
 | 
						|
 | 
						|
//
 | 
						|
// The Runtime Architectural Protocol instance produced by this driver
 | 
						|
//
 | 
						|
EFI_RUNTIME_ARCH_PROTOCOL     mRuntime = {
 | 
						|
  INITIALIZE_LIST_HEAD_VARIABLE (mRuntime.ImageHead),
 | 
						|
  INITIALIZE_LIST_HEAD_VARIABLE (mRuntime.EventHead),
 | 
						|
 | 
						|
  //
 | 
						|
  // Make sure Size != sizeof (EFI_MEMORY_DESCRIPTOR). This will
 | 
						|
  // prevent people from having pointer math bugs in their code.
 | 
						|
  // now you have to use *DescriptorSize to make things work.
 | 
						|
  //
 | 
						|
  sizeof (EFI_MEMORY_DESCRIPTOR) + sizeof (UINT64) - (sizeof (EFI_MEMORY_DESCRIPTOR) % sizeof (UINT64)),
 | 
						|
  EFI_MEMORY_DESCRIPTOR_VERSION,
 | 
						|
  0,
 | 
						|
  NULL,
 | 
						|
  NULL,
 | 
						|
  FALSE,
 | 
						|
  FALSE
 | 
						|
};
 | 
						|
 | 
						|
//
 | 
						|
// Worker Functions
 | 
						|
//
 | 
						|
/**
 | 
						|
 | 
						|
  Calculate the 32-bit CRC in a EFI table using the Runtime Drivers
 | 
						|
  internal function.  The EFI Boot Services Table can not be used because
 | 
						|
  the EFI Boot Services Table was destroyed at ExitBootServices().
 | 
						|
  This is a internal function.
 | 
						|
 | 
						|
 | 
						|
  @param Hdr             Pointer to an EFI standard header
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
RuntimeDriverCalculateEfiHdrCrc (
 | 
						|
  IN OUT EFI_TABLE_HEADER  *Hdr
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32  Crc;
 | 
						|
 | 
						|
  Hdr->CRC32  = 0;
 | 
						|
 | 
						|
  Crc         = 0;
 | 
						|
  RuntimeDriverCalculateCrc32 ((UINT8 *) Hdr, Hdr->HeaderSize, &Crc);
 | 
						|
  Hdr->CRC32 = Crc;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Determines the new virtual address that is to be used on subsequent memory accesses.
 | 
						|
 | 
						|
 | 
						|
  @param DebugDisposition Supplies type information for the pointer being converted.
 | 
						|
  @param ConvertAddress  A pointer to a pointer that is to be fixed to be the value needed
 | 
						|
                         for the new virtual address mappings being applied.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS              The pointer pointed to by Address was modified.
 | 
						|
  @retval  EFI_NOT_FOUND            The pointer pointed to by Address was not found to be part
 | 
						|
                                    of the current memory map. This is normally fatal.
 | 
						|
  @retval  EFI_INVALID_PARAMETER    One of the parameters has an invalid value.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
RuntimeDriverConvertPointer (
 | 
						|
  IN     UINTN  DebugDisposition,
 | 
						|
  IN OUT VOID   **ConvertAddress
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                 Address;
 | 
						|
  UINT64                VirtEndOfRange;
 | 
						|
  EFI_MEMORY_DESCRIPTOR *VirtEntry;
 | 
						|
  UINTN                 Index;
 | 
						|
 | 
						|
  //
 | 
						|
  // Make sure ConvertAddress is a valid pointer
 | 
						|
  //
 | 
						|
  if (ConvertAddress == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Get the address to convert
 | 
						|
  //
 | 
						|
  Address = (UINTN) *ConvertAddress;
 | 
						|
 | 
						|
  //
 | 
						|
  // If this is a null pointer, return if it's allowed
 | 
						|
  //
 | 
						|
  if (Address == 0) {
 | 
						|
    if ((DebugDisposition & EFI_OPTIONAL_PTR) != 0) {
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  VirtEntry = mVirtualMap;
 | 
						|
  for (Index = 0; Index < mVirtualMapMaxIndex; Index++) {
 | 
						|
    //
 | 
						|
    //  To prevent the inclusion of 64-bit math functions a UINTN was placed in
 | 
						|
    //  front of VirtEntry->NumberOfPages to cast it to a 32-bit thing on IA-32
 | 
						|
    //  platforms. If you get this ASSERT remove the UINTN and do a 64-bit
 | 
						|
    //  multiply.
 | 
						|
    //
 | 
						|
    ASSERT (((UINTN) VirtEntry->NumberOfPages < 0xffffffff) || (sizeof (UINTN) > 4));
 | 
						|
 | 
						|
    if ((VirtEntry->Attribute & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {
 | 
						|
      if (Address >= VirtEntry->PhysicalStart) {
 | 
						|
        VirtEndOfRange = VirtEntry->PhysicalStart + (((UINTN) VirtEntry->NumberOfPages) * EFI_PAGE_SIZE);
 | 
						|
        if (Address < VirtEndOfRange) {
 | 
						|
          //
 | 
						|
          // Compute new address
 | 
						|
          //
 | 
						|
          *ConvertAddress = (VOID *) (Address - (UINTN) VirtEntry->PhysicalStart + (UINTN) VirtEntry->VirtualStart);
 | 
						|
          return EFI_SUCCESS;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    VirtEntry = NEXT_MEMORY_DESCRIPTOR (VirtEntry, mVirtualMapDescriptorSize);
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_NOT_FOUND;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Determines the new virtual address that is to be used on subsequent memory accesses
 | 
						|
  for internal pointers.
 | 
						|
  This is a internal function.
 | 
						|
 | 
						|
 | 
						|
  @param ConvertAddress  A pointer to a pointer that is to be fixed to be the value needed
 | 
						|
                         for the new virtual address mappings being applied.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS              The pointer pointed to by Address was modified.
 | 
						|
  @retval  EFI_NOT_FOUND            The pointer pointed to by Address was not found to be part
 | 
						|
                                    of the current memory map. This is normally fatal.
 | 
						|
  @retval  EFI_INVALID_PARAMETER    One of the parameters has an invalid value.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
RuntimeDriverConvertInternalPointer (
 | 
						|
  IN OUT VOID   **ConvertAddress
 | 
						|
  )
 | 
						|
{
 | 
						|
  return RuntimeDriverConvertPointer (0x0, ConvertAddress);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Changes the runtime addressing mode of EFI firmware from physical to virtual.
 | 
						|
 | 
						|
 | 
						|
  @param MemoryMapSize   The size in bytes of VirtualMap.
 | 
						|
  @param DescriptorSize  The size in bytes of an entry in the VirtualMap.
 | 
						|
  @param DescriptorVersion The version of the structure entries in VirtualMap.
 | 
						|
  @param VirtualMap      An array of memory descriptors which contain new virtual
 | 
						|
                         address mapping information for all runtime ranges.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS            The virtual address map has been applied.
 | 
						|
  @retval  EFI_UNSUPPORTED        EFI firmware is not at runtime, or the EFI firmware is already in
 | 
						|
                                  virtual address mapped mode.
 | 
						|
  @retval  EFI_INVALID_PARAMETER  DescriptorSize or DescriptorVersion is invalid.
 | 
						|
  @retval  EFI_NO_MAPPING         A virtual address was not supplied for a range in the memory
 | 
						|
                                  map that requires a mapping.
 | 
						|
  @retval  EFI_NOT_FOUND          A virtual address was supplied for an address that is not found
 | 
						|
                                  in the memory map.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
RuntimeDriverSetVirtualAddressMap (
 | 
						|
  IN UINTN                  MemoryMapSize,
 | 
						|
  IN UINTN                  DescriptorSize,
 | 
						|
  IN UINT32                 DescriptorVersion,
 | 
						|
  IN EFI_MEMORY_DESCRIPTOR  *VirtualMap
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  EFI_RUNTIME_EVENT_ENTRY       *RuntimeEvent;
 | 
						|
  EFI_RUNTIME_IMAGE_ENTRY       *RuntimeImage;
 | 
						|
  LIST_ENTRY                    *Link;
 | 
						|
  EFI_PHYSICAL_ADDRESS          VirtImageBase;
 | 
						|
 | 
						|
  //
 | 
						|
  // Can only switch to virtual addresses once the memory map is locked down,
 | 
						|
  // and can only set it once
 | 
						|
  //
 | 
						|
  if (!mRuntime.AtRuntime || mRuntime.VirtualMode) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Only understand the original descriptor format
 | 
						|
  //
 | 
						|
  if (DescriptorVersion != EFI_MEMORY_DESCRIPTOR_VERSION || DescriptorSize < sizeof (EFI_MEMORY_DESCRIPTOR)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // We are now committed to go to virtual mode, so lets get to it!
 | 
						|
  //
 | 
						|
  mRuntime.VirtualMode = TRUE;
 | 
						|
 | 
						|
  //
 | 
						|
  // ConvertPointer() needs this mVirtualMap to do the conversion. So set up
 | 
						|
  // globals we need to parse the virtual address map.
 | 
						|
  //
 | 
						|
  mVirtualMapDescriptorSize = DescriptorSize;
 | 
						|
  mVirtualMapMaxIndex       = MemoryMapSize / DescriptorSize;
 | 
						|
  mVirtualMap               = VirtualMap;
 | 
						|
 | 
						|
  //
 | 
						|
  // ReporstStatusCodeLib will check and make sure this service can be called in runtime mode.
 | 
						|
  //
 | 
						|
  REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_EFI_RUNTIME_SERVICE | EFI_SW_RS_PC_SET_VIRTUAL_ADDRESS_MAP));
 | 
						|
 | 
						|
  //
 | 
						|
  // Signal all the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE events.
 | 
						|
  // All runtime events are stored in a list in Runtime AP.
 | 
						|
  //
 | 
						|
  for (Link = mRuntime.EventHead.ForwardLink; Link != &mRuntime.EventHead; Link = Link->ForwardLink) {
 | 
						|
    RuntimeEvent = BASE_CR (Link, EFI_RUNTIME_EVENT_ENTRY, Link);
 | 
						|
    if ((RuntimeEvent->Type & EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {
 | 
						|
      RuntimeEvent->NotifyFunction (
 | 
						|
                      RuntimeEvent->Event,
 | 
						|
                      RuntimeEvent->NotifyContext
 | 
						|
                      );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Relocate runtime images. All runtime images are stored in a list in Runtime AP.
 | 
						|
  //
 | 
						|
  for (Link = mRuntime.ImageHead.ForwardLink; Link != &mRuntime.ImageHead; Link = Link->ForwardLink) {
 | 
						|
    RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link);
 | 
						|
    //
 | 
						|
    // We don't want to relocate our selves, as we only run in physical mode.
 | 
						|
    //
 | 
						|
    if (mMyImageBase != RuntimeImage->ImageBase) {
 | 
						|
 | 
						|
      VirtImageBase = (EFI_PHYSICAL_ADDRESS) (UINTN) RuntimeImage->ImageBase;
 | 
						|
      Status  = RuntimeDriverConvertPointer (0, (VOID **) &VirtImageBase);
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
      PeCoffLoaderRelocateImageForRuntime (
 | 
						|
        (EFI_PHYSICAL_ADDRESS) (UINTN) RuntimeImage->ImageBase,
 | 
						|
        VirtImageBase,
 | 
						|
        (UINTN) RuntimeImage->ImageSize,
 | 
						|
        RuntimeImage->RelocationData
 | 
						|
        );
 | 
						|
 | 
						|
      InvalidateInstructionCacheRange (RuntimeImage->ImageBase, (UINTN) RuntimeImage->ImageSize);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Convert all the Runtime Services except ConvertPointer() and SetVirtualAddressMap()
 | 
						|
  // and recompute the CRC-32
 | 
						|
  //
 | 
						|
  RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetTime);
 | 
						|
  RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetTime);
 | 
						|
  RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetWakeupTime);
 | 
						|
  RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetWakeupTime);
 | 
						|
  RuntimeDriverConvertInternalPointer ((VOID **) &gRT->ResetSystem);
 | 
						|
  RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetNextHighMonotonicCount);
 | 
						|
  RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetVariable);
 | 
						|
  RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetVariable);
 | 
						|
  RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetNextVariableName);
 | 
						|
  RuntimeDriverConvertInternalPointer ((VOID **) &gRT->QueryVariableInfo);
 | 
						|
  RuntimeDriverConvertInternalPointer ((VOID **) &gRT->UpdateCapsule);
 | 
						|
  RuntimeDriverConvertInternalPointer ((VOID **) &gRT->QueryCapsuleCapabilities);
 | 
						|
  RuntimeDriverCalculateEfiHdrCrc (&gRT->Hdr);
 | 
						|
 | 
						|
  //
 | 
						|
  // UEFI don't require System Configuration Tables Conversion.
 | 
						|
  //
 | 
						|
 | 
						|
  //
 | 
						|
  // Convert the runtime fields of the EFI System Table and recompute the CRC-32
 | 
						|
  //
 | 
						|
  RuntimeDriverConvertInternalPointer ((VOID **) &gST->FirmwareVendor);
 | 
						|
  RuntimeDriverConvertInternalPointer ((VOID **) &gST->ConfigurationTable);
 | 
						|
  RuntimeDriverConvertInternalPointer ((VOID **) &gST->RuntimeServices);
 | 
						|
  RuntimeDriverCalculateEfiHdrCrc (&gST->Hdr);
 | 
						|
 | 
						|
  //
 | 
						|
  // At this point, gRT and gST are physical pointers, but the contents of these tables
 | 
						|
  // have been converted to runtime.
 | 
						|
  //
 | 
						|
  //
 | 
						|
  // mVirtualMap is only valid during SetVirtualAddressMap() call
 | 
						|
  //
 | 
						|
  mVirtualMap = NULL;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Entry Point for Runtime driver.
 | 
						|
 | 
						|
  This function installs Runtime Architectural Protocol and registers CalculateCrc32 boot services table,
 | 
						|
  SetVirtualAddressMap & ConvertPointer runtime services table.
 | 
						|
 | 
						|
  @param ImageHandle     Image handle of this driver.
 | 
						|
  @param SystemTable     a Pointer to the EFI System Table.
 | 
						|
 | 
						|
  @retval  EFI_SUCEESS  Runtime Driver Architectural Protocol is successfully installed
 | 
						|
  @return  Others       Some error occurs when installing Runtime Driver Architectural Protocol.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
RuntimeDriverInitialize (
 | 
						|
  IN EFI_HANDLE                            ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE                      *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_LOADED_IMAGE_PROTOCOL *MyLoadedImage;
 | 
						|
 | 
						|
  //
 | 
						|
  // This image needs to be excluded from relocation for virtual mode, so cache
 | 
						|
  // a copy of the Loaded Image protocol to test later.
 | 
						|
  //
 | 
						|
  Status = gBS->HandleProtocol (
 | 
						|
                  ImageHandle,
 | 
						|
                  &gEfiLoadedImageProtocolGuid,
 | 
						|
                  (VOID**)&MyLoadedImage
 | 
						|
                  );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  mMyImageBase = MyLoadedImage->ImageBase;
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize the table used to compute 32-bit CRCs
 | 
						|
  //
 | 
						|
  RuntimeDriverInitializeCrc32Table ();
 | 
						|
 | 
						|
  //
 | 
						|
  // Fill in the entries of the EFI Boot Services and EFI Runtime Services Tables
 | 
						|
  //
 | 
						|
  gBS->CalculateCrc32       = RuntimeDriverCalculateCrc32;
 | 
						|
  gRT->SetVirtualAddressMap = RuntimeDriverSetVirtualAddressMap;
 | 
						|
  gRT->ConvertPointer       = RuntimeDriverConvertPointer;
 | 
						|
 | 
						|
  //
 | 
						|
  // Install the Runtime Architectural Protocol onto a new handle
 | 
						|
  //
 | 
						|
  Status = gBS->InstallMultipleProtocolInterfaces (
 | 
						|
                  &mRuntimeHandle,
 | 
						|
                  &gEfiRuntimeArchProtocolGuid,
 | 
						|
                  &mRuntime,
 | 
						|
                  NULL
 | 
						|
                  );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |