--- /dev/null
+/** @file\r
+QNC Smm Library Services that implements SMM Region access, S/W SMI generation and detection.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include <Base.h>\r
+#include <IntelQNCRegs.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Uefi/UefiBaseType.h>\r
+#include <Library/QNCAccessLib.h>\r
+\r
+#define BOOT_SERVICE_SOFTWARE_SMI_DATA 0\r
+#define RUNTIME_SOFTWARE_SMI_DATA 1\r
+\r
+/**\r
+ Triggers a run time or boot time SMI.\r
+\r
+ This function triggers a software SMM interrupt and set the APMC status with an 8-bit Data.\r
+\r
+ @param Data The value to set the APMC status.\r
+\r
+**/\r
+VOID\r
+InternalTriggerSmi (\r
+ IN UINT8 Data\r
+ )\r
+{\r
+ UINT16 PM1BLK_Base;\r
+ UINT16 GPE0BLK_Base;\r
+ UINT32 NewValue;\r
+\r
+ //\r
+ // Get PM1BLK_Base & GPE0BLK_Base\r
+ //\r
+ PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);\r
+ GPE0BLK_Base = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF);\r
+\r
+\r
+ //\r
+ // Enable APM SMI\r
+ //\r
+ IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), B_QNC_GPE0BLK_SMIE_APM);\r
+\r
+ //\r
+ // Enable SMI globally\r
+ //\r
+ NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);\r
+ NewValue |= SMI_EN;\r
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);\r
+\r
+ //\r
+ // Set APM_STS\r
+ //\r
+ IoWrite8 (PcdGet16 (PcdSmmDataPort), Data);\r
+\r
+ //\r
+ // Generate the APM SMI\r
+ //\r
+ IoWrite8 (PcdGet16 (PcdSmmActivationPort), PcdGet8 (PcdSmmActivationData));\r
+\r
+ //\r
+ // Clear the APM SMI Status Bit\r
+ //\r
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);\r
+\r
+ //\r
+ // Set the EOS Bit\r
+ //\r
+ IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);\r
+}\r
+\r
+\r
+/**\r
+ Triggers an SMI at boot time.\r
+\r
+ This function triggers a software SMM interrupt at boot time.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TriggerBootServiceSoftwareSmi (\r
+ VOID\r
+ )\r
+{\r
+ InternalTriggerSmi (BOOT_SERVICE_SOFTWARE_SMI_DATA);\r
+}\r
+\r
+\r
+/**\r
+ Triggers an SMI at run time.\r
+\r
+ This function triggers a software SMM interrupt at run time.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TriggerRuntimeSoftwareSmi (\r
+ VOID\r
+ )\r
+{\r
+ InternalTriggerSmi (RUNTIME_SOFTWARE_SMI_DATA);\r
+}\r
+\r
+\r
+/**\r
+ Gets the software SMI data.\r
+\r
+ This function tests if a software SMM interrupt happens. If a software SMI happens,\r
+ it retrieves the SMM data and returns it as a non-negative value; otherwise a negative\r
+ value is returned.\r
+\r
+ @return Data The data retrieved from SMM data port in case of a software SMI;\r
+ otherwise a negative value.\r
+\r
+**/\r
+INTN\r
+InternalGetSwSmiData (\r
+ VOID\r
+ )\r
+{\r
+ UINT8 SmiStatus;\r
+ UINT8 Data;\r
+\r
+ SmiStatus = IoRead8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS);\r
+ if (((SmiStatus & B_QNC_GPE0BLK_SMIS_APM) != 0) &&\r
+ (IoRead8 (PcdGet16 (PcdSmmActivationPort)) == PcdGet8 (PcdSmmActivationData))) {\r
+ Data = IoRead8 (PcdGet16 (PcdSmmDataPort));\r
+ return (INTN)(UINTN)Data;\r
+ }\r
+\r
+ return -1;\r
+}\r
+\r
+\r
+/**\r
+ Test if a boot time software SMI happened.\r
+\r
+ This function tests if a software SMM interrupt happened. If a software SMM interrupt happened and\r
+ it was triggered at boot time, it returns TRUE. Otherwise, it returns FALSE.\r
+\r
+ @retval TRUE A software SMI triggered at boot time happened.\r
+ @retval FLASE No software SMI happened or the software SMI was triggered at run time.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsBootServiceSoftwareSmi (\r
+ VOID\r
+ )\r
+{\r
+ return (BOOLEAN) (InternalGetSwSmiData () == BOOT_SERVICE_SOFTWARE_SMI_DATA);\r
+}\r
+\r
+\r
+/**\r
+ Test if a run time software SMI happened.\r
+\r
+ This function tests if a software SMM interrupt happened. If a software SMM interrupt happened and\r
+ it was triggered at run time, it returns TRUE. Otherwise, it returns FALSE.\r
+\r
+ @retval TRUE A software SMI triggered at run time happened.\r
+ @retval FLASE No software SMI happened or the software SMI was triggered at boot time.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsRuntimeSoftwareSmi (\r
+ VOID\r
+ )\r
+{\r
+ return (BOOLEAN) (InternalGetSwSmiData () == RUNTIME_SOFTWARE_SMI_DATA);\r
+}\r
+\r
+\r
+\r
+/**\r
+\r
+ Clear APM SMI Status Bit; Set the EOS bit.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ClearSmi (\r
+ VOID\r
+ )\r
+{\r
+\r
+ UINT16 GPE0BLK_Base;\r
+\r
+ //\r
+ // Get GpeBase\r
+ //\r
+ GPE0BLK_Base = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF);\r
+\r
+ //\r
+ // Clear the APM SMI Status Bit\r
+ //\r
+ IoOr16 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_APM);\r
+\r
+ //\r
+ // Set the EOS Bit\r
+ //\r
+ IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_EOS);\r
+}\r
+\r
+/**\r
+ This routine is the chipset code that accepts a request to "open" a region of SMRAM.\r
+ The region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.\r
+ The use of "open" means that the memory is visible from all boot-service\r
+ and SMM agents.\r
+\r
+ @retval FALSE Cannot open a locked SMRAM region\r
+ @retval TRUE Success to open SMRAM region.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+QNCOpenSmramRegion (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 Smram;\r
+\r
+ // Read the SMRAM register\r
+ Smram = QncHsmmcRead ();\r
+\r
+ //\r
+ // Is the platform locked?\r
+ //\r
+ if (Smram & SMM_LOCKED) {\r
+ // Cannot Open a locked region\r
+ DEBUG ((EFI_D_WARN, "Cannot open a locked SMRAM region\n"));\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Open all SMRAM regions for Host access only\r
+ //\r
+ Smram |= (SMM_WRITE_OPEN | SMM_READ_OPEN); // Open for Host.\r
+ Smram &= ~(NON_HOST_SMM_WR_OPEN | NON_HOST_SMM_RD_OPEN); // Not for others.\r
+\r
+ //\r
+ // Write the SMRAM register\r
+ //\r
+ QncHsmmcWrite (Smram);\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ This routine is the chipset code that accepts a request to "close" a region of SMRAM.\r
+ The region could be legacy AB or TSEG near top of physical memory.\r
+ The use of "close" means that the memory is only visible from SMM agents,\r
+ not from BS or RT code.\r
+\r
+ @retval FALSE Cannot open a locked SMRAM region\r
+ @retval TRUE Success to open SMRAM region.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+QNCCloseSmramRegion (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 Smram;\r
+\r
+ // Read the SMRAM register.\r
+ Smram = QncHsmmcRead ();\r
+\r
+ //\r
+ // Is the platform locked?\r
+ //\r
+ if(Smram & SMM_LOCKED) {\r
+ // Cannot Open a locked region\r
+ DEBUG ((EFI_D_WARN, "Cannot close a locked SMRAM region\n"));\r
+ return FALSE;\r
+ }\r
+\r
+ Smram &= (~(SMM_WRITE_OPEN | SMM_READ_OPEN | NON_HOST_SMM_WR_OPEN | NON_HOST_SMM_RD_OPEN));\r
+\r
+ QncHsmmcWrite (Smram);\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ This routine is the chipset code that accepts a request to "lock" SMRAM.\r
+ The region could be legacy AB or TSEG near top of physical memory.\r
+ The use of "lock" means that the memory can no longer be opened\r
+ to BS state.\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCLockSmramRegion (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 Smram;\r
+\r
+ // Read the SMRAM register.\r
+ Smram = QncHsmmcRead ();\r
+ if(Smram & SMM_LOCKED) {\r
+ DEBUG ((EFI_D_WARN, "SMRAM region already locked!\n"));\r
+ }\r
+ Smram |= SMM_LOCKED;\r
+\r
+ QncHsmmcWrite (Smram);\r
+\r
+ return;\r
+}\r