Home | History | Annotate | Download | only in SmmAccessDxe
      1 /** @file
      2 This is the driver that publishes the SMM Access Protocol
      3 instance for the Tylersburg chipset.
      4 
      5 Copyright (c) 2013-2015 Intel Corporation.
      6 
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions of the BSD License
      9 which accompanies this distribution.  The full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "SmmAccessDriver.h"
     18 
     19 
     20 
     21 SMM_ACCESS_PRIVATE_DATA  mSmmAccess;
     22 
     23 VOID
     24 SmmAccessOnBoot (
     25   IN EFI_EVENT                          Event,
     26   IN VOID                               *Context
     27 );
     28 
     29 EFI_STATUS
     30 EFIAPI
     31 SmmAccessDriverEntryPoint (
     32   IN EFI_HANDLE         ImageHandle,
     33   IN EFI_SYSTEM_TABLE   *SystemTable
     34   )
     35 /*++
     36 
     37 Routine Description:
     38 
     39   Installs an SMM Access Protocol.
     40 
     41 Arguments:
     42 
     43   ImageHandle  -  Handle for the image of this driver.
     44   SystemTable  -  Pointer to the EFI System Table.
     45 
     46 Returns:
     47 
     48   EFI_SUCCESS     -  Protocol successfully started and installed.
     49   EFI_UNSUPPORTED -  Protocol can't be started.
     50   EFI_NOT_FOUND   -  Protocol not found.
     51 --*/
     52 {
     53 
     54   EFI_STATUS                      Status;
     55   EFI_EVENT                       BootEvent;
     56   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
     57   UINTN                           Index;
     58   EFI_SMRAM_HOB_DESCRIPTOR_BLOCK  *DescriptorBlock;
     59   EFI_HOB_GUID_TYPE               *GuidHob;
     60 
     61 
     62   //
     63   // Initialize private data
     64   //
     65   ZeroMem (&mSmmAccess, sizeof (mSmmAccess));
     66 
     67   Status = gBS->LocateProtocol (
     68                   &gEfiPciRootBridgeIoProtocolGuid,
     69                   NULL,
     70                   (VOID **) &PciRootBridgeIo
     71                   );
     72   ASSERT_EFI_ERROR (Status);
     73 
     74   //
     75   // Build SMM related information
     76   //
     77   mSmmAccess.Signature        = SMM_ACCESS_PRIVATE_DATA_SIGNATURE;
     78   mSmmAccess.Handle           = NULL;
     79   mSmmAccess.PciRootBridgeIo  = PciRootBridgeIo;
     80 
     81   //
     82   // Get Hob list
     83   //
     84   GuidHob    = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);
     85   DescriptorBlock = GET_GUID_HOB_DATA (GuidHob);
     86   ASSERT (DescriptorBlock);
     87 
     88 
     89   //
     90   // Get CPU Max bus number
     91   //
     92   mSmmAccess.MaxBusNumber         = PCI_BUS_NUMBER_QNC;
     93   for (Index = 0; Index < MAX_CPU_SOCKET; Index++) {
     94     mSmmAccess.SocketPopulated[Index] = TRUE;
     95   }
     96 
     97   //
     98   // Use the hob to publish SMRAM capabilities
     99   //
    100   ASSERT (DescriptorBlock->NumberOfSmmReservedRegions <= MAX_SMRAM_RANGES);
    101   for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) {
    102     mSmmAccess.SmramDesc[Index].PhysicalStart = DescriptorBlock->Descriptor[Index].PhysicalStart;
    103     mSmmAccess.SmramDesc[Index].CpuStart      = DescriptorBlock->Descriptor[Index].CpuStart;
    104     mSmmAccess.SmramDesc[Index].PhysicalSize  = DescriptorBlock->Descriptor[Index].PhysicalSize;
    105     mSmmAccess.SmramDesc[Index].RegionState   = DescriptorBlock->Descriptor[Index].RegionState;
    106     DEBUG ((EFI_D_INFO, "SM RAM index[%d] startaddr:%08X Size :%08X\n", Index, mSmmAccess.SmramDesc[Index].CpuStart,
    107       mSmmAccess.SmramDesc[Index].PhysicalSize));
    108   }
    109 
    110   mSmmAccess.NumberRegions              = Index;
    111   mSmmAccess.SmmAccess.Open             = Open;
    112   mSmmAccess.SmmAccess.Close            = Close;
    113   mSmmAccess.SmmAccess.Lock             = Lock;
    114   mSmmAccess.SmmAccess.GetCapabilities  = GetCapabilities;
    115   mSmmAccess.SmmAccess.LockState        = FALSE;
    116   mSmmAccess.SmmAccess.OpenState        = FALSE;
    117   mSmmAccess.SMMRegionState             = EFI_SMRAM_CLOSED;
    118 
    119   //
    120   // Install our protocol interfaces on the device's handle
    121   //
    122   Status = gBS->InstallMultipleProtocolInterfaces (
    123                 &mSmmAccess.Handle,
    124                 &gEfiSmmAccess2ProtocolGuid,
    125                 &mSmmAccess.SmmAccess,
    126                 NULL
    127                 );
    128   ASSERT_EFI_ERROR (Status);
    129 
    130   DEBUG ((EFI_D_INFO, "SMM  Base: %08X\n", (UINT32)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalStart)));
    131   DEBUG ((EFI_D_INFO, "SMM  Size: %08X\n", (UINT32)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalSize)));
    132 
    133   mSmmAccess.TsegSize = (UINT8)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalSize);
    134   //
    135   // T Seg setting done in QPI RC
    136   //
    137 
    138   //
    139   // Prior ReadyToBoot, lock CSEG
    140   //
    141   Status = EfiCreateEventReadyToBootEx(
    142            TPL_NOTIFY,
    143            SmmAccessOnBoot,
    144            NULL,
    145            &BootEvent );
    146   ASSERT (!EFI_ERROR (Status));
    147   return EFI_SUCCESS;
    148 }
    149 
    150 EFI_STATUS
    151 EFIAPI
    152 Open (
    153   IN EFI_SMM_ACCESS2_PROTOCOL    *This
    154   )
    155 /*++
    156 
    157 Routine Description:
    158 
    159   This routine accepts a request to "open" a region of SMRAM.  The
    160   region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.
    161   The use of "open" means that the memory is visible from all boot-service
    162   and SMM agents.
    163 
    164 Arguments:
    165 
    166   This             -  Pointer to the SMM Access Interface.
    167   DescriptorIndex  -  Region of SMRAM to Open.
    168 
    169 Returns:
    170 
    171   EFI_SUCCESS            -  The region was successfully opened.
    172   EFI_DEVICE_ERROR       -  The region could not be opened because locked by
    173                             chipset.
    174   EFI_INVALID_PARAMETER  -  The descriptor index was out of bounds.
    175 
    176 --*/
    177 {
    178   SMM_ACCESS_PRIVATE_DATA *SmmAccess;
    179 
    180   SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
    181 
    182   if (mSmmAccess.SMMRegionState & EFI_SMRAM_LOCKED) {
    183     DEBUG ((EFI_D_ERROR, "Cannot open a locked SMRAM region\n"));
    184     return EFI_DEVICE_ERROR;
    185   }
    186 
    187   //
    188   // Open TSEG
    189   //
    190   if (!QNCOpenSmramRegion ()) {
    191     mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED;
    192     return EFI_DEVICE_ERROR;
    193   }
    194 
    195   mSmmAccess.SMMRegionState &= ~(EFI_SMRAM_CLOSED | EFI_ALLOCATED);
    196   SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~(EFI_SMRAM_CLOSED | EFI_ALLOCATED)));
    197   mSmmAccess.SMMRegionState |= EFI_SMRAM_OPEN;
    198   SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_OPEN);
    199   SmmAccess->SmmAccess.OpenState = TRUE;
    200 
    201   return EFI_SUCCESS;
    202 }
    203 
    204 EFI_STATUS
    205 EFIAPI
    206 Close (
    207   IN EFI_SMM_ACCESS2_PROTOCOL *This
    208   )
    209 /*++
    210 
    211 Routine Description:
    212 
    213   This routine accepts a request to "close" a region of SMRAM.  This is valid for
    214   compatible SMRAM region.
    215 
    216 Arguments:
    217 
    218   This             -  Pointer to the SMM Access Interface.
    219   DescriptorIndex  -  Region of SMRAM to Close.
    220 
    221 Returns:
    222 
    223   EFI_SUCCESS            -  The region was successfully closed.
    224   EFI_DEVICE_ERROR       -  The region could not be closed because locked by
    225                             chipset.
    226   EFI_INVALID_PARAMETER  -  The descriptor index was out of bounds.
    227 
    228 --*/
    229 {
    230   SMM_ACCESS_PRIVATE_DATA *SmmAccess;
    231   BOOLEAN                 OpenState;
    232   UINTN                   Index;
    233 
    234   SmmAccess     = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
    235 
    236   if (mSmmAccess.SMMRegionState & EFI_SMRAM_LOCKED) {
    237     //
    238     // Cannot close a "locked" region
    239     //
    240     DEBUG ((EFI_D_WARN, "Cannot close the locked SMRAM Region\n"));
    241     return EFI_DEVICE_ERROR;
    242   }
    243 
    244   if (mSmmAccess.SMMRegionState & EFI_SMRAM_CLOSED) {
    245     return EFI_DEVICE_ERROR;
    246   }
    247 
    248   //
    249   // Close TSEG
    250   //
    251   if (!QNCCloseSmramRegion ()) {
    252     mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED;
    253     return EFI_DEVICE_ERROR;
    254   }
    255 
    256   mSmmAccess.SMMRegionState &= ~EFI_SMRAM_OPEN;
    257   SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~EFI_SMRAM_OPEN));
    258   mSmmAccess.SMMRegionState |= (EFI_SMRAM_CLOSED | EFI_ALLOCATED);
    259   SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_CLOSED | EFI_ALLOCATED);
    260 
    261   //
    262   // Find out if any regions are still open
    263   //
    264   OpenState = FALSE;
    265   for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) {
    266     if ((SmmAccess->SmramDesc[Index].RegionState & EFI_SMRAM_OPEN) == EFI_SMRAM_OPEN) {
    267       OpenState = TRUE;
    268     }
    269   }
    270 
    271   SmmAccess->SmmAccess.OpenState = OpenState;
    272 
    273   return EFI_SUCCESS;
    274 }
    275 
    276 EFI_STATUS
    277 EFIAPI
    278 Lock (
    279   IN EFI_SMM_ACCESS2_PROTOCOL   *This
    280   )
    281 /*++
    282 
    283 Routine Description:
    284 
    285   This routine accepts a request to "lock" SMRAM.  The
    286   region could be legacy AB or TSEG near top of physical memory.
    287   The use of "lock" means that the memory can no longer be opened
    288   to BS state..
    289 
    290 Arguments:
    291 
    292   This             -  Pointer to the SMM Access Interface.
    293   DescriptorIndex  -  Region of SMRAM to Lock.
    294 
    295 Returns:
    296 
    297   EFI_SUCCESS            -  The region was successfully locked.
    298   EFI_DEVICE_ERROR       -  The region could not be locked because at least
    299                             one range is still open.
    300   EFI_INVALID_PARAMETER  -  The descriptor index was out of bounds.
    301 
    302 --*/
    303 {
    304   SMM_ACCESS_PRIVATE_DATA *SmmAccess;
    305 
    306   SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
    307 
    308   if (SmmAccess->SmmAccess.OpenState) {
    309     return EFI_DEVICE_ERROR;
    310   }
    311 
    312   mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED;
    313   SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_LOCKED);
    314   SmmAccess->SmmAccess.LockState                     = TRUE;
    315 
    316   //
    317   // Lock TSEG
    318   //
    319   QNCLockSmramRegion ();
    320 
    321   return EFI_SUCCESS;
    322 }
    323 
    324 EFI_STATUS
    325 EFIAPI
    326 GetCapabilities (
    327   IN CONST  EFI_SMM_ACCESS2_PROTOCOL *This,
    328   IN OUT UINTN                       *SmramMapSize,
    329   IN OUT EFI_SMRAM_DESCRIPTOR        *SmramMap
    330   )
    331 /*++
    332 
    333 Routine Description:
    334 
    335   This routine services a user request to discover the SMRAM
    336   capabilities of this platform.  This will report the possible
    337   ranges that are possible for SMRAM access, based upon the
    338   memory controller capabilities.
    339 
    340 Arguments:
    341 
    342   This          -  Pointer to the SMRAM Access Interface.
    343   SmramMapSize  -  Pointer to the variable containing size of the
    344                    buffer to contain the description information.
    345   SmramMap      -  Buffer containing the data describing the Smram
    346                    region descriptors.
    347 Returns:
    348 
    349   EFI_BUFFER_TOO_SMALL  -  The user did not provide a sufficient buffer.
    350   EFI_SUCCESS           -  The user provided a sufficiently-sized buffer.
    351 
    352 --*/
    353 {
    354   EFI_STATUS                Status;
    355   SMM_ACCESS_PRIVATE_DATA  *SmmAccess;
    356   UINTN                     BufferSize;
    357 
    358   SmmAccess           = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
    359   BufferSize          = SmmAccess->NumberRegions * sizeof (EFI_SMRAM_DESCRIPTOR);
    360 
    361   if (*SmramMapSize < BufferSize) {
    362     Status = EFI_BUFFER_TOO_SMALL;
    363   } else {
    364     CopyMem (SmramMap, SmmAccess->SmramDesc, *SmramMapSize);
    365     Status = EFI_SUCCESS;
    366   }
    367   *SmramMapSize = BufferSize;
    368 
    369   return Status;
    370 }
    371 
    372 VOID
    373 SmmAccessOnBoot (
    374   IN EFI_EVENT                          Event,
    375   IN VOID                               *Context
    376 )
    377 {
    378 
    379 }
    380 VOID
    381 SyncRegionState2SmramDesc(
    382   IN BOOLEAN  OrAnd,
    383   IN UINT64   Value
    384   )
    385 {
    386   UINT32 Index;
    387 
    388   for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) {
    389     if (OrAnd) {
    390       mSmmAccess.SmramDesc[Index].RegionState |= Value;
    391     } else {
    392       mSmmAccess.SmramDesc[Index].RegionState &= Value;
    393     }
    394   }
    395 }
    396