Tools for reading/writing Intel package power limits, CPU ratios, and core voltage offset via MCHBAR MMIO and MSRs. Includes a Qt GUI (Wayland/COSMIC friendly via polkit), CLI utilities, and a privileged helper.
This project was made to bypass enforced power limits on a specific test setup by directly adjusting package power limit registers over MSR and MCHBAR MMIO. It has only been tested on an ES i7-13700HX (Q1K3) on an ASUS PRIME B660M-K D4, to bypass 55W (PL1) and 157W (PL2) limits. Other CPUs, steppings, or boards may behave differently.
mchbar_read.c: read a few MCHBAR registers (including the package power limit window at 0x59A0).mchbar_pl_write.c: write the MCHBAR package power limit register (0x59A0).mchbar_scan.c: scan MCHBAR for PL1/PL2 patterns (useful if the PL register offset differs).limits_ui.c: interactive CLI UI to view/set PL1/PL2 in watts and sync MSR <-> MMIO.qt_ui/: Qt Widgets GUI with buttons for read/set/sync, ratio control, and core voltage offset.helper/: privileged helper + polkit policy for running the Qt GUI as your user (Wayland/COSMIC friendly).
- Read/write PL1/PL2 in watts (MSR 0x610 and MCHBAR 0x59A0).
- Sync MSR <-> MMIO power limit values.
- P-core / E-core ratio targets (IA32_PERF_CTL 0x199) with current ratio display (IA32_PERF_STATUS 0x198).
- Core voltage offset (OC mailbox MSR 0x150, core plane).
- Basic CPU info panel in the GUI (model, microcode, core counts, P/E MHz).
- GUI profile save/load (JSON) with optional startup auto-apply and crash-guard fallback.
- Linux with access to
/dev/mem(root). - MSR driver for
/dev/cpu/0/msr(load withmodprobe msr). - Root privileges for reads/writes (helper uses polkit).
- Qt6 or Qt5 Widgets development package (for
qt_ui). - Qt tools / build tools (Qt CMake tooling) for the GUI build.
- Polkit (
pkexec) for the Qt GUI helper on Wayland.
Note on MCHBAR scanning: finding the register offset by pattern matching requires the current PL1/PL2 values. If
you already changed limits, pass those values to mchbar_scan (or use --units) so it can match correctly.
As a typical CMake you can just do the following
cmake -B buildQt UI build only:
cd qt_ui
cmake -S . -B build
cmake --build buildHelper build:
gcc -std=c11 -Wall -Wextra -O2 -o limits_helper helper/limits_helper.c -lmInstall helper + polkit policy (required on Wayland/COSMIC):
sudo install -m 0755 build/limits_helper /usr/local/bin/limits_helper
sudo install -m 0644 helper/com.limits_droper.helper.policy /usr/share/polkit-1/actions/Of course, if you use a build directory other than build/, you should adjust your commands appropriately.
If you install the helper somewhere else, update the policy exec.path to match and export LIMITS_HELPER_PATH.
- Download the Ubuntu or Fedora tarball from the GitHub Releases page.
- Extract it:
tar -xzf Limits_droper-<version>-linux-<distro>.tar.gz
cd Limits_droper-<version>-linux-<distro>- Install the helper + polkit policy (required on Wayland/COSMIC):
sudo install -m 0755 limits_helper /usr/local/bin/limits_helper
sudo install -m 0644 com.limits_droper.helper.policy /usr/share/polkit-1/actions/- Run the GUI:
./limits_ui_qt- Build the tools and GUI:
gcc -std=c11 -Wall -Wextra -O2 -o mchbar_read mchbar_read.c
gcc -std=c11 -Wall -Wextra -O2 -o mchbar_pl_write mchbar_pl_write.c
gcc -std=c11 -Wall -Wextra -O2 -o mchbar_scan mchbar_scan.c -lm
gcc -std=c11 -Wall -Wextra -O2 -o limits_ui limits_ui.c -lm
gcc -std=c11 -Wall -Wextra -O2 -o limits_helper helper/limits_helper.c -lm
cmake -S qt_ui -B qt_ui/build
cmake --build qt_ui/build- Install the helper + polkit policy:
sudo install -m 0755 limits_helper /usr/local/bin/limits_helper
sudo install -m 0644 helper/com.limits_droper.helper.policy /usr/share/polkit-1/actions/- Run the GUI:
./qt_ui/build/limits_ui_qtRead MCHBAR values:
sudo ./build/mchbar_readScan MCHBAR for PL1/PL2 pattern (default 55W/157W):
sudo ./build/mchbar_scanNote: scanning relies on matching the current PL1/PL2 values. If you already changed limits, pass those values
to mchbar_scan (or use --units) so it can find the correct register offset.
Scan using explicit watts:
sudo ./build/mchbar_scan --pl1 55 --pl2 157Scan using raw units (if you already know them):
sudo ./build/mchbar_scan --units 0x1b8 0x4e8Write MCHBAR package limits (PL1/PL2):
sudo build/mchbar_pl_write --set 150 170
sudo build/mchbar_pl_write --restore 0x004284e800df81b8Write kernel powercap limits (intel-rapl, in micro-watts):
sudo ./build/limits_helper --write-powercap 160000000 170000000Start/stop/disable/enable powercap writer services:
sudo ./build/limits_helper --start-thermald
sudo ./build/limits_helper --stop-thermald
sudo ./build/limits_helper --disable-thermald
sudo ./build/limits_helper --enable-thermald
sudo ./build/limits_helper --start-tuned
sudo ./build/limits_helper --stop-tuned
sudo ./build/limits_helper --disable-tuned
sudo ./build/limits_helper --enable-tuned
sudo ./build/limits_helper --start-tuned-ppd
sudo ./build/limits_helper --stop-tuned-ppd
sudo ./build/limits_helper --disable-tuned-ppd
sudo ./build/limits_helper --enable-tuned-ppd--start-* / --stop-* change runtime state now. --enable-* / --disable-* only change boot persistence.
Interactive UI (read/set/sync MSR + MMIO):
sudo build/limits_uiQt UI:
./qt_ui/build/limits_ui_qtIf you cd qt_ui first, run ./build/limits_ui_qt.
The GUI uses polkit via pkexec, so it should be run as your user (no sudo). You can override the helper path with LIMITS_HELPER_PATH.
Profiles + startup:
- Use "Save Profile" / "Load Profile" to store JSON profiles with PL1/PL2, ratios, and core UV.
- Enable "Apply on startup" to auto-apply the selected profile. If the previous auto-apply did not finish (crash/lockup), startup auto-apply is disabled and an optional fallback profile can be applied instead.
- MCHBAR base is discovered from PCI config (host bridge 0x48), package power limit register at offset
0x59A0. - MSR power unit is taken from
IA32_RAPL_POWER_UNIT(0x606) and applied when converting watts. - Power limits are written to
IA32_PKG_POWER_LIMIT(0x610) and/or MCHBAR 0x59A0. - Ratio targets are shown from
IA32_PERF_CTL(0x199); current ratios are read fromIA32_PERF_STATUS(0x198). - P/E detection uses CPUID leaf 0x1A core type when available.
- Core voltage offset uses the OC mailbox (MSR 0x150) with a core-plane offset (mV). Use with caution.
- Tested only on ES i7-13700HX (Q1K3) on PRIME B660M-K D4, used to bypass 55W and 157W limits. Other CPUs/boards may differ.
- GUI shows permission errors: make sure the helper is installed and the polkit policy is in place, then run the GUI as your user (not
sudo). - Verify helper output:
pkexec /usr/local/bin/limits_helper --read
- P/E lists empty: CPUID 0x1A may be unavailable. Use “Set All” ratio or add a manual mapping.
- Intel SDM (MSR/CPUID documentation): Intel® 64 and IA-32 Architectures Software Developer’s Manuals.
linux-intel-undervoltproject for the OC mailbox offset encoding approach: mihic/linux-intel-undervolt.- Qt for the GUI: Qt.
- PolicyKit for privilege separation: PolicyKit.
Writing MSRs/MMIO can destabilize a system or damage hardware. Use at your own risk.