dortania / OpenCore-Legacy-Patcher

Experience macOS just like before
https://dortania.github.io/OpenCore-Legacy-Patcher/
Other
12.76k stars 1.21k forks source link

[Feature Request]: Add support to disable BD PROCHOT for MacBooks without battery #555

Closed 0xF4CED closed 3 years ago

0xF4CED commented 3 years ago

What is the requested feature?

If one needs to remove their battery from their MacBook, for safety reasons (because it is swollen, which happens a lot with older MacBooks) or other reasons, the device can still be used as a stationary Mac with the power cord plugged in. However, the experience is quite bad to unusable because Apple aggressively throttles down the CPU if the battery is missing.

The CPU throttling due to missing battery is triggered by the firmware, and it doesn't make any difference what version of macOS (or other OS) you are running. The reason for this is that the EFI firmware sets on BD PROCHOT which is a CPU register (msr 0x1FC) usually used to tell the CPU that some other component (GPU or whatever) is overheating. This will cause the CPU to throttle even though it is not itself overheating. This is described in Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 4: Model-Specific Registers. (source)

There are however methods to disable BD PROCHOT and restore unthrottled performance with a missing battery which are either EFI or kext based. I have found various implementations of this, but the ones that look the cleanest and most minimal to me are the ones from @arter97. I have successfully incorporated his kext based method into my OpenCore-Legacy configuration and my MacBookPro11,1 without battery runs unthrottled with no issues whatsoever.

Ideally one would use both the kext method and the EFI method combined. The EFI method to have the throttling already disabled at boot level (which also benefits booting any other OSs) and the kext method to keep BD PROCHOT disabled after suspend.

Entering ACPI S3 state(suspend) causes the BD PROCHOT MSR bit getting re-enabled. You need to use some userspace tool for disabling BD PROCHOT for such cases. (source)

However, I was not able to get the EFI method to work: I tried adding arters DisablePROCHOT.efi (which apparently works with rEFInd & Clover) to the drivers directory and config.plist of my OpenCore-Legacy install, but it resulted in a black screen with no boot. So some adjustments would have to be done to that method.

Of course @arter97 would need to give his permission to use his implementations since they are released with All rights reserved, but I am quite confident he would.

I think this feature would be a valuable addition to OpenCore-Legacy since it aligns with the projects goal of extending the lifespan of older Macs.

Any Additional Information

Kext method by @arter97: https://github.com/arter97/SimpleMSR EFI method by @arter97: https://github.com/arter97/DisablePROCHOT

Other resources: https://github.com/balecrim/NoBatteryNoProblem.kext https://github.com/syscl/CPUTune

khronokernel commented 3 years ago

Thank you so much for researching and testing this! It is quite interesting regarding the BD PROCHOT throttling, as I was wondering why only Nahlem and newer Macs seemed affected by firmware based battery throttling.

With regards to usage right, we'll need to request permission from the author or need to reimplement it ourselves. CPUFriend may be a good contender to bring it in-house for easier maintainability.

Regarding disabling via UEFI, may be worth opening an issue within OpenCorePkg:

arter97 commented 3 years ago

Hi.

I didn't expect anyone to find it to be seriously useful, it was more like a "eh I'll just push it on GitHub just in case" thing. I've just pushed commits setting the license to BSD 2-clause, which should be enough.

I'm not using those 2 at the moment. While DisablePROCHOT would still work, I'm not quite sure for SimpleMSR.

Let me know if you guys need anything else :)

Thanks.

khronokernel commented 3 years ago

Thank you so much for the quick reply and adjusting the license! Really do appreciate it

I was able to verify SimpleMSR functions in both Big Sur and Monterey, though will be doing some more testing (hibernation, etc) to ensure no strange bugs pop in (as when you pushed the project Mojave was only in Beta)

protocold commented 3 years ago

@khronokernel so we only need SimpleMSR without DisablePROCHOT ?

