Home | History | Annotate | Download | only in RuntimeDxe
      1 /** @file
      2   This file implements Runtime Architectural Protocol as defined in the
      3   Platform Initialization specification 1.0 VOLUME 2 DXE Core Interface.
      4 
      5   This code is used to produce the EFI runtime virtual switch over
      6 
      7   THIS IS VERY DANGEROUS CODE BE VERY CAREFUL IF YOU CHANGE IT
      8 
      9   The transition for calling EFI Runtime functions in physical mode to calling
     10   them in virtual mode is very very complex. Every pointer in needs to be
     11   converted from physical mode to virtual mode. Be very careful walking linked
     12   lists! Then to make it really hard the code it's self needs be relocated into
     13   the new virtual address space.
     14 
     15   So here is the concept. The code in this module will never ever be called in
     16   virtual mode. This is the code that collects the information needed to convert
     17   to virtual mode (DXE core registers runtime stuff with this code). Since this
     18   code is used to fix up all runtime images, it CAN NOT fix it's self up. So some
     19   code has to stay behind and that is us.
     20 
     21   Also you need to be careful about when you allocate memory, as once we are in
     22   runtime (including our EVT_SIGNAL_EXIT_BOOT_SERVICES event) you can no longer
     23   allocate memory.
     24 
     25   Any runtime driver that gets loaded before us will not be callable in virtual
     26   mode. This is due to the fact that the DXE core can not register the info
     27   needed with us. This is good, since it keeps the code in this file from
     28   getting registered.
     29 
     30 
     31 Revision History:
     32 
     33   - Move the CalculateCrc32 function from Runtime Arch Protocol to Boot Service.
     34   Runtime Arch Protocol definition no longer contains CalculateCrc32. Boot Service
     35   Table now contains an item named CalculateCrc32.
     36 
     37 
     38 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
     39 This program and the accompanying materials
     40 are licensed and made available under the terms and conditions of the BSD License
     41 which accompanies this distribution.  The full text of the license may be found at
     42 http://opensource.org/licenses/bsd-license.php
     43 
     44 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     45 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     46 
     47 **/
     48 
     49 #include "Runtime.h"
     50 
     51 //
     52 // Global Variables
     53 //
     54 EFI_MEMORY_DESCRIPTOR         *mVirtualMap                = NULL;
     55 UINTN                         mVirtualMapDescriptorSize;
     56 UINTN                         mVirtualMapMaxIndex;
     57 VOID                          *mMyImageBase;
     58 
     59 //
     60 // The handle onto which the Runtime Architectural Protocol instance is installed
     61 //
     62 EFI_HANDLE                    mRuntimeHandle = NULL;
     63 
     64 //
     65 // The Runtime Architectural Protocol instance produced by this driver
     66 //
     67 EFI_RUNTIME_ARCH_PROTOCOL     mRuntime = {
     68   INITIALIZE_LIST_HEAD_VARIABLE (mRuntime.ImageHead),
     69   INITIALIZE_LIST_HEAD_VARIABLE (mRuntime.EventHead),
     70 
     71   //
     72   // Make sure Size != sizeof (EFI_MEMORY_DESCRIPTOR). This will
     73   // prevent people from having pointer math bugs in their code.
     74   // now you have to use *DescriptorSize to make things work.
     75   //
     76   sizeof (EFI_MEMORY_DESCRIPTOR) + sizeof (UINT64) - (sizeof (EFI_MEMORY_DESCRIPTOR) % sizeof (UINT64)),
     77   EFI_MEMORY_DESCRIPTOR_VERSION,
     78   0,
     79   NULL,
     80   NULL,
     81   FALSE,
     82   FALSE
     83 };
     84 
     85 //
     86 // Worker Functions
     87 //
     88 /**
     89 
     90   Calculate the 32-bit CRC in a EFI table using the Runtime Drivers
     91   internal function.  The EFI Boot Services Table can not be used because
     92   the EFI Boot Services Table was destroyed at ExitBootServices().
     93   This is a internal function.
     94 
     95 
     96   @param Hdr             Pointer to an EFI standard header
     97 
     98 **/
     99 VOID
    100 RuntimeDriverCalculateEfiHdrCrc (
    101   IN OUT EFI_TABLE_HEADER  *Hdr
    102   )
    103 {
    104   UINT32  Crc;
    105 
    106   Hdr->CRC32  = 0;
    107 
    108   Crc         = 0;
    109   RuntimeDriverCalculateCrc32 ((UINT8 *) Hdr, Hdr->HeaderSize, &Crc);
    110   Hdr->CRC32 = Crc;
    111 }
    112 
    113 /**
    114 
    115   Determines the new virtual address that is to be used on subsequent memory accesses.
    116 
    117 
    118   @param DebugDisposition Supplies type information for the pointer being converted.
    119   @param ConvertAddress  A pointer to a pointer that is to be fixed to be the value needed
    120                          for the new virtual address mappings being applied.
    121 
    122   @retval  EFI_SUCCESS              The pointer pointed to by Address was modified.
    123   @retval  EFI_NOT_FOUND            The pointer pointed to by Address was not found to be part
    124                                     of the current memory map. This is normally fatal.
    125   @retval  EFI_INVALID_PARAMETER    One of the parameters has an invalid value.
    126 
    127 **/
    128 EFI_STATUS
    129 EFIAPI
    130 RuntimeDriverConvertPointer (
    131   IN     UINTN  DebugDisposition,
    132   IN OUT VOID   **ConvertAddress
    133   )
    134 {
    135   UINTN                 Address;
    136   UINT64                VirtEndOfRange;
    137   EFI_MEMORY_DESCRIPTOR *VirtEntry;
    138   UINTN                 Index;
    139 
    140   //
    141   // Make sure ConvertAddress is a valid pointer
    142   //
    143   if (ConvertAddress == NULL) {
    144     return EFI_INVALID_PARAMETER;
    145   }
    146   //
    147   // Get the address to convert
    148   //
    149   Address = (UINTN) *ConvertAddress;
    150 
    151   //
    152   // If this is a null pointer, return if it's allowed
    153   //
    154   if (Address == 0) {
    155     if ((DebugDisposition & EFI_OPTIONAL_PTR) != 0) {
    156       return EFI_SUCCESS;
    157     }
    158 
    159     return EFI_INVALID_PARAMETER;
    160   }
    161 
    162   VirtEntry = mVirtualMap;
    163   for (Index = 0; Index < mVirtualMapMaxIndex; Index++) {
    164     //
    165     //  To prevent the inclusion of 64-bit math functions a UINTN was placed in
    166     //  front of VirtEntry->NumberOfPages to cast it to a 32-bit thing on IA-32
    167     //  platforms. If you get this ASSERT remove the UINTN and do a 64-bit
    168     //  multiply.
    169     //
    170     ASSERT (((UINTN) VirtEntry->NumberOfPages < 0xffffffff) || (sizeof (UINTN) > 4));
    171 
    172     if ((VirtEntry->Attribute & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {
    173       if (Address >= VirtEntry->PhysicalStart) {
    174         VirtEndOfRange = VirtEntry->PhysicalStart + (((UINTN) VirtEntry->NumberOfPages) * EFI_PAGE_SIZE);
    175         if (Address < VirtEndOfRange) {
    176           //
    177           // Compute new address
    178           //
    179           *ConvertAddress = (VOID *) (Address - (UINTN) VirtEntry->PhysicalStart + (UINTN) VirtEntry->VirtualStart);
    180           return EFI_SUCCESS;
    181         }
    182       }
    183     }
    184 
    185     VirtEntry = NEXT_MEMORY_DESCRIPTOR (VirtEntry, mVirtualMapDescriptorSize);
    186   }
    187 
    188   return EFI_NOT_FOUND;
    189 }
    190 
    191 /**
    192 
    193   Determines the new virtual address that is to be used on subsequent memory accesses
    194   for internal pointers.
    195   This is a internal function.
    196 
    197 
    198   @param ConvertAddress  A pointer to a pointer that is to be fixed to be the value needed
    199                          for the new virtual address mappings being applied.
    200 
    201   @retval  EFI_SUCCESS              The pointer pointed to by Address was modified.
    202   @retval  EFI_NOT_FOUND            The pointer pointed to by Address was not found to be part
    203                                     of the current memory map. This is normally fatal.
    204   @retval  EFI_INVALID_PARAMETER    One of the parameters has an invalid value.
    205 
    206 **/
    207 EFI_STATUS
    208 RuntimeDriverConvertInternalPointer (
    209   IN OUT VOID   **ConvertAddress
    210   )
    211 {
    212   return RuntimeDriverConvertPointer (0x0, ConvertAddress);
    213 }
    214 
    215 /**
    216 
    217   Changes the runtime addressing mode of EFI firmware from physical to virtual.
    218 
    219 
    220   @param MemoryMapSize   The size in bytes of VirtualMap.
    221   @param DescriptorSize  The size in bytes of an entry in the VirtualMap.
    222   @param DescriptorVersion The version of the structure entries in VirtualMap.
    223   @param VirtualMap      An array of memory descriptors which contain new virtual
    224                          address mapping information for all runtime ranges.
    225 
    226   @retval  EFI_SUCCESS            The virtual address map has been applied.
    227   @retval  EFI_UNSUPPORTED        EFI firmware is not at runtime, or the EFI firmware is already in
    228                                   virtual address mapped mode.
    229   @retval  EFI_INVALID_PARAMETER  DescriptorSize or DescriptorVersion is invalid.
    230   @retval  EFI_NO_MAPPING         A virtual address was not supplied for a range in the memory
    231                                   map that requires a mapping.
    232   @retval  EFI_NOT_FOUND          A virtual address was supplied for an address that is not found
    233                                   in the memory map.
    234 
    235 **/
    236 EFI_STATUS
    237 EFIAPI
    238 RuntimeDriverSetVirtualAddressMap (
    239   IN UINTN                  MemoryMapSize,
    240   IN UINTN                  DescriptorSize,
    241   IN UINT32                 DescriptorVersion,
    242   IN EFI_MEMORY_DESCRIPTOR  *VirtualMap
    243   )
    244 {
    245   EFI_STATUS                    Status;
    246   EFI_RUNTIME_EVENT_ENTRY       *RuntimeEvent;
    247   EFI_RUNTIME_IMAGE_ENTRY       *RuntimeImage;
    248   LIST_ENTRY                    *Link;
    249   EFI_PHYSICAL_ADDRESS          VirtImageBase;
    250 
    251   //
    252   // Can only switch to virtual addresses once the memory map is locked down,
    253   // and can only set it once
    254   //
    255   if (!mRuntime.AtRuntime || mRuntime.VirtualMode) {
    256     return EFI_UNSUPPORTED;
    257   }
    258   //
    259   // Only understand the original descriptor format
    260   //
    261   if (DescriptorVersion != EFI_MEMORY_DESCRIPTOR_VERSION || DescriptorSize < sizeof (EFI_MEMORY_DESCRIPTOR)) {
    262     return EFI_INVALID_PARAMETER;
    263   }
    264   //
    265   // We are now committed to go to virtual mode, so lets get to it!
    266   //
    267   mRuntime.VirtualMode = TRUE;
    268 
    269   //
    270   // ConvertPointer() needs this mVirtualMap to do the conversion. So set up
    271   // globals we need to parse the virtual address map.
    272   //
    273   mVirtualMapDescriptorSize = DescriptorSize;
    274   mVirtualMapMaxIndex       = MemoryMapSize / DescriptorSize;
    275   mVirtualMap               = VirtualMap;
    276 
    277   //
    278   // ReporstStatusCodeLib will check and make sure this service can be called in runtime mode.
    279   //
    280   REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_EFI_RUNTIME_SERVICE | EFI_SW_RS_PC_SET_VIRTUAL_ADDRESS_MAP));
    281 
    282   //
    283   // Report Status Code here since EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event will be signalled.
    284   //
    285   REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_VIRTUAL_ADDRESS_CHANGE_EVENT));
    286 
    287   //
    288   // Signal all the EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE events.
    289   // All runtime events are stored in a list in Runtime AP.
    290   //
    291   for (Link = mRuntime.EventHead.ForwardLink; Link != &mRuntime.EventHead; Link = Link->ForwardLink) {
    292     RuntimeEvent = BASE_CR (Link, EFI_RUNTIME_EVENT_ENTRY, Link);
    293     if ((RuntimeEvent->Type & EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {
    294       RuntimeEvent->NotifyFunction (
    295                       RuntimeEvent->Event,
    296                       RuntimeEvent->NotifyContext
    297                       );
    298     }
    299   }
    300 
    301   //
    302   // Relocate runtime images. All runtime images are stored in a list in Runtime AP.
    303   //
    304   for (Link = mRuntime.ImageHead.ForwardLink; Link != &mRuntime.ImageHead; Link = Link->ForwardLink) {
    305     RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link);
    306     //
    307     // We don't want to relocate our selves, as we only run in physical mode.
    308     //
    309     if (mMyImageBase != RuntimeImage->ImageBase) {
    310 
    311       VirtImageBase = (EFI_PHYSICAL_ADDRESS) (UINTN) RuntimeImage->ImageBase;
    312       Status  = RuntimeDriverConvertPointer (0, (VOID **) &VirtImageBase);
    313       ASSERT_EFI_ERROR (Status);
    314 
    315       PeCoffLoaderRelocateImageForRuntime (
    316         (EFI_PHYSICAL_ADDRESS) (UINTN) RuntimeImage->ImageBase,
    317         VirtImageBase,
    318         (UINTN) RuntimeImage->ImageSize,
    319         RuntimeImage->RelocationData
    320         );
    321 
    322       InvalidateInstructionCacheRange (RuntimeImage->ImageBase, (UINTN) RuntimeImage->ImageSize);
    323     }
    324   }
    325 
    326   //
    327   // Convert all the Runtime Services except ConvertPointer() and SetVirtualAddressMap()
    328   // and recompute the CRC-32
    329   //
    330   RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetTime);
    331   RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetTime);
    332   RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetWakeupTime);
    333   RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetWakeupTime);
    334   RuntimeDriverConvertInternalPointer ((VOID **) &gRT->ResetSystem);
    335   RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetNextHighMonotonicCount);
    336   RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetVariable);
    337   RuntimeDriverConvertInternalPointer ((VOID **) &gRT->SetVariable);
    338   RuntimeDriverConvertInternalPointer ((VOID **) &gRT->GetNextVariableName);
    339   RuntimeDriverConvertInternalPointer ((VOID **) &gRT->QueryVariableInfo);
    340   RuntimeDriverConvertInternalPointer ((VOID **) &gRT->UpdateCapsule);
    341   RuntimeDriverConvertInternalPointer ((VOID **) &gRT->QueryCapsuleCapabilities);
    342   RuntimeDriverCalculateEfiHdrCrc (&gRT->Hdr);
    343 
    344   //
    345   // UEFI don't require System Configuration Tables Conversion.
    346   //
    347 
    348   //
    349   // Convert the runtime fields of the EFI System Table and recompute the CRC-32
    350   //
    351   RuntimeDriverConvertInternalPointer ((VOID **) &gST->FirmwareVendor);
    352   RuntimeDriverConvertInternalPointer ((VOID **) &gST->ConfigurationTable);
    353   RuntimeDriverConvertInternalPointer ((VOID **) &gST->RuntimeServices);
    354   RuntimeDriverCalculateEfiHdrCrc (&gST->Hdr);
    355 
    356   //
    357   // At this point, gRT and gST are physical pointers, but the contents of these tables
    358   // have been converted to runtime.
    359   //
    360   //
    361   // mVirtualMap is only valid during SetVirtualAddressMap() call
    362   //
    363   mVirtualMap = NULL;
    364 
    365   return EFI_SUCCESS;
    366 }
    367 
    368 /**
    369   Entry Point for Runtime driver.
    370 
    371   This function installs Runtime Architectural Protocol and registers CalculateCrc32 boot services table,
    372   SetVirtualAddressMap & ConvertPointer runtime services table.
    373 
    374   @param ImageHandle     Image handle of this driver.
    375   @param SystemTable     a Pointer to the EFI System Table.
    376 
    377   @retval  EFI_SUCEESS  Runtime Driver Architectural Protocol is successfully installed
    378   @return  Others       Some error occurs when installing Runtime Driver Architectural Protocol.
    379 
    380 **/
    381 EFI_STATUS
    382 EFIAPI
    383 RuntimeDriverInitialize (
    384   IN EFI_HANDLE                            ImageHandle,
    385   IN EFI_SYSTEM_TABLE                      *SystemTable
    386   )
    387 {
    388   EFI_STATUS                Status;
    389   EFI_LOADED_IMAGE_PROTOCOL *MyLoadedImage;
    390 
    391   //
    392   // This image needs to be excluded from relocation for virtual mode, so cache
    393   // a copy of the Loaded Image protocol to test later.
    394   //
    395   Status = gBS->HandleProtocol (
    396                   ImageHandle,
    397                   &gEfiLoadedImageProtocolGuid,
    398                   (VOID**)&MyLoadedImage
    399                   );
    400   ASSERT_EFI_ERROR (Status);
    401   mMyImageBase = MyLoadedImage->ImageBase;
    402 
    403   //
    404   // Initialize the table used to compute 32-bit CRCs
    405   //
    406   RuntimeDriverInitializeCrc32Table ();
    407 
    408   //
    409   // Fill in the entries of the EFI Boot Services and EFI Runtime Services Tables
    410   //
    411   gBS->CalculateCrc32       = RuntimeDriverCalculateCrc32;
    412   gRT->SetVirtualAddressMap = RuntimeDriverSetVirtualAddressMap;
    413   gRT->ConvertPointer       = RuntimeDriverConvertPointer;
    414 
    415   //
    416   // Install the Runtime Architectural Protocol onto a new handle
    417   //
    418   Status = gBS->InstallMultipleProtocolInterfaces (
    419                   &mRuntimeHandle,
    420                   &gEfiRuntimeArchProtocolGuid,
    421                   &mRuntime,
    422                   NULL
    423                   );
    424   ASSERT_EFI_ERROR (Status);
    425 
    426   return Status;
    427 }
    428