Almost all UEFI BIOS versions lock MSR 0xE2. Not that it matters, because we know exactly what/where to look for. Something that has helped us to patch the BIOS before and we are about to do it again. This blog article however will show you the exact UEFI source code that locks BIT 15 of MSR 0xE2 (MSR_PMG_CST_CONFIG_CONTROL). Let’s start with the PowerManagement.inf
#/*++
# 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
#--*/
#
#/*++
#
#Copyright (c) 1999 - 2010 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.
#
#Module Name:
#
# PowerManagement.inf
#
#Abstract:
#
# Component description file for Power Management module
#
#--*/
[defines]
BASE_NAME = PowerManagement2
FILE_GUID = f7731b4c-58a2-4df4-8980-5645d39ece58
COMPONENT_TYPE = RT_DRIVER
[sources.common]
PowerManagement.h
PowerManagement.c
Ppm.h
PpmInitialization.c
PpmRuntime.c
#
# Edk II Glue Driver Entry Point
#
EdkIIGlueSmmDriverEntryPoint.c
[sources.x64]
x64\ProcessorSaveStateSupport.h
x64\ProcessorSaveStateSupport.c
[includes.common]
.
$(EDK_SOURCE)\Foundation
$(EDK_SOURCE)\Foundation\Include
$(EDK_SOURCE)\Foundation\Efi
$(EDK_SOURCE)\Foundation\Efi\Include
$(EDK_SOURCE)\Foundation\Framework
$(EDK_SOURCE)\Foundation\Framework\Include
$(EDK_SOURCE)\Foundation\Include\IndustryStandard
$(EDK_SOURCE)\Foundation\Library\Dxe\Include
$(EFI_SOURCE)
$(EFI_SOURCE)\Include
$(EFI_SOURCE)\Include\IndustryStandard
$(EFI_SOURCE)\Platform\$(PROJECT_FAMILY)\Common
$(EFI_SOURCE)\Platform\$(PROJECT_FAMILY)\Common\Include
$(EFI_SOURCE)\$(PROJECT_PPM_ROOT)
$(EFI_SOURCE)\$(PROJECT_PPM_ROOT)\Include
$(EFI_SOURCE)\$(PROJECT_PPM_ROOT)\Library\SandyBridgePpm\Smm
$(EFI_SOURCE)\$(PROJECT_PCH_ROOT)\Include
$(EFI_SOURCE)\$(PROJECT_PCH_ROOT)\Include\Library
$(EFI_SOURCE)\$(PROJECT_PCH_ROOT)
#
# Typically the sample code referenced will be available in the code base already
# So keep this include at the end to defer to the source base definition
# and only use the sample code definition if source base does not include these files.
#
$(EFI_SOURCE)\$(PROJECT_PPM_ROOT)\SampleCode\Include
$(EFI_SOURCE)\$(PROJECT_PPM_ROOT)\SampleCode
#
# Edk II Glue Library, some hearder are included by R9 header so have to include
#
$(EFI_SOURCE)
$(EFI_SOURCE)\Framework
$(EDK_SOURCE)\Foundation
$(EDK_SOURCE)\Foundation\Framework
$(EDK_SOURCE)\Foundation\Include\IndustryStandard
$(EDK_SOURCE)\Foundation\Core\Dxe
$(EDK_SOURCE)\Foundation\Include\Pei
$(EDK_SOURCE)\Foundation\Library\Dxe\Include
$(EDK_SOURCE)\Foundation\Library\EdkIIGlueLib\Include
[libraries.common]
PowerManagementGuidLib
PowerManagementProtocolLib
SandyBridgePpmLib
DxeAslUpdateLib
EfiProtocolLib
EdkFrameworkProtocolLib
EdkIIGlueBaseLib
EdkIIGlueBaseIoLibIntrinsic
EdkIIGlueBaseMemoryLib
EdkIIGlueDxeMemoryAllocationLib
EdkIIGlueDxeDebugLibReportStatusCode
EdkIIGlueSmmRuntimeDxeReportStatusCodeLib
EdkIIGlueUefiBootServicesTableLib
EdkIIGlueUefiDevicePathLib
EfiScriptLib
EdkProtocolLib
[libraries.ia32,libraries.x64]
CpuIa32Lib
[nmake.common]
IMAGE_ENTRY_POINT = _ModuleEntryPoint
DPX_SOURCE = $(PROCESSOR)\PowerManagement.dxs
#
# Module Entry Point
#
C_FLAGS = $(C_FLAGS) /D__EDKII_GLUE_MODULE_ENTRY_POINT__=InitializePowerManagement
C_FLAGS = $(C_FLAGS) /D __EDKII_GLUE_BASE_LIB__ \
/D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \
/D __EDKII_GLUE_BASE_MEMORY_LIB__ \
/D __EDKII_GLUE_DXE_MEMORY_ALLOCATION_LIB__ \
/D __EDKII_GLUE_DXE_DEBUG_LIB_REPORT_STATUS_CODE__ \
/D __EDKII_GLUE_SMM_RUNTIME_DXE_REPORT_STATUS_CODE_LIB__ \
/D __EDKII_GLUE_UEFI_BOOT_SERVICES_TABLE_LIB__ \
/D __EDKII_GLUE_UEFI_DEVICE_PATH_LIB__
This gives us the target GUID of the Power Management module aka F7731B4C-58A2-4DF4-8980-5645D39ECE58 which is also used for the filename in the iMac13,N EFI.
For example:
F7731B4C-58A2-4DF4-8980-5645D39ECE58_0_164.ROM
F7731B4C-58A2-4DF4-8980-5645D39ECE58_0_170.ROM
This should help you to locate the PM module. Next up. The actual locking code:
//
//---------------------------------------------------------------------------
//
// Procedure: DoCstateProgramming
//
// Description: Program C-state registers.
//
// Input:
// IN VOID *SetupHandle
//
// Output: VOID
//
//---------------------------------------------------------------------------
//
VOID DoCstateProgramming(IN VOID *SetupHandle)
{
UINT32 CpuSignature = GetCpuSignature();
UINT32 CpuSigNoVer = CpuSignature & 0xfffffff0;
UINT8 CpuSigVer = CpuSignature & 0xf;
BOOLEAN IsSandyBridge = CpuSigNoVer == SANDY_BRIDGE || CpuSigNoVer == JAKETOWN || CpuSigNoVer == IVY_BRIDGE || CpuSigNoVer == HASWELL;
UINT8 CstRange;
UINT8 PkgCstLimitProg;
UINT32 PmgCstConfCntr;
UINT32 RegEax, RegEbx, RegEcx, RegEdx;
CPULib_CpuID(5, &RegEax, &RegEbx, &RegEcx, &RegEdx);
//Check if C1E is available.
if ((RegEdx & C1_SUB_STATES_MASK) > 0x10) { //bits [7:4] are for C1
//Enable C1E [1]
ReadWriteMsr(MSR_POWER_CTL, BIT1, (UINT64)-1); //0x1fc
}
if (IsSandyBridge) {
ReadWriteMsr(MSR_PKGC3_IRTL, 0x50 + (2 << 10) + BIT15, (UINT64)0xffffffffffffe00);
ReadWriteMsr(MSR_PKGC6_IRTL, 0x68 + (2 << 10) + BIT15, (UINT64)0xffffffffffffe00);
ReadWriteMsr(MSR_PKGC7_IRTL, 0x6d + (2 < 4 || CpuSigNoVer == JAKETOWN) {
//Enable C1 and C3 Un-demotion and lock.
PmgCstConfCntr |= BIT28 + BIT27 + BIT15;
}
} else {
PmgCstConfCntr |= BIT15; //Lock CFG
}
// Program IO-redirect as well as Package C State Limit
ReadWriteMsr(MSR_PMG_CST_CONFIG_CONTROL, PmgCstConfCntr, (UINT64)-8);
if(RegEdx & C7_SUB_STATES_MASK) CstRange = 2;
else if (RegEdx & C6_SUB_STATES_MASK) CstRange = 1;
else CstRange = 0;
WriteMsr(MSR_PMG_IO_CAPTURE_ADDR, (CstRange << 16) + PM_BASE_ADDRESS + 0x14); //0xe4 - C State IO Capture Base Address.
}
That is it. Nothing more to see. Problem located and ready to get patched!
Note: Intel® Corporation (legal) representatives are kindly asked to contact me per e-mail for the express written consent to publish this – to prevent DMCA take down notices.