/** @file
|
PCH Port 61h bit-4 toggling in SMM IO Trap
|
|
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
|
#include "PchInitSmm.h"
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_CPU_PROTOCOL *mSmmCpu; ///< To read and write save state
|
GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE mPchIoTrapHandle; ///< Pause and resume via EFI_HANDLE
|
GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_IO_TRAP_CONTROL_PROTOCOL *mPchSmmIoTrapControl; ///< To pause and resume IO trap
|
GLOBAL_REMOVE_IF_UNREFERENCED UINTN mInternalState = 0; ///< To store the toggle value for each CPU threads
|
|
/**
|
This SMI handle will pause the IO trap in the beginning
|
|
@param[in] DispatchHandle - The handle of this callback, obtained when registering
|
@param[in] DispatchContext - Pointer to the EFI_SMM_IO_TRAP_DISPATCH_CALLBACK_CONTEXT
|
|
@retval None
|
**/
|
VOID
|
PchIoTrapPort61hSmiCallback (
|
IN EFI_HANDLE DispatchHandle,
|
IN CONST VOID *CallbackContext,
|
IN OUT VOID *CommBuffer,
|
IN OUT UINTN *CommBufferSize
|
)
|
{
|
EFI_STATUS Status;
|
UINTN CpuIndex;
|
UINTN Mask;
|
UINT8 ReadValue, WriteValue;
|
EFI_SMM_SAVE_STATE_IO_INFO IoInfo;
|
//
|
// Disabling the IO Trap, prevent SMI re-enter because of reading port 61h in handler itself
|
//
|
Status = mPchSmmIoTrapControl->Pause (
|
mPchSmmIoTrapControl,
|
mPchIoTrapHandle
|
);
|
ASSERT_EFI_ERROR (Status);
|
|
//
|
// Detects the CPU which causes the IO Trap
|
//
|
for (CpuIndex = 0; CpuIndex < gSmst->NumberOfCpus; CpuIndex++) {
|
Status = mSmmCpu->ReadSaveState (
|
mSmmCpu,
|
sizeof (EFI_SMM_SAVE_STATE_IO_INFO),
|
EFI_SMM_SAVE_STATE_REGISTER_IO,
|
CpuIndex,
|
&IoInfo
|
);
|
if (Status == EFI_SUCCESS) {
|
//
|
// Make sure the IO trap is byte read, port input only, and it is port 0x61
|
//
|
if ((IoInfo.IoWidth == EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8) &&
|
(IoInfo.IoType == EFI_SMM_SAVE_STATE_IO_TYPE_INPUT) &&
|
(IoInfo.IoPort == 0x61)) {
|
//
|
// Read from Port 61h, toggle bit4 based on the internal state
|
//
|
ReadValue = IoRead8 (0x61);
|
Mask = (UINTN) (1 << CpuIndex);
|
mInternalState ^= Mask;
|
WriteValue = (mInternalState & Mask) ? (ReadValue | 0x10) : (ReadValue & ~0x10);
|
Status = mSmmCpu->WriteSaveState (
|
mSmmCpu,
|
sizeof (UINT8),
|
EFI_SMM_SAVE_STATE_REGISTER_RAX,
|
CpuIndex,
|
&WriteValue
|
);
|
ASSERT_EFI_ERROR (Status);
|
} //if the iotrap is the one we want
|
} //if iotrap happens for this thread
|
} //for (iterate for all threads)
|
|
//
|
// Resume the IO Trap
|
// Port 61h bit-4 emulation will be disabled after exit boot service
|
// The disabling mechanism is actually to not resume the trap.
|
// This means, even after exit boot service, this handler will be called once
|
// before it is disabled
|
//
|
if (mPchNvsArea->ExitBootServicesFlag == 0) {
|
Status = mPchSmmIoTrapControl->Resume (
|
mPchSmmIoTrapControl,
|
mPchIoTrapHandle
|
);
|
ASSERT_EFI_ERROR (Status);
|
} else {
|
DEBUG ((DEBUG_INFO, "Port61H trap has been disabled. \n"));
|
}
|
}
|
|
|
/**
|
Locate required protocol and register the IO trap in this entry point
|
|
@param[in] ImageHandle - Handle for the image of this driver
|
@param[in] SystemTable - Pointer to the EFI System Table
|
|
@retval EFI_SUCCESS - PCH SMM handler was installed
|
**/
|
EFI_STATUS
|
EFIAPI
|
InstallIoTrapPort61h (
|
IN EFI_HANDLE ImageHandle,
|
IN EFI_SYSTEM_TABLE *SystemTable
|
)
|
{
|
EFI_STATUS Status;
|
EFI_SMM_IO_TRAP_REGISTER_CONTEXT PchIoTrapContext;
|
|
DEBUG ((DEBUG_INFO, "InstallIoTrapPort61h()\n"));
|
|
if (mPchConfigHob->Port61hSmm.Enable == 0) {
|
return EFI_SUCCESS;
|
}
|
|
//
|
// Locate the protocol to read and write save state
|
//
|
Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **) &mSmmCpu);
|
ASSERT_EFI_ERROR (Status);
|
|
//
|
// Locate the protocol for pause and resume
|
//
|
Status = gSmst->SmmLocateProtocol (&gPchSmmIoTrapControlGuid, NULL, (VOID **) &mPchSmmIoTrapControl);
|
ASSERT_EFI_ERROR (Status);
|
|
//
|
// Configure trap type, in ECP, MergeDisable should be TRUE for pause and resume to work
|
//
|
PchIoTrapContext.Type = ReadTrap;
|
PchIoTrapContext.Length = 1;
|
PchIoTrapContext.Address = 0x61;
|
Status = mPchIoTrap->Register (
|
mPchIoTrap,
|
(EFI_SMM_HANDLER_ENTRY_POINT2) PchIoTrapPort61hSmiCallback,
|
&PchIoTrapContext,
|
&mPchIoTrapHandle
|
);
|
ASSERT_EFI_ERROR (Status);
|
|
return EFI_SUCCESS;
|
}
|