Home | History | Annotate | Download | only in QNCSmmLib
      1 /** @file
      2 QNC Smm Library Services that implements SMM Region access, S/W SMI generation and detection.
      3 
      4 Copyright (c) 2013-2015 Intel Corporation.
      5 
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 
     17 #include <Base.h>
     18 #include <IntelQNCRegs.h>
     19 #include <Library/DebugLib.h>
     20 #include <Library/PcdLib.h>
     21 #include <Library/IoLib.h>
     22 #include <Uefi/UefiBaseType.h>
     23 #include <Library/QNCAccessLib.h>
     24 
     25 #define BOOT_SERVICE_SOFTWARE_SMI_DATA          0
     26 #define RUNTIME_SOFTWARE_SMI_DATA               1
     27 
     28 /**
     29   Triggers a run time or boot time SMI.
     30 
     31   This function triggers a software SMM interrupt and set the APMC status with an 8-bit Data.
     32 
     33   @param  Data                 The value to set the APMC status.
     34 
     35 **/
     36 VOID
     37 InternalTriggerSmi (
     38   IN UINT8                     Data
     39   )
     40 {
     41   UINT16        PM1BLK_Base;
     42   UINT16        GPE0BLK_Base;
     43   UINT32        NewValue;
     44 
     45   //
     46   // Get PM1BLK_Base & GPE0BLK_Base
     47   //
     48   PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);
     49   GPE0BLK_Base = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF);
     50 
     51 
     52   //
     53   // Enable APM SMI
     54   //
     55   IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), B_QNC_GPE0BLK_SMIE_APM);
     56 
     57   //
     58   // Enable SMI globally
     59   //
     60   NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
     61   NewValue |= SMI_EN;
     62   QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
     63 
     64   //
     65   // Set APM_STS
     66   //
     67   IoWrite8 (PcdGet16 (PcdSmmDataPort), Data);
     68 
     69   //
     70   // Generate the APM SMI
     71   //
     72   IoWrite8 (PcdGet16 (PcdSmmActivationPort), PcdGet8 (PcdSmmActivationData));
     73 
     74   //
     75   // Clear the APM SMI Status Bit
     76   //
     77   IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);
     78 
     79   //
     80   // Set the EOS Bit
     81   //
     82   IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);
     83 }
     84 
     85 
     86 /**
     87   Triggers an SMI at boot time.
     88 
     89   This function triggers a software SMM interrupt at boot time.
     90 
     91 **/
     92 VOID
     93 EFIAPI
     94 TriggerBootServiceSoftwareSmi (
     95   VOID
     96   )
     97 {
     98   InternalTriggerSmi (BOOT_SERVICE_SOFTWARE_SMI_DATA);
     99 }
    100 
    101 
    102 /**
    103   Triggers an SMI at run time.
    104 
    105   This function triggers a software SMM interrupt at run time.
    106 
    107 **/
    108 VOID
    109 EFIAPI
    110 TriggerRuntimeSoftwareSmi (
    111   VOID
    112   )
    113 {
    114   InternalTriggerSmi (RUNTIME_SOFTWARE_SMI_DATA);
    115 }
    116 
    117 
    118 /**
    119   Gets the software SMI data.
    120 
    121   This function tests if a software SMM interrupt happens. If a software SMI happens,
    122   it retrieves the SMM data and returns it as a non-negative value; otherwise a negative
    123   value is returned.
    124 
    125   @return Data                 The data retrieved from SMM data port in case of a software SMI;
    126                                otherwise a negative value.
    127 
    128 **/
    129 INTN
    130 InternalGetSwSmiData (
    131   VOID
    132   )
    133 {
    134   UINT8                        SmiStatus;
    135   UINT8                        Data;
    136 
    137   SmiStatus = IoRead8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS);
    138   if (((SmiStatus & B_QNC_GPE0BLK_SMIS_APM) != 0) &&
    139        (IoRead8 (PcdGet16 (PcdSmmActivationPort)) == PcdGet8 (PcdSmmActivationData))) {
    140     Data = IoRead8 (PcdGet16 (PcdSmmDataPort));
    141     return (INTN)(UINTN)Data;
    142   }
    143 
    144   return -1;
    145 }
    146 
    147 
    148 /**
    149   Test if a boot time software SMI happened.
    150 
    151   This function tests if a software SMM interrupt happened. If a software SMM interrupt happened and
    152   it was triggered at boot time, it returns TRUE. Otherwise, it returns FALSE.
    153 
    154   @retval TRUE   A software SMI triggered at boot time happened.
    155   @retval FLASE  No software SMI happened or the software SMI was triggered at run time.
    156 
    157 **/
    158 BOOLEAN
    159 EFIAPI
    160 IsBootServiceSoftwareSmi (
    161   VOID
    162   )
    163 {
    164   return (BOOLEAN) (InternalGetSwSmiData () == BOOT_SERVICE_SOFTWARE_SMI_DATA);
    165 }
    166 
    167 
    168 /**
    169   Test if a run time software SMI happened.
    170 
    171   This function tests if a software SMM interrupt happened. If a software SMM interrupt happened and
    172   it was triggered at run time, it returns TRUE. Otherwise, it returns FALSE.
    173 
    174   @retval TRUE   A software SMI triggered at run time happened.
    175   @retval FLASE  No software SMI happened or the software SMI was triggered at boot time.
    176 
    177 **/
    178 BOOLEAN
    179 EFIAPI
    180 IsRuntimeSoftwareSmi (
    181   VOID
    182   )
    183 {
    184   return (BOOLEAN) (InternalGetSwSmiData () == RUNTIME_SOFTWARE_SMI_DATA);
    185 }
    186 
    187 
    188 
    189 /**
    190 
    191   Clear APM SMI Status Bit; Set the EOS bit.
    192 
    193 **/
    194 VOID
    195 EFIAPI
    196 ClearSmi (
    197   VOID
    198   )
    199 {
    200 
    201   UINT16                       GPE0BLK_Base;
    202 
    203   //
    204   // Get GpeBase
    205   //
    206   GPE0BLK_Base = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF);
    207 
    208   //
    209   // Clear the APM SMI Status Bit
    210   //
    211   IoOr16 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_APM);
    212 
    213   //
    214   // Set the EOS Bit
    215   //
    216   IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_EOS);
    217 }
    218 
    219 /**
    220   This routine is the chipset code that accepts a request to "open" a region of SMRAM.
    221   The region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.
    222   The use of "open" means that the memory is visible from all boot-service
    223   and SMM agents.
    224 
    225   @retval FALSE  Cannot open a locked SMRAM region
    226   @retval TRUE   Success to open SMRAM region.
    227 **/
    228 BOOLEAN
    229 EFIAPI
    230 QNCOpenSmramRegion (
    231   VOID
    232   )
    233 {
    234   UINT32                     Smram;
    235 
    236   // Read the SMRAM register
    237   Smram = QncHsmmcRead ();
    238 
    239   //
    240   //  Is the platform locked?
    241   //
    242   if (Smram & SMM_LOCKED) {
    243     // Cannot Open a locked region
    244     DEBUG ((EFI_D_WARN, "Cannot open a locked SMRAM region\n"));
    245     return FALSE;
    246   }
    247 
    248   //
    249   // Open all SMRAM regions for Host access only
    250   //
    251   Smram |= (SMM_WRITE_OPEN | SMM_READ_OPEN);  // Open for Host.
    252   Smram &= ~(NON_HOST_SMM_WR_OPEN | NON_HOST_SMM_RD_OPEN);  // Not for others.
    253 
    254   //
    255   // Write the SMRAM register
    256   //
    257   QncHsmmcWrite (Smram);
    258 
    259   return TRUE;
    260 }
    261 
    262 /**
    263   This routine is the chipset code that accepts a request to "close" a region of SMRAM.
    264   The region could be legacy AB or TSEG near top of physical memory.
    265   The use of "close" means that the memory is only visible from SMM agents,
    266   not from BS or RT code.
    267 
    268   @retval FALSE  Cannot open a locked SMRAM region
    269   @retval TRUE   Success to open SMRAM region.
    270 **/
    271 BOOLEAN
    272 EFIAPI
    273 QNCCloseSmramRegion (
    274   VOID
    275   )
    276 {
    277   UINT32                    Smram;
    278 
    279   // Read the SMRAM register.
    280   Smram = QncHsmmcRead ();
    281 
    282   //
    283   //  Is the platform locked?
    284   //
    285   if(Smram & SMM_LOCKED) {
    286     // Cannot Open a locked region
    287     DEBUG ((EFI_D_WARN, "Cannot close a locked SMRAM region\n"));
    288     return FALSE;
    289   }
    290 
    291   Smram &= (~(SMM_WRITE_OPEN | SMM_READ_OPEN | NON_HOST_SMM_WR_OPEN | NON_HOST_SMM_RD_OPEN));
    292 
    293   QncHsmmcWrite (Smram);
    294 
    295   return TRUE;
    296 }
    297 
    298 /**
    299   This routine is the chipset code that accepts a request to "lock" SMRAM.
    300   The region could be legacy AB or TSEG near top of physical memory.
    301   The use of "lock" means that the memory can no longer be opened
    302   to BS state.
    303 **/
    304 VOID
    305 EFIAPI
    306 QNCLockSmramRegion (
    307   VOID
    308   )
    309 {
    310   UINT32                    Smram;
    311 
    312   // Read the SMRAM register.
    313   Smram = QncHsmmcRead ();
    314   if(Smram & SMM_LOCKED) {
    315     DEBUG ((EFI_D_WARN, "SMRAM region already locked!\n"));
    316   }
    317   Smram |= SMM_LOCKED;
    318 
    319   QncHsmmcWrite (Smram);
    320 
    321   return;
    322 }
    323