Do you think it will also work on MBP4,1 as it will throttle without battery and it seems like penryn may also respond to BD PROCHOT? (I used to have a MBP4,1 but not anymore.. can someone give this a test?)

0xF4CED commented 3 years ago

Practically, SimpleMSR is enough to make macOS usable, but it only applies when OpenCore injects the kexts. So it would still be an improvement to additionally implement DisablePROCHOT to disable firmware throttling at boot level so that booting Linux, Windows, etc. doesn't take forever and macOS also boots faster until the kexts are injected.

arter97 commented 3 years ago

If BD PROCHOT is active and the CPU is throttling, it'll be stuck at either 0.4 or 0.8 GHz, which is plenty enough to massively slow down BIOS post and bootloader.

I encourage you to implement it on the bootloader level as well. It'll still make a difference.

Though, I think a separate UEFI program for doing that is somewhat overkill, it's literally a one line register write (0x1fc, 0). It'll be better to integrate it to OpenCore directly, but I'm not sure if the upstream is ok with that sort of thing.

protocold commented 3 years ago

@arter97 as you are the original author of DisablePROCHOT, any insight you may have as to why it worked in Clover/rEFInd but not opencore?

arter97 commented 3 years ago

I suppose it's the difference between UEFI drivers/programs.

Try building it as a UEFI driver (dunno the exact build command).

protocold commented 3 years ago

i also tried to build your source as is but it failed.. did you build it under Mac OS or linux?!

0xF4CED commented 3 years ago

This might be helpful: https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/appendix_a_edk_ii_file_templates/a1_uefi_driver_template

+ Here are some UEFI drivers from OpenCorePkg for reference: https://github.com/acidanthera/OpenCorePkg/tree/master/Platform

arter97 commented 3 years ago

i also tried to build your source as is but it failed.. did you build it under Mac OS or linux?!

Linux is my daily driver OS, and I've built that under Ubuntu with gnu-efi installed.

I'm guessing building that under macOS would not be trivial. Try with a live Ubuntu CD if you don't have a Linux installation handy.

0xF4CED commented 3 years ago

I tried building as efi-bsdrv-x86_64 and efi-rtdrv-x86_64 (instead of --target=efi-app-x86_64) but it doesn't help, still black screen with no boot. I think it might have to be rewritten using EDK2, which made me wonder if it would be possible to write a DXE_RUNTIME_DRIVER that could also handle ACPI S3 resume, which would make the kext method obsolete and be a complete OS-agnostic solution.

A DXE runtime driver executes in both boot services and runtime services environments. This means the services that these modules produce are available before and after ExitBootServices() is called, including the time that an operating system is running. (source)

protocold commented 3 years ago

that has gone beyond my head unfortunately.

0xF4CED commented 3 years ago

I did some research and stumbled upon this: The hunt for the s3 boot script That led me to a whole lot of resources, including the following:

Definitions for data structures used in S3 resume. (SMM_S3_RESUME_STATE)

S3Resume.c

This module works with StandAloneBootScriptExecutor to S3 resume to OS. This module will execute the boot script saved during last boot and after that, control is passed to OS waking up handler.

BootScriptExecutorDxe

This driver is dispatched by Dxe core and the driver will reload itself to ACPI reserved memory in the entry point. The functionality is to interpret and restore the S3 boot script

And probably the most useful: A Tour Beyond BIOS Implementing S3 resume with EDKII

These resources led me to believe that it might be possible to write a DXE_RUNTIME_DRIVER that could disable PROCHOT at boot and S3 resume, which would be amazing.

Unfortunately this is above my head as well, but I hope someone with the capabilities may be able to use this information to come up with an implementation.

What do you think @khronokernel?

arter97 commented 3 years ago

While I'm not an expert in this field, I believe that sort of thing requires a BIOS modification.

With a BIOS mod, yes, it's possible to inject a UEFI executable to trip PROCHOT upon boot/S3, but I'm not sure if that's what people wants...