summaryrefslogtreecommitdiff
path: root/ReferenceCode/Chipset/LynxPoint/IoTrap/Smm/IoTrap.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Chipset/LynxPoint/IoTrap/Smm/IoTrap.c')
-rw-r--r--ReferenceCode/Chipset/LynxPoint/IoTrap/Smm/IoTrap.c884
1 files changed, 884 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/LynxPoint/IoTrap/Smm/IoTrap.c b/ReferenceCode/Chipset/LynxPoint/IoTrap/Smm/IoTrap.c
new file mode 100644
index 0000000..74cb450
--- /dev/null
+++ b/ReferenceCode/Chipset/LynxPoint/IoTrap/Smm/IoTrap.c
@@ -0,0 +1,884 @@
+/** @file
+ Main implementation source file for the Io Trap SMM driver
+
+@copyright
+ Copyright (c) 2006 - 2013 Intel Corporation. All rights reserved
+ This software and associated documentation (if any) is furnished
+ under a license and may only be used or copied in accordance
+ with the terms of the license. Except as permitted by such
+ license, no part of this software or documentation may be
+ reproduced, stored in a retrieval system, or transmitted in any
+ form or by any means without the express written consent of
+ Intel Corporation.
+
+ This file contains an 'Intel Peripheral Driver' and uniquely
+ identified as "Intel Reference Module" and is
+ licensed for Intel CPUs and chipsets under the terms of your
+ license agreement with Intel or your vendor. This file may
+ be modified by the user, subject to additional terms of the
+ license agreement
+
+**/
+#include "IoTrap.h"
+
+//
+// Module global variables
+//
+EFI_SMM_BASE_PROTOCOL *mSmmBase;
+EFI_SMM_SYSTEM_TABLE *mSmst;
+EFI_HANDLE mDriverImageHandle;
+EFI_SMM_ICHN_DISPATCH_PROTOCOL *mIchnDispatch;
+EFI_SMM_ICHN_DISPATCH_CONTEXT mIchnContext;
+EFI_HANDLE mIchnHandle;
+UINT32 mPchRootComplexBar;
+
+IO_TRAP_INSTANCE mIoTrapData;
+IO_TRAP_RECORD *mIoTrapRecord;
+
+static CONST UINT16 mLengthTable[7] = { 4, 8, 16, 32, 64, 128, 256 };
+
+/**
+ Register a new IO Trap SMI dispatch function with a parent SMM driver.
+ The caller will provide information about the IO trap characteristics via
+ the context. This includes base address, length, read vs. r/w, etc.
+ This function will autoallocate IO base address from a common pool if the base address is 0,
+ and the RegisterContext Address field will be updated.
+ The service will not perform GCD allocation if the base address is non-zero.
+ In this case, the caller is responsible for the existence and allocation of the
+ specific IO range.
+ This function looks for the suitable handler and Register a new IchnIoTrap handler
+ if the IO Trap handler is not used. It also enable the IO Trap Range to generate
+ SMI.
+
+ @param[in] This Pointer to the EFI_SMM_IO_TRAP_DISPATCH_PROTOCOL instance.
+ @param[in] DispatchFunction Pointer to dispatch function to be invoked for
+ this SMI source.
+ @param[in, out] RegisterContext Pointer to the dispatch function's context.
+ The caller fills this context in before calling
+ the register function to indicate to the register
+ function the IO trap SMI source for which the dispatch
+ function should be invoked. This may not be NULL.
+ @param[out] DispatchHandle Handle of dispatch function, for when interfacing
+ with the parent SMM driver, will be the address of linked
+ list link in the call back record. This may not be NULL.
+
+ @retval EFI_SUCCESS The dispatch function has been successfully
+ registered and the SMI source has been enabled.
+ @retval EFI_DEVICE_ERROR The driver was unable to enable the SMI source.
+ @retval EFI_OUT_OF_RESOURCES Insufficient resources are available
+ @retval EFI_INVALID_PARAMETER Address requested is already in use.
+**/
+static
+EFI_STATUS
+EFIAPI
+IoTrapRegister (
+ IN EFI_SMM_IO_TRAP_DISPATCH_PROTOCOL *This,
+ IN EFI_SMM_IO_TRAP_DISPATCH_CALLBACK DispatchFunction,
+ IN OUT EFI_SMM_IO_TRAP_DISPATCH_REGISTER_CONTEXT *RegisterContext,
+ OUT EFI_HANDLE *DispatchHandle
+ )
+{
+ EFI_STATUS Status;
+ static CONST UINT16 IoTrapHandlerList[IO_TRAP_HANDLER_NUM] = { IchnIoTrap0, IchnIoTrap1, IchnIoTrap2, IchnIoTrap3 };
+ EFI_PHYSICAL_ADDRESS NextBaseAddress;
+ UINT32 NextUsedLength;
+ UINT8 NextTrapHandlerNum;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT32 UsedLength;
+ UINT8 TrapHandlerNum;
+ UINT32 IoTrapRegLowDword;
+ UINT32 IoTrapRegHighDword;
+ UINT8 LengthIndex;
+
+ //
+ // Return error if the type is invalid
+ //
+ if (RegisterContext->Type >= IoTrapTypeMaximum) {
+ DEBUG ((EFI_D_ERROR, "The Dispatch Type %0X is invalid! \n", RegisterContext->Type));
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Return error if the Length is invalid
+ //
+ if (RegisterContext->Length < 1 || RegisterContext->Length > 0x100) {
+ DEBUG ((EFI_D_ERROR, "The Dispatch Length %0X is invalid! \n", RegisterContext->Length));
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Return error if the address is invalid
+ //
+ if (RegisterContext->Address % 4 != 0) {
+ DEBUG ((EFI_D_ERROR, "The Dispatch address %0X is invalid! \n", RegisterContext->Address));
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Loop through the first IO Trap handler, looking for the suitable handler
+ //
+ for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; TrapHandlerNum++) {
+ //
+ // Get information from Io Trap handler register
+ //
+ IoTrapRegLowDword = MmioRead32 (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8);
+
+ //
+ // Check if the IO Trap handler is not used
+ //
+ if ((IoTrapRegLowDword & B_PCH_RCRB_IO_TRAP_IOAD) == 0) {
+ //
+ // Search available IO address and allocate it if the IO address is 0
+ //
+ BaseAddress = RegisterContext->Address;
+ if (BaseAddress == 0) {
+ //
+ // Allocate 256 byte range from GCD for common pool usage
+ //
+ Status = gDS->AllocateIoSpace (
+ EfiGcdAllocateAnySearchBottomUp,
+ EfiGcdIoTypeIo,
+ 8,
+ 0x100,
+ &BaseAddress,
+ mDriverImageHandle,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Can't find any available IO address! \n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ RegisterContext->Address = (UINT16) BaseAddress;
+ UsedLength = 0x100;
+ mIoTrapData.TrapUsedLength[TrapHandlerNum] = RegisterContext->Length;
+ } else {
+ //
+ // PCH only support dword * power of 2 alignment
+ //
+ for (LengthIndex = 0; LengthIndex < sizeof (mLengthTable) / sizeof (UINT16); LengthIndex++) {
+ if (RegisterContext->Length == mLengthTable[LengthIndex]) {
+ break;
+ }
+ }
+ //
+ // Return error if the alignment is not dword * power of 2
+ //
+ if (LengthIndex >= sizeof (mLengthTable) / sizeof (UINT16)) {
+ DEBUG ((EFI_D_ERROR, "The PCH only support dword * power of 2 alignment! \n"));
+ DEBUG ((EFI_D_ERROR, "The Dispatch Length %0X is 0 or invalid! \n", RegisterContext->Length));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UsedLength = RegisterContext->Length;
+ }
+
+ //
+ // Register a new IchnIoTrap handler
+ //
+ mIchnContext.Type = IoTrapHandlerList[TrapHandlerNum];
+ mIchnHandle = NULL;
+ Status = mIchnDispatch->Register (
+ mIchnDispatch,
+ IoTrapCallback,
+ &mIchnContext,
+ &mIchnHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ mIoTrapData.IchnIoTrapHandle[TrapHandlerNum] = mIchnHandle;
+ //
+ // Fill in the Length, address and Enable the IO Trap SMI
+ //
+ IoTrapRegLowDword = (UINT32) (((UsedLength - 1) & ~(BIT1 + BIT0)) << 16) |
+ (UINT16) BaseAddress |
+ B_PCH_RCRB_IO_TRAP_TRSE;
+
+ MmioWrite32 (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8,
+ (UINT32) (IoTrapRegLowDword)
+ );
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINT64) (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8),
+ 1,
+ &IoTrapRegLowDword
+ );
+
+ IoTrapRegHighDword = 0x000000F0 | (UINT32) (RegisterContext->Type << N_PCH_RCRB_IO_TRAP_RWIO);
+ MmioWrite32 (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8 + 4,
+ (UINT32) (IoTrapRegHighDword)
+ );
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINT64) (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8 + 4),
+ 1,
+ &IoTrapRegHighDword
+ );
+
+ //
+ // Set MergeDisable flag of the registered IoTrap
+ //
+ mIoTrapData.MergeDisable[TrapHandlerNum] = RegisterContext->MergeDisable;
+ } else {
+ //
+ // Check next handler if MergeDisable is TRUE or the registered IoTrap if MergeDisable is TRUE
+ //
+ if ((RegisterContext->MergeDisable == TRUE) || (mIoTrapData.MergeDisable[TrapHandlerNum] == TRUE)) {
+ continue;
+ }
+ //
+ // The IO Trap handler is used, calculate the Length
+ //
+ UsedLength = ((IoTrapRegLowDword >> 16) & 0xFC) + 4;
+ BaseAddress = IoTrapRegLowDword & B_PCH_RCRB_IO_TRAP_IOAD;
+ //
+ // Assign an addfress from common pool if the caller's address is 0
+ //
+ if (RegisterContext->Address == 0) {
+ //
+ // Check next handler if it's fully used
+ //
+ if (mIoTrapData.TrapUsedLength[TrapHandlerNum] >= 0x100) {
+ continue;
+ }
+ //
+ // Check next handler if it's not for a common pool
+ //
+ if (UsedLength < 0x100) {
+ continue;
+ }
+ //
+ // Check next handler if the size is too big
+ //
+ if (RegisterContext->Length >= (UINT16) 0x100 - mIoTrapData.TrapUsedLength[TrapHandlerNum]) {
+ continue;
+ }
+ //
+ // For common pool, we don't need to change the BaseAddress and UsedLength
+ //
+ RegisterContext->Address = (UINT16) (BaseAddress + mIoTrapData.TrapUsedLength[TrapHandlerNum]);
+ mIoTrapData.TrapUsedLength[TrapHandlerNum] += RegisterContext->Length;
+ } else {
+ //
+ // Check next handler if the address is smaller than the IO trap handler's start address
+ //
+ if (RegisterContext->Address < (UINT16) BaseAddress) {
+ continue;
+ }
+ //
+ // Check next handler if the max address is bigger than IO trap handler's range
+ //
+ if ((RegisterContext->Address + RegisterContext->Length) > (UINT16) (BaseAddress + 256)) {
+ continue;
+ }
+ //
+ // If this handler is used for common pool, assert if the caller's address is within the range
+ //
+ if (mIoTrapData.TrapUsedLength[TrapHandlerNum] != 0) {
+ DEBUG ((EFI_D_ERROR, "The Dispatch address %0x is used for common pool! \n", RegisterContext->Address));
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Calculate the Length which is maximum use address - start address
+ //
+ UsedLength = RegisterContext->Address + RegisterContext->Length - (UINT16) BaseAddress;
+ //
+ // Check the alignment is dword * power of 2 or not
+ //
+ for (LengthIndex = 0; LengthIndex < sizeof (mLengthTable) / sizeof (UINT16); LengthIndex++) {
+ if (UsedLength == mLengthTable[LengthIndex]) {
+ break;
+ }
+ }
+ //
+ // Check next handler if the alignment is not dword * power of 2
+ //
+ if (LengthIndex >= sizeof (mLengthTable) / sizeof (UINT16)) {
+ continue;
+ }
+ //
+ // Merge the overlap range: remove next Io Trap handler if next Io Trap handler's range is within this handler's range
+ //
+ for (NextTrapHandlerNum = TrapHandlerNum + 1; NextTrapHandlerNum != TrapHandlerNum; NextTrapHandlerNum++) {
+ //
+ // Check if NextTrapHandlerNum overflow
+ //
+ if (NextTrapHandlerNum >= IO_TRAP_HANDLER_NUM) {
+ NextTrapHandlerNum = 0;
+ }
+ //
+ // Get information from Io Trap handler register
+ //
+ IoTrapRegLowDword = MmioRead32 (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + NextTrapHandlerNum * 8);
+ //
+ // Check next handler if the IO Trap handler is not used
+ //
+ if ((IoTrapRegLowDword & B_PCH_RCRB_IO_TRAP_IOAD) == 0) {
+ continue;
+ }
+ //
+ // Check if next Io Trap handler's range is within this handler's range
+ //
+ NextUsedLength = ((IoTrapRegLowDword >> 16) & 0xFC) + 4;
+ NextBaseAddress = IoTrapRegLowDword & B_PCH_RCRB_IO_TRAP_IOAD;
+ if ((BaseAddress > NextBaseAddress) || ((BaseAddress + UsedLength) < (NextBaseAddress + NextUsedLength))) {
+ continue;
+ }
+ //
+ // Unregister the IO Trap handler
+ //
+ mIchnHandle = mIoTrapData.IchnIoTrapHandle[NextTrapHandlerNum];
+ mIchnContext.Type = IoTrapHandlerList[NextTrapHandlerNum];
+ Status = mIchnDispatch->UnRegister (
+ mIchnDispatch,
+ mIchnHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Clear the Io Trap handler register
+ //
+ IoTrapRegLowDword = 0;
+ IoTrapRegHighDword = 0;
+ MmioWrite32 (
+ mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + NextTrapHandlerNum * 8 + 4,
+ (UINT32) (IoTrapRegHighDword)
+ );
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINT64) (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + NextTrapHandlerNum * 8 + 4),
+ 1,
+ &IoTrapRegHighDword
+ );
+
+ MmioWrite32 (
+ mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + NextTrapHandlerNum * 8,
+ (UINT32) (IoTrapRegLowDword)
+ );
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINT64) (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + NextTrapHandlerNum * 8),
+ 1,
+ &IoTrapRegLowDword
+ );
+ }
+ //
+ // Update the Length
+ //
+ IoTrapRegLowDword = (UINT32) (((UsedLength - 1) & ~(BIT1 + BIT0)) << 16) |
+ (UINT16) BaseAddress |
+ B_PCH_RCRB_IO_TRAP_TRSE;
+ MmioWrite32 (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8,
+ (UINT32) (IoTrapRegLowDword)
+ );
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINT64) (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8),
+ 1,
+ &IoTrapRegLowDword
+ );
+ }
+ //
+ // Only set RWM bit when we need both read and write cycles.
+ //
+ IoTrapRegHighDword = MmioRead32 (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8 + 4);
+ if ((IoTrapRegHighDword & B_PCH_RCRB_IO_TRAP_RWM) == 0 &&
+ (UINT32) ((IoTrapRegHighDword & B_PCH_RCRB_IO_TRAP_RWIO) >> N_PCH_RCRB_IO_TRAP_RWIO) !=
+ (UINT32) RegisterContext->Type) {
+ IoTrapRegHighDword = ((IoTrapRegHighDword | B_PCH_RCRB_IO_TRAP_RWM) & ~B_PCH_RCRB_IO_TRAP_RWIO);
+ MmioWrite32 (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8 + 4,
+ (UINT32) (IoTrapRegHighDword)
+ );
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINT64) (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8 + 4),
+ 1,
+ &IoTrapRegHighDword
+ );
+ }
+ }
+ break;
+ }
+
+ if (TrapHandlerNum >= IO_TRAP_HANDLER_NUM) {
+ DEBUG ((EFI_D_ERROR, "All IO Trap handler is used, no available IO Trap handler! \n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Create database record and add to database
+ //
+ Status = mSmst->SmmAllocatePool (
+ EfiRuntimeServicesData,
+ sizeof (IO_TRAP_RECORD),
+ (VOID **) &mIoTrapRecord
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Failed to allocate memory for mIoTrapRecord! \n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Gather information about the registration request
+ //
+ mIoTrapRecord->Signature = IO_TRAP_RECORD_SIGNATURE;
+ mIoTrapRecord->Context = *RegisterContext;
+ mIoTrapRecord->Callback = DispatchFunction;
+
+ InsertTailList (&mIoTrapData.CallbackDataBase, &mIoTrapRecord->Link);
+
+ //
+ // Child's handle will be the address linked list link in the record
+ //
+ *DispatchHandle = (EFI_HANDLE) (&mIoTrapRecord->Link);
+
+ DEBUG ((EFI_D_INFO, "RegisterContext->Address:%x! \n", RegisterContext->Address));
+ DEBUG ((EFI_D_INFO, "RegisterContext->Length:%x! \n", RegisterContext->Length));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Unregister a child SMI source dispatch function with a parent SMM driver.
+
+ @param[in] This Pointer to the EFI_SMM_IO_TRAP_DISPATCH_PROTOCOL instance.
+ @param[in] DispatchHandle Handle of dispatch function to deregister.
+
+ @retval EFI_SUCCESS The dispatch function has been successfully
+ unregistered and the SMI source has been disabled
+ if there are no other registered child dispatch
+ functions for this SMI source.
+ @retval EFI_INVALID_PARAMETER Handle is invalid.
+**/
+EFI_STATUS
+EFIAPI
+IoTrapUnRegister (
+ IN EFI_SMM_IO_TRAP_DISPATCH_PROTOCOL *This,
+ IN EFI_HANDLE *DispatchHandle
+ )
+{
+ EFI_STATUS Status;
+ IO_TRAP_RECORD *RecordToDelete;
+ UINT32 IoTrapRegLowDword;
+ UINT32 IoTrapRegHighDword;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT32 UsedLength;
+ UINT8 TrapHandlerNum;
+ UINT8 LengthIndex;
+
+ if (*DispatchHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RecordToDelete = IO_TRAP_RECORD_FROM_LINK (*DispatchHandle);
+
+ //
+ // Take the entry out of the linked list
+ //
+ if (RecordToDelete->Link.ForwardLink == (LIST_ENTRY *) EFI_BAD_POINTER) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Loop through the first IO Trap handler, looking for the suitable handler
+ //
+ for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; TrapHandlerNum++) {
+ //
+ // Get information from Io Trap handler register
+ //
+ IoTrapRegLowDword = MmioRead32 (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8);
+
+ //
+ // Check next Io Trap handler if the IO Trap handler is not used
+ //
+ if ((IoTrapRegLowDword & B_PCH_RCRB_IO_TRAP_IOAD) == 0) {
+ continue;
+ }
+
+ UsedLength = ((IoTrapRegLowDword >> 16) & 0xFC) + 4;
+ BaseAddress = IoTrapRegLowDword & B_PCH_RCRB_IO_TRAP_IOAD;
+
+ //
+ // Check if it's the maximum address of the Io Trap handler
+ //
+ if (BaseAddress + UsedLength == RecordToDelete->Context.Address + RecordToDelete->Context.Length) {
+
+ if (BaseAddress == RecordToDelete->Context.Address) {
+ //
+ // Disable the IO Trap handler if it's the only child of the Trap handler
+ //
+ mIchnHandle = mIoTrapData.IchnIoTrapHandle[TrapHandlerNum];
+ mIchnContext.Type = IchnIoTrap0 + TrapHandlerNum;
+ Status = mIchnDispatch->UnRegister (
+ mIchnDispatch,
+ mIchnHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Clear the Io Trap handler register
+ //
+ IoTrapRegLowDword = 0;
+ IoTrapRegHighDword = 0;
+ MmioWrite32 (
+ mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8 + 4,
+ (UINT32) (IoTrapRegHighDword)
+ );
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINT64) (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8 + 4),
+ 1,
+ &IoTrapRegHighDword
+ );
+
+ } else {
+ //
+ // Calculate the new IO Trap handler Length
+ //
+ UsedLength = UsedLength - RecordToDelete->Context.Length;
+ //
+ // Check the alignment is dword * power of 2 or not
+ //
+ for (LengthIndex = 0; LengthIndex < sizeof (mLengthTable) / sizeof (UINT16); LengthIndex++) {
+ if (UsedLength == mLengthTable[LengthIndex]) {
+ break;
+ }
+ }
+ //
+ // Do not decrease the length if the alignment is not dword * power of 2
+ //
+ if (LengthIndex >= sizeof (mLengthTable) / sizeof (UINT16)) {
+ break;
+ }
+ //
+ // Decrease the length to prevent the IO trap SMI
+ //
+ IoTrapRegLowDword = (UINT32) ((((UsedLength - 1) &~(BIT1 + BIT0)) << 16) | BaseAddress | B_PCH_RCRB_IO_TRAP_TRSE);
+ }
+
+ MmioWrite32 (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8, (UINT32) (IoTrapRegLowDword));
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINT64) (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8),
+ 1,
+ &IoTrapRegLowDword
+ );
+ break;
+ }
+ }
+
+ RemoveEntryList (&RecordToDelete->Link);
+ Status = mSmst->SmmFreePool (RecordToDelete);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This I/O Trap SMI handler invokes the ACPI reference code to handle the SMI.
+ It currently assumes it owns all of the IO trap SMI.
+
+ @param[in] DispatchHandle Not used
+ @param[in] DispatchContext Not used
+
+ @retval None
+**/
+VOID
+EFIAPI
+IoTrapCallback (
+ IN EFI_HANDLE DispatchHandle,
+ IN EFI_SMM_ICHN_DISPATCH_CONTEXT *DispatchContext
+ )
+{
+ IO_TRAP_RECORD *RecordInDb;
+ LIST_ENTRY *LinkInDb;
+ EFI_SMM_IO_TRAP_DISPATCH_CALLBACK_CONTEXT CurrentIoTrapData;
+ UINT16 BaseAddress;
+ UINT16 StartAddress;
+ UINT16 EndAddress;
+
+ if (!IsListEmpty (&mIoTrapData.CallbackDataBase)) {
+ BaseAddress = MmioRead16 (mPchRootComplexBar + R_PCH_RCRB_TRCR) & B_PCH_RCRB_TRCR_TIOA;
+ StartAddress = (UINT16) ((MmioRead32 (mPchRootComplexBar + R_PCH_RCRB_TRCR) & B_PCH_RCRB_TRCR_AHBE) >> 16);
+ //
+ // StartAddress and EndAddress will be equal if it's byte access
+ //
+ EndAddress = (UINT16) (HighBitSet32 ((UINT32) (StartAddress))) + BaseAddress;
+ StartAddress = (UINT16) (LowBitSet32 ((UINT32) (StartAddress))) + BaseAddress;
+
+ CurrentIoTrapData.Type = (BOOLEAN) ((MmioRead32 (mPchRootComplexBar + R_PCH_RCRB_TRCR) & B_PCH_RCRB_TRCR_RWI) != 0);
+ CurrentIoTrapData.WriteData = MmioRead32 (mPchRootComplexBar + R_PCH_RCRB_TRWDR);
+
+ LinkInDb = GetFirstNode (&mIoTrapData.CallbackDataBase);
+
+ while (!IsNull (&mIoTrapData.CallbackDataBase, LinkInDb)) {
+ RecordInDb = IO_TRAP_RECORD_FROM_LINK (LinkInDb);
+ if ((RecordInDb->Context.Address <= StartAddress) &&
+ (RecordInDb->Context.Address + RecordInDb->Context.Length > EndAddress)) {
+ if (RecordInDb->Context.Type == ReadWriteTrap || RecordInDb->Context.Type == CurrentIoTrapData.Type) {
+ //
+ // Pass the IO trap context information
+ //
+ CurrentIoTrapData.Address = StartAddress;
+ CurrentIoTrapData.Context = RecordInDb->Context.Context;
+ RecordInDb->Callback (&RecordInDb->Link, &CurrentIoTrapData);
+ break;
+ }
+ } else {
+ LinkInDb = GetNextNode (&mIoTrapData.CallbackDataBase, &RecordInDb->Link);
+ if (IsNull (&mIoTrapData.CallbackDataBase, LinkInDb)) {
+ //
+ // An IO access was trapped that does not have a handler registered.
+ // Since this is an invalid state, we will loop here.
+ // It may be appropriate to remove this loop in production systems to avoid potential user issues.
+ // But, this indicates an error condition.
+ //
+ DEBUG_CODE (
+ EFI_DEADLOOP ();
+ );
+ }
+ }
+ }
+ }
+}
+
+/**
+ Pause IoTrap callback function.
+
+ This function disables the SMI enable of IoTrap according to the DispatchHandle,
+ which is returned by IoTrap callback registration. It only supports the DispatchHandle
+ with MergeDisable TRUE and address not zero.
+
+ @param[in] This Pointer to the PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance.
+ @param[in] DispatchHandle Handle of the child service to change state.
+
+ @retval EFI_SUCCESS This operation is complete.
+ @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid.
+ @retval EFI_ACCESS_DENIED The SMI status is alrady PAUSED.
+**/
+EFI_STATUS
+IoTrapControlPause (
+ IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL *This,
+ IN EFI_HANDLE DispatchHandle
+ )
+{
+ IO_TRAP_RECORD *IoTrapRecord;
+ UINT32 IoTrapRegLowDword;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT32 UsedLength;
+ UINT8 TrapHandlerNum;
+
+ if (DispatchHandle == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IoTrapRecord = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
+
+ if ((IoTrapRecord->Signature != IO_TRAP_RECORD_SIGNATURE) ||
+ (IoTrapRecord->Context.MergeDisable != TRUE) ||
+ (IoTrapRecord->Context.Address == 0) ||
+ (IoTrapRecord->Context.Length == 0))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; TrapHandlerNum++) {
+ //
+ // This IoTrap register should be merge disabled.
+ //
+ if (mIoTrapData.MergeDisable[TrapHandlerNum] != TRUE) {
+ continue;
+ }
+
+ IoTrapRegLowDword = MmioRead32 (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8);
+
+ UsedLength = ((IoTrapRegLowDword >> 16) & 0xFC) + 4;
+ BaseAddress = IoTrapRegLowDword & B_PCH_RCRB_IO_TRAP_IOAD;
+
+ //
+ // The address and length of record matches the IoTrap register's.
+ //
+ if ((BaseAddress == IoTrapRecord->Context.Address) &&
+ (UsedLength == IoTrapRecord->Context.Length )) {
+ //
+ // Check if status matched.
+ // If this is already Paused, return warning status.
+ //
+ if ((IoTrapRegLowDword & B_PCH_RCRB_IO_TRAP_TRSE) == 0) {
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // Clear IoTrap register SMI enable bit
+ //
+ IoTrapRegLowDword &= (~B_PCH_RCRB_IO_TRAP_TRSE);
+ MmioWrite32 (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8, (UINT32) (IoTrapRegLowDword));
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ Resume IoTrap callback function.
+
+ This function enables the SMI enable of IoTrap according to the DispatchHandle,
+ which is returned by IoTrap callback registration. It only supports the DispatchHandle
+ with MergeDisable TRUE and address not zero.
+
+ @param[in] This Pointer to the PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance.
+ @param[in] DispatchHandle Handle of the child service to change state.
+
+ @retval EFI_SUCCESS This operation is complete.
+ @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid.
+ @retval EFI_ACCESS_DENIED The SMI status is alrady RESUMED.
+**/
+EFI_STATUS
+IoTrapControlResume (
+ IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL *This,
+ IN EFI_HANDLE DispatchHandle
+ )
+{
+ IO_TRAP_RECORD *IoTrapRecord;
+ UINT32 IoTrapRegLowDword;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT32 UsedLength;
+ UINT8 TrapHandlerNum;
+
+ if (DispatchHandle == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IoTrapRecord = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
+
+ if ((IoTrapRecord->Signature != IO_TRAP_RECORD_SIGNATURE) ||
+ (IoTrapRecord->Context.MergeDisable != TRUE) ||
+ (IoTrapRecord->Context.Address == 0) ||
+ (IoTrapRecord->Context.Length == 0))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; TrapHandlerNum++) {
+ //
+ // This IoTrap register should be merge disabled.
+ //
+ if (mIoTrapData.MergeDisable[TrapHandlerNum] != TRUE) {
+ continue;
+ }
+
+ IoTrapRegLowDword = MmioRead32 (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8);
+
+ UsedLength = ((IoTrapRegLowDword >> 16) & 0xFC) + 4;
+ BaseAddress = IoTrapRegLowDword & B_PCH_RCRB_IO_TRAP_IOAD;
+
+ //
+ // The address and length of record matches the IoTrap register's.
+ //
+ if ((BaseAddress == IoTrapRecord->Context.Address) &&
+ (UsedLength == IoTrapRecord->Context.Length )) {
+ //
+ // Check if status matched.
+ // If this is already Resume, return warning status.
+ //
+ if ((IoTrapRegLowDword & B_PCH_RCRB_IO_TRAP_TRSE) != 0) {
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // Set IoTrap register SMI enable bit
+ //
+ IoTrapRegLowDword |= (B_PCH_RCRB_IO_TRAP_TRSE);
+ MmioWrite32 (mPchRootComplexBar + R_PCH_RCRB_IO_TRAP_0 + TrapHandlerNum * 8, (UINT32) (IoTrapRegLowDword));
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ IO Trap SMM driver entry point function.
+
+ @param[in] ImageHandle Image handle for this driver image
+ @param[in] SystemTable Pointer to the EFI System Table
+
+ @retval EFI_SUCCESS Driver initialization completed successfully
+**/
+EFI_STATUS
+EFIAPI
+InstallIoTrap (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Initialize the EFI SMM driver library
+ //
+ mDriverImageHandle = ImageHandle;
+
+ //
+ // Find the SMM base protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiSmmBaseProtocolGuid, NULL, (VOID **) &mSmmBase);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Initialize global variables.
+ //
+ mSmmBase->GetSmstLocation (mSmmBase, &mSmst);
+
+ //
+ // Add other initialization code
+ //
+ //
+ // PCH RCBA must be initialized prior to run this driver.
+ //
+ mPchRootComplexBar = PCH_RCRB_BASE;
+ ASSERT (mPchRootComplexBar != 0);
+
+ //
+ // Locate the ICHn Dispatch protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiSmmIchnDispatchProtocolGuid, NULL, (VOID **) &mIchnDispatch);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Locate the S3 resume scripting protocol
+ //
+ INITIALIZE_SCRIPT (ImageHandle, SystemTable);
+
+ //
+ // Initialize the IO trap protocol we produce
+ //
+ mIoTrapData.Signature = IO_TRAP_INSTANCE_SIGNATURE;
+ mIoTrapData.EfiSmmIoTrapDispatchProtocol.Register = IoTrapRegister;
+ mIoTrapData.EfiSmmIoTrapDispatchProtocol.UnRegister = IoTrapUnRegister;
+
+ //
+ // Initialize the Io trap control protocol.
+ //
+ mIoTrapData.PchSmmIoTrapControlProtocol.Pause = IoTrapControlPause;
+ mIoTrapData.PchSmmIoTrapControlProtocol.Resume = IoTrapControlResume;
+
+ //
+ // Install protocol interface
+ //
+ mIoTrapData.Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mIoTrapData.Handle,
+ &gEfiSmmIoTrapDispatchProtocolGuid,
+ &mIoTrapData.EfiSmmIoTrapDispatchProtocol,
+ &gPchSmmIoTrapControlGuid,
+ &mIoTrapData.PchSmmIoTrapControlProtocol,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Initialize IO TRAP Callback DataBase
+ //
+ InitializeListHead (&mIoTrapData.CallbackDataBase);
+
+ return EFI_SUCCESS;
+}