summaryrefslogtreecommitdiff
path: root/QuarkSocPkg/QuarkNorthCluster/Smm
diff options
context:
space:
mode:
authorMichael Kinney <michael.d.kinney@intel.com>2015-12-15 19:22:23 +0000
committermdkinney <mdkinney@Edk2>2015-12-15 19:22:23 +0000
commit9b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164 (patch)
treebb30f13e652143e0ac74e589e908ca2a1782da73 /QuarkSocPkg/QuarkNorthCluster/Smm
parent46ff196fde4882fca1a0210f7df9166d8832ad06 (diff)
downloadedk2-platforms-9b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164.tar.xz
QuarkSocPkg: Add new package for Quark SoC X1000
Changes for V4 ============== 1) Remove Unicode character from C source file 2) Move delete of QuarkSocPkg\QuarkNorthCluster\Binary\QuarkMicrocode from QuarkPlatformPkg commit to QuarkSocPkg commit Changes for V2 ============== 1) Sync with new APIs in SmmCpuFeaturesLib class 2) Use new generic PCI serial driver PciSioSerialDxe in MdeModulePkg 3) Remove PCI serial driver from QuarkSocPkg 4) Apply optimizations to MtrrLib from MtrrLib in UefiCpuPkg 5) Convert all UNI files to utf-8 6) Replace tabs with spaces and remove trailing spaces 7) Add License.txt Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Michael Kinney <michael.d.kinney@intel.com> Acked-by: Jordan Justen <jordan.l.justen@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19286 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'QuarkSocPkg/QuarkNorthCluster/Smm')
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf54
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c395
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h235
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c366
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf61
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/CommonHeader.h51
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c38
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c555
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmPeriodicTimer.c430
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c217
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c96
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c153
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h871
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c800
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf87
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c373
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h225
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h19
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h184
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.c382
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf51
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.c282
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf57
23 files changed, 5982 insertions, 0 deletions
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf b/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf
new file mode 100644
index 0000000000..c50ac5329d
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf
@@ -0,0 +1,54 @@
+## @file
+# Component description file for SmmAccess module
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmAccess
+ FILE_GUID = 274F0C8F-9E57-41d8-9966-29CCD48D31C2
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SmmAccessDriverEntryPoint
+
+[Sources]
+ SmmAccessDriver.h
+ SmmAccessDriver.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+ HobLib
+ DebugLib
+ UefiLib
+ BaseLib
+ BaseMemoryLib
+ S3BootScriptLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ PcdLib
+ SmmLib
+
+[Protocols]
+ gEfiPciRootBridgeIoProtocolGuid
+ gEfiSmmAccess2ProtocolGuid
+
+[Guids]
+ gEfiSmmPeiSmramMemoryReserveGuid
+
+[Depex]
+ gEfiPciRootBridgeIoProtocolGuid
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c b/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c
new file mode 100644
index 0000000000..51432b6dcf
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.c
@@ -0,0 +1,395 @@
+/** @file
+This is the driver that publishes the SMM Access Protocol
+instance for the Tylersburg chipset.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "SmmAccessDriver.h"
+
+
+
+SMM_ACCESS_PRIVATE_DATA mSmmAccess;
+
+VOID
+SmmAccessOnBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+);
+
+EFI_STATUS
+EFIAPI
+SmmAccessDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+Routine Description:
+
+ Installs an SMM Access Protocol.
+
+Arguments:
+
+ ImageHandle - Handle for the image of this driver.
+ SystemTable - Pointer to the EFI System Table.
+
+Returns:
+
+ EFI_SUCCESS - Protocol successfully started and installed.
+ EFI_UNSUPPORTED - Protocol can't be started.
+ EFI_NOT_FOUND - Protocol not found.
+--*/
+{
+
+ EFI_STATUS Status;
+ EFI_EVENT BootEvent;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ UINTN Index;
+ EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *DescriptorBlock;
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+
+ //
+ // Initialize private data
+ //
+ ZeroMem (&mSmmAccess, sizeof (mSmmAccess));
+
+ Status = gBS->LocateProtocol (
+ &gEfiPciRootBridgeIoProtocolGuid,
+ NULL,
+ (VOID **) &PciRootBridgeIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Build SMM related information
+ //
+ mSmmAccess.Signature = SMM_ACCESS_PRIVATE_DATA_SIGNATURE;
+ mSmmAccess.Handle = NULL;
+ mSmmAccess.PciRootBridgeIo = PciRootBridgeIo;
+
+ //
+ // Get Hob list
+ //
+ GuidHob = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);
+ DescriptorBlock = GET_GUID_HOB_DATA (GuidHob);
+ ASSERT (DescriptorBlock);
+
+
+ //
+ // Get CPU Max bus number
+ //
+ mSmmAccess.MaxBusNumber = PCI_BUS_NUMBER_QNC;
+ for (Index = 0; Index < MAX_CPU_SOCKET; Index++) {
+ mSmmAccess.SocketPopulated[Index] = TRUE;
+ }
+
+ //
+ // Use the hob to publish SMRAM capabilities
+ //
+ ASSERT (DescriptorBlock->NumberOfSmmReservedRegions <= MAX_SMRAM_RANGES);
+ for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) {
+ mSmmAccess.SmramDesc[Index].PhysicalStart = DescriptorBlock->Descriptor[Index].PhysicalStart;
+ mSmmAccess.SmramDesc[Index].CpuStart = DescriptorBlock->Descriptor[Index].CpuStart;
+ mSmmAccess.SmramDesc[Index].PhysicalSize = DescriptorBlock->Descriptor[Index].PhysicalSize;
+ mSmmAccess.SmramDesc[Index].RegionState = DescriptorBlock->Descriptor[Index].RegionState;
+ DEBUG ((EFI_D_INFO, "SM RAM index[%d] startaddr:%08X Size :%08X\n", Index, mSmmAccess.SmramDesc[Index].CpuStart,
+ mSmmAccess.SmramDesc[Index].PhysicalSize));
+ }
+
+ mSmmAccess.NumberRegions = Index;
+ mSmmAccess.SmmAccess.Open = Open;
+ mSmmAccess.SmmAccess.Close = Close;
+ mSmmAccess.SmmAccess.Lock = Lock;
+ mSmmAccess.SmmAccess.GetCapabilities = GetCapabilities;
+ mSmmAccess.SmmAccess.LockState = FALSE;
+ mSmmAccess.SmmAccess.OpenState = FALSE;
+ mSmmAccess.SMMRegionState = EFI_SMRAM_CLOSED;
+
+ //
+ // Install our protocol interfaces on the device's handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mSmmAccess.Handle,
+ &gEfiSmmAccess2ProtocolGuid,
+ &mSmmAccess.SmmAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((EFI_D_INFO, "SMM Base: %08X\n", (UINT32)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalStart)));
+ DEBUG ((EFI_D_INFO, "SMM Size: %08X\n", (UINT32)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalSize)));
+
+ mSmmAccess.TsegSize = (UINT8)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalSize);
+ //
+ // T Seg setting done in QPI RC
+ //
+
+ //
+ // Prior ReadyToBoot, lock CSEG
+ //
+ Status = EfiCreateEventReadyToBootEx(
+ TPL_NOTIFY,
+ SmmAccessOnBoot,
+ NULL,
+ &BootEvent );
+ ASSERT (!EFI_ERROR (Status));
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+Open (
+ IN EFI_SMM_ACCESS2_PROTOCOL *This
+ )
+/*++
+
+Routine Description:
+
+ This routine accepts a request to "open" a region of SMRAM. The
+ region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.
+ The use of "open" means that the memory is visible from all boot-service
+ and SMM agents.
+
+Arguments:
+
+ This - Pointer to the SMM Access Interface.
+ DescriptorIndex - Region of SMRAM to Open.
+
+Returns:
+
+ EFI_SUCCESS - The region was successfully opened.
+ EFI_DEVICE_ERROR - The region could not be opened because locked by
+ chipset.
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.
+
+--*/
+{
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;
+
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
+
+ if (mSmmAccess.SMMRegionState & EFI_SMRAM_LOCKED) {
+ DEBUG ((EFI_D_ERROR, "Cannot open a locked SMRAM region\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Open TSEG
+ //
+ if (!QNCOpenSmramRegion ()) {
+ mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED;
+ return EFI_DEVICE_ERROR;
+ }
+
+ mSmmAccess.SMMRegionState &= ~(EFI_SMRAM_CLOSED | EFI_ALLOCATED);
+ SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~(EFI_SMRAM_CLOSED | EFI_ALLOCATED)));
+ mSmmAccess.SMMRegionState |= EFI_SMRAM_OPEN;
+ SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_OPEN);
+ SmmAccess->SmmAccess.OpenState = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+Close (
+ IN EFI_SMM_ACCESS2_PROTOCOL *This
+ )
+/*++
+
+Routine Description:
+
+ This routine accepts a request to "close" a region of SMRAM. This is valid for
+ compatible SMRAM region.
+
+Arguments:
+
+ This - Pointer to the SMM Access Interface.
+ DescriptorIndex - Region of SMRAM to Close.
+
+Returns:
+
+ EFI_SUCCESS - The region was successfully closed.
+ EFI_DEVICE_ERROR - The region could not be closed because locked by
+ chipset.
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.
+
+--*/
+{
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;
+ BOOLEAN OpenState;
+ UINTN Index;
+
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
+
+ if (mSmmAccess.SMMRegionState & EFI_SMRAM_LOCKED) {
+ //
+ // Cannot close a "locked" region
+ //
+ DEBUG ((EFI_D_WARN, "Cannot close the locked SMRAM Region\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (mSmmAccess.SMMRegionState & EFI_SMRAM_CLOSED) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Close TSEG
+ //
+ if (!QNCCloseSmramRegion ()) {
+ mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED;
+ return EFI_DEVICE_ERROR;
+ }
+
+ mSmmAccess.SMMRegionState &= ~EFI_SMRAM_OPEN;
+ SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~EFI_SMRAM_OPEN));
+ mSmmAccess.SMMRegionState |= (EFI_SMRAM_CLOSED | EFI_ALLOCATED);
+ SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_CLOSED | EFI_ALLOCATED);
+
+ //
+ // Find out if any regions are still open
+ //
+ OpenState = FALSE;
+ for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) {
+ if ((SmmAccess->SmramDesc[Index].RegionState & EFI_SMRAM_OPEN) == EFI_SMRAM_OPEN) {
+ OpenState = TRUE;
+ }
+ }
+
+ SmmAccess->SmmAccess.OpenState = OpenState;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+Lock (
+ IN EFI_SMM_ACCESS2_PROTOCOL *This
+ )
+/*++
+
+Routine Description:
+
+ This routine accepts a request to "lock" SMRAM. The
+ region could be legacy AB or TSEG near top of physical memory.
+ The use of "lock" means that the memory can no longer be opened
+ to BS state..
+
+Arguments:
+
+ This - Pointer to the SMM Access Interface.
+ DescriptorIndex - Region of SMRAM to Lock.
+
+Returns:
+
+ EFI_SUCCESS - The region was successfully locked.
+ EFI_DEVICE_ERROR - The region could not be locked because at least
+ one range is still open.
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.
+
+--*/
+{
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;
+
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
+
+ if (SmmAccess->SmmAccess.OpenState) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED;
+ SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_LOCKED);
+ SmmAccess->SmmAccess.LockState = TRUE;
+
+ //
+ // Lock TSEG
+ //
+ QNCLockSmramRegion ();
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+GetCapabilities (
+ IN CONST EFI_SMM_ACCESS2_PROTOCOL *This,
+ IN OUT UINTN *SmramMapSize,
+ IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap
+ )
+/*++
+
+Routine Description:
+
+ This routine services a user request to discover the SMRAM
+ capabilities of this platform. This will report the possible
+ ranges that are possible for SMRAM access, based upon the
+ memory controller capabilities.
+
+Arguments:
+
+ This - Pointer to the SMRAM Access Interface.
+ SmramMapSize - Pointer to the variable containing size of the
+ buffer to contain the description information.
+ SmramMap - Buffer containing the data describing the Smram
+ region descriptors.
+Returns:
+
+ EFI_BUFFER_TOO_SMALL - The user did not provide a sufficient buffer.
+ EFI_SUCCESS - The user provided a sufficiently-sized buffer.
+
+--*/
+{
+ EFI_STATUS Status;
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;
+ UINTN BufferSize;
+
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
+ BufferSize = SmmAccess->NumberRegions * sizeof (EFI_SMRAM_DESCRIPTOR);
+
+ if (*SmramMapSize < BufferSize) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ } else {
+ CopyMem (SmramMap, SmmAccess->SmramDesc, *SmramMapSize);
+ Status = EFI_SUCCESS;
+ }
+ *SmramMapSize = BufferSize;
+
+ return Status;
+}
+
+VOID
+SmmAccessOnBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+)
+{
+
+}
+VOID
+SyncRegionState2SmramDesc(
+ IN BOOLEAN OrAnd,
+ IN UINT64 Value
+ )
+{
+ UINT32 Index;
+
+ for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) {
+ if (OrAnd) {
+ mSmmAccess.SmramDesc[Index].RegionState |= Value;
+ } else {
+ mSmmAccess.SmramDesc[Index].RegionState &= Value;
+ }
+ }
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h b/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h
new file mode 100644
index 0000000000..26db976992
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccessDriver.h
@@ -0,0 +1,235 @@
+/** @file
+Header file for SMM Access Driver.
+
+This file includes package header files, library classes and protocol, PPI & GUID definitions.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#ifndef _SMM_ACCESS_DRIVER_H
+#define _SMM_ACCESS_DRIVER_H
+
+#include <PiDxe.h>
+#include <IndustryStandard/Pci.h>
+
+#include <Library/HobLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PcdLib.h>
+
+//
+// Driver Consumed Protocol Prototypes
+//
+#include <Protocol/PciRootBridgeIo.h>
+
+//
+// Driver Consumed GUID Prototypes
+//
+#include <Guid/SmramMemoryReserve.h>
+
+//
+// Driver produced protocol
+//
+#include <Protocol/SmmAccess2.h>
+
+#include <Library/QNCSmmLib.h>
+#include <QNCAccess.h>
+
+#define MAX_CPU_SOCKET 1
+#define MAX_SMRAM_RANGES 4
+
+//
+// Private data structure
+//
+#define SMM_ACCESS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('i', 's', 'm', 'a')
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_SMM_ACCESS2_PROTOCOL SmmAccess;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ UINTN NumberRegions;
+ EFI_SMRAM_DESCRIPTOR SmramDesc[MAX_SMRAM_RANGES];
+ UINT8 TsegSize;
+ UINT8 MaxBusNumber;
+ UINT8 SocketPopulated[MAX_CPU_SOCKET];
+ UINT64 SMMRegionState;
+ UINT8 ActualNLIioBusNumber;
+} SMM_ACCESS_PRIVATE_DATA;
+
+
+#define SMM_ACCESS_PRIVATE_DATA_FROM_THIS(a) \
+ CR ( \
+ a, \
+ SMM_ACCESS_PRIVATE_DATA, \
+ SmmAccess, \
+ SMM_ACCESS_PRIVATE_DATA_SIGNATURE \
+ )
+
+
+//
+// Prototypes
+// Driver model protocol interface
+//
+EFI_STATUS
+EFIAPI
+SmmAccessDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+Routine Description:
+
+ This is the standard EFI driver point that detects
+ whether there is an proper chipset in the system
+ and if so, installs an SMM Access Protocol.
+
+Arguments:
+
+ ImageHandle - Handle for the image of this driver.
+ SystemTable - Pointer to the EFI System Table.
+
+Returns:
+
+ EFI_SUCCESS - Protocol successfully started and installed.
+ EFI_UNSUPPORTED - Protocol can't be started.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+Open (
+ IN EFI_SMM_ACCESS2_PROTOCOL *This
+ )
+/*++
+
+Routine Description:
+
+ This routine accepts a request to "open" a region of SMRAM. The
+ region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.
+ The use of "open" means that the memory is visible from all boot-service
+ and SMM agents.
+
+Arguments:
+
+ This - Pointer to the SMM Access Interface.
+ DescriptorIndex - Region of SMRAM to Open.
+
+Returns:
+
+ EFI_SUCCESS - The region was successfully opened.
+ EFI_DEVICE_ERROR - The region could not be opened because locked by
+ chipset.
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+Close (
+ IN EFI_SMM_ACCESS2_PROTOCOL *This
+ )
+/*++
+
+Routine Description:
+
+ This routine accepts a request to "close" a region of SMRAM. This is valid for
+ compatible SMRAM region.
+
+Arguments:
+
+ This - Pointer to the SMM Access Interface.
+ DescriptorIndex - Region of SMRAM to Close.
+
+Returns:
+
+ EFI_SUCCESS - The region was successfully closed.
+ EFI_DEVICE_ERROR - The region could not be closed because locked by
+ chipset.
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+Lock (
+ IN EFI_SMM_ACCESS2_PROTOCOL *This
+ )
+/*++
+
+Routine Description:
+
+ This routine accepts a request to "lock" SMRAM. The
+ region could be legacy AB or TSEG near top of physical memory.
+ The use of "lock" means that the memory can no longer be opened
+ to BS state..
+
+Arguments:
+
+ This - Pointer to the SMM Access Interface.
+ DescriptorIndex - Region of SMRAM to Lock.
+
+Returns:
+
+ EFI_SUCCESS - The region was successfully locked.
+ EFI_DEVICE_ERROR - The region could not be locked because at least
+ one range is still open.
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+GetCapabilities (
+ IN CONST EFI_SMM_ACCESS2_PROTOCOL *This,
+ IN OUT UINTN *SmramMapSize,
+ IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap
+ )
+/*++
+
+Routine Description:
+
+ This routine services a user request to discover the SMRAM
+ capabilities of this platform. This will report the possible
+ ranges that are possible for SMRAM access, based upon the
+ memory controller capabilities.
+
+Arguments:
+
+ This - Pointer to the SMRAM Access Interface.
+ SmramMapSize - Pointer to the variable containing size of the
+ buffer to contain the description information.
+ SmramMap - Buffer containing the data describing the Smram
+ region descriptors.
+
+Returns:
+
+ EFI_BUFFER_TOO_SMALL - The user did not provide a sufficient buffer.
+ EFI_SUCCESS - The user provided a sufficiently-sized buffer.
+
+--*/
+;
+VOID
+SyncRegionState2SmramDesc(
+ IN BOOLEAN OrAnd,
+ IN UINT64 Value
+ );
+
+#endif
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c b/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c
new file mode 100644
index 0000000000..72ba79767f
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c
@@ -0,0 +1,366 @@
+/** @file
+This module produces the SMM COntrol2 Protocol for QNC
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/SmmControl2.h>
+#include <IndustryStandard/Pci.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/PcdLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+#include <IntelQNCDxe.h>
+#include <Library/QNCAccessLib.h>
+#include <Uefi/UefiBaseType.h>
+
+#define EFI_INTERNAL_POINTER 0x00000004
+
+extern EFI_GUID gEfiEventVirtualAddressChangeGuid;
+
+/**
+ Generates an SMI using the parameters passed in.
+
+ @param This A pointer to an instance of
+ EFI_SMM_CONTROL2_PROTOCOL
+ @param ArgumentBuffer The argument buffer
+ @param ArgumentBufferSize The size of the argument buffer
+ @param Periodic TRUE to indicate a periodical SMI
+ @param ActivationInterval Interval of the periodical SMI
+
+ @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1
+ @return Return value from SmmTrigger().
+
+**/
+EFI_STATUS
+EFIAPI
+Activate (
+ IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
+ IN OUT UINT8 *CommandPort OPTIONAL,
+ IN OUT UINT8 *DataPort OPTIONAL,
+ IN BOOLEAN Periodic OPTIONAL,
+ IN EFI_SMM_PERIOD ActivationInterval OPTIONAL
+ );
+
+/**
+ Clears an SMI.
+
+ @param This Pointer to an instance of EFI_SMM_CONTROL2_PROTOCOL
+ @param Periodic TRUE to indicate a periodical SMI
+
+ @return Return value from SmmClear()
+
+**/
+EFI_STATUS
+EFIAPI
+Deactivate (
+ IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
+ IN BOOLEAN Periodic OPTIONAL
+ );
+
+///
+/// Handle for the SMM Control2 Protocol
+///
+EFI_HANDLE mSmmControl2Handle = NULL;
+
+///
+/// SMM COntrol2 Protocol instance
+///
+EFI_SMM_CONTROL2_PROTOCOL mSmmControl2 = {
+ Activate,
+ Deactivate,
+ 0
+};
+
+VOID
+EFIAPI
+SmmControlVirtualddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+/*++
+
+Routine Description:
+
+ Fixup internal data pointers so that the services can be called in virtual mode.
+
+Arguments:
+
+ Event The event registered.
+ Context Event context.
+
+Returns:
+
+ None.
+
+--*/
+{
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSmmControl2.Trigger));
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSmmControl2.Clear));
+}
+
+/**
+ Clear SMI related chipset status and re-enable SMI by setting the EOS bit.
+
+ @retval EFI_SUCCESS The requested operation has been carried out successfully
+ @retval EFI_DEVICE_ERROR The EOS bit could not be set.
+
+**/
+EFI_STATUS
+SmmClear (
+ VOID
+ )
+{
+ UINT16 PM1BLK_Base;
+ UINT16 GPE0BLK_Base;
+
+ //
+ // Get PM1BLK_Base & GPE0BLK_Base
+ //
+ PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);
+ GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
+
+ //
+ // Clear the Power Button Override Status Bit, it gates EOS from being set.
+ // In QuarkNcSocId - Bit is read only. Handled by external SMC, do nothing.
+ //
+
+ //
+ // Clear the APM SMI Status Bit
+ //
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);
+
+ //
+ // Set the EOS Bit
+ //
+ IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Generates an SMI using the parameters passed in.
+
+ @param This A pointer to an instance of
+ EFI_SMM_CONTROL_PROTOCOL
+ @param ArgumentBuffer The argument buffer
+ @param ArgumentBufferSize The size of the argument buffer
+ @param Periodic TRUE to indicate a periodical SMI
+ @param ActivationInterval Interval of the periodical SMI
+
+ @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1
+ @retval EFI_SUCCESS SMI generated
+
+**/
+EFI_STATUS
+EFIAPI
+Activate (
+ IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
+ IN OUT UINT8 *CommandPort OPTIONAL,
+ IN OUT UINT8 *DataPort OPTIONAL,
+ IN BOOLEAN Periodic OPTIONAL,
+ IN EFI_SMM_PERIOD ActivationInterval OPTIONAL
+ )
+{
+ UINT16 GPE0BLK_Base;
+ UINT32 NewValue;
+
+ //
+ // Get GPE0BLK_Base
+ //
+ GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
+
+ if (Periodic) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Clear any pending the APM SMI
+ //
+ if (EFI_ERROR (SmmClear())) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Enable the APMC SMI
+ //
+ IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIE, B_QNC_GPE0BLK_SMIE_APM);
+
+ //
+ // Enable SMI globally
+ //
+ NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
+ NewValue |= SMI_EN;
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
+
+
+ //
+ // Set APMC_STS
+ //
+ if (DataPort == NULL) {
+ IoWrite8 (PcdGet16 (PcdSmmDataPort), 0xFF);
+ } else {
+ IoWrite8 (PcdGet16 (PcdSmmDataPort), *DataPort);
+ }
+
+ //
+ // Generate the APMC SMI
+ //
+ if (CommandPort == NULL) {
+ IoWrite8 (PcdGet16 (PcdSmmActivationPort), 0xFF);
+ } else {
+ IoWrite8 (PcdGet16 (PcdSmmActivationPort), *CommandPort);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Clears an SMI.
+
+ @param This Pointer to an instance of EFI_SMM_CONTROL_PROTOCOL
+ @param Periodic TRUE to indicate a periodical SMI
+
+ @return Return value from SmmClear()
+
+**/
+EFI_STATUS
+EFIAPI
+Deactivate (
+ IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
+ IN BOOLEAN Periodic
+ )
+{
+ if (Periodic) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return SmmClear();
+}
+
+/**
+ This is the constructor for the SMM Control protocol.
+
+ This function installs EFI_SMM_CONTROL2_PROTOCOL.
+
+ @param ImageHandle Handle for the image of this driver
+ @param SystemTable Pointer to the EFI System Table
+
+ @retval EFI_UNSUPPORTED There's no Intel ICH on this platform
+ @return The status returned from InstallProtocolInterface().
+
+--*/
+EFI_STATUS
+SmmControl2Init (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+ UINT16 PM1BLK_Base;
+ UINT16 GPE0BLK_Base;
+ BOOLEAN SciEn;
+ UINT32 NewValue;
+
+ //
+ // Get PM1BLK_Base & GPE0BLK_Base
+ //
+ PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);
+ GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
+
+ //
+ // Install our protocol interfaces on the device's handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mSmmControl2Handle,
+ &gEfiSmmControl2ProtocolGuid, &mSmmControl2,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Determine whether an ACPI OS is present (via the SCI_EN bit)
+ //
+ SciEn = (BOOLEAN)((IoRead16 (PM1BLK_Base + R_QNC_PM1BLK_PM1C) & B_QNC_PM1BLK_PM1C_SCIEN) != 0);
+ if (!SciEn) {
+ //
+ // Clear any SMIs that double as SCIs (when SCI_EN==0)
+ //
+ IoWrite16 ((PM1BLK_Base + R_QNC_PM1BLK_PM1S), B_QNC_PM1BLK_PM1S_ALL);
+ IoWrite16 ((PM1BLK_Base + R_QNC_PM1BLK_PM1E), 0x00000000);
+ IoWrite32 ((PM1BLK_Base + R_QNC_PM1BLK_PM1C), 0x00000000);
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_GPE0S), B_QNC_GPE0BLK_GPE0S_ALL);
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_GPE0E), 0x00000000);
+ }
+
+ //
+ // Clear and disable all SMIs that are unaffected by SCI_EN
+ // Set EOS
+ //
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), 0x00000000);
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), (B_QNC_GPE0BLK_SMIS_EOS + B_QNC_GPE0BLK_SMIS_ALL));
+
+ //
+ // Enable SMI globally
+ //
+ NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
+ NewValue |= SMI_EN;
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
+
+ //
+ // Make sure to write this register last -- EOS re-enables SMIs for the QNC
+ //
+ IoAndThenOr32 (
+ GPE0BLK_Base + R_QNC_GPE0BLK_SMIE,
+ (UINT32)(~B_QNC_GPE0BLK_SMIE_ALL),
+ B_QNC_GPE0BLK_SMIE_APM
+ );
+
+ //
+ // Make sure EOS bit cleared
+ //
+ DEBUG_CODE_BEGIN ();
+ if (IoRead32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS) & B_QNC_GPE0BLK_SMIS_EOS) {
+ DEBUG ((
+ EFI_D_ERROR,
+ "******************************************************************************\n"
+ "BIG ERROR: SmmControl constructor couldn't properly initialize the ACPI table.\n"
+ " SmmControl->Clear will probably hang. \n"
+ " NOTE: SCI_EN = %d \n"
+ "******************************************************************************\n",
+ SciEn
+ ));
+
+ //
+ // If we want the system to stop, then keep the ASSERT(FALSE).
+ // Otherwise, comment it out.
+ //
+ ASSERT (FALSE);
+ }
+ DEBUG_CODE_END ();
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ SmmControlVirtualddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf b/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf
new file mode 100644
index 0000000000..e498463f31
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf
@@ -0,0 +1,61 @@
+## @file
+# QNC SmmControl driver to install EFI_SMM_CONTROL_PROTOCOL.
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmControlDxe
+ FILE_GUID = A03A9429-C570-4ef9-9E00-C7A673976E5F
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SmmControl2Init
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmControlDriver.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ DebugLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ PcdLib
+ IoLib
+ PciLib
+ QNCAccessLib
+
+[Protocols]
+ gEfiSmmControl2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+
+[Pcd]
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmDataPort
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdGbaIoBaseAddress
+
+[Guids]
+ gEfiEventVirtualAddressChangeGuid
+
+[Depex]
+ TRUE
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/CommonHeader.h b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/CommonHeader.h
new file mode 100644
index 0000000000..3a5b15220a
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/CommonHeader.h
@@ -0,0 +1,51 @@
+/** @file
+Common header file shared by all source files.
+
+This file includes package header files, library classes and protocol, PPI & GUID definitions.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#ifndef __COMMON_HEADER_H_
+#define __COMMON_HEADER_H_
+
+
+
+#include <PiSmm.h>
+#include <IntelQNCDxe.h>
+
+#include <Protocol/SmmUsbDispatch2.h>
+#include <Protocol/SmmPeriodicTimerDispatch2.h>
+#include <Protocol/SmmIchnDispatch2.h>
+#include <Protocol/SmmPowerButtonDispatch2.h>
+#include <Protocol/SmmGpiDispatch2.h>
+#include <Protocol/SmmSxDispatch2.h>
+#include <Protocol/SmmSwDispatch2.h>
+#include <Protocol/SmmIoTrapDispatch2.h>
+#include <Protocol/SmmCpu.h>
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/IoLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/S3IoLib.h>
+#include <Library/QNCAccessLib.h>
+
+#include <Uefi/UefiBaseType.h>
+#endif
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c
new file mode 100644
index 0000000000..eb9c6df5fa
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmGpi.c
@@ -0,0 +1,38 @@
+/** @file
+File to contain all the hardware specific stuff for the Smm Gpi dispatch protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmmHelpers.h"
+
+CONST QNC_SMM_SOURCE_DESC GPI_SOURCE_DESC = {
+ QNC_SMM_NO_FLAGS,
+ {
+ {
+ {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_GPIO
+ },
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ {
+ {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_GPIO
+ }
+ }
+};
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c
new file mode 100644
index 0000000000..9784359de1
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c
@@ -0,0 +1,555 @@
+/** @file
+
+This driver is responsible for the registration of child drivers
+and the abstraction of the QNC SMI sources.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmmHelpers.h"
+
+//
+// Help handle porting bit shifts to IA-64.
+//
+#define BIT_ZERO 0x00000001
+
+
+VOID
+QNCSmmPublishDispatchProtocols(
+ VOID
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+
+ //
+ // Install protocol interfaces.
+ //
+ for (Index = 0; Index < NUM_PROTOCOLS; Index++) {
+ Status = gSmst->SmmInstallProtocolInterface (
+ &mPrivateData.InstallMultProtHandle,
+ mPrivateData.Protocols[Index].Guid,
+ EFI_NATIVE_INTERFACE,
+ &mPrivateData.Protocols[Index].Protocols.Generic
+ );
+
+ ASSERT_EFI_ERROR (Status);
+}
+}
+
+EFI_STATUS
+QNCSmmInitHardware(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Initialize bits that aren't necessarily related to an SMI source.
+
+Dependencies:
+
+ gSmst - SMM System Table; contains an entry for SMM CPU IO
+
+Returns:
+
+ EFI_SUCCESS. Asserts, otherwise.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ //
+ // Clear all SMIs
+ //
+ QNCSmmClearSmi();
+
+ Status = QNCSmmEnableGlobalSmiBit ();
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Be *really* sure to clear all SMIs
+ //
+ QNCSmmClearSmi ();
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+QNCSmmEnableGlobalSmiBit (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Enables the QNC to generate SMIs. Note that no SMIs will be generated
+ if no SMI sources are enabled. Conversely, no enabled SMI source will
+ generate SMIs if SMIs are not globally enabled. This is the main
+ switchbox for SMI generation.
+
+Arguments:
+
+ None
+
+Returns:
+
+ EFI_SUCCESS.
+ Asserts, otherwise.
+
+--*/
+{
+ UINT32 NewValue;
+
+ //
+ // Enable SMI globally
+ //
+ NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
+ NewValue |= SMI_EN;
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+QNCSmmClearSmi(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Clears the SMI after all SMI source have been processed.
+ Note that this function will not work correctly (as it is
+ written) unless all SMI sources have been processed.
+ A revision of this function could manually clear all SMI
+ status bits to guarantee success.
+
+Returns:
+
+ EFI_SUCCESS.
+ Asserts, otherwise.
+
+--*/
+{
+ BOOLEAN EosSet;
+ BOOLEAN SciEn;
+
+ UINT32 Pm1Cnt = 0;
+ UINT16 Pm1Sts = 0;
+ UINT32 Gpe0Sts = 0;
+ UINT32 SmiSts = 0;
+
+ //
+ // Determine whether an ACPI OS is present (via the SCI_EN bit)
+ //
+ Pm1Cnt = IoRead32(PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
+ SciEn = (BOOLEAN)((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == B_QNC_PM1BLK_PM1C_SCIEN);
+
+ if (SciEn == FALSE) {
+
+ //
+ // Clear any SMIs that double as SCIs (when SCI_EN==0)
+ //
+ Pm1Sts = (B_QNC_PM1BLK_PM1S_WAKE | B_QNC_PM1BLK_PM1S_PCIEWSTS | B_QNC_PM1BLK_PM1S_RTC | B_QNC_PM1BLK_PM1S_GLOB | B_QNC_PM1BLK_PM1S_TO);
+
+ Gpe0Sts = B_QNC_GPE0BLK_GPE0S_ALL;
+
+ IoOr16((PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S), Pm1Sts);
+ IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S), Gpe0Sts);
+ }
+
+ //
+ // Clear all SMIs that are unaffected by SCI_EN
+ //
+ SmiSts = IoRead32((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS);
+ SmiSts |= B_QNC_GPE0BLK_SMIS_ALL;
+ IoWrite32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS), SmiSts);
+
+ //
+ // Try to clear the EOS bit. ASSERT on an error
+ //
+ EosSet = QNCSmmSetAndCheckEos();
+ ASSERT (EosSet);
+
+ return EFI_SUCCESS;
+}
+
+BOOLEAN
+QNCSmmSetAndCheckEos(
+ VOID
+ )
+{
+ //
+ // Reset the QNC to generate subsequent SMIs
+ //
+ IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);
+ return TRUE;
+}
+
+BOOLEAN
+QNCSmmGetSciEn(
+ )
+{
+ BOOLEAN SciEn;
+ UINT32 Pm1Cnt;
+
+ //
+ // Determine whether an ACPI OS is present (via the SCI_EN bit)
+ //
+ Pm1Cnt = IoRead32(PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
+
+ SciEn = (BOOLEAN)((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == B_QNC_PM1BLK_PM1C_SCIEN);
+
+ return SciEn;
+}
+
+//
+// These may or may not need to change w/ the QNC version; they're highly IA-32 dependent, though.
+//
+
+BOOLEAN
+ReadBitDesc (
+ CONST QNC_SMM_BIT_DESC *BitDesc
+ )
+{
+ UINT64 Register;
+ UINT32 PciBus;
+ UINT32 PciDev;
+ UINT32 PciFun;
+ UINT32 PciReg;
+ BOOLEAN BitWasOne;
+
+ ASSERT (BitDesc != NULL );
+ ASSERT (!IS_BIT_DESC_NULL( *BitDesc ) );
+
+ Register = 0;
+ BitWasOne = FALSE;
+
+ switch (BitDesc->Reg.Type) {
+
+ case ACPI_ADDR_TYPE:
+ //
+ // Double check that we correctly read in the acpi base address
+ //
+ ASSERT ((PcdGet16 (PcdPm1blkIoBaseAddress) != 0x0) && ((PcdGet16 (PcdPm1blkIoBaseAddress) & 0x1) != 0x1) );
+
+ switch (BitDesc->SizeInBytes) {
+
+ case 0:
+ //
+ // Chances are that this field didn't get initialized.
+ // Check your assignments to bit descriptions.
+ //
+ ASSERT (FALSE );
+ break;
+
+ case 1:
+ Register = (UINT64) IoRead8 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);
+ break;
+
+ case 2:
+ Register = (UINT64) IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);
+ break;
+
+ case 4:
+ Register = (UINT64) IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);
+ break;
+
+ default:
+ //
+ // Unsupported or invalid register size
+ //
+ ASSERT (FALSE );
+ break;
+ };
+
+ if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {
+ BitWasOne = TRUE;
+ } else {
+ BitWasOne = FALSE;
+ }
+ break;
+
+ case GPE_ADDR_TYPE:
+ //
+ // Double check that we correctly read in the gpe base address
+ //
+ ASSERT (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) != 0x0) && (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) & 0x1) != 0x1) );
+
+ switch (BitDesc->SizeInBytes) {
+
+ case 0:
+ //
+ // Chances are that this field didn't get initialized.
+ // Check your assignments to bit descriptions.
+ //
+ ASSERT (FALSE );
+ break;
+
+ case 1:
+ Register = (UINT64) IoRead8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);
+ break;
+
+ case 2:
+ Register = (UINT64) IoRead16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);
+ break;
+
+ case 4:
+ Register = (UINT64) IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);
+ break;
+
+ default:
+ //
+ // Unsupported or invalid register size
+ //
+ ASSERT (FALSE );
+ break;
+ };
+
+ if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {
+ BitWasOne = TRUE;
+ } else {
+ BitWasOne = FALSE;
+ }
+ break;
+
+ case MEMORY_MAPPED_IO_ADDRESS_TYPE:
+ //
+ // Read the register, and it with the bit to read
+ //
+
+ //
+ // This code does not support reads greater then 64 bits
+ //
+ ASSERT (BitDesc->SizeInBytes <= 8);
+ CopyMem (&Register, BitDesc->Reg.Data.Mmio, BitDesc->SizeInBytes);
+ Register &= LShiftU64 (BIT0, BitDesc->Bit);
+ if (Register) {
+ BitWasOne = TRUE;
+ } else {
+ BitWasOne = FALSE;
+ }
+ break;
+
+ case PCI_ADDR_TYPE:
+ PciBus = BitDesc->Reg.Data.pci.Fields.Bus;
+ PciDev = BitDesc->Reg.Data.pci.Fields.Dev;
+ PciFun = BitDesc->Reg.Data.pci.Fields.Fnc;
+ PciReg = BitDesc->Reg.Data.pci.Fields.Reg;
+ switch (BitDesc->SizeInBytes) {
+
+ case 0:
+ //
+ // Chances are that this field didn't get initialized.
+ // Check your assignments to bit descriptions.
+ ASSERT (FALSE );
+ break;
+
+ case 1:
+ Register = (UINT64) PciRead8 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));
+ break;
+
+ case 2:
+ Register = (UINT64) PciRead16 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));
+ break;
+
+ case 4:
+ Register = (UINT64) PciRead32 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));
+ break;
+
+ default:
+ //
+ // Unsupported or invalid register size
+ //
+ ASSERT (FALSE );
+ break;
+ };
+
+ if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {
+ BitWasOne = TRUE;
+ } else {
+ BitWasOne = FALSE;
+ }
+ break;
+
+ default:
+ //
+ // This address type is not yet implemented
+ //
+ ASSERT (FALSE );
+ break;
+ };
+
+ return BitWasOne;
+}
+
+VOID
+WriteBitDesc (
+ CONST QNC_SMM_BIT_DESC *BitDesc,
+ CONST BOOLEAN ValueToWrite
+ )
+{
+ UINT64 Register;
+ UINT64 AndVal;
+ UINT64 OrVal;
+ UINT32 PciBus;
+ UINT32 PciDev;
+ UINT32 PciFun;
+ UINT32 PciReg;
+
+ ASSERT (BitDesc != NULL);
+ ASSERT (!IS_BIT_DESC_NULL(*BitDesc));
+
+ AndVal = ~(BIT_ZERO << (BitDesc->Bit));
+ OrVal = ((UINT32)ValueToWrite) << (BitDesc->Bit);
+
+ switch (BitDesc->Reg.Type) {
+
+ case ACPI_ADDR_TYPE:
+ //
+ // Double check that we correctly read in the acpi base address
+ //
+ ASSERT ((PcdGet16 (PcdPm1blkIoBaseAddress) != 0x0) && ((PcdGet16 (PcdPm1blkIoBaseAddress) & 0x1) != 0x1));
+
+ switch (BitDesc->SizeInBytes) {
+
+ case 0:
+ //
+ // Chances are that this field didn't get initialized.
+ // Check your assignments to bit descriptions.
+ //
+ ASSERT (FALSE );
+ break;
+
+ case 1:
+ IoAndThenOr8 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT8)AndVal, (UINT8)OrVal);
+ break;
+
+ case 2:
+ IoAndThenOr16 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT16)AndVal, (UINT16)OrVal);
+ break;
+
+ case 4:
+ IoAndThenOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT32)AndVal, (UINT32)OrVal);
+ break;
+
+ default:
+ //
+ // Unsupported or invalid register size
+ //
+ ASSERT (FALSE );
+ break;
+ };
+ break;
+
+ case GPE_ADDR_TYPE:
+ //
+ // Double check that we correctly read in the gpe base address
+ //
+ ASSERT (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) != 0x0) && (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) & 0x1) != 0x1));
+
+ switch (BitDesc->SizeInBytes) {
+
+ case 0:
+ //
+ // Chances are that this field didn't get initialized.
+ // Check your assignments to bit descriptions.
+ //
+ ASSERT (FALSE );
+ break;
+
+ case 1:
+ IoAndThenOr8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT8)AndVal, (UINT8)OrVal);
+ break;
+
+ case 2:
+ IoAndThenOr16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT16)AndVal, (UINT16)OrVal);
+ break;
+
+ case 4:
+ IoAndThenOr32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT32)AndVal, (UINT32)OrVal);
+ break;
+
+ default:
+ //
+ // Unsupported or invalid register size
+ //
+ ASSERT (FALSE );
+ break;
+ };
+ break;
+
+ case MEMORY_MAPPED_IO_ADDRESS_TYPE:
+ //
+ // Read the register, or it with the bit to set, then write it back.
+ //
+
+ //
+ // This code does not support writes greater then 64 bits
+ //
+ ASSERT (BitDesc->SizeInBytes <= 8);
+ CopyMem (&Register, BitDesc->Reg.Data.Mmio, BitDesc->SizeInBytes);
+ Register &= AndVal;
+ Register |= OrVal;
+ CopyMem (BitDesc->Reg.Data.Mmio, &Register, BitDesc->SizeInBytes);
+ break;
+
+ case PCI_ADDR_TYPE:
+ PciBus = BitDesc->Reg.Data.pci.Fields.Bus;
+ PciDev = BitDesc->Reg.Data.pci.Fields.Dev;
+ PciFun = BitDesc->Reg.Data.pci.Fields.Fnc;
+ PciReg = BitDesc->Reg.Data.pci.Fields.Reg;
+ switch (BitDesc->SizeInBytes) {
+
+ case 0:
+ //
+ // Chances are that this field didn't get initialized -- check your assignments
+ // to bit descriptions.
+ //
+ ASSERT (FALSE );
+ break;
+
+ case 1:
+ PciAndThenOr8 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT8) AndVal, (UINT8) OrVal);
+ break;
+
+ case 2:
+ PciAndThenOr16 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT16) AndVal, (UINT16) OrVal);
+ break;
+
+ case 4:
+ PciAndThenOr32 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT32) AndVal, (UINT32) OrVal);
+ break;
+
+ default:
+ //
+ // Unsupported or invalid register size
+ //
+ ASSERT (FALSE );
+ break;
+ };
+ break;
+
+ default:
+ //
+ // This address type is not yet implemented
+ //
+ ASSERT (FALSE );
+ break;
+ };
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmPeriodicTimer.c b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmPeriodicTimer.c
new file mode 100644
index 0000000000..1d1030c0ae
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmPeriodicTimer.c
@@ -0,0 +1,430 @@
+/** @file
+File to contain all the hardware specific stuff for the Periodical Timer dispatch protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmmHelpers.h"
+
+typedef enum {
+ PERIODIC_TIMER = 0,
+ NUM_TIMERS
+} SUPPORTED_TIMER;
+
+typedef struct _TIMER_INTERVAL
+{
+ UINT64 Interval;
+ UINT8 AssociatedTimer;
+} TIMER_INTERVAL;
+
+//
+// Time constants, in 100 nano-second units
+//
+#define TIME_64s 640000000 /* 64 s */
+#define TIME_32s 320000000 /* 32 s */
+#define TIME_16s 160000000 /* 16 s */
+#define TIME_8s 80000000 /* 8 s */
+#define TIME_64ms 640000 /* 64 ms */
+#define TIME_32ms 320000 /* 32 ms */
+#define TIME_16ms 160000 /* 16 ms */
+#define TIME_1_5ms 15000 /* 1.5 ms */
+
+// PMCW (GPE+28h) [2:0] Periodic SMI Rate selection
+// 000 1.5ms
+// 001 16ms
+// 010 32ms
+// 011 64ms
+// 100 8s
+// 101 16s
+// 110 32s
+// 111 64s
+
+typedef enum {
+ INDEX_TIME_1_5ms = 0,
+ INDEX_TIME_16ms,
+ INDEX_TIME_32ms,
+ INDEX_TIME_64ms,
+ INDEX_TIME_8s,
+ INDEX_TIME_16s,
+ INDEX_TIME_32s,
+ INDEX_TIME_64s,
+ INDEX_TIME_MAX
+} TIMER_INTERVAL_INDEX;
+
+TIMER_INTERVAL mSmmPeriodicTimerIntervals[INDEX_TIME_MAX] = {
+ {TIME_1_5ms, PERIODIC_TIMER},
+ {TIME_16ms, PERIODIC_TIMER},
+ {TIME_32ms, PERIODIC_TIMER},
+ {TIME_64ms, PERIODIC_TIMER},
+ { TIME_8s, PERIODIC_TIMER },
+ {TIME_16s, PERIODIC_TIMER},
+ {TIME_32s, PERIODIC_TIMER},
+ {TIME_64s, PERIODIC_TIMER}
+};
+
+typedef struct _TIMER_INFO {
+ UINTN NumChildren; // number of children using this timer
+ UINT64 MinReqInterval; // minimum interval required by children
+ UINTN CurrentSetting; // interval this timer is set at right now (index into interval table)
+} TIMER_INFO;
+
+TIMER_INFO mTimers[NUM_TIMERS];
+
+QNC_SMM_SOURCE_DESC mTIMER_SOURCE_DESCS[NUM_TIMERS] = {
+ {
+ QNC_SMM_NO_FLAGS,
+ {
+ {{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_SWT},
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ {{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_SWT}
+ }
+ }
+};
+
+VOID
+QNCSmmPeriodicTimerProgramTimers(
+ VOID
+ );
+
+
+TIMER_INTERVAL *
+ContextToTimerInterval (
+ IN QNC_SMM_CONTEXT *RegisterContext
+ )
+{
+ UINTN loopvar;
+
+ //
+ // Determine which timer this child is using
+ //
+ for (loopvar = 0; loopvar < INDEX_TIME_MAX; loopvar++) {
+ if (((RegisterContext->PeriodicTimer.SmiTickInterval == 0) && (RegisterContext->PeriodicTimer.Period >= mSmmPeriodicTimerIntervals[loopvar].Interval)) ||
+ (RegisterContext->PeriodicTimer.SmiTickInterval == mSmmPeriodicTimerIntervals[loopvar].Interval)
+ ) {
+ return &mSmmPeriodicTimerIntervals[loopvar];
+ }
+ }
+
+ //
+ // If this assertion fires, then either:
+ // (1) the context contains an invalid interval
+ // (2) the timer interval table is corrupt
+ //
+ // ASSERT (FALSE);
+
+ return NULL;
+}
+
+EFI_STATUS
+MapPeriodicTimerToSrcDesc (
+ IN QNC_SMM_CONTEXT *RegisterContext,
+ OUT QNC_SMM_SOURCE_DESC *SrcDesc
+ )
+{
+ TIMER_INTERVAL *TimerInterval;
+
+ //
+ // Figure out which timer the child is requesting and
+ // send back the source description
+ //
+ TimerInterval = ContextToTimerInterval (RegisterContext);
+ if (TimerInterval == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ CopyMem (SrcDesc, &mTIMER_SOURCE_DESCS[TimerInterval->AssociatedTimer], sizeof (QNC_SMM_SOURCE_DESC));;
+
+ //
+ // Program the value of the interval into hardware
+ //
+ QNCSmmPeriodicTimerProgramTimers ();
+
+ return EFI_SUCCESS;
+}
+
+VOID
+PeriodicTimerGetContext (
+ IN DATABASE_RECORD *Record,
+ OUT QNC_SMM_CONTEXT *HwContext
+ )
+{
+ TIMER_INTERVAL *TimerInterval;
+
+ ASSERT (Record->ProtocolType == PeriodicTimerType);
+
+ TimerInterval = ContextToTimerInterval (&Record->ChildContext);
+
+ if (TimerInterval != NULL) {
+ //
+ // Ignore the hardware context. It's not required for this protocol.
+ // Instead, just increment the child's context.
+ // Update the elapsed time w/ the data from our tables
+ //
+ Record->CommBuffer.PeriodicTimer.ElapsedTime += TimerInterval->Interval;
+ *HwContext = Record->ChildContext;
+ }
+}
+
+BOOLEAN
+PeriodicTimerCmpContext (
+ IN QNC_SMM_CONTEXT *HwContext,
+ IN QNC_SMM_CONTEXT *ChildContext
+ )
+{
+ DATABASE_RECORD *Record;
+
+ Record = DATABASE_RECORD_FROM_CONTEXT (ChildContext);
+
+ if (Record->CommBuffer.PeriodicTimer.ElapsedTime >= ChildContext->PeriodicTimer.Period) {
+ //
+ // This child should be dispatched
+ // The timer will be restarted on the "ClearSource" call.
+ //
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+VOID
+PeriodicTimerGetBuffer (
+ IN DATABASE_RECORD * Record
+ )
+{
+ //
+ // CommBuffer has been updated by PeriodicTimerGetContext, so return directly
+ //
+ return;
+}
+
+VOID
+QNCSmmPeriodicTimerProgramTimers (
+ VOID
+ )
+{
+ UINT32 GpePmcwValue;
+ SUPPORTED_TIMER Timer;
+ DATABASE_RECORD *RecordInDb;
+ LIST_ENTRY *LinkInDb;
+ TIMER_INTERVAL *TimerInterval;
+
+ //
+ // Find the minimum required interval for each timer
+ //
+ for (Timer = (SUPPORTED_TIMER)0; Timer < NUM_TIMERS; Timer++) {
+ mTimers[Timer].MinReqInterval = ~(UINT64)0x0;
+ mTimers[Timer].NumChildren = 0;
+ }
+ LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
+ while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
+ RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
+ if (RecordInDb->ProtocolType == PeriodicTimerType) {
+ //
+ // This child is registerd with the PeriodicTimer protocol
+ //
+ TimerInterval = ContextToTimerInterval (&RecordInDb->ChildContext);
+
+ if(TimerInterval != NULL) {
+ Timer = (SUPPORTED_TIMER)((TIMER_INTERVAL *) (TimerInterval))->AssociatedTimer;
+
+ ASSERT (Timer >= 0 && Timer < NUM_TIMERS);
+
+ if (mTimers[Timer].MinReqInterval > RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval) {
+ mTimers[Timer].MinReqInterval = RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval;
+ }
+ mTimers[Timer].NumChildren++;
+ }
+ }
+ LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
+ }
+
+ //
+ // Program the hardware
+ //
+ GpePmcwValue = 0;
+ if (mTimers[PERIODIC_TIMER].NumChildren > 0) {
+ switch (mTimers[PERIODIC_TIMER].MinReqInterval) {
+
+ case TIME_64s:
+ GpePmcwValue = INDEX_TIME_64s;
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64s;
+ break;
+
+ case TIME_32s:
+ GpePmcwValue = INDEX_TIME_32s;
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32s;
+ break;
+
+ case TIME_16s:
+ GpePmcwValue = INDEX_TIME_16s;
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16s;
+ break;
+
+ case TIME_8s:
+ GpePmcwValue = INDEX_TIME_8s;
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_8s;
+ break;
+
+ case TIME_64ms:
+ GpePmcwValue = INDEX_TIME_64ms;
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64ms;
+ break;
+
+ case TIME_32ms:
+ GpePmcwValue = INDEX_TIME_32ms;
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32ms;
+ break;
+
+ case TIME_16ms:
+ GpePmcwValue = INDEX_TIME_16ms;
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16ms;
+ break;
+
+ case TIME_1_5ms:
+ GpePmcwValue = INDEX_TIME_1_5ms;
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_1_5ms;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ };
+
+ GpePmcwValue |= B_QNC_GPE0BLK_PMCW_PSE;
+
+ IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_PMCW), GpePmcwValue);
+
+ //
+ // Restart the timer here, just need to clear the SMI
+ //
+ QNCSmmClearSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]);
+ } else {
+ QNCSmmDisableSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]);
+ }
+}
+
+EFI_STATUS
+QNCSmmPeriodicTimerDispatchGetNextShorterInterval (
+ IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This,
+ IN OUT UINT64 **SmiTickInterval
+ )
+/*++
+
+Routine Description:
+
+ This services returns the next SMI tick period that is supported by the chipset.
+ The order returned is from longest to shortest interval period.
+
+Arguments:
+
+ This - Pointer to the EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance.
+ SmiTickInterval - Pointer to pointer of the next shorter SMI interval period that is supported by the child.
+
+Returns:
+
+ EFI_SUCCESS - The service returned successfully.
+ EFI_INVALID_PARAMETER - The parameter SmiTickInterval is invalid.
+
+--*/
+{
+ TIMER_INTERVAL *IntervalPointer;
+
+ ASSERT (SmiTickInterval != NULL);
+
+ IntervalPointer = (TIMER_INTERVAL*)*SmiTickInterval;
+
+ if (IntervalPointer == NULL) {
+ //
+ // The first time child requesting an interval
+ //
+ IntervalPointer = &mSmmPeriodicTimerIntervals[0];
+ } else if (IntervalPointer == &mSmmPeriodicTimerIntervals[INDEX_TIME_MAX - 1]) {
+ //
+ // At end of the list
+ //
+ IntervalPointer = NULL;
+ } else {
+ if ((IntervalPointer >= &mSmmPeriodicTimerIntervals[0]) &&
+ (IntervalPointer < &mSmmPeriodicTimerIntervals[INDEX_TIME_MAX - 1])) {
+ //
+ // Get the next interval in the list
+ //
+ IntervalPointer++;
+ } else {
+ //
+ // Input is out of range
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (IntervalPointer != NULL) {
+ *SmiTickInterval = &IntervalPointer->Interval;
+ } else {
+ *SmiTickInterval = NULL;
+ }
+
+ return EFI_SUCCESS;
+}
+
+VOID
+QNCSmmPeriodicTimerClearSource (
+ IN QNC_SMM_SOURCE_DESC *SrcDesc
+ )
+/*++
+
+Routine Description:
+
+ This function is responsible for calculating and enabling any timers that are required
+ to dispatch messages to children. The SrcDesc argument isn't acutally used.
+
+Arguments:
+
+ SrcDesc - Pointer to the QNC_SMM_SOURCE_DESC instance.
+
+Returns:
+
+ None.
+
+--*/
+{
+ DATABASE_RECORD *RecordInDb;
+ LIST_ENTRY *LinkInDb;
+
+ QNCSmmPeriodicTimerProgramTimers ();
+
+ //
+ // Reset Elapsed time
+ //
+ LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
+ while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
+ RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
+ if (RecordInDb->ProtocolType == PeriodicTimerType) {
+ //
+ // This child is registerd with the PeriodicTimer protocol and Callback
+ // has been invoked, so reset the ElapsedTime to 0
+ //
+ if (RecordInDb->CommBuffer.PeriodicTimer.ElapsedTime >= RecordInDb->ChildContext.PeriodicTimer.Period) {
+ RecordInDb->CommBuffer.PeriodicTimer.ElapsedTime = 0;
+ }
+ }
+ LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
+ }
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c
new file mode 100644
index 0000000000..53ee3eadf6
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmQncn.c
@@ -0,0 +1,217 @@
+/** @file
+File to contain all the hardware specific stuff for the Smm QNCn dispatch protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmmHelpers.h"
+
+QNC_SMM_SOURCE_DESC QNCN_SOURCE_DESCS[NUM_ICHN_TYPES] = {
+
+ // QNCnMch (0)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnPme (1)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnRtcAlarm (2)
+ {
+ QNC_SMM_NO_FLAGS,
+ {
+ {{ACPI_ADDR_TYPE, {R_QNC_PM1BLK_PM1E}}, S_QNC_PM1BLK_PM1E, N_QNC_PM1BLK_PM1E_RTC},
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ {{ACPI_ADDR_TYPE, {R_QNC_PM1BLK_PM1S}}, S_QNC_PM1BLK_PM1S, N_QNC_PM1BLK_PM1S_RTC}
+ }
+ },
+
+ // QNCnRingIndicate (3)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnAc97Wake (4)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnSerialIrq (5)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnY2KRollover (6)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnTcoTimeout (7)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnOsTco (8)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnNmi (9)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnIntruderDetect (10)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnBiosWp (11)
+ {
+ QNC_SMM_CLEAR_WITH_ZERO,
+ {
+ {
+ {
+ PCI_ADDR_TYPE,
+ {
+ (
+ (PCI_BUS_NUMBER_QNC << 24) |
+ (PCI_DEVICE_NUMBER_QNC_LPC << 16) |
+ (PCI_FUNCTION_NUMBER_QNC_LPC << 8) |
+ R_QNC_LPC_BIOS_CNTL
+ )
+ }
+ },
+ S_QNC_LPC_BIOS_CNTL,
+ N_QNC_LPC_BIOS_CNTL_BLE
+ },
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ {
+ {
+ PCI_ADDR_TYPE,
+ {
+ (
+ (PCI_BUS_NUMBER_QNC << 24) |
+ (PCI_DEVICE_NUMBER_QNC_LPC << 16) |
+ (PCI_FUNCTION_NUMBER_QNC_LPC << 8) |
+ R_QNC_LPC_BIOS_CNTL
+ )
+ }
+ },
+ S_QNC_LPC_BIOS_CNTL,
+ N_QNC_LPC_BIOS_CNTL_BIOSWE
+ }
+ }
+ },
+
+ // QNCnMcSmi (12)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnPmeB0 (13)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnThrmSts (14)
+ {
+ QNC_SMM_SCI_EN_DEPENDENT,
+ {
+ {{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_GPE0E}}, S_QNC_GPE0BLK_GPE0E, N_QNC_GPE0BLK_GPE0E_THRM},
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ {{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_GPE0S}}, S_QNC_GPE0BLK_GPE0S, N_QNC_GPE0BLK_GPE0S_THRM}
+ }
+ },
+
+ // QNCnSmBus (15)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnIntelUsb2 (16)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnMonSmi7 (17)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnMonSmi6 (18)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnMonSmi5 (19)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnMonSmi4 (20)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnDevTrap13 (21)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnDevTrap12 (22)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnDevTrap11 (23)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnDevTrap10 (24)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnDevTrap9 (25)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnDevTrap8 (26)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnDevTrap7 (27)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnDevTrap6 (28)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnDevTrap5 (29)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnDevTrap3 (30)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnDevTrap2 (31)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnDevTrap1 (32)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnDevTrap0 (33)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnIoTrap3 (34)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnIoTrap2 (35)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnIoTrap1 (36)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnIoTrap0 (37)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnPciExpress (38)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnMonitor (39)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnSpi (40)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnQRT (41)
+ NULL_SOURCE_DESC_INITIALIZER,
+
+ // QNCnGpioUnlock (42)
+ NULL_SOURCE_DESC_INITIALIZER
+};
+
+VOID
+QNCSmmQNCnClearSource(
+ QNC_SMM_SOURCE_DESC *SrcDesc
+ )
+{
+ QNCSmmClearSource (SrcDesc);
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c
new file mode 100644
index 0000000000..b4f56e899d
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSw.c
@@ -0,0 +1,96 @@
+/** @file
+File to contain all the hardware specific stuff for the Smm Sw dispatch protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmmHelpers.h"
+
+EFI_SMM_CPU_PROTOCOL *mSmmCpu = NULL;
+
+CONST QNC_SMM_SOURCE_DESC SW_SOURCE_DESC = {
+ QNC_SMM_NO_FLAGS,
+ {
+ {
+ {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_APM
+ },
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ {
+ {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_APM
+ }
+ }
+};
+
+VOID
+SwGetContext(
+ IN DATABASE_RECORD *Record,
+ OUT QNC_SMM_CONTEXT *Context
+ )
+{
+ Context->Sw.SwSmiInputValue = IoRead8 (R_APM_CNT);
+}
+
+BOOLEAN
+SwCmpContext (
+ IN QNC_SMM_CONTEXT *Context1,
+ IN QNC_SMM_CONTEXT *Context2
+ )
+{
+ return (BOOLEAN)( Context1->Sw.SwSmiInputValue == Context2->Sw.SwSmiInputValue );
+}
+
+VOID
+SwGetBuffer (
+ IN DATABASE_RECORD * Record
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN CpuIndex;
+ EFI_SMM_SAVE_STATE_IO_INFO IoState;
+
+ //
+ // Locate SMM CPU protocol to retrieve the CPU save state
+ //
+ if (mSmmCpu == NULL) {
+ Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **) &mSmmCpu);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Find the CPU which generated the software SMI
+ //
+ CpuIndex = 0;
+ for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
+ Status = mSmmCpu->ReadSaveState (
+ mSmmCpu,
+ sizeof (EFI_SMM_SAVE_STATE_IO_INFO),
+ EFI_SMM_SAVE_STATE_REGISTER_IO,
+ Index,
+ &IoState
+ );
+ if (!EFI_ERROR (Status) && (IoState.IoPort == R_APM_CNT)) {
+ CpuIndex = Index;
+ break;
+ }
+ }
+
+ Record->CommBuffer.Sw.SwSmiCpuIndex = CpuIndex;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c
new file mode 100644
index 0000000000..9d0de36b63
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmSx.c
@@ -0,0 +1,153 @@
+/** @file
+File to contain all the hardware specific stuff for the Smm Sx dispatch protocol.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmmHelpers.h"
+
+CONST QNC_SMM_SOURCE_DESC SX_SOURCE_DESC = {
+ QNC_SMM_NO_FLAGS,
+ {
+ {
+ {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_SLP
+ },
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ {
+ {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_SLP
+ }
+ }
+};
+
+VOID
+SxGetContext(
+ IN DATABASE_RECORD *Record,
+ OUT QNC_SMM_CONTEXT *Context
+ )
+{
+ UINT32 Pm1Cnt;
+
+ Pm1Cnt = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
+
+ //
+ // By design, the context phase will always be ENTRY
+ //
+ Context->Sx.Phase = SxEntry;
+
+ //
+ // Map the PM1_CNT register's SLP_TYP bits to the context type
+ //
+ switch (Pm1Cnt & B_QNC_PM1BLK_PM1C_SLPTP) {
+
+ case V_S0:
+ Context->Sx.Type = SxS0;
+ break;
+
+ case V_S3:
+ Context->Sx.Type = SxS3;
+ break;
+
+ case V_S4:
+ Context->Sx.Type = SxS4;
+ break;
+
+ case V_S5:
+ Context->Sx.Type = SxS5;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ };
+}
+
+BOOLEAN
+SxCmpContext (
+ IN QNC_SMM_CONTEXT *Context1,
+ IN QNC_SMM_CONTEXT *Context2
+ )
+{
+ return (BOOLEAN)(Context1->Sx.Type == Context2->Sx.Type);
+}
+
+VOID
+QNCSmmSxGoToSleep(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ When we get an SMI that indicates that we are transitioning to a sleep state,
+ we need to actually transition to that state. We do this by disabling the
+ "SMI on sleep enable" feature, which generates an SMI when the operating system
+ tries to put the system to sleep, and then physically putting the system to sleep.
+
+Returns:
+
+ None.
+
+--*/
+{
+ UINT32 Pm1Cnt;
+
+ //
+ // Flush cache into memory before we go to sleep. It is necessary for S3 sleep
+ // because we may update memory in SMM Sx sleep handlers -- the updates are in cache now
+ //
+ AsmWbinvd();
+
+ //
+ // Disable SMIs
+ //
+ QNCSmmClearSource (&SX_SOURCE_DESC );
+ QNCSmmDisableSource (&SX_SOURCE_DESC);
+
+ //
+ // Clear Sleep Type Enable
+ //
+ IoAnd16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIE, (UINT16)(~B_QNC_GPE0BLK_SMIE_SLP));
+
+ // clear sleep SMI status
+ IoAnd16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS, (UINT16)(S_QNC_GPE0BLK_SMIS));
+
+ //
+ // Now that SMIs are disabled, write to the SLP_EN bit again to trigger the sleep
+ //
+ Pm1Cnt = IoOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, B_QNC_PM1BLK_PM1C_SLPEN);
+
+ //
+ // The system just went to sleep. If the sleep state was S1, then code execution will resume
+ // here when the system wakes up.
+ //
+ Pm1Cnt = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
+ if ((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == 0) {
+ //
+ // An ACPI OS isn't present, clear the sleep information
+ //
+ Pm1Cnt &= ~B_QNC_PM1BLK_PM1C_SLPTP;
+ Pm1Cnt |= V_S0;
+
+ IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Pm1Cnt);
+ }
+
+ QNCSmmClearSource (&SX_SOURCE_DESC);
+ QNCSmmEnableSource (&SX_SOURCE_DESC);
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h
new file mode 100644
index 0000000000..892294fa71
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmm.h
@@ -0,0 +1,871 @@
+/** @file
+Prototypes and defines for the QNC SMM Dispatcher.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef QNC_SMM_H
+#define QNC_SMM_H
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmmRegisters.h"
+
+extern EFI_HANDLE mQNCSmmDispatcherImageHandle;
+
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// SUPPORTED PROTOCOLS
+//
+
+//
+// Define an enumeration for all the supported protocols
+//
+typedef enum {
+ // UsbType, DELETE:on QuarkNcSocId, there is no usb smi supported
+ SxType,
+ SwType,
+ GpiType,
+ QNCnType,
+ PowerButtonType,
+ PeriodicTimerType,
+ NUM_PROTOCOLS
+} QNC_SMM_PROTOCOL_TYPE;
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// SPECIFYING A REGISTER
+// We want a general way of referring to addresses. For this case, we'll only
+// need addresses in the ACPI table (and the TCO entries within the ACPI table).
+// However, it's interesting to consider what it would take to support other types
+// of addresses. To address Will's concern, I think it prudent to accommodate it
+// early on in the design.
+//
+// Addresses we need to consider:
+//
+// Type: Required:
+// I/O Yes
+// ACPI (special case of I/O) Only if we want to
+// TCO (special case of ACPI) Only if we want to
+// Memory (or Memory Mapped I/O) Only if we want to
+// PCI Yes, for BiosWp
+//
+typedef enum {
+ //
+ // IO_ADDR_TYPE, // unimplemented
+ //
+ ACPI_ADDR_TYPE,
+ GPE_ADDR_TYPE,
+ //
+ // MEMORY_ADDR_TYPE, // unimplemented
+ //
+ MEMORY_MAPPED_IO_ADDRESS_TYPE,
+ PCI_ADDR_TYPE,
+ NUM_ADDR_TYPES, // count of items in this enum
+ QNC_SMM_ADDR_TYPE_NULL = -1 // sentinel to indicate NULL or to signal end of arrays
+} ADDR_TYPE;
+
+//
+// Assumption: 32-bits -- enum's evaluate to integer
+// Assumption: This code will only run on IA-32. Justification: IA-64 doesn't have SMIs.
+// We don't have to worry about 64-bit addresses.
+// Typedef the size of addresses in case the numbers I'm using are wrong or in case
+// this changes. This is a good idea because PCI_ADDR will change, for example, when
+// we add support for PciExpress.
+//
+typedef UINT16 IO_ADDR;
+typedef IO_ADDR ACPI_ADDR; // can omit
+typedef IO_ADDR GPE_ADDR; // can omit
+typedef IO_ADDR TCO_ADDR; // can omit
+typedef VOID *MEM_ADDR;
+typedef MEM_ADDR MEMORY_MAPPED_IO_ADDRESS;
+typedef union {
+ UINT32 Raw;
+ struct {
+ UINT8 Reg;
+ UINT8 Fnc;
+ UINT8 Dev;
+ UINT8 Bus;
+ } Fields;
+} PCI_ADDR;
+
+typedef struct {
+ ADDR_TYPE Type;
+ union {
+ //
+ // used to initialize during declaration/definition
+ //
+ UINTN raw;
+
+ //
+ // used to access useful data
+ //
+ IO_ADDR io;
+ ACPI_ADDR acpi;
+ GPE_ADDR gpe;
+ TCO_ADDR tco;
+ MEM_ADDR mem;
+ MEMORY_MAPPED_IO_ADDRESS Mmio;
+ PCI_ADDR pci;
+
+ } Data;
+
+} QNC_SMM_ADDRESS;
+//
+// Assumption: total size is 64 bits (32 for type and 32 for data) or 8 bytes
+//
+#define EFI_PCI_ADDRESS_PORT 0xcf8
+#define EFI_PCI_DATA_PORT 0xcfc
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// SPECIFYING BITS WITHIN A REGISTER
+// Here's a struct that helps us specify a source or enable bit.
+//
+typedef struct {
+ QNC_SMM_ADDRESS Reg;
+ UINT8 SizeInBytes; // of the register
+ UINT8 Bit;
+} QNC_SMM_BIT_DESC;
+
+//
+// Sometimes, we'll have bit descriptions that are unused. It'd be great to have a
+// way to easily identify them:
+//
+#define IS_BIT_DESC_NULL(BitDesc) ((BitDesc).Reg.Type == QNC_SMM_ADDR_TYPE_NULL) // "returns" true when BitDesc is NULL
+#define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type = QNC_SMM_ADDR_TYPE_NULL) // will "return" an integer w/ value of 0
+#define NULL_BIT_DESC_INITIALIZER \
+ { \
+ { \
+ QNC_SMM_ADDR_TYPE_NULL, \
+ { \
+ 0 \
+ } \
+ }, \
+ 0, 0 \
+ }
+//
+// I'd like a type to specify the callback's Sts & En bits because they'll
+// be commonly used together:
+//
+#define NUM_EN_BITS 2
+#define NUM_STS_BITS 1
+
+//
+// Flags
+//
+typedef UINT8 QNC_SMM_SOURCE_FLAGS;
+
+//
+// Flags required today
+//
+#define QNC_SMM_NO_FLAGS 0
+#define QNC_SMM_SCI_EN_DEPENDENT (BIT0)
+#define QNC_SMM_CLEAR_WITH_ZERO (BIT6)
+
+//
+// Flags that might be required tomorrow
+// #define QNC_SMM_CLEAR_WITH_ONE 2 // may need to support bits that clear by writing 0
+// #define QNC_SMM_MULTIBIT_FIELD 3 // may need to support status/enable fields 2 bits wide
+//
+typedef struct {
+ QNC_SMM_SOURCE_FLAGS Flags;
+ QNC_SMM_BIT_DESC En[NUM_EN_BITS];
+ QNC_SMM_BIT_DESC Sts[NUM_STS_BITS];
+} QNC_SMM_SOURCE_DESC;
+//
+// 31 bytes, I think
+//
+#define NULL_SOURCE_DESC_INITIALIZER \
+ { \
+ QNC_SMM_NO_FLAGS, \
+ { \
+ NULL_BIT_DESC_INITIALIZER, NULL_BIT_DESC_INITIALIZER \
+ }, \
+ { \
+ NULL_BIT_DESC_INITIALIZER \
+ } \
+ }
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// CHILD CONTEXTS
+// To keep consistent w/ the architecture, we'll need to provide the context
+// to the child when we call its callback function. After talking with Will,
+// we agreed that we'll need functions to "dig" the context out of the hardware
+// in many cases (Sx, Trap, Gpi, etc), and we'll need a function to compare those
+// contexts to prevent unnecessary dispatches. I'd like a general type for these
+// "GetContext" functions, so I'll need a union of all the protocol contexts for
+// our internal use:
+//
+typedef union {
+ //
+ // (in no particular order)
+ //
+ EFI_SMM_ICHN_REGISTER_CONTEXT QNCn;
+ EFI_SMM_SX_REGISTER_CONTEXT Sx;
+ EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT PeriodicTimer;
+ EFI_SMM_SW_REGISTER_CONTEXT Sw;
+ EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT PowerButton;
+ // EFI_SMM_USB_REGISTER_CONTEXT Usb; DELETE:on QuarkNcSocId, there is no usb smi supported
+ EFI_SMM_GPI_REGISTER_CONTEXT Gpi;
+} QNC_SMM_CONTEXT;
+
+typedef union {
+ //
+ // (in no particular order)
+ //
+ EFI_SMM_SW_CONTEXT Sw;
+ EFI_SMM_PERIODIC_TIMER_CONTEXT PeriodicTimer;
+} QNC_SMM_BUFFER;
+
+//
+// Assumption: PeriodicTimer largest at 3x64-bits or 24 bytes
+//
+typedef struct _DATABASE_RECORD DATABASE_RECORD;
+
+typedef
+VOID
+(EFIAPI *GET_CONTEXT) (
+ IN DATABASE_RECORD * Record,
+ OUT QNC_SMM_CONTEXT * Context
+ );
+//
+// Assumption: the GET_CONTEXT function will be as small and simple as possible.
+// Assumption: We don't need to pass in an enumeration for the protocol because each
+// GET_CONTEXT function is written for only one protocol.
+// We also need a function to compare contexts to see if the child should be dispatched
+//
+typedef
+BOOLEAN
+(EFIAPI *CMP_CONTEXT) (
+ IN QNC_SMM_CONTEXT * Context1,
+ IN QNC_SMM_CONTEXT * Context2
+ );
+
+/*
+ Returns: True when contexts are equivalent; False otherwise
+*/
+
+//
+// This function is used to get the content of CommBuffer that will be passed
+// to Callback function
+//
+typedef
+VOID
+(EFIAPI *GET_BUFFER) (
+ IN DATABASE_RECORD * Record
+ );
+
+//
+// Finally, every protocol will require a "Get Context", "Compare Context"
+// and "Get CommBuffer" call, so we may as well wrap that up in a table, too.
+//
+typedef struct {
+ GET_CONTEXT GetContext;
+ CMP_CONTEXT CmpContext;
+ GET_BUFFER GetBuffer;
+} CONTEXT_FUNCTIONS;
+
+extern CONTEXT_FUNCTIONS ContextFunctions[NUM_PROTOCOLS];
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// MAPPING CONTEXT TO BIT DESCRIPTIONS
+// I'd like to have a general approach to mapping contexts to bit descriptions.
+// Sometimes, we'll find that we can use table lookups or CONSTant assignments;
+// other times, we'll find that we'll need to use a function to perform the mapping.
+// If we define a macro to mask that process, we'll never have to change the code.
+// I don't know if this is desirable or not -- if it isn't, then we can get rid
+// of the macros and just use function calls or variable assignments. Doesn't matter
+// to me.
+// Mapping complex contexts requires a function
+//
+// DELETE:on QuarkNcSocId, there is no usb smi supported
+//EFI_STATUS
+//EFIAPI
+//MapUsbToSrcDesc (
+// IN QNC_SMM_CONTEXT *RegisterContext,
+// OUT QNC_SMM_SOURCE_DESC *SrcDesc
+// )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ RegisterContext - GC_TODO: add argument description
+ SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+MapPeriodicTimerToSrcDesc (
+ IN QNC_SMM_CONTEXT *RegisterContext,
+ OUT QNC_SMM_SOURCE_DESC *SrcDesc
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ RegisterContext - GC_TODO: add argument description
+ SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+//
+// Mapping simple contexts can be done by assignment or lookup table
+//
+extern CONST QNC_SMM_SOURCE_DESC SW_SOURCE_DESC;
+extern CONST QNC_SMM_SOURCE_DESC SX_SOURCE_DESC;
+
+//
+// With the changes we've made to the protocols, we can now use table
+// lookups for the following protocols:
+//
+extern CONST QNC_SMM_SOURCE_DESC GPI_SOURCE_DESC;
+
+extern QNC_SMM_SOURCE_DESC QNCN_SOURCE_DESCS[NUM_ICHN_TYPES];
+
+
+//
+// For QNCx, APMC is UINT8 port, so the MAX SWI Value is 0xFF.
+//
+#define MAXIMUM_SWI_VALUE 0xFF
+
+
+//
+// Open: Need to make sure this kind of type cast will actually work.
+// May need an intermediate form w/ two VOID* arguments. I'll figure
+// that out when I start compiling.
+
+///////////////////////////////////////////////////////////////////////////////
+//
+typedef
+VOID
+(EFIAPI *QNC_SMM_CLEAR_SOURCE) (
+ QNC_SMM_SOURCE_DESC * SrcDesc
+ );
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// "DATABASE" RECORD
+// Linked list data structures
+//
+#define DATABASE_RECORD_SIGNATURE SIGNATURE_32 ('D', 'B', 'R', 'C')
+
+struct _DATABASE_RECORD {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ //
+ // Status and Enable bit description
+ //
+ QNC_SMM_SOURCE_DESC SrcDesc;
+
+ //
+ // Callback function
+ //
+ EFI_SMM_HANDLER_ENTRY_POINT2 Callback;
+ QNC_SMM_CONTEXT ChildContext;
+ QNC_SMM_BUFFER CommBuffer;
+ UINTN BufferSize;
+
+ //
+ // Special handling hooks -- init them to NULL if unused/unneeded
+ //
+ QNC_SMM_CLEAR_SOURCE ClearSource; // needed for SWSMI timer
+ // Functions required to make callback code general
+ //
+ CONTEXT_FUNCTIONS ContextFunctions;
+
+ //
+ // The protocol that this record dispatches
+ //
+ QNC_SMM_PROTOCOL_TYPE ProtocolType;
+
+};
+
+#define DATABASE_RECORD_FROM_LINK(_record) CR (_record, DATABASE_RECORD, Link, DATABASE_RECORD_SIGNATURE)
+#define DATABASE_RECORD_FROM_CONTEXT(_record) CR (_record, DATABASE_RECORD, ChildContext, DATABASE_RECORD_SIGNATURE)
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// HOOKING INTO THE ARCHITECTURE
+//
+typedef
+EFI_STATUS
+(EFIAPI *QNC_SMM_GENERIC_REGISTER) (
+ IN VOID **This,
+ IN VOID *DispatchFunction,
+ IN VOID *RegisterContext,
+ OUT EFI_HANDLE * DispatchHandle
+ );
+typedef
+EFI_STATUS
+(EFIAPI *QNC_SMM_GENERIC_UNREGISTER) (
+ IN VOID **This,
+ IN EFI_HANDLE DispatchHandle
+ );
+
+//
+// Define a memory "stamp" equivalent in size and function to most of the protocols
+//
+typedef struct {
+ QNC_SMM_GENERIC_REGISTER Register;
+ QNC_SMM_GENERIC_UNREGISTER Unregister;
+ UINTN Extra1;
+ UINTN Extra2; // may not need this one
+} QNC_SMM_GENERIC_PROTOCOL;
+
+EFI_STATUS
+QNCSmmCoreRegister (
+ IN QNC_SMM_GENERIC_PROTOCOL *This,
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
+ IN QNC_SMM_CONTEXT *RegisterContext,
+ OUT EFI_HANDLE *DispatchHandle
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ This - GC_TODO: add argument description
+ DispatchFunction - GC_TODO: add argument description
+ RegisterContext - GC_TODO: add argument description
+ DispatchHandle - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+EFI_STATUS
+QNCSmmCoreUnRegister (
+ IN QNC_SMM_GENERIC_PROTOCOL *This,
+ IN EFI_HANDLE DispatchHandle
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ This - GC_TODO: add argument description
+ DispatchHandle - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+typedef union {
+ QNC_SMM_GENERIC_PROTOCOL Generic;
+
+ // EFI_SMM_USB_DISPATCH2_PROTOCOL Usb; DELETE:on QuarkNcSocId, there is no usb smi supported
+ EFI_SMM_SX_DISPATCH2_PROTOCOL Sx;
+ EFI_SMM_SW_DISPATCH2_PROTOCOL Sw;
+ EFI_SMM_GPI_DISPATCH2_PROTOCOL Gpi;
+ EFI_SMM_ICHN_DISPATCH2_PROTOCOL QNCn;
+ EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL PowerButton;
+ EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL PeriodicTimer;
+} QNC_SMM_PROTOCOL;
+
+//
+// Define a structure to help us identify the generic protocol
+//
+#define PROTOCOL_SIGNATURE SIGNATURE_32 ('P', 'R', 'O', 'T')
+
+typedef struct {
+ UINTN Signature;
+
+ QNC_SMM_PROTOCOL_TYPE Type;
+ EFI_GUID *Guid;
+ QNC_SMM_PROTOCOL Protocols;
+} QNC_SMM_QUALIFIED_PROTOCOL;
+
+#define QUALIFIED_PROTOCOL_FROM_GENERIC(_generic) \
+ CR (_generic, \
+ QNC_SMM_QUALIFIED_PROTOCOL, \
+ Protocols, \
+ PROTOCOL_SIGNATURE \
+ )
+
+//
+// Create private data for the protocols that we'll publish
+//
+typedef struct {
+ LIST_ENTRY CallbackDataBase;
+ EFI_HANDLE SmiHandle;
+ EFI_HANDLE InstallMultProtHandle;
+ QNC_SMM_QUALIFIED_PROTOCOL Protocols[NUM_PROTOCOLS];
+} PRIVATE_DATA;
+
+extern PRIVATE_DATA mPrivateData;
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+//
+VOID
+EFIAPI
+SwGetContext (
+ IN DATABASE_RECORD *Record,
+ OUT QNC_SMM_CONTEXT *Context
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ Record - GC_TODO: add argument description
+ Context - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+EFIAPI
+SwCmpContext (
+ IN QNC_SMM_CONTEXT *Context1,
+ IN QNC_SMM_CONTEXT *Context2
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ Context1 - GC_TODO: add argument description
+ Context2 - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+VOID
+SwGetBuffer (
+ IN DATABASE_RECORD * Record
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ Record - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+VOID
+EFIAPI
+SxGetContext (
+ IN DATABASE_RECORD *Record,
+ OUT QNC_SMM_CONTEXT *Context
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ Record - GC_TODO: add argument description
+ Context - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+EFIAPI
+SxCmpContext (
+ IN QNC_SMM_CONTEXT *Context1,
+ IN QNC_SMM_CONTEXT *Context2
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ Context1 - GC_TODO: add argument description
+ Context2 - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+VOID
+EFIAPI
+PeriodicTimerGetContext (
+ IN DATABASE_RECORD *Record,
+ OUT QNC_SMM_CONTEXT *Context
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ Record - GC_TODO: add argument description
+ Context - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+EFIAPI
+PeriodicTimerCmpContext (
+ IN QNC_SMM_CONTEXT *Context1,
+ IN QNC_SMM_CONTEXT *Context2
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ Context1 - GC_TODO: add argument description
+ Context2 - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+VOID
+PeriodicTimerGetBuffer (
+ IN DATABASE_RECORD * Record
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ Record - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+VOID
+EFIAPI
+PowerButtonGetContext (
+ IN DATABASE_RECORD *Record,
+ OUT QNC_SMM_CONTEXT *Context
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ Record - GC_TODO: add argument description
+ Context - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+EFIAPI
+PowerButtonCmpContext (
+ IN QNC_SMM_CONTEXT *Context1,
+ IN QNC_SMM_CONTEXT *Context2
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ Context1 - GC_TODO: add argument description
+ Context2 - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+//
+VOID
+EFIAPI
+QNCSmmPeriodicTimerClearSource (
+ QNC_SMM_SOURCE_DESC *SrcDesc
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+QNCSmmPeriodicTimerDispatchGetNextShorterInterval (
+ IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This,
+ IN OUT UINT64 **SmiTickInterval
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ This - GC_TODO: add argument description
+ SmiTickInterval - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+VOID
+QNCSmmSxGoToSleep (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ None
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+VOID
+EFIAPI
+QNCSmmQNCnClearSource (
+ QNC_SMM_SOURCE_DESC *SrcDesc
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+#endif
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c
new file mode 100644
index 0000000000..ba8c721773
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmCore.c
@@ -0,0 +1,800 @@
+/** @file
+This driver is responsible for the registration of child drivers
+and the abstraction of the QNC SMI sources.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmm.h"
+#include "QNCSmmHelpers.h"
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// MODULE / GLOBAL DATA
+//
+// Module variables used by the both the main dispatcher and the source dispatchers
+// Declared in QNCSmmSources.h
+//
+UINT32 mPciData;
+UINT32 mPciAddress;
+
+PRIVATE_DATA mPrivateData = { // for the structure
+ {
+ NULL
+ }, // CallbackDataBase linked list head
+ NULL, // Handler returned whan calling SmiHandlerRegister
+ NULL, // EFI handle returned when calling InstallMultipleProtocolInterfaces
+ { // protocol arrays
+ // elements within the array
+ //
+ {
+ PROTOCOL_SIGNATURE,
+ SxType,
+ &gEfiSmmSxDispatch2ProtocolGuid,
+ {
+ {
+ (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,
+ (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister
+ }
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ SwType,
+ &gEfiSmmSwDispatch2ProtocolGuid,
+ {
+ {
+ (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,
+ (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,
+ (UINTN) MAXIMUM_SWI_VALUE
+ }
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ GpiType,
+ &gEfiSmmGpiDispatch2ProtocolGuid,
+ {
+ {
+ (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,
+ (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,
+ (UINTN) 1
+ }
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ QNCnType,
+ &gEfiSmmIchnDispatch2ProtocolGuid,
+ {
+ {
+ (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,
+ (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister
+ }
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ PowerButtonType,
+ &gEfiSmmPowerButtonDispatch2ProtocolGuid,
+ {
+ {
+ (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,
+ (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister
+ }
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ PeriodicTimerType,
+ &gEfiSmmPeriodicTimerDispatch2ProtocolGuid,
+ {
+ {
+ (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,
+ (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,
+ (UINTN) QNCSmmPeriodicTimerDispatchGetNextShorterInterval
+ }
+ }
+ },
+ }
+};
+
+CONTEXT_FUNCTIONS mContextFunctions[NUM_PROTOCOLS] = {
+ {
+ SxGetContext,
+ SxCmpContext,
+ NULL
+ },
+ {
+ SwGetContext,
+ SwCmpContext,
+ SwGetBuffer
+ },
+ {
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ PeriodicTimerGetContext,
+ PeriodicTimerCmpContext,
+ PeriodicTimerGetBuffer,
+ },
+};
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// PROTOTYPES
+//
+// Functions use only in this file
+//
+EFI_STATUS
+QNCSmmCoreDispatcher (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context, OPTIONAL
+ IN OUT VOID *CommBuffer, OPTIONAL
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ );
+
+
+UINTN
+DevicePathSize (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// FUNCTIONS
+//
+// Driver entry point
+//
+EFI_STATUS
+EFIAPI
+InitializeQNCSmmDispatcher (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+Routine Description:
+
+ Initializes the QNC SMM Dispatcher
+
+Arguments:
+
+ ImageHandle - Pointer to the loaded image protocol for this driver
+ SystemTable - Pointer to the EFI System Table
+
+Returns:
+ Status - EFI_SUCCESS
+
+--*/
+{
+ EFI_STATUS Status;
+
+ QNCSmmPublishDispatchProtocols ();
+
+ //
+ // Register a callback function to handle subsequent SMIs. This callback
+ // will be called by SmmCoreDispatcher.
+ //
+ Status = gSmst->SmiHandlerRegister (QNCSmmCoreDispatcher, NULL, &mPrivateData.SmiHandle);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Initialize Callback DataBase
+ //
+ InitializeListHead (&mPrivateData.CallbackDataBase);
+
+ //
+ // Enable SMIs on the QNC now that we have a callback
+ //
+ QNCSmmInitHardware ();
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SaveState (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Save Index registers to avoid corrupting the foreground environment
+
+Arguments:
+ None
+
+Returns:
+ Status - EFI_SUCCESS
+
+--*/
+{
+ mPciAddress = IoRead32 (EFI_PCI_ADDRESS_PORT);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+RestoreState (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Restore Index registers to avoid corrupting the foreground environment
+
+Arguments:
+ None
+
+Returns:
+ Status - EFI_SUCCESS
+
+--*/
+{
+ IoWrite32 (EFI_PCI_ADDRESS_PORT, mPciAddress);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SmiInputValueDuplicateCheck (
+ UINTN FedSwSmiInputValue
+ )
+/*++
+
+Routine Description:
+
+ Check the Fed SwSmiInputValue to see if there is a duplicated one in the database
+
+Arguments:
+ None
+
+Returns:
+ Status - EFI_SUCCESS, EFI_INVALID_PARAMETER
+
+--*/
+// GC_TODO: FedSwSmiInputValue - add argument and description to function comment
+{
+
+ DATABASE_RECORD *RecordInDb;
+ LIST_ENTRY *LinkInDb;
+
+ LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
+ while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
+ RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
+
+ if (RecordInDb->ProtocolType == SwType) {
+ if (RecordInDb->ChildContext.Sw.SwSmiInputValue == FedSwSmiInputValue) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+QNCSmmCoreRegister (
+ IN QNC_SMM_GENERIC_PROTOCOL *This,
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
+ IN QNC_SMM_CONTEXT *RegisterContext,
+ OUT EFI_HANDLE *DispatchHandle
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Returns:
+
+--*/
+// GC_TODO: This - add argument and description to function comment
+// GC_TODO: DispatchFunction - add argument and description to function comment
+// GC_TODO: RegisterContext - add argument and description to function comment
+// GC_TODO: DispatchHandle - add argument and description to function comment
+// GC_TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
+// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment
+// GC_TODO: EFI_SUCCESS - add return value to function comment
+// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment
+{
+ EFI_STATUS Status;
+ DATABASE_RECORD *Record;
+ QNC_SMM_QUALIFIED_PROTOCOL *Qualified;
+ INTN Index;
+
+ //
+ // Check for invalid parameter
+ //
+ if (This == NULL || RegisterContext == NULL || DispatchHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Create database record and add to database
+ //
+ Record = (DATABASE_RECORD *) AllocateZeroPool (sizeof (DATABASE_RECORD));
+ if (Record == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Gather information about the registration request
+ //
+ Record->Callback = DispatchFunction;
+ Record->ChildContext = *RegisterContext;
+
+ Qualified = QUALIFIED_PROTOCOL_FROM_GENERIC (This);
+
+ Record->ProtocolType = Qualified->Type;
+
+ CopyMem (&Record->ContextFunctions, &mContextFunctions[Qualified->Type], sizeof (Record->ContextFunctions));
+ //
+ // Perform linked list housekeeping
+ //
+ Record->Signature = DATABASE_RECORD_SIGNATURE;
+
+ switch (Qualified->Type) {
+ //
+ // By the end of this switch statement, we'll know the
+ // source description the child is registering for
+ //
+ case SxType:
+ //
+ // Check the validity of Context Type and Phase
+ //
+ if ((Record->ChildContext.Sx.Type < SxS0) ||
+ (Record->ChildContext.Sx.Type >= EfiMaximumSleepType) ||
+ (Record->ChildContext.Sx.Phase < SxEntry) ||
+ (Record->ChildContext.Sx.Phase >= EfiMaximumPhase)
+ ) {
+ goto Error;
+ }
+
+ InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
+ CopyMem (&Record->SrcDesc, &SX_SOURCE_DESC, sizeof (Record->SrcDesc));
+ //
+ // use default clear source function
+ //
+ break;
+
+ case SwType:
+ if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) {
+ //
+ // If SwSmiInputValue is set to (UINTN) -1 then a unique value will be assigned and returned in the structure.
+ //
+ Status = EFI_NOT_FOUND;
+ for (Index = 1; Index < MAXIMUM_SWI_VALUE; Index++) {
+ Status = SmiInputValueDuplicateCheck (Index);
+ if (!EFI_ERROR (Status)) {
+ RegisterContext->Sw.SwSmiInputValue = Index;
+ break;
+ }
+ }
+ if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) {
+ Status = gSmst->SmmFreePool (Record);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Update ChildContext again as SwSmiInputValue has been changed
+ //
+ Record->ChildContext = *RegisterContext;
+ }
+
+ //
+ // Check the validity of Context Value
+ //
+ if (Record->ChildContext.Sw.SwSmiInputValue > MAXIMUM_SWI_VALUE) {
+ goto Error;
+ }
+
+ if (EFI_ERROR (SmiInputValueDuplicateCheck (Record->ChildContext.Sw.SwSmiInputValue))) {
+ goto Error;
+ }
+
+ InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
+ CopyMem (&Record->SrcDesc, &SW_SOURCE_DESC, sizeof (Record->SrcDesc));
+ Record->BufferSize = sizeof (EFI_SMM_SW_REGISTER_CONTEXT);
+ //
+ // use default clear source function
+ //
+ break;
+
+ case GpiType:
+
+ InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
+ CopyMem (&Record->SrcDesc, &GPI_SOURCE_DESC, sizeof (Record->SrcDesc));
+ //
+ // use default clear source function
+ //
+ break;
+
+ case QNCnType:
+ //
+ // Check the validity of Context Type
+ //
+ if ((Record->ChildContext.QNCn.Type < IchnMch) || (Record->ChildContext.QNCn.Type >= NUM_ICHN_TYPES)) {
+ goto Error;
+ }
+
+ InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
+ CopyMem (&Record->SrcDesc, &QNCN_SOURCE_DESCS[Record->ChildContext.QNCn.Type], sizeof (Record->SrcDesc));
+ Record->ClearSource = QNCSmmQNCnClearSource;
+ break;
+
+ case PeriodicTimerType:
+
+ Status = MapPeriodicTimerToSrcDesc (RegisterContext, &(Record->SrcDesc));
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
+ Record->BufferSize = sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT);
+ Record->ClearSource = QNCSmmPeriodicTimerClearSource;
+ break;
+
+ default:
+ goto Error;
+ break;
+ };
+
+ if (Record->ClearSource == NULL) {
+ //
+ // Clear the SMI associated w/ the source using the default function
+ //
+ QNCSmmClearSource (&Record->SrcDesc);
+ } else {
+ //
+ // This source requires special handling to clear
+ //
+ Record->ClearSource (&Record->SrcDesc);
+ }
+
+ QNCSmmEnableSource (&Record->SrcDesc);
+
+ //
+ // Child's handle will be the address linked list link in the record
+ //
+ *DispatchHandle = (EFI_HANDLE) (&Record->Link);
+
+ return EFI_SUCCESS;
+
+Error:
+ FreePool (Record);
+ //
+ // DEBUG((EFI_D_ERROR,"Free pool status %d\n", Status ));
+ //
+ return EFI_INVALID_PARAMETER;
+}
+
+EFI_STATUS
+QNCSmmCoreUnRegister (
+ IN QNC_SMM_GENERIC_PROTOCOL *This,
+ IN EFI_HANDLE DispatchHandle
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Returns:
+
+--*/
+// GC_TODO: This - add argument and description to function comment
+// GC_TODO: DispatchHandle - add argument and description to function comment
+// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment
+// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment
+// GC_TODO: EFI_SUCCESS - add return value to function comment
+{
+ BOOLEAN SafeToDisable;
+ DATABASE_RECORD *RecordToDelete;
+ DATABASE_RECORD *RecordInDb;
+ LIST_ENTRY *LinkInDb;
+
+ if (DispatchHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BASE_CR (DispatchHandle, DATABASE_RECORD, Link)->Signature != DATABASE_RECORD_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
+
+ RemoveEntryList (&RecordToDelete->Link);
+ RecordToDelete->Signature = 0;
+
+ //
+ // See if we can disable the source, reserved for future use since this might
+ // not be the only criteria to disable
+ //
+ SafeToDisable = TRUE;
+ LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
+ while(!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
+ RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
+ if (CompareEnables (&RecordToDelete->SrcDesc, &RecordInDb->SrcDesc)) {
+ SafeToDisable = FALSE;
+ break;
+ }
+ LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
+ }
+ if (SafeToDisable) {
+ QNCSmmDisableSource( &RecordToDelete->SrcDesc );
+}
+
+ FreePool (RecordToDelete);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is the main entry point for an SMM handler dispatch
+ or communicate-based callback.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param RegisterContext Points to an optional handler context which was specified when the handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+QNCSmmCoreDispatcher (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *RegisterContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ //
+ // Used to prevent infinite loops
+ //
+ UINTN EscapeCount;
+
+ BOOLEAN ContextsMatch;
+ BOOLEAN ResetListSearch;
+ BOOLEAN EosSet;
+ BOOLEAN SxChildWasDispatched;
+ BOOLEAN ChildWasDispatched;
+
+ DATABASE_RECORD *RecordInDb;
+ LIST_ENTRY *LinkInDb;
+ DATABASE_RECORD *RecordToExhaust;
+ LIST_ENTRY *LinkToExhaust;
+
+ QNC_SMM_CONTEXT Context;
+ VOID *CommunicationBuffer;
+ UINTN BufferSize;
+
+ EFI_STATUS Status;
+ UINT32 NewValue;
+
+ QNC_SMM_SOURCE_DESC ActiveSource = NULL_SOURCE_DESC_INITIALIZER;
+
+ EscapeCount = 100;
+ ContextsMatch = FALSE;
+ ResetListSearch = FALSE;
+ EosSet = FALSE;
+ SxChildWasDispatched = FALSE;
+ Status = EFI_WARN_INTERRUPT_SOURCE_PENDING;
+ ChildWasDispatched = FALSE;
+
+ //
+ // Preserve Index registers
+ //
+ SaveState ();
+
+ if (!IsListEmpty (&mPrivateData.CallbackDataBase)) {
+ //
+ // We have children registered w/ us -- continue
+ //
+ while ((!EosSet) && (EscapeCount > 0)) {
+ EscapeCount--;
+
+ //
+ // Reset this flag in order to be able to process multiple SMI Sources in one loop.
+ //
+ ResetListSearch = FALSE;
+
+ LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
+
+ while ((!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) && (ResetListSearch == FALSE)) {
+ RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
+
+ //
+ // look for the first active source
+ //
+ if (!SourceIsActive (&RecordInDb->SrcDesc)) {
+ //
+ // Didn't find the source yet, keep looking
+ //
+ LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
+
+ } else {
+ //
+ // We found a source. If this is a sleep type, we have to go to
+ // appropriate sleep state anyway.No matter there is sleep child or not
+ //
+ if (RecordInDb->ProtocolType == SxType) {
+ SxChildWasDispatched = TRUE;
+ }
+ //
+ // "cache" the source description and don't query I/O anymore
+ //
+ CopyMem (&ActiveSource, &RecordInDb->SrcDesc, sizeof (ActiveSource));
+ LinkToExhaust = LinkInDb;
+
+ //
+ // exhaust the rest of the queue looking for the same source
+ //
+ while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) {
+ RecordToExhaust = DATABASE_RECORD_FROM_LINK (LinkToExhaust);
+
+ if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource)) {
+ //
+ // These source descriptions are equal, so this callback should be
+ // dispatched.
+ //
+ if (RecordToExhaust->ContextFunctions.GetContext != NULL) {
+ //
+ // This child requires that we get a calling context from
+ // hardware and compare that context to the one supplied
+ // by the child.
+ //
+ ASSERT (RecordToExhaust->ContextFunctions.CmpContext != NULL);
+
+ //
+ // Make sure contexts match before dispatching event to child
+ //
+ RecordToExhaust->ContextFunctions.GetContext (RecordToExhaust, &Context);
+ ContextsMatch = RecordToExhaust->ContextFunctions.CmpContext (&Context, &RecordToExhaust->ChildContext);
+
+ } else {
+ //
+ // This child doesn't require any more calling context beyond what
+ // it supplied in registration. Simply pass back what it gave us.
+ //
+ ASSERT (RecordToExhaust->Callback != NULL);
+ Context = RecordToExhaust->ChildContext;
+ ContextsMatch = TRUE;
+ }
+
+ if (ContextsMatch) {
+
+ if (RecordToExhaust->BufferSize != 0) {
+ ASSERT (RecordToExhaust->ContextFunctions.GetBuffer != NULL);
+
+ RecordToExhaust->ContextFunctions.GetBuffer (RecordToExhaust);
+
+ CommunicationBuffer = &RecordToExhaust->CommBuffer;
+ BufferSize = RecordToExhaust->BufferSize;
+ } else {
+ CommunicationBuffer = NULL;
+ BufferSize = 0;
+ }
+
+ ASSERT (RecordToExhaust->Callback != NULL);
+
+ RecordToExhaust->Callback (
+ (EFI_HANDLE) & RecordToExhaust->Link,
+ &Context,
+ CommunicationBuffer,
+ &BufferSize
+ );
+
+ ChildWasDispatched = TRUE;
+ if (RecordToExhaust->ProtocolType == SxType) {
+ SxChildWasDispatched = TRUE;
+ }
+ }
+ }
+ //
+ // Get next record in DB
+ //
+ LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase, &RecordToExhaust->Link);
+ }
+
+ if (RecordInDb->ClearSource == NULL) {
+ //
+ // Clear the SMI associated w/ the source using the default function
+ //
+ QNCSmmClearSource (&ActiveSource);
+ } else {
+ //
+ // This source requires special handling to clear
+ //
+ RecordInDb->ClearSource (&ActiveSource);
+ }
+
+ if (ChildWasDispatched) {
+ //
+ // The interrupt was handled and quiesced
+ //
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // The interrupt was not handled but quiesced
+ //
+ Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED;
+ }
+
+ //
+ // Queue is empty, reset the search
+ //
+ ResetListSearch = TRUE;
+
+ }
+ }
+ EosSet = QNCSmmSetAndCheckEos ();
+ }
+ }
+ //
+ // If you arrive here, there are two possible reasons:
+ // (1) you've got problems with clearing the SMI status bits in the
+ // ACPI table. If you don't properly clear the SMI bits, then you won't be able to set the
+ // EOS bit. If this happens too many times, the loop exits.
+ // (2) there was a SMM communicate for callback messages that was received prior
+ // to this driver.
+ // If there is an asynchronous SMI that occurs while processing the Callback, let
+ // all of the drivers (including this one) have an opportunity to scan for the SMI
+ // and handle it.
+ // If not, we don't want to exit and have the foreground app. clear EOS without letting
+ // these other sources get serviced.
+ //
+ ASSERT (EscapeCount > 0);
+
+ //
+ // Restore Index registers
+ //
+ RestoreState ();
+
+ if (SxChildWasDispatched) {
+ //
+ // A child of the SmmSxDispatch protocol was dispatched during this call;
+ // put the system to sleep.
+ //
+ QNCSmmSxGoToSleep ();
+ }
+
+ //
+ // Ensure that SMI signal pin indicator is clear at the end of SMM handling.
+ //
+ NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG);
+ NewValue &= ~(HLEGACY_SMI_PIN_VALUE);
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG, NewValue);
+
+ return Status;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf
new file mode 100644
index 0000000000..ed948253e9
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf
@@ -0,0 +1,87 @@
+## @file
+# Component description file for QuarkNcSocId SmmDispatcher module.
+#
+# This driver is responsible for the registration of child drivers
+# and the abstraction of the ICH SMI sources.
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = QNCSmmDispatcher
+ FILE_GUID = 2480271C-09C6-4f36-AD75-5E1390BD9929
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = InitializeQNCSmmDispatcher
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ QNC/QNCSmmPeriodicTimer.c
+ QNC/QNCSmmQncn.c
+ QNC/QNCSmmSx.c
+ QNC/QNCSmmSw.c
+ QNC/QNCSmmGpi.c
+ QNC/QNCSmmHelpers.c
+ QNCSmmHelpers.c
+ QNCSmmCore.c
+ QNCSmmHelpers.h
+ QNCxSmmHelpers.h
+ QNCSmmRegisters.h
+ QNCSmm.h
+ CommonHeader.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ QuarkSocPkg/QuarkSocPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ SmmServicesTableLib
+ UefiBootServicesTableLib
+ DxeServicesTableLib
+ MemoryAllocationLib
+ PciLib
+ PcdLib
+ BaseMemoryLib
+ DebugLib
+ BaseLib
+ IoLib
+ DevicePathLib
+ S3IoLib
+ QNCAccessLib
+
+[Protocols]
+ gEfiSmmCpuProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiSmmReadyToLockProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiSmmPeriodicTimerDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+ gEfiSmmPowerButtonDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+ gEfiSmmIchnDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+ gEfiSmmGpiDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+ gEfiSmmSwDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+ gEfiSmmSxDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+ gEfiSmmUsbDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+ gEfiSmmIoTrapDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+
+[Pcd]
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress
+
+[Depex]
+ gEfiSmmCpuProtocolGuid AND gEfiPciRootBridgeIoProtocolGuid
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c
new file mode 100644
index 0000000000..db6102981b
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.c
@@ -0,0 +1,373 @@
+/** @file
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmm.h"
+#include "QNCSmmHelpers.h"
+
+//
+// #define BIT_ZERO 0x00000001
+//
+CONST UINT32 BIT_ZERO = 0x00000001;
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// SUPPORT / HELPER FUNCTIONS (QNC version-independent)
+//
+BOOLEAN
+CompareEnables (
+ CONST IN QNC_SMM_SOURCE_DESC *Src1,
+ CONST IN QNC_SMM_SOURCE_DESC *Src2
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ Src1 - GC_TODO: add argument description
+ Src2 - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+{
+ BOOLEAN IsEqual;
+ UINTN loopvar;
+
+ IsEqual = TRUE;
+ for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) {
+ //
+ // It's okay to compare a NULL bit description to a non-NULL bit description.
+ // They are unequal and these tests will generate the correct result.
+ //
+ if (Src1->En[loopvar].Bit != Src2->En[loopvar].Bit ||
+ Src1->En[loopvar].Reg.Type != Src2->En[loopvar].Reg.Type ||
+ Src1->En[loopvar].Reg.Data.raw != Src2->En[loopvar].Reg.Data.raw
+ ) {
+ IsEqual = FALSE;
+ break;
+ //
+ // out of for loop
+ //
+ }
+ }
+
+ return IsEqual;
+}
+
+BOOLEAN
+CompareStatuses (
+ CONST IN QNC_SMM_SOURCE_DESC *Src1,
+ CONST IN QNC_SMM_SOURCE_DESC *Src2
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ Src1 - GC_TODO: add argument description
+ Src2 - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+{
+ BOOLEAN IsEqual;
+ UINTN loopvar;
+
+ IsEqual = TRUE;
+
+ for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) {
+ //
+ // It's okay to compare a NULL bit description to a non-NULL bit description.
+ // They are unequal and these tests will generate the correct result.
+ //
+ if (Src1->Sts[loopvar].Bit != Src2->Sts[loopvar].Bit ||
+ Src1->Sts[loopvar].Reg.Type != Src2->Sts[loopvar].Reg.Type ||
+ Src1->Sts[loopvar].Reg.Data.raw != Src2->Sts[loopvar].Reg.Data.raw
+ ) {
+ IsEqual = FALSE;
+ break;
+ //
+ // out of for loop
+ //
+ }
+ }
+
+ return IsEqual;
+}
+
+BOOLEAN
+CompareSources (
+ CONST IN QNC_SMM_SOURCE_DESC *Src1,
+ CONST IN QNC_SMM_SOURCE_DESC *Src2
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ Src1 - GC_TODO: add argument description
+ Src2 - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+{
+ return (BOOLEAN) (CompareEnables (Src1, Src2) && CompareStatuses (Src1, Src2));
+}
+
+BOOLEAN
+SourceIsActive (
+ CONST IN QNC_SMM_SOURCE_DESC *Src
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ Src - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+{
+ BOOLEAN IsActive;
+ UINTN loopvar;
+
+ BOOLEAN SciEn;
+
+ IsActive = TRUE;
+
+ SciEn = QNCSmmGetSciEn ();
+
+ if ((Src->Flags & QNC_SMM_SCI_EN_DEPENDENT) && (SciEn)) {
+ //
+ // This source is dependent on SciEn, and SciEn == 1. An ACPI OS is present,
+ // so we shouldn't do anything w/ this source until SciEn == 0.
+ //
+ IsActive = FALSE;
+
+ } else {
+ //
+ // Read each bit desc from hardware and make sure it's a one
+ //
+ for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) {
+
+ if (!IS_BIT_DESC_NULL (Src->En[loopvar])) {
+
+ if (ReadBitDesc (&Src->En[loopvar]) == 0) {
+ IsActive = FALSE;
+ break;
+ //
+ // out of for loop
+ //
+ }
+
+ }
+ }
+
+ if (IsActive) {
+ //
+ // Read each bit desc from hardware and make sure it's a one
+ //
+ for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) {
+
+ if (!IS_BIT_DESC_NULL (Src->Sts[loopvar])) {
+
+ if (ReadBitDesc (&Src->Sts[loopvar]) == 0) {
+ IsActive = FALSE;
+ break;
+ //
+ // out of for loop
+ //
+ }
+
+ }
+ }
+ }
+ }
+
+ return IsActive;
+}
+
+VOID
+QNCSmmEnableSource (
+ CONST QNC_SMM_SOURCE_DESC *SrcDesc
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+{
+ UINTN loopvar;
+
+ //
+ // Set enables to 1 by writing a 1
+ //
+ for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) {
+ if (!IS_BIT_DESC_NULL (SrcDesc->En[loopvar])) {
+ WriteBitDesc (&SrcDesc->En[loopvar], 1);
+ }
+ }
+
+ QNCSmmClearSource (SrcDesc);
+
+}
+
+VOID
+QNCSmmDisableSource (
+ CONST QNC_SMM_SOURCE_DESC *SrcDesc
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+{
+ UINTN loopvar;
+
+ for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) {
+ if (!IS_BIT_DESC_NULL (SrcDesc->En[loopvar])) {
+ WriteBitDesc (&SrcDesc->En[loopvar], 0);
+ }
+ }
+}
+
+VOID
+QNCSmmClearSource (
+ CONST QNC_SMM_SOURCE_DESC *SrcDesc
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+{
+ UINTN loopvar;
+ BOOLEAN ValueToWrite;
+
+ ValueToWrite =
+ ((SrcDesc->Flags & QNC_SMM_CLEAR_WITH_ZERO) == 0) ? TRUE : FALSE;
+
+ for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) {
+ if (!IS_BIT_DESC_NULL (SrcDesc->Sts[loopvar])) {
+ WriteBitDesc (&SrcDesc->Sts[loopvar], ValueToWrite);
+ }
+ }
+}
+
+VOID
+QNCSmmClearSourceAndBlock (
+ CONST QNC_SMM_SOURCE_DESC *SrcDesc
+ )
+// GC_TODO: function comment should start with '/*++'
+/*
+ Sets the source to a 1 or 0 and then waits for it to clear.
+ Be very careful when calling this function -- it will not
+ ASSERT. An acceptable case to call the function is when
+ waiting for the NEWCENTURY_STS bit to clear (which takes
+ 3 RTCCLKs).
+*/
+// GC_TODO: function comment should end with '--*/'
+// GC_TODO: function comment is missing 'Routine Description:'
+// GC_TODO: function comment is missing 'Arguments:'
+// GC_TODO: function comment is missing 'Returns:'
+// GC_TODO: SrcDesc - add argument and description to function comment
+{
+ UINTN loopvar;
+ BOOLEAN IsSet;
+ BOOLEAN ValueToWrite;
+
+ ValueToWrite =
+ ((SrcDesc->Flags & QNC_SMM_CLEAR_WITH_ZERO) == 0) ? TRUE : FALSE;
+
+ for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) {
+
+ if (!IS_BIT_DESC_NULL (SrcDesc->Sts[loopvar])) {
+ //
+ // Write the bit
+ //
+ WriteBitDesc (&SrcDesc->Sts[loopvar], ValueToWrite);
+
+ //
+ // Don't return until the bit actually clears.
+ //
+ IsSet = TRUE;
+ while (IsSet) {
+ IsSet = ReadBitDesc (&SrcDesc->Sts[loopvar]);
+ //
+ // IsSet will eventually clear -- or else we'll have
+ // an infinite loop.
+ //
+ }
+ }
+ }
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h
new file mode 100644
index 0000000000..d2572d3e92
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmHelpers.h
@@ -0,0 +1,225 @@
+/** @file
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef QNC_SMM_HELPERS_H
+#define QNC_SMM_HELPERS_H
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmm.h"
+#include "QNCxSmmHelpers.h"
+
+//
+// /////////////////////////////////////////////////////////////////////////////
+// SUPPORT / HELPER FUNCTIONS (QNC version-independent)
+//
+VOID
+QNCSmmPublishDispatchProtocols (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ None
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+CompareEnables (
+ CONST IN QNC_SMM_SOURCE_DESC *Src1,
+ CONST IN QNC_SMM_SOURCE_DESC *Src2
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ Src1 - GC_TODO: add argument description
+ Src2 - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+CompareStatuses (
+ CONST IN QNC_SMM_SOURCE_DESC *Src1,
+ CONST IN QNC_SMM_SOURCE_DESC *Src2
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ Src1 - GC_TODO: add argument description
+ Src2 - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+CompareSources (
+ CONST IN QNC_SMM_SOURCE_DESC *Src1,
+ CONST IN QNC_SMM_SOURCE_DESC *Src2
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ Src1 - GC_TODO: add argument description
+ Src2 - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+SourceIsActive (
+ CONST IN QNC_SMM_SOURCE_DESC *Src
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ Src - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+VOID
+QNCSmmEnableSource (
+ CONST QNC_SMM_SOURCE_DESC *SrcDesc
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+VOID
+QNCSmmDisableSource (
+ CONST QNC_SMM_SOURCE_DESC *SrcDesc
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+VOID
+QNCSmmClearSource (
+ CONST QNC_SMM_SOURCE_DESC *SrcDesc
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+VOID
+QNCSmmClearSourceAndBlock (
+ CONST QNC_SMM_SOURCE_DESC *SrcDesc
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ SrcDesc - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+#endif
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h
new file mode 100644
index 0000000000..3474c56ae2
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmRegisters.h
@@ -0,0 +1,19 @@
+/** @file
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef QNC_SMM_REGISTERS_H
+#define QNC_SMM_REGISTERS_H
+#include "CommonHeader.h"
+
+#endif
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h
new file mode 100644
index 0000000000..53027c4bf4
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCxSmmHelpers.h
@@ -0,0 +1,184 @@
+/** @file
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef QNCX_SMM_HELPERS_H
+#define QNCX_SMM_HELPERS_H
+
+//
+// Include common header file for this module.
+//
+#include "CommonHeader.h"
+
+#include "QNCSmm.h"
+
+EFI_STATUS
+QNCSmmInitHardware (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ None
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+QNCSmmEnableGlobalSmiBit (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Enables the QNC to generate SMIs. Note that no SMIs will be generated
+ if no SMI sources are enabled. Conversely, no enabled SMI source will
+ generate SMIs if SMIs are not globally enabled. This is the main
+ switchbox for SMI generation.
+
+Arguments:
+
+ None
+
+Returns:
+
+ EFI_SUCCESS.
+ Asserts, otherwise.
+
+--*/
+;
+
+EFI_STATUS
+QNCSmmClearSmi (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ None
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+QNCSmmSetAndCheckEos (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ None
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+QNCSmmGetSciEn (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ None
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+//
+// ///////////////////////////////////////////////////////////////////////////
+//
+// These may or may not need to change w/ the QNC version;
+// they're here because they're highly IA-32 dependent.
+//
+BOOLEAN
+ReadBitDesc (
+ CONST QNC_SMM_BIT_DESC *BitDesc
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ BitDesc - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+VOID
+WriteBitDesc (
+ CONST QNC_SMM_BIT_DESC *BitDesc,
+ CONST BOOLEAN ValueToWrite
+ )
+/*++
+
+Routine Description:
+
+ GC_TODO: Add function description
+
+Arguments:
+
+ BitDesc - GC_TODO: add argument description
+ ValueToWrite - GC_TODO: add argument description
+
+Returns:
+
+ GC_TODO: add return values
+
+--*/
+;
+
+#endif
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.c b/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.c
new file mode 100644
index 0000000000..70fdf09611
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.c
@@ -0,0 +1,382 @@
+/** @file
+This is the driver that publishes the SMM Access Ppi
+instance for the Quark SOC.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include <PiPei.h>
+#include <Ppi/SmmAccess.h>
+#include <Guid/SmramMemoryReserve.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/PciLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/QNCSmmLib.h>
+#include <QNCAccess.h>
+
+#define SMM_ACCESS_PRIVATE_DATA_FROM_THIS(a) \
+ CR ( \
+ a, \
+ SMM_ACCESS_PRIVATE_DATA, \
+ SmmAccess, \
+ SMM_ACCESS_PRIVATE_DATA_SIGNATURE \
+ )
+
+#define MAX_CPU_SOCKET 1
+#define MAX_SMRAM_RANGES 4
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ PEI_SMM_ACCESS_PPI SmmAccess;
+ UINTN NumberRegions;
+ EFI_SMRAM_DESCRIPTOR SmramDesc[MAX_SMRAM_RANGES];
+ UINT8 TsegSize;
+ UINT8 MaxBusNumber;
+ UINT8 SocketPopulated[MAX_CPU_SOCKET];
+ UINT8 SocketBusNum[MAX_CPU_SOCKET];
+} SMM_ACCESS_PRIVATE_DATA;
+
+#define SMM_ACCESS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('i', 's', 'm', 'a')
+
+
+EFI_STATUS
+EFIAPI
+Open (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_ACCESS_PPI *This,
+ IN UINTN DescriptorIndex
+ )
+/*++
+
+Routine Description:
+
+ This routine accepts a request to "open" a region of SMRAM. The
+ region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.
+ The use of "open" means that the memory is visible from all PEIM
+ and SMM agents.
+
+Arguments:
+
+ PeiServices - General purpose services available to every PEIM.
+ This - Pointer to the SMM Access Interface.
+ DescriptorIndex - Region of SMRAM to Open.
+
+Returns:
+
+ EFI_SUCCESS - The region was successfully opened.
+ EFI_DEVICE_ERROR - The region could not be opened because locked by
+ chipset.
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.
+
+--*/
+{
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;
+
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
+
+ if (DescriptorIndex >= SmmAccess->NumberRegions) {
+ return EFI_INVALID_PARAMETER;
+ } else if (SmmAccess->SmramDesc[DescriptorIndex].RegionState & EFI_SMRAM_LOCKED) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Open TSEG
+ //
+ if (!QNCOpenSmramRegion ()) {
+ SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_LOCKED;
+ return EFI_DEVICE_ERROR;
+ }
+
+ SmmAccess->SmramDesc[DescriptorIndex].RegionState &= ~(EFI_SMRAM_CLOSED | EFI_ALLOCATED);
+ SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_OPEN;
+ SmmAccess->SmmAccess.OpenState = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+Close (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_ACCESS_PPI *This,
+ IN UINTN DescriptorIndex
+ )
+/*++
+
+Routine Description:
+
+ This routine accepts a request to "close" a region of SMRAM. This is valid for
+ compatible SMRAM region.
+
+Arguments:
+
+ PeiServices - General purpose services available to every PEIM.
+ This - Pointer to the SMM Access Interface.
+ DescriptorIndex - Region of SMRAM to Close.
+
+Returns:
+
+ EFI_SUCCESS - The region was successfully closed.
+ EFI_DEVICE_ERROR - The region could not be closed because locked by
+ chipset.
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.
+
+--*/
+{
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;
+ BOOLEAN OpenState;
+ UINTN Index;
+
+
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
+
+ if (DescriptorIndex >= SmmAccess->NumberRegions) {
+ return EFI_INVALID_PARAMETER;
+ } else if (SmmAccess->SmramDesc[DescriptorIndex].RegionState & EFI_SMRAM_LOCKED) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (SmmAccess->SmramDesc[DescriptorIndex].RegionState & EFI_SMRAM_CLOSED) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Close TSEG
+ //
+ if (!QNCCloseSmramRegion ()) {
+ SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_LOCKED;
+ return EFI_DEVICE_ERROR;
+ }
+
+ SmmAccess->SmramDesc[DescriptorIndex].RegionState &= ~EFI_SMRAM_OPEN;
+ SmmAccess->SmramDesc[DescriptorIndex].RegionState |= (EFI_SMRAM_CLOSED | EFI_ALLOCATED);
+
+ //
+ // Find out if any regions are still open
+ //
+ OpenState = FALSE;
+ for (Index = 0; Index < SmmAccess->NumberRegions; Index++) {
+ if ((SmmAccess->SmramDesc[Index].RegionState & EFI_SMRAM_OPEN) == EFI_SMRAM_OPEN) {
+ OpenState = TRUE;
+ }
+ }
+
+ SmmAccess->SmmAccess.OpenState = OpenState;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+Lock (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_ACCESS_PPI *This,
+ IN UINTN DescriptorIndex
+ )
+/*++
+
+Routine Description:
+
+ This routine accepts a request to "lock" SMRAM. The
+ region could be legacy AB or TSEG near top of physical memory.
+ The use of "lock" means that the memory can no longer be opened
+ to PEIM.
+
+Arguments:
+
+ PeiServices - General purpose services available to every PEIM.
+ This - Pointer to the SMM Access Interface.
+ DescriptorIndex - Region of SMRAM to Lock.
+
+Returns:
+
+ EFI_SUCCESS - The region was successfully locked.
+ EFI_DEVICE_ERROR - The region could not be locked because at least
+ one range is still open.
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.
+
+--*/
+{
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;
+
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
+
+ if (DescriptorIndex >= SmmAccess->NumberRegions) {
+ return EFI_INVALID_PARAMETER;
+ } else if (SmmAccess->SmmAccess.OpenState) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_LOCKED;
+ SmmAccess->SmmAccess.LockState = TRUE;
+
+ //
+ // Lock TSEG
+ //
+ QNCLockSmramRegion ();
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+GetCapabilities (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_ACCESS_PPI *This,
+ IN OUT UINTN *SmramMapSize,
+ IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap
+ )
+/*++
+
+Routine Description:
+
+ This routine services a user request to discover the SMRAM
+ capabilities of this platform. This will report the possible
+ ranges that are possible for SMRAM access, based upon the
+ memory controller capabilities.
+
+Arguments:
+
+ PeiServices - General purpose services available to every PEIM.
+ This - Pointer to the SMRAM Access Interface.
+ SmramMapSize - Pointer to the variable containing size of the
+ buffer to contain the description information.
+ SmramMap - Buffer containing the data describing the Smram
+ region descriptors.
+Returns:
+
+ EFI_BUFFER_TOO_SMALL - The user did not provide a sufficient buffer.
+ EFI_SUCCESS - The user provided a sufficiently-sized buffer.
+
+--*/
+{
+ EFI_STATUS Status;
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;
+ UINTN BufferSize;
+
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
+ BufferSize = SmmAccess->NumberRegions * sizeof (EFI_SMRAM_DESCRIPTOR);
+
+ if (*SmramMapSize < BufferSize) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ } else {
+ CopyMem (SmramMap, SmmAccess->SmramDesc, *SmramMapSize);
+ Status = EFI_SUCCESS;
+ }
+
+ *SmramMapSize = BufferSize;
+
+ return Status;
+}
+
+
+EFI_STATUS
+EFIAPI
+SmmAccessPeiEntryPoint (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+/*++
+
+Routine Description:
+
+ This is the constructor for the SMM Access Ppi
+
+Arguments:
+
+ FfsHeader - FfsHeader.
+ PeiServices - General purpose services available to every PEIM.
+
+Returns:
+
+ EFI_SUCCESS - Protocol successfully started and installed.
+ EFI_UNSUPPORTED - Protocol can't be started.
+--*/
+{
+
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *DescriptorBlock;
+ SMM_ACCESS_PRIVATE_DATA *SmmAccessPrivate;
+ EFI_PEI_PPI_DESCRIPTOR *PpiList;
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ //
+ // Initialize private data
+ //
+ SmmAccessPrivate = AllocatePool (sizeof(*SmmAccessPrivate));
+ ASSERT(SmmAccessPrivate);
+
+ PpiList = AllocatePool (sizeof(*PpiList));
+ ASSERT (PpiList);
+
+ //
+ // Build SMM related information
+ //
+ SmmAccessPrivate->Signature = SMM_ACCESS_PRIVATE_DATA_SIGNATURE;
+
+ //
+ // Get Hob list
+ //
+ GuidHob = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);
+ DescriptorBlock = GET_GUID_HOB_DATA (GuidHob);
+ ASSERT (DescriptorBlock);
+
+ // Get CPU Max bus number
+
+ SmmAccessPrivate->MaxBusNumber = PCI_BUS_NUMBER_QNC;
+ for (Index = 0; Index < MAX_CPU_SOCKET; Index++) {
+ SmmAccessPrivate->SocketPopulated[Index] = TRUE;
+ SmmAccessPrivate->SocketBusNum[Index] = PCI_BUS_NUMBER_QNC;
+ }
+
+ //
+ // Use the hob to publish SMRAM capabilities
+ //
+ ASSERT (DescriptorBlock->NumberOfSmmReservedRegions <= MAX_SMRAM_RANGES);
+ for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) {
+ SmmAccessPrivate->SmramDesc[Index].PhysicalStart = DescriptorBlock->Descriptor[Index].PhysicalStart;
+ SmmAccessPrivate->SmramDesc[Index].CpuStart = DescriptorBlock->Descriptor[Index].CpuStart;
+ SmmAccessPrivate->SmramDesc[Index].PhysicalSize = DescriptorBlock->Descriptor[Index].PhysicalSize;
+ SmmAccessPrivate->SmramDesc[Index].RegionState = DescriptorBlock->Descriptor[Index].RegionState;
+ }
+
+ SmmAccessPrivate->NumberRegions = Index;
+ SmmAccessPrivate->SmmAccess.Open = Open;
+ SmmAccessPrivate->SmmAccess.Close = Close;
+ SmmAccessPrivate->SmmAccess.Lock = Lock;
+ SmmAccessPrivate->SmmAccess.GetCapabilities = GetCapabilities;
+ SmmAccessPrivate->SmmAccess.LockState = FALSE;
+ SmmAccessPrivate->SmmAccess.OpenState = FALSE;
+
+ PpiList->Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
+ PpiList->Guid = &gPeiSmmAccessPpiGuid;
+ PpiList->Ppi = &SmmAccessPrivate->SmmAccess;
+
+ Status = (**PeiServices).InstallPpi (PeiServices, PpiList);
+ ASSERT_EFI_ERROR(Status);
+
+ DEBUG (
+ (EFI_D_INFO, "SMM Base:Size %08X:%08X\n",
+ (UINTN)(SmmAccessPrivate->SmramDesc[SmmAccessPrivate->NumberRegions-1].PhysicalStart),
+ (UINTN)(SmmAccessPrivate->SmramDesc[SmmAccessPrivate->NumberRegions-1].PhysicalSize)
+ ));
+
+ SmmAccessPrivate->TsegSize = (UINT8)(SmmAccessPrivate->SmramDesc[SmmAccessPrivate->NumberRegions-1].PhysicalSize);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf b/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf
new file mode 100644
index 0000000000..a1e4af7725
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf
@@ -0,0 +1,51 @@
+## @file
+# Component description file for SmmAccessPei module
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+INF_VERSION = 0x00010005
+BASE_NAME = SmmAccessPei
+FILE_GUID = B4E0CDFC-30CD-4b29-A445-B0AA95A532E4
+MODULE_TYPE = PEIM
+VERSION_STRING = 1.0
+ENTRY_POINT = SmmAccessPeiEntryPoint
+
+[Sources]
+ SmmAccessPei.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+ PeimEntryPoint
+ BaseMemoryLib
+ MemoryAllocationLib
+ DebugLib
+ HobLib
+ PeiServicesLib
+ PciLib
+ SmmLib
+
+[Guids]
+ gEfiSmmPeiSmramMemoryReserveGuid # ALWAYS_CONSUMED
+
+[Ppis]
+ gPeiSmmAccessPpiGuid # ALWAYS_PRODUCED
+ gEfiPeiMemoryDiscoveredPpiGuid # ALWAYS_CONSUMED
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.c b/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.c
new file mode 100644
index 0000000000..8c82611056
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.c
@@ -0,0 +1,282 @@
+/** @file
+This module provides an implementation of the SMM Control PPI for use with
+the QNC.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+
+#include <Ppi/SmmControl.h>
+
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+
+#include <IntelQNCPeim.h>
+#include <Library/QNCAccessLib.h>
+#include <Uefi/UefiBaseType.h>
+
+/**
+ Generates an SMI using the parameters passed in.
+
+ @param PeiServices Describes the list of possible PEI Services.
+ @param This A pointer to an instance of
+ EFI_SMM_CONTROL_PPI
+ @param ArgumentBuffer The argument buffer
+ @param ArgumentBufferSize The size of the argument buffer
+ @param Periodic TRUE to indicate a periodical SMI
+ @param ActivationInterval Interval of the periodical SMI
+
+ @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1
+ @retval EFI_SUCCESS SMI generated
+
+**/
+EFI_STATUS
+EFIAPI
+PeiActivate (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_CONTROL_PPI *This,
+ IN OUT INT8 *ArgumentBuffer OPTIONAL,
+ IN OUT UINTN *ArgumentBufferSize OPTIONAL,
+ IN BOOLEAN Periodic OPTIONAL,
+ IN UINTN ActivationInterval OPTIONAL
+ );
+
+/**
+ Clears an SMI.
+
+ @param PeiServices Describes the list of possible PEI Services.
+ @param This Pointer to an instance of EFI_SMM_CONTROL_PPI
+ @param Periodic TRUE to indicate a periodical SMI
+
+ @return Return value from SmmClear()
+
+**/
+EFI_STATUS
+EFIAPI
+PeiDeactivate (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_CONTROL_PPI *This,
+ IN BOOLEAN Periodic OPTIONAL
+ );
+
+PEI_SMM_CONTROL_PPI mSmmControlPpi = {
+ PeiActivate,
+ PeiDeactivate
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPpiList = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gPeiSmmControlPpiGuid,
+ &mSmmControlPpi
+};
+
+/**
+ Clear SMI related chipset status and re-enable SMI by setting the EOS bit.
+
+ @retval EFI_SUCCESS The requested operation has been carried out successfully
+ @retval EFI_DEVICE_ERROR The EOS bit could not be set.
+
+**/
+EFI_STATUS
+SmmClear (
+ VOID
+ )
+{
+ UINT16 PM1BLK_Base;
+ UINT16 GPE0BLK_Base;
+
+ //
+ // Get PM1BLK_Base & GPE0BLK_Base
+ //
+ PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);
+ GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
+
+ //
+ // Clear the Power Button Override Status Bit, it gates EOS from being set.
+ // In QuarkNcSocId - Bit is read only. Handled by external SMC, do nothing.
+ //
+
+ //
+ // Clear the APM SMI Status Bit
+ //
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);
+
+ //
+ // Set the EOS Bit
+ //
+ IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+SmmTrigger (
+ IN UINT8 Data
+ )
+/*++
+
+Routine Description:
+
+ Trigger the software SMI
+
+Arguments:
+
+ Data The value to be set on the software SMI data port
+
+Returns:
+
+ EFI_SUCCESS Function completes successfully
+
+--*/
+{
+ UINT16 GPE0BLK_Base;
+ UINT32 NewValue;
+
+ //
+ // Get GPE0BLK_Base
+ //
+ GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
+
+ //
+ // Enable the APMC SMI
+ //
+ IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIE, B_QNC_GPE0BLK_SMIE_APM);
+
+ //
+ // Enable SMI globally
+ //
+ NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
+ NewValue |= SMI_EN;
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
+
+
+ //
+ // Generate the APMC SMI
+ //
+ IoWrite8 (PcdGet16 (PcdSmmActivationPort), Data);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Generates an SMI using the parameters passed in.
+
+ @param PeiServices Describes the list of possible PEI Services.
+ @param This A pointer to an instance of
+ EFI_SMM_CONTROL_PPI
+ @param ArgumentBuffer The argument buffer
+ @param ArgumentBufferSize The size of the argument buffer
+ @param Periodic TRUE to indicate a periodical SMI
+ @param ActivationInterval Interval of the periodical SMI
+
+ @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1
+ @retval EFI_SUCCESS SMI generated
+
+**/
+EFI_STATUS
+EFIAPI
+PeiActivate (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_CONTROL_PPI *This,
+ IN OUT INT8 *ArgumentBuffer OPTIONAL,
+ IN OUT UINTN *ArgumentBufferSize OPTIONAL,
+ IN BOOLEAN Periodic OPTIONAL,
+ IN UINTN ActivationInterval OPTIONAL
+ )
+{
+ INT8 Data;
+ EFI_STATUS Status;
+ //
+ // Periodic SMI not supported.
+ //
+ if (Periodic) {
+ DEBUG ((DEBUG_WARN, "Invalid parameter\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ArgumentBuffer == NULL) {
+ Data = 0xFF;
+ } else {
+ if (ArgumentBufferSize == NULL || *ArgumentBufferSize != 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Data = *ArgumentBuffer;
+ }
+ //
+ // Clear any pending the APM SMI
+ //
+ Status = SmmClear ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return SmmTrigger (Data);
+}
+
+/**
+ Clears an SMI.
+
+ @param PeiServices Describes the list of possible PEI Services.
+ @param This Pointer to an instance of EFI_SMM_CONTROL_PPI
+ @param Periodic TRUE to indicate a periodical SMI
+
+ @return Return value from SmmClear()
+
+**/
+EFI_STATUS
+EFIAPI
+PeiDeactivate (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_SMM_CONTROL_PPI *This,
+ IN BOOLEAN Periodic OPTIONAL
+ )
+{
+ if (Periodic) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return SmmClear ();
+}
+
+/**
+ This is the constructor for the SMM Control Ppi.
+
+ This function installs EFI_SMM_CONTROL_PPI.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_UNSUPPORTED There's no Intel ICH on this platform
+ @return The status returned from InstallPpi().
+
+--*/
+EFI_STATUS
+EFIAPI
+SmmControlPeiEntry (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+
+ Status = (**PeiServices).InstallPpi (PeiServices, &mPpiList);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf b/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf
new file mode 100644
index 0000000000..6b1dd1bcfd
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf
@@ -0,0 +1,57 @@
+## @file
+# Component description file for SmmControlPei module.
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmControlPei
+ FILE_GUID = 60EC7720-512B-4490-9FD1-A336769AE01F
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SmmControlPeiEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmControlPei.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ QuarkSocPkg/QuarkSocPkg.dec
+
+[LibraryClasses]
+ PeimEntryPoint
+ DebugLib
+ PeiServicesLib
+ PcdLib
+ IoLib
+ PciLib
+ QNCAccessLib
+
+[Ppis]
+ gPeiSmmControlPpiGuid # ALWAYS_PRODUCED
+
+[Pcd]
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort
+
+[Depex]
+ TRUE