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.
That’s exciting, not that I understand the contents, but definetly the meaning of that. I’m glad you’re almost there!
Flashing might still be a bit problematic, but it means that PMPatch (CodeRush) can be used with a minor tweak.
Well, l’m not a coder/programmer but I did a lot of reading and research. Tracing the code I “believe” this is the start of check for Cstates./Lock MSR_e2
405: b9 e2 00 00 00 mov $0xe2,%ecx //move state of MSR_e2 >%ecx
40a: 48 dec %eax
40b: 8b 10 mov (%eax),%edx
40d: 8b 7a 09 mov 0x9(%edx),%edi
410: 8b df mov %edi,%ebx
412: 83 e7 0f and $0xf,%edi
415: 81 e3 f0 0f ff 0f and $0xfff0ff0,%ebx
41b: f6 42 01 7a testb $0x7a,0x1(%edx) //bits [7:4] are for C1 //Enable C1E [1]
41f: 75 19 jne 0x43a //checks flags if not Equal or 0x01jump?
We want this to happen no matter what??
So my question is: Am I on the right track? If not I’ll look deeper. There are only 2 other places where MSR_e2 is checked. But I believe this to be the JMP that need to be non conditional.
Don’t bother looking into this problem. The MSR 0xE2 is under control already. We also have a tool to patch BIOS files. The only problem left to solve is to flash a mod BIOS file, which certain motherboards reject with a security violation error.
Pingback: Setting up MSI Z97i-AC motherboard (for running OS X) | mackonsti