Home | History | Annotate | Download | only in Misc
      1 /** @file
      2   UEFI MemoryAttributesTable support
      3 
      4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include <PiDxe.h>
     16 #include <Library/BaseLib.h>
     17 #include <Library/BaseMemoryLib.h>
     18 #include <Library/MemoryAllocationLib.h>
     19 #include <Library/UefiBootServicesTableLib.h>
     20 #include <Library/DxeServicesTableLib.h>
     21 #include <Library/DebugLib.h>
     22 #include <Library/UefiLib.h>
     23 
     24 #include <Guid/EventGroup.h>
     25 
     26 #include <Guid/MemoryAttributesTable.h>
     27 #include <Guid/PropertiesTable.h>
     28 
     29 #include "DxeMain.h"
     30 
     31 /**
     32   This function for GetMemoryMap() with properties table capability.
     33 
     34   It calls original GetMemoryMap() to get the original memory map information. Then
     35   plus the additional memory map entries for PE Code/Data seperation.
     36 
     37   @param  MemoryMapSize          A pointer to the size, in bytes, of the
     38                                  MemoryMap buffer. On input, this is the size of
     39                                  the buffer allocated by the caller.  On output,
     40                                  it is the size of the buffer returned by the
     41                                  firmware  if the buffer was large enough, or the
     42                                  size of the buffer needed  to contain the map if
     43                                  the buffer was too small.
     44   @param  MemoryMap              A pointer to the buffer in which firmware places
     45                                  the current memory map.
     46   @param  MapKey                 A pointer to the location in which firmware
     47                                  returns the key for the current memory map.
     48   @param  DescriptorSize         A pointer to the location in which firmware
     49                                  returns the size, in bytes, of an individual
     50                                  EFI_MEMORY_DESCRIPTOR.
     51   @param  DescriptorVersion      A pointer to the location in which firmware
     52                                  returns the version number associated with the
     53                                  EFI_MEMORY_DESCRIPTOR.
     54 
     55   @retval EFI_SUCCESS            The memory map was returned in the MemoryMap
     56                                  buffer.
     57   @retval EFI_BUFFER_TOO_SMALL   The MemoryMap buffer was too small. The current
     58                                  buffer size needed to hold the memory map is
     59                                  returned in MemoryMapSize.
     60   @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value.
     61 
     62 **/
     63 EFI_STATUS
     64 EFIAPI
     65 CoreGetMemoryMapWithSeparatedImageSection (
     66   IN OUT UINTN                  *MemoryMapSize,
     67   IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,
     68   OUT UINTN                     *MapKey,
     69   OUT UINTN                     *DescriptorSize,
     70   OUT UINT32                    *DescriptorVersion
     71   );
     72 
     73 extern EFI_PROPERTIES_TABLE  mPropertiesTable;
     74 EFI_MEMORY_ATTRIBUTES_TABLE  *mMemoryAttributesTable = NULL;
     75 BOOLEAN                      mMemoryAttributesTableReadyToBoot = FALSE;
     76 
     77 /**
     78   Install MemoryAttributesTable.
     79 
     80 **/
     81 VOID
     82 InstallMemoryAttributesTable (
     83   VOID
     84   )
     85 {
     86   UINTN                          MemoryMapSize;
     87   EFI_MEMORY_DESCRIPTOR          *MemoryMap;
     88   EFI_MEMORY_DESCRIPTOR          *MemoryMapStart;
     89   UINTN                          MapKey;
     90   UINTN                          DescriptorSize;
     91   UINT32                         DescriptorVersion;
     92   UINTN                          Index;
     93   EFI_STATUS                     Status;
     94   UINT32                         RuntimeEntryCount;
     95   EFI_MEMORY_ATTRIBUTES_TABLE    *MemoryAttributesTable;
     96   EFI_MEMORY_DESCRIPTOR          *MemoryAttributesEntry;
     97 
     98   if (gMemoryMapTerminated) {
     99     //
    100     // Directly return after MemoryMap terminated.
    101     //
    102     return;
    103   }
    104 
    105   if ((mPropertiesTable.MemoryProtectionAttribute & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) {
    106     DEBUG ((EFI_D_VERBOSE, "MemoryProtectionAttribute NON_EXECUTABLE_PE_DATA is not set, "));
    107     DEBUG ((EFI_D_VERBOSE, "because Runtime Driver Section Alignment is not %dK.\n", EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT >> 10));
    108     return ;
    109   }
    110 
    111   if (mMemoryAttributesTable == NULL) {
    112     //
    113     // InstallConfigurationTable here to occupy one entry for MemoryAttributesTable
    114     // before GetMemoryMap below, as InstallConfigurationTable may allocate runtime
    115     // memory for the new entry.
    116     //
    117     Status = gBS->InstallConfigurationTable (&gEfiMemoryAttributesTableGuid, (VOID *) (UINTN) MAX_ADDRESS);
    118     ASSERT_EFI_ERROR (Status);
    119   }
    120 
    121   MemoryMapSize = 0;
    122   MemoryMap = NULL;
    123   Status = CoreGetMemoryMapWithSeparatedImageSection (
    124              &MemoryMapSize,
    125              MemoryMap,
    126              &MapKey,
    127              &DescriptorSize,
    128              &DescriptorVersion
    129              );
    130   ASSERT (Status == EFI_BUFFER_TOO_SMALL);
    131 
    132   do {
    133     MemoryMap = AllocatePool (MemoryMapSize);
    134     ASSERT (MemoryMap != NULL);
    135 
    136     Status = CoreGetMemoryMapWithSeparatedImageSection (
    137                &MemoryMapSize,
    138                MemoryMap,
    139                &MapKey,
    140                &DescriptorSize,
    141                &DescriptorVersion
    142                );
    143     if (EFI_ERROR (Status)) {
    144       FreePool (MemoryMap);
    145     }
    146   } while (Status == EFI_BUFFER_TOO_SMALL);
    147 
    148   MemoryMapStart = MemoryMap;
    149   RuntimeEntryCount = 0;
    150   for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) {
    151     switch (MemoryMap->Type) {
    152     case EfiRuntimeServicesCode:
    153     case EfiRuntimeServicesData:
    154       RuntimeEntryCount ++;
    155       break;
    156     }
    157     MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
    158   }
    159 
    160   //
    161   // Allocate MemoryAttributesTable
    162   //
    163   MemoryAttributesTable = AllocatePool (sizeof(EFI_MEMORY_ATTRIBUTES_TABLE) + DescriptorSize * RuntimeEntryCount);
    164   ASSERT (MemoryAttributesTable != NULL);
    165   MemoryAttributesTable->Version         = EFI_MEMORY_ATTRIBUTES_TABLE_VERSION;
    166   MemoryAttributesTable->NumberOfEntries = RuntimeEntryCount;
    167   MemoryAttributesTable->DescriptorSize  = (UINT32)DescriptorSize;
    168   MemoryAttributesTable->Reserved        = 0;
    169   DEBUG ((EFI_D_VERBOSE, "MemoryAttributesTable:\n"));
    170   DEBUG ((EFI_D_VERBOSE, "  Version              - 0x%08x\n", MemoryAttributesTable->Version));
    171   DEBUG ((EFI_D_VERBOSE, "  NumberOfEntries      - 0x%08x\n", MemoryAttributesTable->NumberOfEntries));
    172   DEBUG ((EFI_D_VERBOSE, "  DescriptorSize       - 0x%08x\n", MemoryAttributesTable->DescriptorSize));
    173   MemoryAttributesEntry = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1);
    174   MemoryMap = MemoryMapStart;
    175   for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) {
    176     switch (MemoryMap->Type) {
    177     case EfiRuntimeServicesCode:
    178     case EfiRuntimeServicesData:
    179       CopyMem (MemoryAttributesEntry, MemoryMap, DescriptorSize);
    180       MemoryAttributesEntry->Attribute &= (EFI_MEMORY_RO|EFI_MEMORY_XP|EFI_MEMORY_RUNTIME);
    181       DEBUG ((EFI_D_VERBOSE, "Entry (0x%x)\n", MemoryAttributesEntry));
    182       DEBUG ((EFI_D_VERBOSE, "  Type              - 0x%x\n", MemoryAttributesEntry->Type));
    183       DEBUG ((EFI_D_VERBOSE, "  PhysicalStart     - 0x%016lx\n", MemoryAttributesEntry->PhysicalStart));
    184       DEBUG ((EFI_D_VERBOSE, "  VirtualStart      - 0x%016lx\n", MemoryAttributesEntry->VirtualStart));
    185       DEBUG ((EFI_D_VERBOSE, "  NumberOfPages     - 0x%016lx\n", MemoryAttributesEntry->NumberOfPages));
    186       DEBUG ((EFI_D_VERBOSE, "  Attribute         - 0x%016lx\n", MemoryAttributesEntry->Attribute));
    187       MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR(MemoryAttributesEntry, DescriptorSize);
    188       break;
    189     }
    190     MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
    191   }
    192   MemoryMap = MemoryMapStart;
    193   FreePool (MemoryMap);
    194 
    195   //
    196   // Update configuratoin table for MemoryAttributesTable.
    197   //
    198   Status = gBS->InstallConfigurationTable (&gEfiMemoryAttributesTableGuid, MemoryAttributesTable);
    199   ASSERT_EFI_ERROR (Status);
    200 
    201   if (mMemoryAttributesTable != NULL) {
    202     FreePool (mMemoryAttributesTable);
    203   }
    204   mMemoryAttributesTable = MemoryAttributesTable;
    205 }
    206 
    207 /**
    208   Install MemoryAttributesTable on memory allocation.
    209 
    210   @param[in] MemoryType EFI memory type.
    211 **/
    212 VOID
    213 InstallMemoryAttributesTableOnMemoryAllocation (
    214   IN EFI_MEMORY_TYPE    MemoryType
    215   )
    216 {
    217   //
    218   // Install MemoryAttributesTable after ReadyToBoot on runtime memory allocation.
    219   //
    220   if (mMemoryAttributesTableReadyToBoot &&
    221       ((MemoryType == EfiRuntimeServicesCode) || (MemoryType == EfiRuntimeServicesData))) {
    222     InstallMemoryAttributesTable ();
    223   }
    224 }
    225 
    226 /**
    227   Install MemoryAttributesTable on ReadyToBoot.
    228 
    229   @param[in] Event      The Event this notify function registered to.
    230   @param[in] Context    Pointer to the context data registered to the Event.
    231 **/
    232 VOID
    233 EFIAPI
    234 InstallMemoryAttributesTableOnReadyToBoot (
    235   IN EFI_EVENT          Event,
    236   IN VOID               *Context
    237   )
    238 {
    239   InstallMemoryAttributesTable ();
    240   mMemoryAttributesTableReadyToBoot = TRUE;
    241 }
    242 
    243 /**
    244   Initialize MemoryAttrubutesTable support.
    245 **/
    246 VOID
    247 EFIAPI
    248 CoreInitializeMemoryAttributesTable (
    249   VOID
    250   )
    251 {
    252   EFI_STATUS  Status;
    253   EFI_EVENT   ReadyToBootEvent;
    254 
    255   //
    256   // Construct the table at ReadyToBoot.
    257   //
    258   Status = CoreCreateEventInternal (
    259              EVT_NOTIFY_SIGNAL,
    260              TPL_CALLBACK - 1,
    261              InstallMemoryAttributesTableOnReadyToBoot,
    262              NULL,
    263              &gEfiEventReadyToBootGuid,
    264              &ReadyToBootEvent
    265              );
    266   ASSERT_EFI_ERROR (Status);
    267   return ;
    268 }
    269