diff options
Diffstat (limited to 'QuarkSocPkg/QuarkNorthCluster/Smm')
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
|