Home | History | Annotate | Download | only in SmmMemLib
      1 /** @file
      2   Instance of SMM memory check library.
      3 
      4   SMM memory check library library implementation. This library consumes SMM_ACCESS2_PROTOCOL
      5   to get SMRAM information. In order to use this library instance, the platform should produce
      6   all SMRAM range via SMM_ACCESS2_PROTOCOL, including the range for firmware (like SMM Core
      7   and SMM driver) and/or specific dedicated hardware.
      8 
      9   Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
     10   This program and the accompanying materials
     11   are licensed and made available under the terms and conditions of the BSD License
     12   which accompanies this distribution.  The full text of the license may be found at
     13   http://opensource.org/licenses/bsd-license.php
     14 
     15   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     16   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     17 
     18 **/
     19 
     20 
     21 #include <PiSmm.h>
     22 
     23 #include <Library/BaseLib.h>
     24 #include <Library/BaseMemoryLib.h>
     25 #include <Library/DebugLib.h>
     26 #include <Library/MemoryAllocationLib.h>
     27 #include <Library/UefiBootServicesTableLib.h>
     28 #include <Library/SmmServicesTableLib.h>
     29 #include <Library/HobLib.h>
     30 #include <Protocol/SmmAccess2.h>
     31 
     32 EFI_SMRAM_DESCRIPTOR *mSmmMemLibInternalSmramRanges;
     33 UINTN                mSmmMemLibInternalSmramCount;
     34 
     35 //
     36 // Maximum support address used to check input buffer
     37 //
     38 EFI_PHYSICAL_ADDRESS  mSmmMemLibInternalMaximumSupportAddress = 0;
     39 
     40 /**
     41   Calculate and save the maximum support address.
     42 
     43 **/
     44 VOID
     45 SmmMemLibInternalCalculateMaximumSupportAddress (
     46   VOID
     47   )
     48 {
     49   VOID         *Hob;
     50   UINT32       RegEax;
     51   UINT8        PhysicalAddressBits;
     52 
     53   //
     54   // Get physical address bits supported.
     55   //
     56   Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
     57   if (Hob != NULL) {
     58     PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
     59   } else {
     60     AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
     61     if (RegEax >= 0x80000008) {
     62       AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
     63       PhysicalAddressBits = (UINT8) RegEax;
     64     } else {
     65       PhysicalAddressBits = 36;
     66     }
     67   }
     68   //
     69   // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
     70   //
     71   ASSERT (PhysicalAddressBits <= 52);
     72   if (PhysicalAddressBits > 48) {
     73     PhysicalAddressBits = 48;
     74   }
     75 
     76   //
     77   // Save the maximum support address in one global variable
     78   //
     79   mSmmMemLibInternalMaximumSupportAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)(LShiftU64 (1, PhysicalAddressBits) - 1);
     80   DEBUG ((EFI_D_INFO, "mSmmMemLibInternalMaximumSupportAddress = 0x%lx\n", mSmmMemLibInternalMaximumSupportAddress));
     81 }
     82 
     83 /**
     84   This function check if the buffer is valid per processor architecture and not overlap with SMRAM.
     85 
     86   @param Buffer  The buffer start address to be checked.
     87   @param Length  The buffer length to be checked.
     88 
     89   @retval TRUE  This buffer is valid per processor architecture and not overlap with SMRAM.
     90   @retval FALSE This buffer is not valid per processor architecture or overlap with SMRAM.
     91 **/
     92 BOOLEAN
     93 EFIAPI
     94 SmmIsBufferOutsideSmmValid (
     95   IN EFI_PHYSICAL_ADDRESS  Buffer,
     96   IN UINT64                Length
     97   )
     98 {
     99   UINTN  Index;
    100 
    101   //
    102   // Check override.
    103   // NOTE: (B:0->L:4G) is invalid for IA32, but (B:1->L:4G-1)/(B:4G-1->L:1) is valid.
    104   //
    105   if ((Length > mSmmMemLibInternalMaximumSupportAddress) ||
    106       (Buffer > mSmmMemLibInternalMaximumSupportAddress) ||
    107       ((Length != 0) && (Buffer > (mSmmMemLibInternalMaximumSupportAddress - (Length - 1)))) ) {
    108     //
    109     // Overflow happen
    110     //
    111     DEBUG ((
    112       EFI_D_ERROR,
    113       "SmmIsBufferOutsideSmmValid: Overflow: Buffer (0x%lx) - Length (0x%lx), MaximumSupportAddress (0x%lx)\n",
    114       Buffer,
    115       Length,
    116       mSmmMemLibInternalMaximumSupportAddress
    117       ));
    118     return FALSE;
    119   }
    120 
    121   for (Index = 0; Index < mSmmMemLibInternalSmramCount; Index ++) {
    122     if (((Buffer >= mSmmMemLibInternalSmramRanges[Index].CpuStart) && (Buffer < mSmmMemLibInternalSmramRanges[Index].CpuStart + mSmmMemLibInternalSmramRanges[Index].PhysicalSize)) ||
    123         ((mSmmMemLibInternalSmramRanges[Index].CpuStart >= Buffer) && (mSmmMemLibInternalSmramRanges[Index].CpuStart < Buffer + Length))) {
    124       DEBUG ((
    125         EFI_D_ERROR,
    126         "SmmIsBufferOutsideSmmValid: Overlap: Buffer (0x%lx) - Length (0x%lx), ",
    127         Buffer,
    128         Length
    129         ));
    130       DEBUG ((
    131         EFI_D_ERROR,
    132         "CpuStart (0x%lx) - PhysicalSize (0x%lx)\n",
    133         mSmmMemLibInternalSmramRanges[Index].CpuStart,
    134         mSmmMemLibInternalSmramRanges[Index].PhysicalSize
    135         ));
    136       return FALSE;
    137     }
    138   }
    139 
    140   return TRUE;
    141 }
    142 
    143 /**
    144   Copies a source buffer (non-SMRAM) to a destination buffer (SMRAM).
    145 
    146   This function copies a source buffer (non-SMRAM) to a destination buffer (SMRAM).
    147   It checks if source buffer is valid per processor architecture and not overlap with SMRAM.
    148   If the check passes, it copies memory and returns EFI_SUCCESS.
    149   If the check fails, it return EFI_SECURITY_VIOLATION.
    150   The implementation must be reentrant.
    151 
    152   @param  DestinationBuffer   The pointer to the destination buffer of the memory copy.
    153   @param  SourceBuffer        The pointer to the source buffer of the memory copy.
    154   @param  Length              The number of bytes to copy from SourceBuffer to DestinationBuffer.
    155 
    156   @retval EFI_SECURITY_VIOLATION The SourceBuffer is invalid per processor architecture or overlap with SMRAM.
    157   @retval EFI_SUCCESS            Memory is copied.
    158 
    159 **/
    160 EFI_STATUS
    161 EFIAPI
    162 SmmCopyMemToSmram (
    163   OUT VOID       *DestinationBuffer,
    164   IN CONST VOID  *SourceBuffer,
    165   IN UINTN       Length
    166   )
    167 {
    168   if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)SourceBuffer, Length)) {
    169     DEBUG ((EFI_D_ERROR, "SmmCopyMemToSmram: Security Violation: Source (0x%x), Length (0x%x)\n", SourceBuffer, Length));
    170     return EFI_SECURITY_VIOLATION;
    171   }
    172   CopyMem (DestinationBuffer, SourceBuffer, Length);
    173   return EFI_SUCCESS;
    174 }
    175 
    176 /**
    177   Copies a source buffer (SMRAM) to a destination buffer (NON-SMRAM).
    178 
    179   This function copies a source buffer (non-SMRAM) to a destination buffer (SMRAM).
    180   It checks if destination buffer is valid per processor architecture and not overlap with SMRAM.
    181   If the check passes, it copies memory and returns EFI_SUCCESS.
    182   If the check fails, it returns EFI_SECURITY_VIOLATION.
    183   The implementation must be reentrant.
    184 
    185   @param  DestinationBuffer   The pointer to the destination buffer of the memory copy.
    186   @param  SourceBuffer        The pointer to the source buffer of the memory copy.
    187   @param  Length              The number of bytes to copy from SourceBuffer to DestinationBuffer.
    188 
    189   @retval EFI_SECURITY_VIOLATION The DesinationBuffer is invalid per processor architecture or overlap with SMRAM.
    190   @retval EFI_SUCCESS            Memory is copied.
    191 
    192 **/
    193 EFI_STATUS
    194 EFIAPI
    195 SmmCopyMemFromSmram (
    196   OUT VOID       *DestinationBuffer,
    197   IN CONST VOID  *SourceBuffer,
    198   IN UINTN       Length
    199   )
    200 {
    201   if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)DestinationBuffer, Length)) {
    202     DEBUG ((EFI_D_ERROR, "SmmCopyMemFromSmram: Security Violation: Destination (0x%x), Length (0x%x)\n", DestinationBuffer, Length));
    203     return EFI_SECURITY_VIOLATION;
    204   }
    205   CopyMem (DestinationBuffer, SourceBuffer, Length);
    206   return EFI_SUCCESS;
    207 }
    208 
    209 /**
    210   Copies a source buffer (NON-SMRAM) to a destination buffer (NON-SMRAM).
    211 
    212   This function copies a source buffer (non-SMRAM) to a destination buffer (SMRAM).
    213   It checks if source buffer and destination buffer are valid per processor architecture and not overlap with SMRAM.
    214   If the check passes, it copies memory and returns EFI_SUCCESS.
    215   If the check fails, it returns EFI_SECURITY_VIOLATION.
    216   The implementation must be reentrant, and it must handle the case where source buffer overlaps destination buffer.
    217 
    218   @param  DestinationBuffer   The pointer to the destination buffer of the memory copy.
    219   @param  SourceBuffer        The pointer to the source buffer of the memory copy.
    220   @param  Length              The number of bytes to copy from SourceBuffer to DestinationBuffer.
    221 
    222   @retval EFI_SECURITY_VIOLATION The DesinationBuffer is invalid per processor architecture or overlap with SMRAM.
    223   @retval EFI_SECURITY_VIOLATION The SourceBuffer is invalid per processor architecture or overlap with SMRAM.
    224   @retval EFI_SUCCESS            Memory is copied.
    225 
    226 **/
    227 EFI_STATUS
    228 EFIAPI
    229 SmmCopyMem (
    230   OUT VOID       *DestinationBuffer,
    231   IN CONST VOID  *SourceBuffer,
    232   IN UINTN       Length
    233   )
    234 {
    235   if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)DestinationBuffer, Length)) {
    236     DEBUG ((EFI_D_ERROR, "SmmCopyMem: Security Violation: Destination (0x%x), Length (0x%x)\n", DestinationBuffer, Length));
    237     return EFI_SECURITY_VIOLATION;
    238   }
    239   if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)SourceBuffer, Length)) {
    240     DEBUG ((EFI_D_ERROR, "SmmCopyMem: Security Violation: Source (0x%x), Length (0x%x)\n", SourceBuffer, Length));
    241     return EFI_SECURITY_VIOLATION;
    242   }
    243   CopyMem (DestinationBuffer, SourceBuffer, Length);
    244   return EFI_SUCCESS;
    245 }
    246 
    247 /**
    248   Fills a target buffer (NON-SMRAM) with a byte value.
    249 
    250   This function fills a target buffer (non-SMRAM) with a byte value.
    251   It checks if target buffer is valid per processor architecture and not overlap with SMRAM.
    252   If the check passes, it fills memory and returns EFI_SUCCESS.
    253   If the check fails, it returns EFI_SECURITY_VIOLATION.
    254 
    255   @param  Buffer    The memory to set.
    256   @param  Length    The number of bytes to set.
    257   @param  Value     The value with which to fill Length bytes of Buffer.
    258 
    259   @retval EFI_SECURITY_VIOLATION The Buffer is invalid per processor architecture or overlap with SMRAM.
    260   @retval EFI_SUCCESS            Memory is set.
    261 
    262 **/
    263 EFI_STATUS
    264 EFIAPI
    265 SmmSetMem (
    266   OUT VOID  *Buffer,
    267   IN UINTN  Length,
    268   IN UINT8  Value
    269   )
    270 {
    271   if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, Length)) {
    272     DEBUG ((EFI_D_ERROR, "SmmSetMem: Security Violation: Source (0x%x), Length (0x%x)\n", Buffer, Length));
    273     return EFI_SECURITY_VIOLATION;
    274   }
    275   SetMem (Buffer, Length, Value);
    276   return EFI_SUCCESS;
    277 }
    278 
    279 /**
    280   The constructor function initializes the Smm Mem library
    281 
    282   @param  ImageHandle   The firmware allocated handle for the EFI image.
    283   @param  SystemTable   A pointer to the EFI System Table.
    284 
    285   @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
    286 
    287 **/
    288 EFI_STATUS
    289 EFIAPI
    290 SmmMemLibConstructor (
    291   IN EFI_HANDLE        ImageHandle,
    292   IN EFI_SYSTEM_TABLE  *SystemTable
    293   )
    294 {
    295   EFI_STATUS                    Status;
    296   EFI_SMM_ACCESS2_PROTOCOL      *SmmAccess;
    297   UINTN                         Size;
    298 
    299   //
    300   // Get SMRAM information
    301   //
    302   Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);
    303   ASSERT_EFI_ERROR (Status);
    304 
    305   Size = 0;
    306   Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL);
    307   ASSERT (Status == EFI_BUFFER_TOO_SMALL);
    308 
    309   mSmmMemLibInternalSmramRanges = AllocatePool (Size);
    310   ASSERT (mSmmMemLibInternalSmramRanges != NULL);
    311 
    312   Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmmMemLibInternalSmramRanges);
    313   ASSERT_EFI_ERROR (Status);
    314 
    315   mSmmMemLibInternalSmramCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
    316 
    317   //
    318   // Calculate and save maximum support address
    319   //
    320   SmmMemLibInternalCalculateMaximumSupportAddress ();
    321 
    322   return EFI_SUCCESS;
    323 }
    324 
    325 /**
    326   The destructor function frees resource used in the Smm Mem library
    327 
    328   @param[in]  ImageHandle   The firmware allocated handle for the EFI image.
    329   @param[in]  SystemTable   A pointer to the EFI System Table.
    330 
    331   @retval     EFI_SUCCESS   The deconstructor always returns EFI_SUCCESS.
    332 **/
    333 EFI_STATUS
    334 EFIAPI
    335 SmmMemLibDestructor (
    336   IN EFI_HANDLE        ImageHandle,
    337   IN EFI_SYSTEM_TABLE  *SystemTable
    338   )
    339 {
    340   FreePool (mSmmMemLibInternalSmramRanges);
    341 
    342   return EFI_SUCCESS;
    343 }
    344