Skip to content

Commit

Permalink
Add a new submodule as an alternative to Backlight Registers Fix (BLR…
Browse files Browse the repository at this point in the history
…), fixing the 3-minute dark screen issue and making Backlight Smoother (BLS) work on mobile Coffee Lake platforms running macOS 13.4 or later (#113)
  • Loading branch information
0xFireWolf committed Jun 10, 2023
1 parent f4b09c7 commit 70ade87
Show file tree
Hide file tree
Showing 6 changed files with 713 additions and 43 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Expand Up @@ -2,6 +2,7 @@ WhateverGreen Changelog
=======================
#### v1.6.5
- Added constants for macOS 14 support
- Added a new boot argument `-igfxblt` to revert the optimizations done by the compiler in backlight related functions, fixing the 3-minute dark screen issue and making Backlight Smoother (BLS) work on mobile Coffee Lake platforms running macOS 13.4 or later. (by @0xFireWolf)

#### v1.6.4
- Fixed Radeon RX 5500 XT identification regression
Expand Down
8 changes: 8 additions & 0 deletions Manual/FAQ.IntelHD.cn.md
Expand Up @@ -2021,6 +2021,14 @@ igfx: @ (DBG) BLS: [COMM] Processing the request: Current = 0x00014ead; Target =

</details>

## 修复在 Coffee Lake 平台上运行 macOS 13.4 或以上版本的笔记本开机持续3分钟暗屏问题

如果你之前使用“亮度寄存器修复”(也就是 `-igfxblr` 这个启动参数)来解决笔记本开机持续3分钟左右暗屏的问题,在升级到 macOS 13.4 或之后的版本后你会发现该补丁失效了。这是因为苹果简化了显卡驱动中读写寄存器相关的函数,导致编译器优化了函数调用的汇编代码,进而导致“亮度寄存器修复”以及“亮度丝滑器”注册的钩子失效。从 v1.6.5 开始,*WEG* 提供了新的补丁来撤销编译器对亮度调节相关函数的优化以及为 Coffee Lake 平台的笔记本重写了调节亮度的函数,从而解决开机持续3分钟暗屏以及“亮度丝滑器”失效的问题。

请注意这个新补丁仅适用于使用 macOS 13.4 以及以上的 Coffee Lake 核显驱动的笔记本用户。你可以为核显添加 `enable-backlight-registers-alternative-fix` 属性或者直接使用 `-igfxblt` 启动参数来启用这个新的补丁。与此同时,你可以删除原“亮度寄存器修复”的 `enable-backlight-registers-fix` 设备属性或者 `-igfxbls` 启动参数。如果你想在 macOS 13.4 或以上系统中使用“亮度丝滑器”,你需要添加 `-igfxblt` 以及 `-igfxbls` 这两个启动参数。

Ice Lake 平台的笔记本用户不受此问题影响,然而 Kaby Lake 平台的笔记本用户可能在 macOS 13.4 或以上系统中遇到类似的3分钟暗屏问题。由于没有足够空间来覆盖读取亮度相关寄存器的汇编指令,此新补丁暂不支持 Kaby Lake 平台。

## 修复 Ice Lake 平台上笔记本开机持续花屏7到15秒的问题

为核显添加 `enable-dbuf-early-optimizer` 属性或者直接使用 `-igfxdbeo` 启动参数以修复 Ice Lake 笔记本开机后内屏短暂花屏的问题。
Expand Down
8 changes: 8 additions & 0 deletions Manual/FAQ.IntelHD.en.md
Expand Up @@ -2671,6 +2671,14 @@ igfx: @ (DBG) BLS: [COMM] Processing the request: Current = 0x00014ead; Target =

</details>

## Fix the 3-minute black screen issue on CFL platforms running macOS 13.4 or later

If you have a CFL-based laptop and rely on the Backlight Registers Fix (BLR) to fix the 3-minute black screen issue, you may notice that BLR (`-igfxblr`) no longer work on macOS 13.4 or later. This is because Apple has simplified the implementation of the functions, `ReadRegister32` and `WriteRegister32`, in Coffee Lake's framebuffer driver shipped by macOS 13.4, so the compiler chose to inline invocations of those functions as many as possible. As a result, the `WriteRegister32` hooks registered by the Backlight Registers Fix (BLR) and the Backlight Smoother (BLS) submodules no longer work. Starting from v1.6.5, WEG can revert the optimizations done by the compiler in backlight related functions, provide an alternative to BLR and make BLS work properly on macOS 13.4 or later.

Note that this alternative fix is only available for users who have laptops using Coffee Lake's graphics driver and running macOS 13.4 or later. You can add the property `enable-backlight-registers-alternative-fix` to `IGPU` or use the boot argument `-igfxblt` to enable this new fix and remove the boot argument `-igfxbls` and/or the device property `enable-backlight-registers-fix`. If you wish to use the Backlight Smoother on macOS 13.4 or later, you need to add both `-igfxblt` and `-igfxbrs` to the boot arguments.

Note that Ice Lake platforms are not affected because `WriteRegister32` is not inlined in backlight related functions, while Kaby Lake platforms may be affected but are not supported by this new fix at this moment, because it is hard to fix the write operation on the register `0xC8250` due to the space limit.

## Fix the issue that the builtin display remains garbled after the system boots on ICL platforms

Add the `enable-dbuf-early-optimizer` property to `IGPU` or use the `-igfxdbeo` boot argument instead to fix the Display Data Buffer (DBUF) allocation issue on ICL platforms,
Expand Down
3 changes: 2 additions & 1 deletion README.md
Expand Up @@ -94,6 +94,7 @@ Read [FAQs](./Manual/) and avoid asking any questions. No support is provided fo
|--- |--- |--- |
| `-igfxblr` | `enable-backlight-registers-fix` property on IGPU | Fix backlight registers on KBL, CFL and ICL platforms |
| `-igfxbls` | `enable-backlight-smoother` property on IGPU | Make brightness transitions smoother on IVB+ platforms. [Read the manual](./Manual/FAQ.IntelHD.en.md#customize-the-behavior-of-the-backlight-smoother-to-improve-your-experience) |
| `-igfxblt` | `enable-backlight-registers-alternative-fix` property on IGPU | An alternative to the Backlight Registers Fix and make Backlight Smoother work on CFL platform running macOS 13.4 or later. [Read the manual](./Manual/FAQ.IntelHD.en.md#fix-the-3-minute-black-screen-issue-on-cfl-platforms-running-macos-134-or-later) |
| `-igfxcdc` | `enable-cdclk-frequency-fix` property on IGPU | Support all valid Core Display Clock (CDCLK) frequencies on ICL platforms. [Read the manual](./Manual/FAQ.IntelHD.en.md#support-all-possible-core-display-clock-cdclk-frequencies-on-icl-platforms) |
| `-igfxdbeo` | `enable-dbuf-early-optimizer` property on IGPU | Fix the Display Data Buffer (DBUF) issues on ICL+ platforms. [Read the manual](./Manual/FAQ.IntelHD.en.md#fix-the-issue-that-the-builtin-display-remains-garbled-after-the-system-boots-on-icl-platforms) |
| `-igfxdump` | N/A | Dump IGPU framebuffer kext to `/var/log/AppleIntelFramebuffer_X_Y` (available in DEBUG binaries) |
Expand Down Expand Up @@ -148,7 +149,7 @@ Read [FAQs](./Manual/) and avoid asking any questions. No support is provided fo
- [AMD](https://www.amd.com) for ATOM VBIOS parsing code
- [The PCI ID Repository](http://pci-ids.ucw.cz) for multiple GPU model names
- [Andrey1970AppleLife](https://github.com/Andrey1970AppleLife) for [FAQs](./Manual/)
- [FireWolf](https://github.com/0xFireWolf/) for the DPCD maximum link rate fix, infinite loop fix for Intel HDMI connections, LSPCON driver support, Core Display Clock frequency fix for ICL platforms, DVMT pre-allocated memory calculation fix for ICL platforms, Backlight Smoother for IVB+ platforms, and Display Data Buffer fix for ICL platforms.
- [FireWolf](https://github.com/0xFireWolf/) for the DPCD maximum link rate fix, infinite loop fix for Intel HDMI connections, LSPCON driver support, Core Display Clock frequency fix for ICL platforms, DVMT pre-allocated memory calculation fix for ICL platforms, Backlight Smoother for IVB+ platforms, Display Data Buffer fix for ICL platforms, and Backlight Registers Alternative Fix.
- [Floris497](https://github.com/Floris497) for the CoreDisplay [patches](https://github.com/Floris497/mac-pixel-clock-patch-v2)
- [Fraxul](https://github.com/Fraxul) for original CFL backlight patch
- [headkaze](https://github.com/headkaze) for Intel framebuffer patching code and CFL backlight patch improvements
Expand Down
138 changes: 136 additions & 2 deletions WhateverGreen/kern_igfx.hpp
Expand Up @@ -1526,7 +1526,7 @@ class IGFX {
/**
* Fallback user-requested backlight frequency in case 0 was initially written to the register.
*/
static constexpr uint32_t FallbackTargetBacklightFrequency = 120000;
static constexpr uint32_t kFallbackTargetBacklightFrequency = 120000;

/**
* [COMM] User-requested backlight frequency obtained from BXT_BLC_PWM_FREQ1 at system start.
Expand Down Expand Up @@ -1600,6 +1600,134 @@ class IGFX {
void processFramebufferKext(KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size) override;
} modBacklightRegistersFix;

/**
* A submodule to revert invocations of backlight-related functions and patch backlight register values on macOS 13.4.
*
* @note Supported Platforms: CFL.
*/
class BacklightRegistersAltFix: public PatchSubmodule {
/**
* Fallback PWM frequency if the system was initialized with a frequency of 0
*/
static constexpr uint32_t kFallbackBacklightFrequency = 120000;

/**
* Record the location of the inlined invocation of `hwSetBacklight()` and the register that stores the controller instance
* so that this patch submodule can revert the inlined invocation in the function of interest
*/
struct InvocationContext {
/**
* The start address, relative to the address of the function, of the inlined invocation of `hwSetBacklight()`
*/
size_t start {0};

/**
* The end address, relative to the address of the function, of the inlined invocation of `hwSetBacklight()`
*
* @note This is the address of the first instruction after `call hwSetBacklight` returns.
*/
size_t end {0};

/**
* Record which register stores the implicit framebuffer controller instance
*/
uint32_t registerController {0};

/**
* Validate this invocation context
*/
bool isValid() const {
return this->start != 0 && this->end != 0 && this->registerController != 0;
}

/**
* Calculate the number of bytes that can be safely replaced
*/
size_t freeSpace() const {
return this->end - this->start;
}
};

/**
* Record the PWM frequency initialized by the system firmware
*/
uint32_t firmwareBacklightFrequency {0};

/**
* Record the offset of the member field in the framebuffer controller that stores the PWM frequency divider
*/
size_t offsetFrequencyDivider {0};

/**
* Record the offset of the member field in the framebuffer controller that stores the current brightness level
*/
size_t offsetBrightnessLevel {0};

/**
* Find the offset of the member fields that store the PWM frequency divider and the current brightness level
*
* @param address The address of `hwSetBacklight()` to be analyzed
* @param instructions The maximum number of instructions to be analyzed
* @return The offset of the member field that stores the PWM frequency divider and
* the offset of the member field that stores the current brightness level.
*/
ppair<size_t, size_t> probeMemberOffsets(mach_vm_address_t address, size_t instructions) const;

/**
* Find the location of the inlined invocation of `hwSetBacklight()` in the function that starts at the given address
*
* @param address The address of the function to be analyzed
* @param instructions The maximum number of instructions to be analyzed
* @return A pair of `<Start, End>` offsets, relative to the given address, indicating the location of inlined invocation of `hwSetBacklight()`,
* and the register that stores the implicit framebuffer controller instance.
*/
InvocationContext probeInlinedInvocation(mach_vm_address_t address, size_t instructions) const;

/**
* Revert the inlined invocation of `hwSetBacklight()` in the function that starts at the given address
*
* @param patcher The kernel patcher
* @param address The address of the function to be patched
* @param orgHwSetBacklight The address of the original `hwSetBacklight()`
* @param context The invocation context indicating where to patch the function and which register stores the controller instance
* @return `true` if the function at the given address has been patched to invoke `hwSetBacklight()` explicitly, `false` otherwise.
*/
bool revertInlinedInvocation(KernelPatcher &patcher, mach_vm_address_t address, mach_vm_address_t orgHwSetBacklight, const InvocationContext &context) const;

/**
* Wrapper to set the backlight compatible with the current machine
*
* @param controller The implicit framebuffer controller
* @param brightness The new brightness level
* @return `kIOReturnSuccess`.
* @note When this function returns, the given brightness level should be stored into the given framebuffer controller.
* @note Unlike the original fix implemented in BLR, BLR-ALT computes the value of the frequency register and the duty register
* compatible with the current machine and commit those values using the original version of `WriteRegister32()`.
* Apple's implementation will not be used by this submodule.
*/
static IOReturn wrapHwSetBacklight(void *controller, uint32_t brightness);

/**
* Get the name of the register at the given index
*
* @param index The register index
* @return The register name, `INVALID` if the given index is invalid.
*/
static inline const char* registerName(size_t index) {
static constexpr const char* kNames[] = {
"%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi",
"%r8" , "%r9" , "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
};
return index < arrsize(kNames) ? kNames[index] : "INVALID";
}

public:
// MARK: Patch Submodule IMP
void init() override;
void processKernel(KernelPatcher &patcher, DeviceInfo *info) override;
void processFramebufferKext(KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size) override;
} modBacklightRegistersAltFix;

/**
* Brightness request event source needs access to the original WriteRegister32 function
*/
Expand All @@ -1617,6 +1745,11 @@ class IGFX {
* Backlight registers fix submodule needs access to the smoother version of `WriteRegister32()`
*/
friend class BacklightRegistersFix;

/**
* Backlight registers alternative fix submodule needs access to the smoother version of `WriteRegister32()`
*/
friend class BacklightRegistersAltFix;

/**
* Brightness request event source needs access to the queue and config parameters
Expand Down Expand Up @@ -1835,7 +1968,7 @@ class IGFX {
/**
* A collection of submodules
*/
PatchSubmodule *submodules[20] = {
PatchSubmodule *submodules[21] = {
&modDVMTCalcFix,
&modDPCDMaxLinkRateFix,
&modCoreDisplayClockFix,
Expand All @@ -1852,6 +1985,7 @@ class IGFX {
&modPAVPDisabler,
&modReadDescriptorPatch,
&modBacklightRegistersFix,
&modBacklightRegistersAltFix,
&modBacklightSmoother,
&modFramebufferDebugSupport,
&modMaxPixelClockOverride,
Expand Down

0 comments on commit 70ade87

Please sign in to comment.