├── .github └── workflows │ └── main.yml ├── .gitignore ├── CPUFriend.xcodeproj └── project.pbxproj ├── CPUFriend ├── CPUFriend.cpp ├── CPUFriend.hpp ├── Info.plist └── kern_start.cpp ├── Changelog.md ├── Instructions.md ├── LICENSE ├── README.md └── Tools ├── FrequencyVectors.bt ├── FrequencyVectors.tcl └── ResourceConverter.sh /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | release: 8 | types: [published] 9 | 10 | env: 11 | PROJECT_TYPE: KEXT 12 | 13 | jobs: 14 | build: 15 | name: Build 16 | runs-on: macos-latest 17 | env: 18 | JOB_TYPE: BUILD 19 | steps: 20 | - uses: actions/checkout@v4 21 | - uses: actions/checkout@v4 22 | with: 23 | repository: acidanthera/MacKernelSDK 24 | path: MacKernelSDK 25 | - name: CI Bootstrap 26 | run: | 27 | src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/ocbuild/master/ci-bootstrap.sh) && eval "$src" || exit 1 28 | - name: Lilu Bootstrap 29 | run: | 30 | src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/Lilu/master/Lilu/Scripts/bootstrap.sh) && eval "$src" || exit 1 31 | 32 | - run: xcodebuild -jobs 1 -configuration Debug 33 | - run: xcodebuild -jobs 1 -configuration Release 34 | 35 | - name: Upload to Artifacts 36 | uses: actions/upload-artifact@v4 37 | with: 38 | name: Artifacts 39 | path: build/*/*.zip 40 | - name: Upload to Release 41 | if: github.event_name == 'release' 42 | uses: svenstaro/upload-release-action@v2 43 | with: 44 | repo_token: ${{ secrets.GITHUB_TOKEN }} 45 | file: build/*/*.zip 46 | tag: ${{ github.ref }} 47 | file_glob: true 48 | 49 | analyze-clang: 50 | name: Analyze Clang 51 | runs-on: macos-latest 52 | env: 53 | JOB_TYPE: ANALYZE 54 | steps: 55 | - uses: actions/checkout@v4 56 | - uses: actions/checkout@v4 57 | with: 58 | repository: acidanthera/MacKernelSDK 59 | path: MacKernelSDK 60 | - name: CI Bootstrap 61 | run: | 62 | src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/ocbuild/master/ci-bootstrap.sh) && eval "$src" || exit 1 63 | - name: Lilu Bootstrap 64 | run: | 65 | src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/Lilu/master/Lilu/Scripts/bootstrap.sh) && eval "$src" || exit 1 66 | 67 | - run: xcodebuild analyze -quiet -scheme CPUFriend -configuration Debug CLANG_ANALYZER_OUTPUT=plist-html CLANG_ANALYZER_OUTPUT_DIR="$(pwd)/clang-analyze" && [ "$(find clang-analyze -name "*.html")" = "" ] 68 | - run: xcodebuild analyze -quiet -scheme CPUFriend -configuration Release CLANG_ANALYZER_OUTPUT=plist-html CLANG_ANALYZER_OUTPUT_DIR="$(pwd)/clang-analyze" && [ "$(find clang-analyze -name "*.html")" = "" ] 69 | 70 | analyze-coverity: 71 | name: Analyze Coverity 72 | runs-on: macos-latest 73 | env: 74 | JOB_TYPE: COVERITY 75 | if: github.repository_owner == 'acidanthera' && github.event_name != 'pull_request' 76 | steps: 77 | - uses: actions/checkout@v4 78 | - uses: actions/checkout@v4 79 | with: 80 | repository: acidanthera/MacKernelSDK 81 | path: MacKernelSDK 82 | - name: CI Bootstrap 83 | run: | 84 | src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/ocbuild/master/ci-bootstrap.sh) && eval "$src" || exit 1 85 | - name: Lilu Bootstrap 86 | run: | 87 | src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/Lilu/master/Lilu/Scripts/bootstrap.sh) && eval "$src" || exit 1 88 | 89 | - name: Run Coverity 90 | run: | 91 | src=$(/usr/bin/curl -Lfs https://raw.githubusercontent.com/acidanthera/ocbuild/master/coverity/covstrap.sh) && eval "$src" || exit 1 92 | env: 93 | COVERITY_SCAN_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} 94 | COVERITY_SCAN_EMAIL: ${{ secrets.COVERITY_SCAN_EMAIL }} 95 | COVERITY_BUILD_COMMAND: xcodebuild -configuration Release 96 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Other 35 | .DS_Store 36 | 37 | CPUFriend.xcodeproj/xcuserdata 38 | CPUFriend.xcodeproj/project.xcworkspace/xcuserdata 39 | CPUFriend/.DS_Store 40 | xcuserdata 41 | xcshareddata 42 | project.xcworkspace 43 | 44 | Lilu.kext 45 | DerivedData 46 | /MacKernelSDK 47 | build 48 | -------------------------------------------------------------------------------- /CPUFriend.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1C748C2D1C21952C0024EED2 /* kern_start.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C748C2C1C21952C0024EED2 /* kern_start.cpp */; }; 11 | CE405ED91E4A080700AA0B3D /* plugin_start.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE405ED81E4A080700AA0B3D /* plugin_start.cpp */; }; 12 | CE8DA0BF2517DD4A008C44E8 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8DA0BE2517DD4A008C44E8 /* libkmod.a */; }; 13 | CEBD8C191F372A4600BBCB85 /* CPUFriend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEBD8C171F372A4600BBCB85 /* CPUFriend.cpp */; }; 14 | CEBD8C1A1F372A4600BBCB85 /* CPUFriend.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CEBD8C181F372A4600BBCB85 /* CPUFriend.hpp */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | 1C748C271C21952C0024EED2 /* CPUFriend.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CPUFriend.kext; sourceTree = BUILT_PRODUCTS_DIR; }; 19 | 1C748C2C1C21952C0024EED2 /* kern_start.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = kern_start.cpp; sourceTree = ""; }; 20 | 1C748C2E1C21952C0024EED2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 21 | 1CF01C901C8CF97F002DCEA3 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 22 | 1CF01C921C8CF997002DCEA3 /* Changelog.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Changelog.md; sourceTree = ""; }; 23 | 1CF01C931C8DF02E002DCEA3 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 24 | 83023F381F3747EC00850499 /* Instructions.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Instructions.md; sourceTree = ""; }; 25 | CE405EBA1E49DD7100AA0B3D /* kern_compression.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_compression.hpp; sourceTree = ""; }; 26 | CE405EBB1E49DD7100AA0B3D /* kern_disasm.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_disasm.hpp; sourceTree = ""; }; 27 | CE405EBC1E49DD7100AA0B3D /* kern_file.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_file.hpp; sourceTree = ""; }; 28 | CE405EBD1E49DD7100AA0B3D /* kern_iokit.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_iokit.hpp; sourceTree = ""; }; 29 | CE405EBE1E49DD7100AA0B3D /* kern_mach.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_mach.hpp; sourceTree = ""; }; 30 | CE405EBF1E49DD7100AA0B3D /* kern_patcher.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_patcher.hpp; sourceTree = ""; }; 31 | CE405EC01E49DD7100AA0B3D /* kern_policy.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_policy.hpp; sourceTree = ""; }; 32 | CE405EC31E49DD7100AA0B3D /* kern_user.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_user.hpp; sourceTree = ""; }; 33 | CE405EC41E49DD7100AA0B3D /* kern_util.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_util.hpp; sourceTree = ""; }; 34 | CE405EC61E49DD7100AA0B3D /* LegacyIOService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LegacyIOService.h; sourceTree = ""; }; 35 | CE405EC71E49DD7100AA0B3D /* libkmod.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libkmod.a; sourceTree = ""; }; 36 | CE405ECF1E49EC9100AA0B3D /* kern_config.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = kern_config.hpp; sourceTree = ""; }; 37 | CE405ED21E49F9FC00AA0B3D /* kern_api.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_api.hpp; sourceTree = ""; }; 38 | CE405ED81E4A080700AA0B3D /* plugin_start.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = plugin_start.cpp; sourceTree = ""; }; 39 | CE405EDA1E4A080F00AA0B3D /* plugin_start.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = plugin_start.hpp; sourceTree = ""; }; 40 | CE8DA0BE2517DD4A008C44E8 /* libkmod.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libkmod.a; path = ../Lilu/MacKernelSDK/Library/x86_64/libkmod.a; sourceTree = ""; }; 41 | CEBD8C171F372A4600BBCB85 /* CPUFriend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CPUFriend.cpp; sourceTree = ""; }; 42 | CEBD8C181F372A4600BBCB85 /* CPUFriend.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CPUFriend.hpp; sourceTree = ""; }; 43 | CEDF9CEF27F4B68A0030425C /* FrequencyVectors.tcl */ = {isa = PBXFileReference; lastKnownFileType = text; path = FrequencyVectors.tcl; sourceTree = ""; }; 44 | CEDF9CF027F4B68A0030425C /* FrequencyVectors.bt */ = {isa = PBXFileReference; lastKnownFileType = text; path = FrequencyVectors.bt; sourceTree = ""; }; 45 | CEDF9CF127F4B68A0030425C /* ResourceConverter.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = ResourceConverter.sh; sourceTree = ""; }; 46 | /* End PBXFileReference section */ 47 | 48 | /* Begin PBXFrameworksBuildPhase section */ 49 | 1C748C231C21952C0024EED2 /* Frameworks */ = { 50 | isa = PBXFrameworksBuildPhase; 51 | buildActionMask = 2147483647; 52 | files = ( 53 | CE8DA0BF2517DD4A008C44E8 /* libkmod.a in Frameworks */, 54 | ); 55 | runOnlyForDeploymentPostprocessing = 0; 56 | }; 57 | /* End PBXFrameworksBuildPhase section */ 58 | 59 | /* Begin PBXGroup section */ 60 | 1C748C1D1C21952C0024EED2 = { 61 | isa = PBXGroup; 62 | children = ( 63 | CE405EC81E49DD7B00AA0B3D /* SDK */, 64 | 1CF01C911C8CF982002DCEA3 /* Docs */, 65 | CEDF9CEE27F4B68A0030425C /* Tools */, 66 | 1C748C291C21952C0024EED2 /* CPUFriend */, 67 | 1C748C281C21952C0024EED2 /* Products */, 68 | CE8DA0BD2517DD4A008C44E8 /* Frameworks */, 69 | ); 70 | sourceTree = ""; 71 | }; 72 | 1C748C281C21952C0024EED2 /* Products */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | 1C748C271C21952C0024EED2 /* CPUFriend.kext */, 76 | ); 77 | name = Products; 78 | sourceTree = ""; 79 | }; 80 | 1C748C291C21952C0024EED2 /* CPUFriend */ = { 81 | isa = PBXGroup; 82 | children = ( 83 | CEBD8C181F372A4600BBCB85 /* CPUFriend.hpp */, 84 | CEBD8C171F372A4600BBCB85 /* CPUFriend.cpp */, 85 | 1C748C2C1C21952C0024EED2 /* kern_start.cpp */, 86 | 1C748C2E1C21952C0024EED2 /* Info.plist */, 87 | ); 88 | path = CPUFriend; 89 | sourceTree = ""; 90 | }; 91 | 1CF01C911C8CF982002DCEA3 /* Docs */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 1CF01C931C8DF02E002DCEA3 /* LICENSE */, 95 | 1CF01C921C8CF997002DCEA3 /* Changelog.md */, 96 | 83023F381F3747EC00850499 /* Instructions.md */, 97 | 1CF01C901C8CF97F002DCEA3 /* README.md */, 98 | ); 99 | name = Docs; 100 | sourceTree = ""; 101 | }; 102 | CE405EB91E49DD7100AA0B3D /* Headers */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | CE405ED21E49F9FC00AA0B3D /* kern_api.hpp */, 106 | CE405ECF1E49EC9100AA0B3D /* kern_config.hpp */, 107 | CE405EBA1E49DD7100AA0B3D /* kern_compression.hpp */, 108 | CE405EBB1E49DD7100AA0B3D /* kern_disasm.hpp */, 109 | CE405EBC1E49DD7100AA0B3D /* kern_file.hpp */, 110 | CE405EBD1E49DD7100AA0B3D /* kern_iokit.hpp */, 111 | CE405EBE1E49DD7100AA0B3D /* kern_mach.hpp */, 112 | CE405EBF1E49DD7100AA0B3D /* kern_patcher.hpp */, 113 | CE405EC01E49DD7100AA0B3D /* kern_policy.hpp */, 114 | CE405EC31E49DD7100AA0B3D /* kern_user.hpp */, 115 | CE405EC41E49DD7100AA0B3D /* kern_util.hpp */, 116 | CE405EDA1E4A080F00AA0B3D /* plugin_start.hpp */, 117 | ); 118 | name = Headers; 119 | path = Lilu.kext/Contents/Resources/Headers; 120 | sourceTree = SOURCE_ROOT; 121 | }; 122 | CE405EC51E49DD7100AA0B3D /* Library */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | CE405EC61E49DD7100AA0B3D /* LegacyIOService.h */, 126 | CE405EC71E49DD7100AA0B3D /* libkmod.a */, 127 | CE405ED81E4A080700AA0B3D /* plugin_start.cpp */, 128 | ); 129 | name = Library; 130 | path = Lilu.kext/Contents/Resources/Library; 131 | sourceTree = SOURCE_ROOT; 132 | }; 133 | CE405EC81E49DD7B00AA0B3D /* SDK */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | CE405EB91E49DD7100AA0B3D /* Headers */, 137 | CE405EC51E49DD7100AA0B3D /* Library */, 138 | ); 139 | name = SDK; 140 | sourceTree = ""; 141 | }; 142 | CE8DA0BD2517DD4A008C44E8 /* Frameworks */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | CE8DA0BE2517DD4A008C44E8 /* libkmod.a */, 146 | ); 147 | name = Frameworks; 148 | sourceTree = ""; 149 | }; 150 | CEDF9CEE27F4B68A0030425C /* Tools */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | CEDF9CF027F4B68A0030425C /* FrequencyVectors.bt */, 154 | CEDF9CEF27F4B68A0030425C /* FrequencyVectors.tcl */, 155 | CEDF9CF127F4B68A0030425C /* ResourceConverter.sh */, 156 | ); 157 | path = Tools; 158 | sourceTree = ""; 159 | }; 160 | /* End PBXGroup section */ 161 | 162 | /* Begin PBXHeadersBuildPhase section */ 163 | 1C748C241C21952C0024EED2 /* Headers */ = { 164 | isa = PBXHeadersBuildPhase; 165 | buildActionMask = 2147483647; 166 | files = ( 167 | CEBD8C1A1F372A4600BBCB85 /* CPUFriend.hpp in Headers */, 168 | ); 169 | runOnlyForDeploymentPostprocessing = 0; 170 | }; 171 | /* End PBXHeadersBuildPhase section */ 172 | 173 | /* Begin PBXNativeTarget section */ 174 | 1C748C261C21952C0024EED2 /* CPUFriend */ = { 175 | isa = PBXNativeTarget; 176 | buildConfigurationList = 1C748C311C21952C0024EED2 /* Build configuration list for PBXNativeTarget "CPUFriend" */; 177 | buildPhases = ( 178 | 1C748C221C21952C0024EED2 /* Sources */, 179 | 1C748C231C21952C0024EED2 /* Frameworks */, 180 | 1C748C241C21952C0024EED2 /* Headers */, 181 | CE5356961FB9BD050051346D /* Archive */, 182 | ); 183 | buildRules = ( 184 | ); 185 | dependencies = ( 186 | ); 187 | name = CPUFriend; 188 | productName = CPUFriend; 189 | productReference = 1C748C271C21952C0024EED2 /* CPUFriend.kext */; 190 | productType = "com.apple.product-type.kernel-extension"; 191 | }; 192 | /* End PBXNativeTarget section */ 193 | 194 | /* Begin PBXProject section */ 195 | 1C748C1E1C21952C0024EED2 /* Project object */ = { 196 | isa = PBXProject; 197 | attributes = { 198 | LastUpgradeCheck = 1330; 199 | ORGANIZATIONNAME = Acidanthera; 200 | TargetAttributes = { 201 | 1C748C261C21952C0024EED2 = { 202 | CreatedOnToolsVersion = 7.2; 203 | }; 204 | }; 205 | }; 206 | buildConfigurationList = 1C748C211C21952C0024EED2 /* Build configuration list for PBXProject "CPUFriend" */; 207 | compatibilityVersion = "Xcode 3.2"; 208 | developmentRegion = en; 209 | hasScannedForEncodings = 0; 210 | knownRegions = ( 211 | en, 212 | Base, 213 | ); 214 | mainGroup = 1C748C1D1C21952C0024EED2; 215 | productRefGroup = 1C748C281C21952C0024EED2 /* Products */; 216 | projectDirPath = ""; 217 | projectRoot = ""; 218 | targets = ( 219 | 1C748C261C21952C0024EED2 /* CPUFriend */, 220 | ); 221 | }; 222 | /* End PBXProject section */ 223 | 224 | /* Begin PBXShellScriptBuildPhase section */ 225 | CE5356961FB9BD050051346D /* Archive */ = { 226 | isa = PBXShellScriptBuildPhase; 227 | buildActionMask = 2147483647; 228 | files = ( 229 | ); 230 | inputPaths = ( 231 | ); 232 | name = Archive; 233 | outputPaths = ( 234 | ); 235 | runOnlyForDeploymentPostprocessing = 0; 236 | shellPath = /bin/bash; 237 | shellScript = "cd \"${TARGET_BUILD_DIR}\"\n\ndist=(\"$FULL_PRODUCT_NAME\")\nif [ -d \"$DWARF_DSYM_FILE_NAME\" ]; then dist+=(\"$DWARF_DSYM_FILE_NAME\")\nfi\nif [ -d \"$SOURCE_ROOT/Tools\" ]; then\n cp -a \"$SOURCE_ROOT/Tools\" \"Tools\"\n dist+=(\"Tools\")\nfi\nif [ -f \"$SOURCE_ROOT/Instructions.md\" ]; then\n cp -a \"$SOURCE_ROOT/Instructions.md\" \"Instructions.md\"\n dist+=(\"Instructions.md\")\nfi\n\narchive=\"${PRODUCT_NAME}-${MODULE_VERSION}-$(echo $CONFIGURATION | tr /a-z/ /A-Z/).zip\"\nrm -rf *.zip\nif [ \"$CONFIGURATION\" == \"Release\" ]; then\n strip -x -T \"${EXECUTABLE_PATH}\" &>/dev/null || strip -x \"${EXECUTABLE_PATH}\"\nfi\nzip -qry -FS \"${archive}\" \"${dist[@]}\"\n\nrm -rf \"Tools\"\n"; 238 | }; 239 | /* End PBXShellScriptBuildPhase section */ 240 | 241 | /* Begin PBXSourcesBuildPhase section */ 242 | 1C748C221C21952C0024EED2 /* Sources */ = { 243 | isa = PBXSourcesBuildPhase; 244 | buildActionMask = 2147483647; 245 | files = ( 246 | CEBD8C191F372A4600BBCB85 /* CPUFriend.cpp in Sources */, 247 | CE405ED91E4A080700AA0B3D /* plugin_start.cpp in Sources */, 248 | 1C748C2D1C21952C0024EED2 /* kern_start.cpp in Sources */, 249 | ); 250 | runOnlyForDeploymentPostprocessing = 0; 251 | }; 252 | /* End PBXSourcesBuildPhase section */ 253 | 254 | /* Begin XCBuildConfiguration section */ 255 | 1C748C2F1C21952C0024EED2 /* Debug */ = { 256 | isa = XCBuildConfiguration; 257 | buildSettings = { 258 | ALWAYS_SEARCH_USER_PATHS = NO; 259 | CLANG_CXX_LANGUAGE_STANDARD = "c++14"; 260 | CLANG_CXX_LIBRARY = "libc++"; 261 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 262 | CLANG_WARN_BOOL_CONVERSION = YES; 263 | CLANG_WARN_COMMA = YES; 264 | CLANG_WARN_CONSTANT_CONVERSION = YES; 265 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 266 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 267 | CLANG_WARN_EMPTY_BODY = YES; 268 | CLANG_WARN_ENUM_CONVERSION = YES; 269 | CLANG_WARN_INFINITE_RECURSION = YES; 270 | CLANG_WARN_INT_CONVERSION = YES; 271 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 272 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 273 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 274 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 275 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 276 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 277 | CLANG_WARN_STRICT_PROTOTYPES = YES; 278 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 279 | CLANG_WARN_UNREACHABLE_CODE = YES; 280 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 281 | DEBUG_INFORMATION_FORMAT = dwarf; 282 | ENABLE_STRICT_OBJC_MSGSEND = YES; 283 | ENABLE_TESTABILITY = YES; 284 | GCC_C_LANGUAGE_STANDARD = c11; 285 | GCC_NO_COMMON_BLOCKS = YES; 286 | GCC_OPTIMIZATION_LEVEL = 0; 287 | GCC_PREPROCESSOR_DEFINITIONS = ( 288 | "DEBUG=1", 289 | "$(inherited)", 290 | ); 291 | GCC_SYMBOLS_PRIVATE_EXTERN = YES; 292 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 293 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 294 | GCC_WARN_UNDECLARED_SELECTOR = YES; 295 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 296 | GCC_WARN_UNUSED_FUNCTION = YES; 297 | GCC_WARN_UNUSED_VARIABLE = YES; 298 | KERNEL_EXTENSION_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; 299 | KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; 300 | ONLY_ACTIVE_ARCH = YES; 301 | SDKROOT = macosx; 302 | }; 303 | name = Debug; 304 | }; 305 | 1C748C301C21952C0024EED2 /* Release */ = { 306 | isa = XCBuildConfiguration; 307 | buildSettings = { 308 | ALWAYS_SEARCH_USER_PATHS = NO; 309 | CLANG_CXX_LANGUAGE_STANDARD = "c++14"; 310 | CLANG_CXX_LIBRARY = "libc++"; 311 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 312 | CLANG_WARN_BOOL_CONVERSION = YES; 313 | CLANG_WARN_COMMA = YES; 314 | CLANG_WARN_CONSTANT_CONVERSION = YES; 315 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 316 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 317 | CLANG_WARN_EMPTY_BODY = YES; 318 | CLANG_WARN_ENUM_CONVERSION = YES; 319 | CLANG_WARN_INFINITE_RECURSION = YES; 320 | CLANG_WARN_INT_CONVERSION = YES; 321 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 322 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 323 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 324 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 325 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 326 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 327 | CLANG_WARN_STRICT_PROTOTYPES = YES; 328 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 329 | CLANG_WARN_UNREACHABLE_CODE = YES; 330 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 331 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 332 | ENABLE_STRICT_OBJC_MSGSEND = YES; 333 | GCC_C_LANGUAGE_STANDARD = c11; 334 | GCC_NO_COMMON_BLOCKS = YES; 335 | GCC_OPTIMIZATION_LEVEL = 3; 336 | GCC_SYMBOLS_PRIVATE_EXTERN = YES; 337 | GCC_UNROLL_LOOPS = YES; 338 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 339 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 340 | GCC_WARN_UNDECLARED_SELECTOR = YES; 341 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 342 | GCC_WARN_UNUSED_FUNCTION = YES; 343 | GCC_WARN_UNUSED_VARIABLE = YES; 344 | KERNEL_EXTENSION_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; 345 | KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; 346 | SDKROOT = macosx; 347 | }; 348 | name = Release; 349 | }; 350 | 1C748C321C21952C0024EED2 /* Debug */ = { 351 | isa = XCBuildConfiguration; 352 | buildSettings = { 353 | ARCHS = x86_64; 354 | CLANG_ENABLE_OBJC_WEAK = YES; 355 | COPY_PHASE_STRIP = NO; 356 | CURRENT_PROJECT_VERSION = "$(MODULE_VERSION)"; 357 | DEPLOYMENT_POSTPROCESSING = YES; 358 | GCC_ENABLE_FLOATING_POINT_LIBRARY_CALLS = NO; 359 | GCC_ENABLE_KERNEL_DEVELOPMENT = NO; 360 | GCC_GENERATE_DEBUGGING_SYMBOLS = NO; 361 | GCC_PREPROCESSOR_DEFINITIONS = ( 362 | "MODULE_VERSION=$(MODULE_VERSION)", 363 | "PRODUCT_NAME=$(PRODUCT_NAME)", 364 | "$(inherited)", 365 | ); 366 | HEADER_SEARCH_PATHS = "${PROJECT_DIR}/Lilu.kext/Contents/Resources"; 367 | INFOPLIST_FILE = CPUFriend/Info.plist; 368 | LIBRARY_SEARCH_PATHS = ( 369 | "$(inherited)", 370 | "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", 371 | ); 372 | MACOSX_DEPLOYMENT_TARGET = 10.8; 373 | MODULE_NAME = org.acidanthera.driver.CPUFriend; 374 | MODULE_START = "$(PRODUCT_NAME)_kern_start"; 375 | MODULE_STOP = "$(PRODUCT_NAME)_kern_stop"; 376 | MODULE_VERSION = 1.3.0; 377 | OTHER_CFLAGS = ( 378 | "-mmmx", 379 | "-msse", 380 | "-msse2", 381 | "-msse3", 382 | "-mfpmath=sse", 383 | "-mssse3", 384 | "-ftree-vectorize", 385 | "-fno-non-call-exceptions", 386 | "-fno-builtin", 387 | "-fno-asynchronous-unwind-tables", 388 | "-Wno-unknown-warning-option", 389 | "-Wno-ossharedptr-misuse", 390 | "-Wno-vla", 391 | ); 392 | OTHER_LDFLAGS = "-static"; 393 | PRODUCT_BUNDLE_IDENTIFIER = org.acidanthera.driver.CPUFriend; 394 | PRODUCT_NAME = "$(TARGET_NAME)"; 395 | WRAPPER_EXTENSION = kext; 396 | }; 397 | name = Debug; 398 | }; 399 | 1C748C331C21952C0024EED2 /* Release */ = { 400 | isa = XCBuildConfiguration; 401 | buildSettings = { 402 | ARCHS = x86_64; 403 | CLANG_ENABLE_OBJC_WEAK = YES; 404 | CURRENT_PROJECT_VERSION = "$(MODULE_VERSION)"; 405 | DEAD_CODE_STRIPPING = YES; 406 | DEPLOYMENT_POSTPROCESSING = YES; 407 | GCC_ENABLE_FLOATING_POINT_LIBRARY_CALLS = NO; 408 | GCC_ENABLE_KERNEL_DEVELOPMENT = NO; 409 | GCC_GENERATE_DEBUGGING_SYMBOLS = YES; 410 | GCC_OPTIMIZATION_LEVEL = s; 411 | GCC_PREPROCESSOR_DEFINITIONS = ( 412 | "MODULE_VERSION=$(MODULE_VERSION)", 413 | "PRODUCT_NAME=$(PRODUCT_NAME)", 414 | ); 415 | HEADER_SEARCH_PATHS = "${PROJECT_DIR}/Lilu.kext/Contents/Resources"; 416 | INFOPLIST_FILE = CPUFriend/Info.plist; 417 | LIBRARY_SEARCH_PATHS = ( 418 | "$(inherited)", 419 | "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", 420 | ); 421 | LLVM_LTO = YES; 422 | MACOSX_DEPLOYMENT_TARGET = 10.8; 423 | MODULE_NAME = org.acidanthera.driver.CPUFriend; 424 | MODULE_START = "$(PRODUCT_NAME)_kern_start"; 425 | MODULE_STOP = "$(PRODUCT_NAME)_kern_stop"; 426 | MODULE_VERSION = 1.3.0; 427 | OTHER_CFLAGS = ( 428 | "-mmmx", 429 | "-msse", 430 | "-msse2", 431 | "-msse3", 432 | "-mfpmath=sse", 433 | "-mssse3", 434 | "-ftree-vectorize", 435 | "-fno-non-call-exceptions", 436 | "-fno-builtin", 437 | "-fno-asynchronous-unwind-tables", 438 | "-Wno-unknown-warning-option", 439 | "-Wno-ossharedptr-misuse", 440 | "-Wno-vla", 441 | ); 442 | OTHER_LDFLAGS = "-static"; 443 | PRODUCT_BUNDLE_IDENTIFIER = org.acidanthera.driver.CPUFriend; 444 | PRODUCT_NAME = "$(TARGET_NAME)"; 445 | STRIP_STYLE = "non-global"; 446 | WRAPPER_EXTENSION = kext; 447 | }; 448 | name = Release; 449 | }; 450 | /* End XCBuildConfiguration section */ 451 | 452 | /* Begin XCConfigurationList section */ 453 | 1C748C211C21952C0024EED2 /* Build configuration list for PBXProject "CPUFriend" */ = { 454 | isa = XCConfigurationList; 455 | buildConfigurations = ( 456 | 1C748C2F1C21952C0024EED2 /* Debug */, 457 | 1C748C301C21952C0024EED2 /* Release */, 458 | ); 459 | defaultConfigurationIsVisible = 0; 460 | defaultConfigurationName = Release; 461 | }; 462 | 1C748C311C21952C0024EED2 /* Build configuration list for PBXNativeTarget "CPUFriend" */ = { 463 | isa = XCConfigurationList; 464 | buildConfigurations = ( 465 | 1C748C321C21952C0024EED2 /* Debug */, 466 | 1C748C331C21952C0024EED2 /* Release */, 467 | ); 468 | defaultConfigurationIsVisible = 0; 469 | defaultConfigurationName = Release; 470 | }; 471 | /* End XCConfigurationList section */ 472 | }; 473 | rootObject = 1C748C1E1C21952C0024EED2 /* Project object */; 474 | } 475 | -------------------------------------------------------------------------------- /CPUFriend/CPUFriend.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // CPUFriend.cpp 3 | // CPUFriend 4 | // 5 | // Copyright © 2017-2022 PMheart. All rights reserved. 6 | // 7 | 8 | #include 9 | 10 | #include "CPUFriend.hpp" 11 | 12 | static const char *kextACPISMC[] { "/System/Library/Extensions/IOPlatformPluginFamily.kext/Contents/PlugIns/ACPI_SMC_PlatformPlugin.kext/Contents/MacOS/ACPI_SMC_PlatformPlugin" }; 13 | static const char *kextX86PP[] { "/System/Library/Extensions/IOPlatformPluginFamily.kext/Contents/PlugIns/X86PlatformPlugin.kext/Contents/MacOS/X86PlatformPlugin" }; 14 | 15 | enum : size_t { 16 | KextACPISMC, 17 | KextX86PP, 18 | }; 19 | 20 | static KernelPatcher::KextInfo kextList[] { 21 | { "com.apple.driver.ACPI_SMC_PlatformPlugin", kextACPISMC, arrsize(kextACPISMC), {}, {}, KernelPatcher::KextInfo::Unloaded }, 22 | { "com.apple.driver.X86PlatformPlugin", kextX86PP, arrsize(kextX86PP), {}, {}, KernelPatcher::KextInfo::Unloaded }, 23 | }; 24 | 25 | static constexpr size_t kextListSize = arrsize(kextList); 26 | 27 | static CPUFriendPlugin *callbackCpuf = nullptr; 28 | 29 | OSDefineMetaClassAndStructors(CPUFriendData, IOService) 30 | 31 | IOService *CPUFriendData::probe(IOService *provider, SInt32 *score) 32 | { 33 | if (!provider) { 34 | return nullptr; 35 | } 36 | 37 | if (!callbackCpuf) { 38 | SYSLOG("cpuf", "missing storage instance"); 39 | return nullptr; 40 | } 41 | 42 | if (callbackCpuf->frequencyData) { 43 | DBGLOG("cpuf", "frequency data already obtained, skipping"); 44 | return nullptr; 45 | } 46 | 47 | DBGLOG("cpuf", "looking for cf-frequency-data in %s", safeString(provider->getName())); 48 | auto data = OSDynamicCast(OSData, provider->getProperty("cf-frequency-data")); 49 | if (!data) { 50 | auto cpu = provider->getParentEntry(gIOServicePlane); 51 | if (!cpu) { 52 | SYSLOG("cpuf", "unable to access cpu parent"); 53 | return nullptr; 54 | } 55 | 56 | DBGLOG("cpuf", "looking for cf-frequency-data again in %s", safeString(cpu->getName())); 57 | data = OSDynamicCast(OSData, cpu->getProperty("cf-frequency-data")); 58 | } 59 | 60 | if (data) { 61 | callbackCpuf->frequencyDataSize = data->getLength(); 62 | callbackCpuf->frequencyData = data->getBytesNoCopy(); 63 | } else { 64 | // This is expected for first start, second will do. 65 | DBGLOG("cpuf", "failed to obtain cf-frequency-data"); 66 | } 67 | 68 | return nullptr; 69 | } 70 | 71 | void CPUFriendPlugin::init() 72 | { 73 | callbackCpuf = this; 74 | 75 | lilu.onKextLoadForce( 76 | kextList, 77 | kextListSize, 78 | [](void *user, KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size) { 79 | static_cast(user)->processKext(patcher, index, address, size); 80 | }, 81 | this 82 | ); 83 | } 84 | 85 | void CPUFriendPlugin::updateResource(kern_return_t &result, const void * &resourceData, uint32_t &resourceDataLength) 86 | { 87 | if (!callbackCpuf) { 88 | SYSLOG("cpuf", "config callback arrived at nowhere"); 89 | return; 90 | } 91 | 92 | auto data = callbackCpuf->frequencyData; 93 | auto size = callbackCpuf->frequencyDataSize; 94 | if (data && size > 0) { 95 | DBGLOG("cpuf", "feeding frequency data, size %u", size); 96 | resourceData = data; 97 | resourceDataLength = size; 98 | result = kOSReturnSuccess; 99 | } else { 100 | // this is fine when not providing customized data, 101 | // in the worst case it's just the original 102 | // frequencyData and frequencyDataSize get handled, 103 | // which looks safe enough. 104 | DBGLOG("cpuf", "failed to feed cpu data (size %u, %d), feeding data from org callback", size, data != nullptr); 105 | } 106 | } 107 | 108 | void CPUFriendPlugin::myACPISMCConfigResourceCallback(uint32_t requestTag, kern_return_t result, const void *resourceData, uint32_t resourceDataLength, void *context) 109 | { 110 | DBGLOG("cpuf", "myACPISMCConfigResourceCallback before (tag %u, result %d, data %d, size %u, context %d)", requestTag, result, resourceData != nullptr, resourceDataLength, context != nullptr); 111 | callbackCpuf->updateResource(result, resourceData, resourceDataLength); 112 | DBGLOG("cpuf", "myACPISMCConfigResourceCallback after (tag %u, result %d, data %d, size %u, context %d)", requestTag, result, resourceData != nullptr, resourceDataLength, context != nullptr); 113 | FunctionCast(myACPISMCConfigResourceCallback, callbackCpuf->orgACPISMCConfigLoadCallback)(requestTag, result, resourceData, resourceDataLength, context); 114 | } 115 | 116 | void CPUFriendPlugin::myX86PPConfigResourceCallback(uint32_t requestTag, kern_return_t result, const void *resourceData, uint32_t resourceDataLength, void *context) 117 | { 118 | DBGLOG("cpuf", "myX86PPConfigResourceCallback before (tag %u, result %d, data %d, size %u, context %d)", requestTag, result, resourceData != nullptr, resourceDataLength, context != nullptr); 119 | callbackCpuf->updateResource(result, resourceData, resourceDataLength); 120 | DBGLOG("cpuf", "myX86PPConfigResourceCallback after (tag %u, result %d, data %d, size %u, context %d)", requestTag, result, resourceData != nullptr, resourceDataLength, context != nullptr); 121 | FunctionCast(myX86PPConfigResourceCallback, callbackCpuf->orgX86PPConfigLoadCallback)(requestTag, result, resourceData, resourceDataLength, context); 122 | } 123 | 124 | void CPUFriendPlugin::processKext(KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size) 125 | { 126 | if (kextList[KextACPISMC].loadIndex == index) { 127 | DBGLOG("cpuf", "patching KextACPISMC"); 128 | KernelPatcher::RouteRequest request( 129 | "__ZL22configResourceCallbackjiPKvjPv", 130 | myACPISMCConfigResourceCallback, 131 | orgACPISMCConfigLoadCallback 132 | ); 133 | patcher.routeMultiple(index, &request, 1, address, size); 134 | } else if (kextList[KextX86PP].loadIndex == index) { 135 | DBGLOG("cpuf", "patching KextX86PP"); 136 | KernelPatcher::RouteRequest request( 137 | "__ZN17X86PlatformPlugin22configResourceCallbackEjiPKvjPv", 138 | myX86PPConfigResourceCallback, 139 | orgX86PPConfigLoadCallback 140 | ); 141 | patcher.routeMultiple(index, &request, 1, address, size); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /CPUFriend/CPUFriend.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // CPUFriend.hpp 3 | // CPUFriend 4 | // 5 | // Copyright © 2017-2022 PMheart. All rights reserved. 6 | // 7 | 8 | #ifndef kern_cpuf_hpp 9 | #define kern_cpuf_hpp 10 | 11 | #include 12 | #include 13 | 14 | class EXPORT CPUFriendData : public IOService { 15 | OSDeclareDefaultStructors(CPUFriendData) 16 | public: 17 | IOService *probe(IOService *provider, SInt32 *score) override; 18 | }; 19 | 20 | class CPUFriendPlugin { 21 | public: 22 | void init(); 23 | 24 | /** 25 | * Loaded user-specified frequency data 26 | */ 27 | const void *frequencyData = nullptr; 28 | 29 | /** 30 | * Loaded user-specified frequency data size 31 | */ 32 | uint32_t frequencyDataSize = 0; 33 | 34 | private: 35 | /** 36 | * Trampolines for original resource load callback 37 | */ 38 | mach_vm_address_t orgACPISMCConfigLoadCallback {0}; 39 | mach_vm_address_t orgX86PPConfigLoadCallback {0}; 40 | 41 | /** 42 | * Update resource request parameters with hooked data if necessary 43 | * 44 | * @param result kOSReturnSuccess on resource update 45 | * @param resourceData resource data reference 46 | * @param resourceDataLength resource data length reference 47 | */ 48 | void updateResource(kern_return_t &result, const void * &resourceData, uint32_t &resourceDataLength); 49 | 50 | /** 51 | * Hooked functions 52 | */ 53 | static void myACPISMCConfigResourceCallback(uint32_t requestTag, kern_return_t result, const void *resourceData, uint32_t resourceDataLength, void *context); 54 | static void myX86PPConfigResourceCallback(uint32_t requestTag, kern_return_t result, const void *resourceData, uint32_t resourceDataLength, void *context); 55 | 56 | /** 57 | * Patch kext if needed and prepare other patches 58 | * 59 | * @param patcher KernelPatcher instance 60 | * @param index kinfo handle 61 | * @param address kinfo load address 62 | * @param size kinfo memory size 63 | */ 64 | void processKext(KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size); 65 | }; 66 | 67 | #endif /* kern_cpuf_hpp */ 68 | -------------------------------------------------------------------------------- /CPUFriend/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | KEXT 17 | CFBundleShortVersionString 18 | $(MODULE_VERSION) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(MODULE_VERSION) 23 | IOKitPersonalities 24 | 25 | CPUFriend 26 | 27 | CFBundleIdentifier 28 | $(PRODUCT_BUNDLE_IDENTIFIER) 29 | IOClass 30 | $(PRODUCT_NAME:rfc1034identifier) 31 | IOMatchCategory 32 | $(PRODUCT_NAME:rfc1034identifier) 33 | IOProviderClass 34 | IOResources 35 | IOResourceMatch 36 | IOKit 37 | 38 | CPUFriendPlatform 39 | 40 | CFBundleIdentifier 41 | $(PRODUCT_BUNDLE_IDENTIFIER) 42 | IOClass 43 | CPUFriendData 44 | IOProbeScore 45 | 6000 46 | IOPropertyMatch 47 | 48 | IOCPUNumber 49 | 0 50 | 51 | IOProviderClass 52 | AppleACPICPU 53 | IOResourceMatch 54 | ACPI 55 | 56 | 57 | NSHumanReadableCopyright 58 | Copyright © 2017-2022 PMheart. All rights reserved. 59 | OSBundleCompatibleVersion 60 | 1.0 61 | OSBundleLibraries 62 | 63 | as.vit9696.Lilu 64 | 1.2.0 65 | com.apple.iokit.IOACPIFamily 66 | 1.0.0d1 67 | com.apple.kpi.bsd 68 | 10.0.0 69 | com.apple.kpi.dsep 70 | 10.0.0 71 | com.apple.kpi.iokit 72 | 10.0.0 73 | com.apple.kpi.libkern 74 | 10.0.0 75 | com.apple.kpi.mach 76 | 10.0.0 77 | com.apple.kpi.unsupported 78 | 10.0.0 79 | 80 | OSBundleRequired 81 | Root 82 | 83 | 84 | -------------------------------------------------------------------------------- /CPUFriend/kern_start.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // kern_start.cpp 3 | // CPUFriend 4 | // 5 | // Copyright © 2017-2022 PMheart. All rights reserved. 6 | // 7 | 8 | #include 9 | #include 10 | 11 | #include "CPUFriend.hpp" 12 | 13 | static CPUFriendPlugin cpuf; 14 | 15 | static const char *bootargOff[] { 16 | "-cpufoff" 17 | }; 18 | 19 | static const char *bootargDebug[] { 20 | "-cpufdbg" 21 | }; 22 | 23 | static const char *bootargBeta[] { 24 | "-cpufbeta" 25 | }; 26 | 27 | PluginConfiguration ADDPR(config) { 28 | xStringify(PRODUCT_NAME), 29 | parseModuleVersion(xStringify(MODULE_VERSION)), 30 | LiluAPI::AllowNormal | LiluAPI::AllowInstallerRecovery | LiluAPI::AllowSafeMode, 31 | bootargOff, 32 | arrsize(bootargOff), 33 | bootargDebug, 34 | arrsize(bootargDebug), 35 | bootargBeta, 36 | arrsize(bootargBeta), 37 | KernelVersion::SnowLeopard, 38 | KernelVersion::Sequoia, 39 | []() { 40 | cpuf.init(); 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /Changelog.md: -------------------------------------------------------------------------------- 1 | CPUFriend Changelog 2 | =================== 3 | #### v1.2.9 4 | - Fixed loading on macOS 10.10 and older due to a MacKernelSDK regression 5 | 6 | #### v1.2.8 7 | - Added constants for macOS 15 support 8 | 9 | #### v1.2.7 10 | - Added constants for macOS 14 support 11 | 12 | #### v1.2.6 13 | - Added constants for macOS 13 support 14 | 15 | #### v1.2.5 16 | - Added support from macOS 10.6 17 | - Improved FrequencyVectors analyzer by @usr-sse2 18 | - Changed project ownership to Acidanthera 19 | 20 | #### v1.2.4 21 | - Added constants for macOS 12 support 22 | 23 | #### v1.2.3 24 | - Improved path handling in generator scripts 25 | 26 | #### v1.2.2 27 | - Added MacKernelSDK with Xcode 12 compatibility 28 | 29 | #### v1.2.1 30 | - Added constants for 11.0 support 31 | 32 | #### v1.2.0 33 | - Dropped broken AppleIntelMCEReporter prevention support 34 | 35 | #### v1.1.9 36 | - Unified release archive names 37 | - Added support for prevention of AppleIntelMCEReporter, details can be found [here](https://github.com/acidanthera/bugtracker/issues/424#issuecomment-512596034) 38 | 39 | #### v1.1.8 40 | - Allow loading on 10.15 without `-lilubetaall` 41 | 42 | #### v1.1.7 43 | - Reduced debug logging in release builds 44 | 45 | #### v1.1.6 46 | - Fixed a bug where CPUFriend ceased to work on v1.1.5 47 | 48 | #### v1.1.5 49 | - Support for the old ACPI_SMC_Plugin (as claimed in TO-DO) 50 | 51 | #### v1.1.4 52 | - Sync with Lilu 1.2.5 53 | - Native macOS 10.14 support 54 | 55 | #### v1.1.3 56 | - Added Lilu 1.2.3 compatibility 57 | - Requires Lilu 1.2.3 or higher 58 | 59 | #### v1.1.2 60 | - Code style changed 61 | 62 | #### v1.1.1 63 | - Various typo fixes 64 | 65 | #### v1.1.0 66 | - Requires Lilu 1.2.0 or higher 67 | 68 | #### v1.0.1 69 | - Corrected some typos. 70 | 71 | #### v1.0.0 72 | - Initial release 73 | -------------------------------------------------------------------------------- /Instructions.md: -------------------------------------------------------------------------------- 1 | CPUFriend Installation & Usage 2 | =================================== 3 | 4 | ## WARNING 5 | **CPUFriend is most likely _NOT_ required when not sure whether or not to use it.** 6 | 7 | In most cases the native CPU power management data from `ACPI_SMC_PlatformPlugin` or `X86PlatformPlugin` work out of the box. 8 | Do not use CPUFriend for data customization until one knows clearly what power management data really is. 9 | If possible, changing SMBIOS, which results in other data being used, can be more reasonable. 10 | In [Tools](https://github.com/acidanthera/CPUFriend/tree/master/Tools), several analyzer scripts for `FrequencyVectors` are provided as a good beginning. 11 | Also, CPUFriend should not be used to break the native CPU performance tuning mechanism by patching e.g. LFM (Low Frequency Mode). 12 | In case of necessity for manual performance tuning, the following scripts might be used: 13 | - [CPUFriendFriend](https://github.com/corpnewt/CPUFriendFriend) by [corpnewt](https://github.com/corpnewt) 14 | - [one-key-cpufriend](https://github.com/stevezhengshiqi/one-key-cpufriend) by [stevezhengshiqi](https://github.com/stevezhengshiqi) 15 | 16 | Nevertheless, _NO support_ will be provided from the side of CPUFriend as it only handles data injection. Please file issues at the corresponding repositories instead. 17 | 18 | While such automated scripts bring convenience, it is, however, still necessary to understand the meaning of these modifications. Otherwise once again, consider not using CPUFriend. 19 | 20 | #### Technical background 21 | - Function `configResourceCallback()` from `ACPI_SMC_PlatformPlugin` or `X86PlatformPlugin` is hooked so as to handle customized CPU power management data from user. If nothing is provided, CPUFriend does nothing and the original data is to be used as if this kext is not installed. 22 | 23 | #### Installation 24 | First and foremost, both `ACPI_SMC_PlatformPlugin` and `X86PlatformPlugin` should remain untouched. 25 | Injection via bootloader is highly recommended. 26 | When installing to system folders (i.e. `/System/Library/Extensions` or `/Library/Extensions`), [LiluFriend](https://github.com/PMheart/LiluFriend) may be required to ensure full functionality. This is, however, strongly discouraged. 27 | 28 | #### Available kernel flags 29 | Add `-cpufdbg` to enable debug logging (ONLY available in DEBUG binaries). 30 | 31 | Add `-cpufoff` to disable CPUFriend entirely. 32 | 33 | Add `-cpufbeta` to enable CPUFriend on unsupported OS versions. 34 | 35 | #### Configuration 36 | `Tools/ResourceConverter.sh` is meant to generate a working copy of either `CPUFriendDataProvider.kext` or `ssdt_data.dsl`, from which CPUFriend reads data. 37 | 38 | **NOTE:** For simplicity, `CPUFriendDataProvider.kext` is always preferred. Where there is another SSDT generated by [ssdtPRGen.sh](https://github.com/Piker-Alpha/ssdtPRGen.sh), combination between `ssdt_data.dsl` and the SSDT table produced by this script is required. See [Data Combination](https://github.com/acidanthera/CPUFriend/blob/master/Instructions.md#data-combination) for further details. 39 | 40 | #### Usage of ResourceConverter.sh 41 | `--kext /path/to/file` 42 | Create `CPUFriendDataProvider.kext` with information provided by `file`. 43 | 44 | `--acpi /path/to/file` 45 | Create `ssdt_data.dsl` with information provided by `file`. 46 | 47 | **NOTE:** 48 | - The kext/ssdt is produced in the current working directory that can be revealed with `pwd`. 49 | - `file` should be a ***complete plist*** from `Recources` inside `ACPI_SMC_PlatformPlugin` or `X86PlatformPlugin` ***with certain modifications*** in lieu of e.g. a raw `FrequencyVectors` entry. 50 | 51 | #### Data Combination 52 | 1. Generate a correct copy of `CPUFriendDataProvider.kext` with `./ResourceConverter.sh --acpi /path/to/file`. 53 | 2. Open SSDT previously generated by [ssdtPRGen.sh](https://github.com/Piker-Alpha/ssdtPRGen.sh), and search for `Method (_DSM, 4, NotSerialized)` in a text editor. 54 | 3. Paste `"cf-frequency-data"` entry from `ssdt_data.dsl` to the SSDT generated by [ssdtPRGen.sh](https://github.com/Piker-Alpha/ssdtPRGen.sh). A glance at the final work looks as follows. 55 | ``` 56 | // 57 | // Context of the SSDT generated by ssdtPRGen.sh 58 | // 59 | Method (_DSM, 4, NotSerialized) 60 | { 61 | If (LEqual (Arg2, Zero)) 62 | { 63 | Return (Buffer (One) 64 | { 65 | 0x03 66 | }) 67 | } 68 | 69 | Return (Package () // size removed 70 | { 71 | "plugin-type", 72 | One, 73 | 74 | // 75 | // Paste it from ssdt_data.dsl 76 | // 77 | "cf-frequency-data", 78 | Buffer () // size removed 79 | { 80 | // Data from ssdt_data.dsl 81 | } 82 | }) 83 | } 84 | // 85 | // Context of the SSDT generated by ssdtPRGen.sh 86 | // 87 | ``` 88 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-2022, PMheart 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | 11 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CPUFriend 2 | ========= 3 | 4 | [![Build Status](https://github.com/acidanthera/CPUFriend/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/acidanthera/CPUFriend/actions) [![Scan Status](https://scan.coverity.com/projects/16841/badge.svg?flat=1)](https://scan.coverity.com/projects/16841) 5 | 6 | A [Lilu](https://github.com/acidanthera/Lilu) plug-in for dynamic power management data injection. 7 | 8 | #### Notes 9 | This repository must be compiled with latest [Lilu](https://github.com/acidanthera/Lilu) and [MacKernelSDK](https://github.com/acidanthera/MacKernelSDK), otherwise the compilation will fail! 10 | 11 | Note: ***Debug version of Lilu.kext and MacKernelSDK project folder should be put in the same folder as CPUFriend! And debug versions of Lilu and CPUFriend should also be used together when debugging!*** 12 | 13 | #### Configuration 14 | This kext is most likely not required when the CPU is natively supported by XNU (macOS kernel). In case of necessity, please see [Instructions](https://github.com/acidanthera/CPUFriend/blob/master/Instructions.md) for configuration. 15 | 16 | #### Credits 17 | - [Apple](https://www.apple.com) for macOS 18 | - [vit9696](https://github.com/vit9696) for [Lilu.kext](https://github.com/acidanthera/Lilu) and various helps 19 | - [PMheart](https://github.com/PMheart) for writing the software and maintaining it 20 | -------------------------------------------------------------------------------- /Tools/FrequencyVectors.bt: -------------------------------------------------------------------------------- 1 | /** 2 | * 010 Editor v8.0.1 Binary Template 3 | * 4 | * File: X86PlatformPlugin.kext resources (IOPlatformPluginFamily.kext) 5 | * Authors: vit9696 6 | * Version: 0.1 7 | * Purpose: Intel XCPM Frequency and IOPMSystemSleepPolicyVariables Decoding 8 | * 9 | * Copyright (c) 2018-2022 vit9696. All rights reserved. 10 | * 11 | * Thanks to Apple for XNU Debug Information <3. 12 | */ 13 | 14 | LittleEndian(); 15 | 16 | typedef unsigned char uint8_t; 17 | typedef uint16 uint16_t; 18 | typedef uint32 uint32_t; 19 | typedef uint64 uint64_t; 20 | 21 | /* These enum values are passed as pmCPUControl commands and are also used in /dev/xcpm ioctl */ 22 | enum { 23 | /* Calls FreeStats(cmd, data) */ 24 | LEGACY_PM_FREE_STATS = 0x20005001, 25 | /* Calls pmProcessor->EnableCStateLimit(1) */ 26 | LEGACY_ENABLE_PSTATE_LIMIT_1 = 0x20005022, 27 | /* Calls pmProcessor->EnableCStateLimit(0) */ 28 | LEGACY_ENABLE_PSTATE_LIMIT_0 = 0x20005023, 29 | /* Calls i386_pmsStart(cmd, data) */ 30 | LEGACY_PM_START = 0x20005032, 31 | /* Calls i386_pmsPark -> pmStopCPU */ 32 | LEGACY_PM_PSTATE_RESET = 0x20005033, 33 | /* Calls i386_pmsPark -> pmStopCPU and then i386_SetPState(501) */ 34 | LEGACY_PM_PSTATE_501 = 0x20005035, 35 | /* Calls i386_pmsPark -> pmStopCPU and then i386_SetPState(500) */ 36 | LEGACY_PM_PSTATE_500 = 0x20005036, 37 | /* Calls i386_pmsSleep -> pmStopCPU */ 38 | LEGACY_PM_SLEEP = 0x20005037, 39 | /* Calls i386_pmsPark -> pmStopCPU, supposedly EXIT */ 40 | LEGACY_PM_PSTATE_RESET2 = 0x20005039, 41 | /* Calls pmSetTurboHWState(15) */ 42 | LEGACY_PM_SET_TURBO_HWSTATE_15 = 0x20005045, 43 | /* Calls mCPUStepperStart(cmd, data) */ 44 | LEGACY_PM_STEPPER_START = 0x20005071, 45 | /* Calls pmCPUStepperStop(cmd, data) */ 46 | LEGACY_PM_STEPPER_STOP = 0x20005072, 47 | /* Calls pmInitStepperTests and tests */ 48 | LEGACY_PM_RUN_TESTS = 0x200050B9, 49 | /* Calls pmCPUStepperCopyOriginalProgram(cmd, data) */ 50 | LEGACY_PM_COPY_ORIGINAL_PROGRAM = 0x20005073, 51 | /* Unimplemented for any processor */ 52 | LEGACY_PM_UKNOWN_OFF160 = 0x80085004, 53 | /* Contains number of CPUs and something else */ 54 | LEGACY_PM_GET_CPUINFO = 0x80085005, 55 | /* Sets HPET parameters */ 56 | LEGACY_PM_SET_HPETINFO = 0x80085007, 57 | /* Sets CSTATES and PSTATES to enabled */ 58 | LEGACY_PM_ENABLE_STATES = 0x80085009, 59 | /* Sets CSTATES and PSTATES to enabled */ 60 | LEGACY_PM_DISABLE_STATES = 0x8008500A, 61 | 62 | 63 | SEND_PSTATE_TABLE_INFO_AICPM_1 = 0x800850A2, 64 | SEND_PSTATE_TABLE_INFO_AICPM_2 = 0x800850C3, 65 | 66 | /* TODO: continue */ 67 | 68 | /* Calls xcpm_ioctl_get_version */ 69 | XCPM_GET_VERSION = 0xC0045800, 70 | /* Calls xcpm_ioctl_set_thermal_levels */ 71 | XCPM_SET_THERMAL_LEVELS = 0xC0045814, 72 | /* Calls xcpm_ioctl_get_thermal_levels */ 73 | XCPM_GET_THERMAL_LEVELS = 0xC0045815, 74 | /* Calls xcpm_ioctl_set_min_thermal_levels */ 75 | XCPM_SET_MIN_THERMAL_LEVELS = 0xC0045818, 76 | /* Calls xcpm_ioctl_get_min_thermal_levels */ 77 | XCPM_GET_MIN_THERMAL_LEVELS = 0xC0045819, 78 | /* Calls xcpm_ioctl_poll_thermal_levels */ 79 | XCPM_POLL_THERMAL_LEVELS = 0xC004581A, 80 | /* Calls xcpm_ioctl_set_qos_thermal_thresholds */ 81 | XCPM_SET_QOS_THERMAL_THRESHOLDS = 0xC004581B, 82 | /* Calls xcpm_ioctl_get_qos_thermal_thresholds */ 83 | XCPM_GET_QOS_THERMAL_THRESHOLDS = 0xC004581C, 84 | /* Calls xcpm_ioctl_ui_boost_enable */ 85 | XCPM_UI_BOOST_ENABLE = 0xC004581E, 86 | /* Calls xcpm_ioctl_set_power_source */ 87 | XCPM_SET_POWER_SOURCE = 0xC004581F, 88 | /* Calls xcpm_ioctl_get_pstate_limits for PL_SMC_STD */ 89 | XCPM_GET_PSTATE_LIMITS_SMC_STD = 0xC0085802, 90 | /* Calls xcpm_ioctl_set_pstate_limits for PL_SMC_STD */ 91 | XCPM_SET_PSTATE_LIMITS_SMC_STD = 0xC0085803, 92 | /* Calls xcpm_ioctl_get_forced_idle */ 93 | XCPM_GET_FORCED_IDLE = 0xC008580A, 94 | /* Calls xcpm_ioctl_set_forced_idle */ 95 | XCPM_SET_FORCED_IDLE = 0xC008580B, 96 | /* Calls xcpm_ioctl_get_pstate_limits for PL_TOOL_SOFT */ 97 | XCPM_GET_PSTATE_LIMITS_TOOL_SOFT = 0xC0085810, 98 | /* Calls xcpm_ioctl_set_pstate_limits for PL_TOOL_SOFT */ 99 | XCPM_SET_PSTATE_LIMITS_TOOL_SOFT = 0xC0085811, 100 | /* Calls xcpm_ioctl_get_pstate_limits for PL_SMC_BOOST */ 101 | XCPM_GET_PSTATE_LIMITS_SMC_BOOST = 0xC0085820, 102 | /* Calls xcpm_ioctl_set_pstate_limits for PL_SMC_BOOST */ 103 | XCPM_SET_PSTATE_LIMITS_SMC_BOOST = 0xC0085821, 104 | /* Calls xcpm_ioctl_get_cstate_info */ 105 | XCPM_GET_CSTATE_INFO = 0xC0155804, 106 | /* Calls xcpm_ioctl_set_cstate_info */ 107 | XCPM_SET_CSTATE_INFO = 0xC0155805, 108 | /* Calls xcpm_ioctl_get_limit_stats */ 109 | XCPM_GET_LIMIT_STATS = 0xC0185813, 110 | /* Calls xcpm_ioctl_ws_stat_update */ 111 | XCPM_WS_STAT_UPDATE = 0xC030581D, 112 | /* Calls xcpm_ioctl_get_pstate_table */ 113 | XCPM_GET_PSTATE_TABLE = 0x20005801, 114 | /* Calls xcpm_ioctl_get_freq_vectors */ 115 | XCPM_GET_FREQUENCY_VECTORS = 0x20005806, 116 | /* Calls xcpm_ioctl_set_freq_vectors */ 117 | XCPM_SET_FREQUENCY_VECTORS = 0x20005807, 118 | /* Calls xcpm_dvfs_pause */ 119 | XCPM_DVFS_PAUSE = 0x20005808, 120 | /* Calls xcpm_dvfs_resume */ 121 | XCPM_DVFS_RESUME = 0x20005809, 122 | /* Calls xcpm_ioctl_get_pstate_ctrs */ 123 | XCPM_GET_PSTATE_CTRS = 0x2000580D, 124 | /* Calls xcpm_enable_pstate_ctrs */ 125 | XCPM_ENABLE_PSTATE_CTRS = 0x2000580E, 126 | /* Calls xcpm_ioctl_set_pstate_table */ 127 | XCPM_SET_PSTATE_TABLE = 0x2000580F, 128 | /* Calls xcpm_ioctl_get_cpu_status */ 129 | XCPM_GET_CPU_STATUS = 0x20005812, 130 | /* Calls xcpm_ioctl_get_qos_names */ 131 | XCPM_GET_QOS_NAMES = 0x20005816, 132 | /* Calls xcpm_ioctl_get_qos_times */ 133 | XCPM_SET_QOS_TIMES = 0x20005817, 134 | 135 | }; 136 | 137 | enum xcpmio_fv_t { 138 | XCPMIO_FV_NONE = 0x0, 139 | XCPMIO_FV_ABSOLUTE = 0x1, 140 | XCPMIO_FV_NON_TURBO_PCT = 0x2, 141 | XCPMIO_FV_TURBO_PCT = 0x3, 142 | XCPMIO_FV_LPM_PCT = 0x4, 143 | XCPMIO_FMAX_VMIN = 0x5, 144 | }; 145 | 146 | typedef struct xcpmio_idle { 147 | uint64_t idle_duration; 148 | uint8_t idle_next; 149 | uint8_t idle_scale_percent; 150 | } xcpmio_idle_t; 151 | 152 | typedef struct xcpmio_vector { 153 | uint32_t fv_specifier; 154 | xcpmio_fv_t fv_type; 155 | uint32_t fv_mhz; 156 | uint64_t fv_ttd_us; 157 | xcpmio_idle_t idle[16]; 158 | } xcpmio_vector_t; 159 | 160 | typedef struct xcpmio_qos { 161 | char qos_name[16]; 162 | uint8_t qos_min_index; 163 | uint8_t qos_max_index; 164 | uint16_t qos_scales[32]; 165 | uint8_t qos_epp; 166 | } xcpmio_qos_t; 167 | 168 | typedef union xcpmio_var_value { 169 | uint64_t v_uint64; 170 | char v_string[16]; 171 | } xcpmio_var_value_t; 172 | 173 | typedef struct xcpmio_var { 174 | char var_name[16]; 175 | uint32_t var_type; 176 | xcpmio_var_value_t var_value; 177 | } xcpmio_var_t; 178 | 179 | typedef struct xcpmio_vectors { 180 | uint32 version; 181 | xcpmio_vector_t vector[32]; 182 | xcpmio_qos_t qos[16]; 183 | xcpmio_var_t vars[16]; 184 | } xcpmio_vectors_t; 185 | 186 | 187 | enum IOPMSleepReason { 188 | kIOPMSleepReasonClamshell = 101, 189 | kIOPMSleepReasonPowerButton = 102, 190 | kIOPMSleepReasonSoftware = 103, 191 | kIOPMSleepReasonOSSwitchHibernate = 104, 192 | kIOPMSleepReasonIdle = 105, 193 | kIOPMSleepReasonLowPower = 106, 194 | kIOPMSleepReasonThermalEmergency = 107, 195 | kIOPMSleepReasonMaintenance = 108, 196 | kIOPMSleepReasonSleepServiceExit = 109, 197 | kIOPMSleepReasonDarkWakeThermalEmergency = 110 198 | }; 199 | 200 | #define kIOPMSystemSleepPolicySignature 0x54504c53 201 | #define kIOPMSystemSleepPolicyVersion 2 202 | 203 | typedef struct IOPMSystemSleepPolicyVariables_ { 204 | uint32_t signature; /* kIOPMSystemSleepPolicySignature */ 205 | uint32_t version; /* kIOPMSystemSleepPolicyVersion */ 206 | uint64_t currentCapability; /* current system capability bits */ 207 | uint64_t highestCapability; /* highest system capability bits */ 208 | uint64_t sleepFactors; /* sleep factor bits */ 209 | IOPMSleepReason sleepReason; /* kIOPMSleepReason* */ 210 | uint32_t sleepPhase; /* identify the sleep phase */ 211 | uint32_t hibernateMode; /* current hibernate mode */ 212 | uint32_t standbyDelay; /* standby delay in seconds */ 213 | uint32_t standbyTimer; /* standby timer in seconds */ 214 | uint32_t poweroffDelay; /* auto-poweroff delay in seconds */ 215 | uint32_t scheduledAlarms; /* bitmask of scheduled alarm types */ 216 | uint32_t poweroffTimer; /* auto-poweroff timer in seconds */ 217 | uint32_t reserved[49]; /* pad sizeof 256 bytes */ 218 | } IOPMSystemSleepPolicyVariables; 219 | 220 | typedef struct IOPMSystemSleepPolicyEntryV1_ { 221 | uint32_t factorMask; 222 | uint32_t factorBits; 223 | uint32_t sleepFlags; 224 | uint32_t wakeEvents; 225 | } IOPMSystemSleepPolicyEntryV1; 226 | 227 | typedef struct IOPMSystemSleepPolicyTableV1_ { 228 | uint32_t signature; 229 | uint16_t version; 230 | uint16_t entryCount; 231 | IOPMSystemSleepPolicyEntryV1 entries[entryCount]; 232 | } IOPMSystemSleepPolicyTableV1; 233 | 234 | /* Unused currently, yet present in plists. */ 235 | typedef struct IOPMSystemSleepPolicyEntryV2_ { 236 | uint32_t unknown[8]; 237 | } IOPMSystemSleepPolicyEntryV2; 238 | 239 | typedef struct IOPMSystemSleepPolicyTableV2_ { 240 | uint32_t signature; 241 | uint16_t version; 242 | uint16_t entryCount; 243 | IOPMSystemSleepPolicyEntryV2 entries[entryCount]; 244 | } IOPMSystemSleepPolicyTableV2; 245 | 246 | if (ReadUInt(0) == kIOPMSystemSleepPolicySignature) { 247 | if (ReadUShort(4) == 1) 248 | IOPMSystemSleepPolicyTableV1 sleep_policy; 249 | else if (ReadUShort(4) == 2) 250 | IOPMSystemSleepPolicyTableV2 sleep_policy; 251 | } else if (ReadUInt(0) == 2) { 252 | xcpmio_vectors_t vectors; 253 | } 254 | -------------------------------------------------------------------------------- /Tools/FrequencyVectors.tcl: -------------------------------------------------------------------------------- 1 | # 2 | # HexFiend 2.14.1 Binary Template 3 | # 4 | # File: X86PlatformPlugin.kext resources (IOPlatformPluginFamily.kext) 5 | # Authors: vit9696 6 | # Version: 0.1 7 | # Purpose: Intel XCPM Frequency and IOPMSystemSleepPolicyVariables Decoding 8 | # 9 | # Adapted to HexFiend format by usr-sse2. 10 | # Copyright (c) 2018-2022 vit9696. All rights reserved. 11 | # 12 | # Thanks to Apple for XNU Debug Information <3. 13 | # 14 | 15 | little_endian 16 | 17 | proc uint32_dict { name dict {default ""} } { 18 | set n [uint32] 19 | set v $default 20 | if { [dict exists $dict $n] } { 21 | set v [dict get $dict $n] 22 | } 23 | entry $name [format "%s (%d)" $v $n] 4 [expr [pos]-4] 24 | return $n 25 | } 26 | 27 | set xcpmio_fv_t [dict create \ 28 | 0 "XCPMIO_FV_NONE" \ 29 | 1 "XCPMIO_FV_ABSOLUTE" \ 30 | 2 "XCPMIO_FV_NON_TURBO_PCT" \ 31 | 3 "XCPMIO_FV_TURBO_PCT" \ 32 | 4 "XCPMIO_FV_LPM_PCT" \ 33 | 5 "XCPMIO_FMAX_VMIN" 34 | ] 35 | 36 | proc xcpmio_idle_t {} { 37 | uint64 "idle_duration" 38 | uint8 "idle_next" 39 | uint8 "idle_scale_percent" 40 | } 41 | 42 | proc xcpmio_vector_t {} { 43 | global xcpmio_fv_t 44 | uint32 "fv_specifier" 45 | uint32_dict "fv_type" $xcpmio_fv_t "" 46 | uint32 "fv_mhz" 47 | uint64 "fv_ttd_us" 48 | section "idle" { 49 | for {set i 0} {$i < 16} {incr i} { 50 | section "$i" { 51 | xcpmio_idle_t 52 | } 53 | } 54 | } 55 | } 56 | 57 | proc xcpmio_qos_t {} { 58 | ascii 16 "qos_name" 59 | uint8 "qos_min_index" 60 | uint8 "qos_max_index" 61 | section "qos_scales" { 62 | for {set i 0} {$i < 32} {incr i} { 63 | uint16 "$i" 64 | } 65 | } 66 | uint8 "qos_epp" 67 | } 68 | 69 | set xcpmio_var_type_t [dict create \ 70 | 0 "UINT64" \ 71 | 1 "STRING" 72 | ] 73 | 74 | proc xcpmio_var_t {} { 75 | global xcpmio_var_type_t 76 | ascii 16 "var_name" 77 | set var_type [uint32] 78 | move -4 79 | uint32_dict "var_type" $xcpmio_var_type_t "" 80 | if {$var_type == 0} { 81 | uint64 "v_uint64" 82 | move 8 83 | } elseif {$var_type == 1} { 84 | ascii 16 "v_string" 85 | } else { 86 | move 16 87 | } 88 | } 89 | 90 | proc xcpmio_vectors_t {} { 91 | uint32 "version" 92 | section "vector" { 93 | for {set i 0} {$i < 32} {incr i} { 94 | section "$i" { 95 | xcpmio_vector_t 96 | } 97 | } 98 | } 99 | section "qos" { 100 | for {set i 0} {$i < 16} {incr i} { 101 | section "$i" { 102 | xcpmio_qos_t 103 | } 104 | } 105 | } 106 | section "vars" { 107 | for {set i 0} {$i < 16} {incr i} { 108 | section "$i" { 109 | xcpmio_var_t 110 | } 111 | } 112 | } 113 | } 114 | 115 | set kIOPMSystemSleepPolicySignature 0x54504c53 116 | set kIOPMSystemSleepPolicyVersion 2 117 | 118 | proc IOPMSystemSleepPolicyEntryV1 {} { 119 | uint32 "factorMask" 120 | uint32 "factorBits" 121 | uint32 "sleepFlags" 122 | uint32 "wakeEvents" 123 | } 124 | 125 | proc IOPMSystemSleepPolicyTableV1 {} { 126 | uint32 "signature" 127 | uint16 "version" 128 | set entryCount [uint16] 129 | move -2 130 | uint16 "entryCount" 131 | section "entries" { 132 | for {set i 0} {$i < $entryCount} {incr i} { 133 | section "$i" { 134 | IOPMSystemSleepPolicyEntryV1 135 | } 136 | } 137 | } 138 | } 139 | 140 | proc IOPMSystemSleepPolicyEntryV2 {} { 141 | section "unknown" { 142 | for {set i 0} {$i < 8} {incr i} { 143 | uint32 "$i" 144 | } 145 | } 146 | } 147 | 148 | proc IOPMSystemSleepPolicyTableV2 {} { 149 | uint32 "signature" 150 | uint16 "version" 151 | set entryCount [uint16] 152 | move -2 153 | uint16 "entryCount" 154 | section "entries" { 155 | for {set i 0} {$i < $entryCount} {incr i} { 156 | section "$i" { 157 | IOPMSystemSleepPolicyEntryV2 158 | } 159 | } 160 | } 161 | } 162 | 163 | 164 | set sleepPolicySignature [uint32] 165 | if {$sleepPolicySignature == $kIOPMSystemSleepPolicySignature} { 166 | set sleepPolicyTableVersion [uint16] 167 | move -6 168 | section "sleep_policy" { 169 | if {$sleepPolicyTableVersion == 1} { 170 | IOPMSystemSleepPolicyTableV1 171 | } else { 172 | IOPMSystemSleepPolicyTableV2 173 | } 174 | } 175 | } else { 176 | move -4 177 | xcpmio_vectors_t; 178 | } 179 | -------------------------------------------------------------------------------- /Tools/ResourceConverter.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | kextFile="CPUFriendDataProvider.kext" 4 | ssdtFile="ssdt_data.dsl" 5 | 6 | function abort() { 7 | echo "ERROR: $1!" 8 | exit 1 9 | } 10 | 11 | function showHelp() { 12 | echo "Usage:" 13 | echo 14 | echo "-h, --help Show this help message." 15 | echo "-a, --acpi Create ${ssdtFile} with CPU power management data provided by file." 16 | echo 17 | echo "-k, --kext (version) Create ${kextFile} with CPU power management data provided by file." 18 | echo "For cross-version compatibility, version can be specified when creating the kext bundle to be used together with OC MinKernel/MaxKernel." 19 | echo "e.g. $0 --kext path/to/PM/plist 110 - This creates CPUFriendDataProvider_110.kext." 20 | } 21 | 22 | function genSSDT() { 23 | local src="$1" 24 | local data2Hex=$(xxd -pr -u "${src}" | tr -d '\n' | sed 's/.\{2\}/\0x&, /g') 25 | 26 | local ifs=$IFS 27 | IFS=$'\n' 28 | local cpuNames=(`ioreg -p IODeviceTree -c IOACPIPlatformDevice -k cpu-type -k clock-frequency | egrep name | sed -e 's/ *[-|="]//g'`) 29 | local cpuName="${cpuNames[0]}" 30 | # restore IFS 31 | IFS=$ifs 32 | 33 | cat << EOF > "${ssdtFile}" 34 | DefinitionBlock ("", "SSDT", 2, "ACDT", "FreqData", 0x00000000) 35 | { 36 | // 37 | // CPU device name, detected from ioreg. 38 | // 39 | External (_PR_.${cpuName}, DeviceObj) 40 | 41 | Scope (\_PR.${cpuName}) 42 | { 43 | Method (_DSM, 4, NotSerialized) 44 | { 45 | If (LEqual (Arg2, Zero)) 46 | { 47 | Return (Buffer (One) 48 | { 49 | 0x03 50 | }) 51 | } 52 | 53 | Return (Package (0x04) 54 | { 55 | // 56 | // Inject plugin-type = 1 to load X86*.kext 57 | // 58 | "plugin-type", 59 | One, 60 | 61 | // 62 | // Power management data file to be injected by CPUFriend. 63 | // 64 | "cf-frequency-data", 65 | Buffer () 66 | { 67 | ${data2Hex} 68 | } 69 | }) 70 | } 71 | } 72 | } 73 | EOF 74 | } 75 | 76 | function genKext() { 77 | local src="$1" 78 | local dataBase64=$(cat "$src" | base64) 79 | 80 | mkdir -p "${kextFile}/Contents" && pushd "${kextFile}/Contents" &> /dev/null 81 | 82 | cat << EOF > Info.plist 83 | 84 | 85 | 86 | 87 | CFBundleIdentifier 88 | org.acidanthera.driver.CPUFriendDataProvider 89 | CFBundleInfoDictionaryVersion 90 | 6.0 91 | CFBundleName 92 | CPUFriendDataProvider 93 | CFBundlePackageType 94 | KEXT 95 | CFBundleShortVersionString 96 | 1.0.1 97 | CFBundleVersion 98 | 1.0.1 99 | IOKitPersonalities 100 | 101 | CPUFriendDataProvider 102 | 103 | CFBundleIdentifier 104 | com.apple.driver.AppleACPIPlatform 105 | IOClass 106 | AppleACPICPU 107 | IONameMatch 108 | processor 109 | IOProbeScore 110 | 1100 111 | IOProviderClass 112 | IOACPIPlatformDevice 113 | cf-frequency-data 114 | ${dataBase64} 115 | 116 | 117 | NSHumanReadableCopyright 118 | Copyright © 2017-2022 PMheart. All rights reserved. 119 | OSBundleRequired 120 | Root 121 | 122 | 123 | EOF 124 | 125 | popd &> /dev/null 126 | } 127 | 128 | function main() { 129 | case "$1" in 130 | -h|--help) 131 | showHelp 132 | exit 0 133 | ;; 134 | 135 | -a|--acpi ) 136 | # now $1 is the resource plist 137 | shift 138 | if [ ! -f "$1" ]; then 139 | abort "$1 does not exist!" 140 | fi 141 | 142 | if [ -f "${ssdtFile}" ]; then 143 | read -p "${ssdtFile} already exists, override? (y/N) " ask4NewSSDT 144 | case "${ask4NewSSDT}" in 145 | y|Y ) 146 | ;; 147 | 148 | * ) 149 | exit 0 150 | ;; 151 | esac 152 | 153 | rm -f "${ssdtFile}" 154 | fi 155 | 156 | genSSDT "$1" 157 | ;; 158 | 159 | -k|--kext ) 160 | # now $1 is the resource plist 161 | shift 162 | if [ ! -f "$1" ]; then 163 | abort "$1 does not exist!" 164 | fi 165 | 166 | # $2 is the optional version info 167 | if [ "$2" != "" ]; then 168 | kextFile="CPUFriendDataProvider_$2.kext" 169 | fi 170 | 171 | if [ -d "${kextFile}" ]; then 172 | read -p "${kextFile} already exists, override? (y/N) " ask4NewKext 173 | case "${ask4NewKext}" in 174 | y|Y ) 175 | ;; 176 | 177 | * ) 178 | exit 0 179 | ;; 180 | esac 181 | 182 | rm -rf "${kextFile}" 183 | fi 184 | 185 | genKext "$1" 186 | ;; 187 | 188 | * ) 189 | showHelp 190 | exit 1 191 | ;; 192 | esac 193 | } 194 | 195 | main "$@" 196 | exit 0 197 | --------------------------------------------------------------------------------