From e5543d8a856fff747fead9e038c5c51f824dca97 Mon Sep 17 00:00:00 2001 From: vit9696 Date: Wed, 6 Jan 2021 20:11:14 +0300 Subject: [PATCH] Implemented `unfairgva` device property for MP5,1 --- Changelog.md | 3 + Manual/FAQ.Chart.md | 1 + WhateverGreen.xcodeproj/project.pbxproj | 10 ++- WhateverGreen/kern_shiki.cpp | 32 +------ WhateverGreen/kern_shiki.hpp | 5 -- WhateverGreen/kern_unfair.cpp | 110 ++++++++++++++++++++++++ WhateverGreen/kern_unfair.hpp | 71 +++++++++++++++ WhateverGreen/kern_weg.cpp | 56 ++++++++++-- WhateverGreen/kern_weg.hpp | 11 +++ 9 files changed, 257 insertions(+), 42 deletions(-) create mode 100644 WhateverGreen/kern_unfair.cpp create mode 100644 WhateverGreen/kern_unfair.hpp diff --git a/Changelog.md b/Changelog.md index 7f69f275..374621d4 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ WhateverGreen Changelog ======================= +#### v1.4.7 +- Implemented `unfairgva` device property (use `<01 00 00 00>` value for MP5,1 to enable streaming DRM) + #### v1.4.6 - Backlight registers fix replaces the previous Coffee Lake backlight fix and is now available on Intel Ice Lake platforms. - Boot argument `igfxcflbklt=1` as well as device property `enable-cfl-backlight-fix` are deprecated and replaced by `-igfxblr` and `enable-backlight-registers-fix`. diff --git a/Manual/FAQ.Chart.md b/Manual/FAQ.Chart.md index be5dd8c6..ce1f2162 100644 --- a/Manual/FAQ.Chart.md +++ b/Manual/FAQ.Chart.md @@ -33,6 +33,7 @@ Things to keep in mind: - WhateverGreen Shiki functionality is not planned for inclusion for macOS 11 - AMD GPU video decoder preference can be chosen through preferences overrides for some types of DRM content (like Apple TV and iTunes movie streaming) - Only IGPU-free Mac models allow for full DRM content access given a compatible AMD GPU video decoder +- For old CPUs (e.g. Xeons or Quad 2 Quad) and supported AMD GPUs injecting `unfairgva` with `<01 00 00 00>` value is required for streaming DRM List of overrides: diff --git a/WhateverGreen.xcodeproj/project.pbxproj b/WhateverGreen.xcodeproj/project.pbxproj index 8094ceda..ef94c804 100644 --- a/WhateverGreen.xcodeproj/project.pbxproj +++ b/WhateverGreen.xcodeproj/project.pbxproj @@ -14,6 +14,8 @@ CE1970FF21C380DF00B02AB4 /* kern_nvhda.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE1970FD21C380DF00B02AB4 /* kern_nvhda.cpp */; }; CE19710021C380DF00B02AB4 /* kern_nvhda.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CE1970FE21C380DF00B02AB4 /* kern_nvhda.hpp */; }; CE1F61B92432DEE800201DF4 /* kern_igfx_debug.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE1F61B82432DEE800201DF4 /* kern_igfx_debug.cpp */; }; + CE3DADB025A425FC009991FB /* kern_unfair.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE3DADAE25A425FC009991FB /* kern_unfair.cpp */; }; + CE3DADB125A425FC009991FB /* kern_unfair.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CE3DADAF25A425FC009991FB /* kern_unfair.hpp */; }; CE405ED91E4A080700AA0B3D /* plugin_start.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE405ED81E4A080700AA0B3D /* plugin_start.cpp */; }; CE766ED6210763B200A84567 /* kern_guc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE766ED4210763B200A84567 /* kern_guc.cpp */; }; CE766ED7210763B200A84567 /* kern_guc.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CE766ED5210763B200A84567 /* kern_guc.hpp */; }; @@ -92,6 +94,8 @@ CE1F61B82432DEE800201DF4 /* kern_igfx_debug.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = kern_igfx_debug.cpp; sourceTree = ""; }; CE271B4C1F319BD000D2BC1C /* reference.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = reference.cpp; sourceTree = ""; }; CE363A7D20FE4EEC00ED7DC0 /* IntelFramebuffer.bt */ = {isa = PBXFileReference; lastKnownFileType = text; name = IntelFramebuffer.bt; path = Manual/IntelFramebuffer.bt; sourceTree = ""; }; + CE3DADAE25A425FC009991FB /* kern_unfair.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = kern_unfair.cpp; sourceTree = ""; }; + CE3DADAF25A425FC009991FB /* kern_unfair.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_unfair.hpp; sourceTree = ""; }; CE405EBA1E49DD7100AA0B3D /* kern_compression.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_compression.hpp; sourceTree = ""; }; CE405EBB1E49DD7100AA0B3D /* kern_disasm.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_disasm.hpp; sourceTree = ""; }; CE405EBC1E49DD7100AA0B3D /* kern_file.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = kern_file.hpp; sourceTree = ""; }; @@ -219,6 +223,8 @@ CEA03B5D20EE825A00BA842F /* kern_weg.hpp */, CE7FC0B220F6809600138088 /* kern_shiki.cpp */, CE7FC0B320F6809600138088 /* kern_shiki.hpp */, + CE3DADAE25A425FC009991FB /* kern_unfair.cpp */, + CE3DADAF25A425FC009991FB /* kern_unfair.hpp */, CE8190A11F1E3ECE00DE95F4 /* kern_model.cpp */, CE7FC0C920F682A200138088 /* kern_resources.cpp */, CE7FC0C820F682A200138088 /* kern_resources.hpp */, @@ -331,6 +337,7 @@ CEA03B5F20EE825A00BA842F /* kern_weg.hpp in Headers */, E2BE6CE220FB209400ED2D55 /* kern_fb.hpp in Headers */, CE7FC0AB20F55E7400138088 /* kern_ngfx.hpp in Headers */, + CE3DADB125A425FC009991FB /* kern_unfair.hpp in Headers */, CE7FC0CA20F682A300138088 /* kern_resources.hpp in Headers */, CE7FC0AF20F5622700138088 /* kern_igfx.hpp in Headers */, CEC0863624331E9B00F5B701 /* kern_agdc.hpp in Headers */, @@ -391,7 +398,7 @@ 1C748C1E1C21952C0024EED2 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1220; + LastUpgradeCheck = 1230; ORGANIZATIONNAME = vit9696; TargetAttributes = { 1C748C261C21952C0024EED2 = { @@ -472,6 +479,7 @@ CEA03B5E20EE825A00BA842F /* kern_weg.cpp in Sources */, CE8190A21F1E3ECE00DE95F4 /* kern_model.cpp in Sources */, CE1970FF21C380DF00B02AB4 /* kern_nvhda.cpp in Sources */, + CE3DADB025A425FC009991FB /* kern_unfair.cpp in Sources */, D5C32F5624FC45D30078A824 /* kern_igfx_memory.cpp in Sources */, CE405ED91E4A080700AA0B3D /* plugin_start.cpp in Sources */, CE7FC0CB20F682A300138088 /* kern_resources.cpp in Sources */, diff --git a/WhateverGreen/kern_shiki.cpp b/WhateverGreen/kern_shiki.cpp index 36a5dfe7..93d84f4a 100644 --- a/WhateverGreen/kern_shiki.cpp +++ b/WhateverGreen/kern_shiki.cpp @@ -15,6 +15,7 @@ #include #include +#include "kern_weg.hpp" #include "kern_resources.hpp" void SHIKI::init() { @@ -39,33 +40,6 @@ void SHIKI::deinit() { } -bool SHIKI::getBootArgument(DeviceInfo *info, const char *name, void *bootarg, int size) { - if (PE_parse_boot_argn(name, bootarg, size)) - return true; - - for (size_t i = 0; i < info->videoExternal.size(); i++) { - auto prop = OSDynamicCast(OSData, info->videoExternal[i].video->getProperty(name)); - auto propSize = prop ? prop->getLength() : 0; - if (propSize > 0 && propSize <= size) { - lilu_os_memcpy(bootarg, prop->getBytesNoCopy(), propSize); - memset(static_cast(bootarg) + propSize, 0, size - propSize); - return true; - } - } - - if (info->videoBuiltin) { - auto prop = OSDynamicCast(OSData, info->videoBuiltin->getProperty(name)); - auto propSize = prop ? prop->getLength() : 0; - if (propSize > 0 && propSize <= size) { - lilu_os_memcpy(bootarg, prop->getBytesNoCopy(), propSize); - memset(static_cast(bootarg) + propSize, 0, size - propSize); - return true; - } - } - - return false; -} - UserPatcher::BinaryModPatch *SHIKI::getPatchSection(uint32_t section) { for (size_t i = 0; i < ADDPR(binaryModSize); i++) { auto patches = ADDPR(binaryMod)[i].patches; @@ -97,7 +71,7 @@ void SHIKI::processKernel(KernelPatcher &patcher, DeviceInfo *info) { lilu_os_strlcpy(reinterpret_cast(selfBoardId), bdi.boardIdentifier, sizeof(selfBoardId)); int bootarg {0}; - if (getBootArgument(info, "shikigva", &bootarg, sizeof(bootarg))) { + if (WEG::getVideoArgument(info, "shikigva", &bootarg, sizeof(bootarg))) { forceOnlineRenderer = bootarg & ForceOnlineRenderer; allowNonBGRA = bootarg & AllowNonBGRA; forceCompatibleRenderer = bootarg & ForceCompatibleRenderer; @@ -187,7 +161,7 @@ void SHIKI::processKernel(KernelPatcher &patcher, DeviceInfo *info) { // Custom board-id may be overridden by a boot-arg if (replaceBoardID) { - if (getBootArgument(info, "shiki-id", customBoardID, sizeof(customBoardID))) + if (WEG::getVideoArgument(info, "shiki-id", customBoardID, sizeof(customBoardID))) customBoardID[sizeof(customBoardID)-1] = '\0'; else snprintf(customBoardID, sizeof(customBoardID), "Mac-27ADBB7B4CEE8E61"); // iMac14,2 diff --git a/WhateverGreen/kern_shiki.hpp b/WhateverGreen/kern_shiki.hpp index cfea43fe..ca2b90e4 100644 --- a/WhateverGreen/kern_shiki.hpp +++ b/WhateverGreen/kern_shiki.hpp @@ -135,11 +135,6 @@ class SHIKI { */ bool setCompatibleRendererPatch(); - /** - * Get overridable boot argument from kernel args (priority) and GPU properties - */ - bool getBootArgument(DeviceInfo *info, const char *name, void *bootarg, int size); - /** * Get patch by section */ diff --git a/WhateverGreen/kern_unfair.cpp b/WhateverGreen/kern_unfair.cpp new file mode 100644 index 00000000..69f426c4 --- /dev/null +++ b/WhateverGreen/kern_unfair.cpp @@ -0,0 +1,110 @@ +// +// kern_unfair.cpp +// WhateverGreen +// +// Copyright © 2021 vit9696. All rights reserved. +// + +#include "kern_unfair.hpp" +#include "kern_weg.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +UNFAIR *UNFAIR::callbackUNFAIR; + +void UNFAIR::init() { + callbackUNFAIR = this; + + disableUnfair = !(lilu.getRunMode() & LiluAPI::RunningNormal); + disableUnfair |= checkKernelArgument("-unfairoff"); + + if (disableUnfair) + return; + + sharedCachePath = UserPatcher::getSharedCachePath(); + DBGLOG("unfair", "chosen shared cache path is %s", sharedCachePath); +} + +void UNFAIR::deinit() { + +} + +void UNFAIR::csValidatePage(vnode *vp, memory_object_t pager, memory_object_offset_t page_offset, const void *data, int *validated_p, int *tainted_p, int *nx_p) { + FunctionCast(csValidatePage, callbackUNFAIR->orgCsValidatePage)(vp, pager, page_offset, data, validated_p, tainted_p, nx_p); + + char path[PATH_MAX]; + int pathlen = PATH_MAX; + if (vn_getpath(vp, path, &pathlen) == 0) { + //DBGLOG("unfair", "csValidatePage %s", path); + + if ((callbackUNFAIR->unfairGva & UnfairDyldSharedCache) != 0 && UNLIKELY(strcmp(path, callbackUNFAIR->sharedCachePath) == 0)) { + if ((callbackUNFAIR->unfairGva & UnfairRelaxHdcpRequirements) != 0) { + static const uint8_t find[29] = { + 0x4D, 0x61, 0x63, 0x50, 0x72, 0x6F, 0x35, 0x2C, 0x31, 0x00, 0x4D, 0x61, 0x63, 0x50, 0x72, 0x6F, + 0x36, 0x2C, 0x31, 0x00, 0x49, 0x4F, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65 + }; + if (UNLIKELY(KernelPatcher::findAndReplace(const_cast(data), PAGE_SIZE, find, sizeof(find), BaseDeviceInfo::get().modelIdentifier, 20))) + DBGLOG("unfair", "patched relaxed drm model"); + } + + if ((callbackUNFAIR->unfairGva & UnfairCustomAppleGvaBoardId) != 0) { + static const uint8_t find[18] = { + 0x62, 0x6F, 0x61, 0x72, 0x64, 0x2D, 0x69, 0x64, 0x00, 0x68, 0x77, 0x2E, 0x6D, 0x6F, 0x64, 0x65, + 0x6C + }; + static const uint8_t repl[5] = { + 0x68, 0x77, 0x67, 0x76, 0x61 + }; + if (UNLIKELY(KernelPatcher::findAndReplace(const_cast(data), PAGE_SIZE, find, sizeof(find), repl, sizeof(repl)))) + DBGLOG("unfair", "patched board-id -> hwgva-id"); + } + + } else if ((callbackUNFAIR->unfairGva & UnfairAllowHardwareDrmStreamDecoderOnOldCpuid) != 0 && + (UNLIKELY(strcmp(path, "/System/Library/PrivateFrameworks/CoreLSKDMSE.framework/Versions/A/CoreLSKDMSE") == 0) || + UNLIKELY(strcmp(path, "/System/Library/PrivateFrameworks/CoreLSKD.framework/Versions/A/CoreLSKD") == 0))) { + static const uint8_t find[] = {0xC7, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x0F, 0xA2}; + static const uint8_t repl[] = {0xC7, 0xC0, 0xC3, 0x06, 0x03, 0x00, 0x90, 0x90}; + if (UNLIKELY(KernelPatcher::findAndReplace(const_cast(data), PAGE_SIZE, find, sizeof(find), repl, sizeof(repl)))) + DBGLOG("unfair", "patched streaming cpuid to haswell"); + } + } +} + +void UNFAIR::processKernel(KernelPatcher &patcher, DeviceInfo *info) { + if (disableUnfair) + return; + + WEG::getVideoArgument(info, "unfairgva", &unfairGva, sizeof(unfairGva)); + if (unfairGva == 0) { + DBGLOG("unfair", "disabling unfair gva due to missing boot argument"); + disableUnfair = true; + return; + } + + DBGLOG("unfair", "activating with %d bitmask", unfairGva); + + if ((unfairGva & UnfairCustomAppleGvaBoardId) != 0) { + auto entry = IORegistryEntry::fromPath("/", gIODTPlane); + if (entry) { + DBGLOG("unfair", "setting hwgva-id to iMacPro1,1"); + entry->setProperty("hwgva-id", const_cast("Mac-7BA5B2D9E42DDD94"), static_cast(sizeof("Mac-7BA5B2D9E42DDD94"))); + entry->release(); + } else { + SYSLOG("shiki", "failed to obtain iodt tree"); + unfairGva &= ~UnfairCustomAppleGvaBoardId; + } + } + + KernelPatcher::RouteRequest csRoute("_cs_validate_page", csValidatePage, orgCsValidatePage); + if (!patcher.routeMultipleLong(KernelPatcher::KernelID, &csRoute, 1)) { + SYSLOG("unfair", "failed to route cs validation pages"); + } +} diff --git a/WhateverGreen/kern_unfair.hpp b/WhateverGreen/kern_unfair.hpp new file mode 100644 index 00000000..8cf6966e --- /dev/null +++ b/WhateverGreen/kern_unfair.hpp @@ -0,0 +1,71 @@ +// +// kern_unfair.hpp +// WhateverGreen +// +// Copyright © 2021 vit9696. All rights reserved. +// + +#ifndef kern_unfair_hpp +#define kern_unfair_hpp + +#include +#include +#include +#include + +class UNFAIR { +public: + void init(); + void deinit(); + + /** + * Property patching routine + * + * @param patcher KernelPatcher instance + * @param info device info + */ + void processKernel(KernelPatcher &patcher, DeviceInfo *info); + +private: + /** + * Private self instance for callbacks + */ + static UNFAIR *callbackUNFAIR; + + /** + * Disable unfair, based on mode + */ + bool disableUnfair {false}; + + /** + * GVA bitmask as specified in unfairgva boot argument / property. + */ + enum : uint32_t { + UnfairAllowHardwareDrmStreamDecoderOnOldCpuid = 1, + UnfairRelaxHdcpRequirements = 2, + UnfairCustomAppleGvaBoardId = 4, + UnfairDyldSharedCache = UnfairRelaxHdcpRequirements | UnfairCustomAppleGvaBoardId, + }; + + /** + * Patch rule bitmask (0 means none). + */ + uint32_t unfairGva {0}; + + /** + * Codesign page validation wrapper used for userspace patching + */ + static void csValidatePage(vnode *vp, memory_object_t pager, memory_object_offset_t page_offset, const void *data, int *validated_p, int *tainted_p, int *nx_p); + + /** + * Original codesign page validation pointer. + */ + mach_vm_address_t orgCsValidatePage {0}; + + /** + * Cyrrent shared cache. + */ + const char *sharedCachePath {nullptr}; +}; + +#endif /* kern_unfair_hpp */ diff --git a/WhateverGreen/kern_weg.cpp b/WhateverGreen/kern_weg.cpp index 5fe5c2e7..481ef107 100644 --- a/WhateverGreen/kern_weg.cpp +++ b/WhateverGreen/kern_weg.cpp @@ -137,16 +137,26 @@ void WEG::init() { igfx.init(); ngfx.init(); rad.init(); - shiki.init(); - cdf.init(); + + if (getKernelVersion() >= KernelVersion::BigSur) { + unfair.init(); + } else { + shiki.init(); + cdf.init(); + } } void WEG::deinit() { igfx.deinit(); ngfx.deinit(); rad.deinit(); - shiki.deinit(); - cdf.deinit(); + + if (getKernelVersion() >= KernelVersion::BigSur) { + unfair.deinit(); + } else { + shiki.deinit(); + cdf.deinit(); + } } void WEG::processKernel(KernelPatcher &patcher) { @@ -307,8 +317,13 @@ void WEG::processKernel(KernelPatcher &patcher) { igfx.processKernel(patcher, devInfo); ngfx.processKernel(patcher, devInfo); rad.processKernel(patcher, devInfo); - shiki.processKernel(patcher, devInfo); - cdf.processKernel(patcher, devInfo); + + if (getKernelVersion() >= KernelVersion::BigSur) { + unfair.processKernel(patcher, devInfo); + } else { + shiki.processKernel(patcher, devInfo); + cdf.processKernel(patcher, devInfo); + } DeviceInfo::deleter(devInfo); } @@ -380,7 +395,7 @@ void WEG::processKext(KernelPatcher &patcher, size_t index, mach_vm_address_t ad if (rad.processKext(patcher, index, address, size)) return; - if (cdf.processKext(patcher, index, address, size)) + if (getKernelVersion() < KernelVersion::BigSur && cdf.processKext(patcher, index, address, size)) return; } @@ -824,3 +839,30 @@ bool WEG::wrapApplePanelSetDisplay(IOService *that, IODisplay *display) { return result; } + +bool WEG::getVideoArgument(DeviceInfo *info, const char *name, void *bootarg, int size) { + if (PE_parse_boot_argn(name, bootarg, size)) + return true; + + for (size_t i = 0; i < info->videoExternal.size(); i++) { + auto prop = OSDynamicCast(OSData, info->videoExternal[i].video->getProperty(name)); + auto propSize = prop ? prop->getLength() : 0; + if (propSize > 0 && propSize <= size) { + lilu_os_memcpy(bootarg, prop->getBytesNoCopy(), propSize); + memset(static_cast(bootarg) + propSize, 0, size - propSize); + return true; + } + } + + if (info->videoBuiltin) { + auto prop = OSDynamicCast(OSData, info->videoBuiltin->getProperty(name)); + auto propSize = prop ? prop->getLength() : 0; + if (propSize > 0 && propSize <= size) { + lilu_os_memcpy(bootarg, prop->getBytesNoCopy(), propSize); + memset(static_cast(bootarg) + propSize, 0, size - propSize); + return true; + } + } + + return false; +} diff --git a/WhateverGreen/kern_weg.hpp b/WhateverGreen/kern_weg.hpp index e760a753..7d4aa0c8 100644 --- a/WhateverGreen/kern_weg.hpp +++ b/WhateverGreen/kern_weg.hpp @@ -16,6 +16,7 @@ #include "kern_ngfx.hpp" #include "kern_rad.hpp" #include "kern_shiki.hpp" +#include "kern_unfair.hpp" class IOFramebuffer; class IODisplay; @@ -25,6 +26,11 @@ class WEG { void init(); void deinit(); + /** + * Get overridable boot argument from kernel args (priority) and GPU properties + */ + static bool getVideoArgument(DeviceInfo *info, const char *name, void *bootarg, int size); + private: /** * Private self instance for callbacks @@ -56,6 +62,11 @@ class WEG { */ SHIKI shiki; + /** + * FairPlay fixes for modern operating systems + */ + UNFAIR unfair; + /** * FB_DETECT autodetects based on the installed GPU. * FB_RESET enforces -v like usual patch.