Skip to content

Add semantic Intel bi-directional PROCHOT control - #96

Draft
celsonaemen wants to merge 2 commits into
namazso:mainfrom
celsonaemen:feature/intel-bidir-prochot
Draft

Add semantic Intel bi-directional PROCHOT control#96
celsonaemen wants to merge 2 commits into
namazso:mainfrom
celsonaemen:feature/intel-bidir-prochot

Conversation

@celsonaemen

@celsonaemen celsonaemen commented Aug 23, 2026

Copy link
Copy Markdown

Summary

Adds a semantic module for reading and controlling the Intel bi-directional PROCHOT input response without exposing arbitrary MSR writes.

Intel documents bit 0 of MSR_POWER_CTL (0x1FC) as ENABLE_BIDIR_PROCHOT. Clearing that bit makes the processor ignore an externally asserted PROCHOT input; it does not disable the processor's internal adaptive thermal monitor or THERMTRIP protection.

Intel SDM Volume 4 reference:
https://cdrdv2-public.intel.com/874253/335592-090-sdm-vol-4.pdf

Intel bi-directional PROCHOT behavior:
https://edc.intel.com/content/www/us/en/design/products/platforms/details/meteor-lake-u-p/core-ultra-processor-datasheet-volume-1-of-2/002/bi-directional-prochot/

Exposed operations

  • ioctl_bidir_prochot_status reads the current/saved response state, raw MSR_POWER_CTL, IA32_THERM_STATUS and IA32_PACKAGE_THERM_STATUS.
  • ioctl_set_bidir_prochot changes only ENABLE_BIDIR_PROCHOT and verifies readback.
  • ioctl_keep_bidir_off disables the response, verifies readback, and intentionally preserves the disabled state when the module unloads. Firmware or a processor reset may initialize the MSR again, so callers can reapply this policy at boot/resume.
  • ioctl_restore_bidir_prochot explicitly restores the response state captured when the module loaded and restores the normal unload behavior.
  • Unload restores the load-time state unless the caller explicitly selected ioctl_keep_bidir_off.

Safety properties

  • x64, Intel vendor and family 6 gate
  • MSR_POWER_CTL is probed during module initialization
  • no caller-controlled MSR address or arbitrary MSR value
  • read-modify-write preserves every MSR_POWER_CTL bit except bit 0
  • boolean input for the general setter
  • readback is mandatory after every state change
  • persistent behavior is explicit rather than an automatic module-load side effect
  • Doxygen documents that disabling the response removes protection requested by other platform components

Validation

Compiled with the bundled Pawn 4.1.7152 compiler and repository CI flags:

pawncc IntelBidirProchot.p -iinclude -C64 -;+ -(+ -p

Completed successfully with zero warnings.

The main review questions are whether the family-6 plus successful-MSR-read gate is sufficiently conservative and whether the explicit persistent operation is preferable to requiring clients to keep a module handle open.

@hexawyz

hexawyz commented Aug 24, 2026

Copy link
Copy Markdown

I'm quite interested in this, as I was myself considering adding something to fix the recurring PROCHOT issues in Intel laptops.

From my understanding, it is no longer possible to disable BD_PROCHOT on recent hardware, as the firmware will lock it. This will be reflected in e.g. ThrottleStop UI.
It is however possible to clear the signaling flag for PROCHOT and also other thermal logs, and manually opening ThrottleStop to click the PROCHOT warning has generally always restored the computer to its expected performance level for me, which sometimes even rebooting wouldn't do. I have not yet taken time to read the Intel docs regarding this, so I'm not sure this new module will allow this usecase which is the only one allowed when BD_PROCHOT is locked, a thing that is becoming increasingly common.

  1. This module should detect, understand and expose the lock (read-only)
  2. Can you tell me if this module will properly be able to clear the PROCHOT warning without error? (And that alone, e.g. if BD_PROCHOT is locked)
  3. If not, could you add this feature?

@namazso
namazso marked this pull request as draft August 30, 2026 00:28
@namazso

namazso commented Aug 30, 2026

Copy link
Copy Markdown
Owner

I'm interested in the answers to @hexawyz's questions too.

Also, I changed this to draft, please test it on the unrestricted driver (you'll have to use 2.1.0 or your own builds because 2.2.0 accidentally shipped with signature verification enabled on the unrestricted driver as well) before marking it as ready.

@celsonaemen

Copy link
Copy Markdown
Author

Thanks @hexawyz and @namazso . I reran the verification and will keep this PR in draft until the unrestricted-driver test is complete.
Source and build evidence

The complete module source is IntelBidirProchot.p, split across these two commits:

  • d9936ad: semantic status/set/restore operations
  • 495518e: explicit keep-disabled-on-unload operation

Fresh build with the repository include files and Pawn 4.1.7152:

pawncc IntelBidirProchot.p -iinclude -C64 -;+ -(+ -p
Pawn compiler 4.1.7152
Completed successfully
0 warnings
IntelBidirProchot.amx: 11128 bytes

Hardware validation performed so far

Target machine:

  • Acer Aspire A315-56
  • Intel Core i3-1005G1 (Ice Lake, GenuineIntel family/model/stepping 06/7E/05)
  • 2 cores / 4 logical processors
  • Windows 11 x64

I also built a companion hardware-validation harness. It pins the thread to each logical processor, reads IA32_CLOCK_MODULATION (0x19A) and MSR_POWER_CTL (0x1FC), computes only power_ctl & ~1, writes only when bit 0 differs, then rejects the operation unless readback confirms that 0x19A and every other 0x1FC bit were preserved.

The relevant policy and assertion are:

csharp
targetPowerControl = currentPowerControl & ~1UL;

AssertEqual(originalClockModulation, verifiedClockModulation);
AssertEqual(originalPowerControl & ~1UL, verifiedPowerControl);
AssertEqual(originalPowerControl & ~1UL,
verifiedPowerControl & ~1UL);

Results:

Controller build: succeeded, 0 warnings, 0 errors
Policy/runtime test: PASS

Verified readback on logical processors 0..3:
IA32_CLOCK_MODULATION = 0x0000000000000000
MSR_POWER_CTL = 0x000000000024005E

Observed recovery event on this laptop:
before = 197.4 MHz
after = 3399.9 MHz

Important scope distinction: those hardware results were obtained through the existing pinned MSR-driver backend, not by loading this Pawn module. They validate the exact read/modify/write policy on the target laptop, but they are not a substitute for the PawnIO unrestricted-driver test requested here.

Answers to the three questions

  1. Lock detection/exposure: not fully implemented in the current revision. ioctl_bidir_prochot_status exposes the raw MSR_POWER_CTL; a requested state change that does not survive readback returns STATUS_UNSUCCESSFUL. That detects a blocked transition, but it does not classify or expose a documented locked capability. A generic family-6 interpretation would also be unsafe: Intel documents bit 23 as VR_THERM_ALERT_DISABLE_LOCK for some newer model tables, while the current Ice Lake/general table does not document that bit with the same semantic. This needs a model/capability-specific gate rather than naming bit 23 as a lock on every family-6 CPU.

  2. Clearing only the PROCHOT warning/log while BD_PROCHOT is locked: no, not in the current revision. The module only reads IA32_THERM_STATUS (0x19C) and IA32_PACKAGE_THERM_STATUS (0x1B1). It never writes their W0C log bits and does not access MSR_CORE_PERF_LIMIT_REASONS (0x64F), whose bit 16 is the documented PROCHOT log on applicable processors. Therefore a locked MSR_POWER_CTL[0] transition will fail readback, and the current module will not independently clear a stale PROCHOT log.

  3. Feature addition: yes, this should be a separate narrow operation. My proposed follow-up is:

    • expose model-qualified lock/capability information read-only;
    • add an ioctl that clears only documented PROCHOT log bits, using the correct W0C semantics and preserving unrelated thermal/power logs;
    • keep this independent from changing MSR_POWER_CTL[0], so it can work when that control is locked;
    • add before/after readback and unrestricted-driver tests for both the unlocked and locked paths.

Remaining PawnIO-specific test

This system currently has PawnIO 2.2.0. The freshly compiled unsigned AMX is rejected with 0x80070057, consistent with the 2.2.0 unrestricted-driver signature-verification issue mentioned above. The current boot has Secure Boot enabled and Windows test signing disabled, so I cannot honestly report a completed unrestricted/test-mode module load from this run.

I will test the AMX with PawnIO 2.1.0 unrestricted (or a locally built unrestricted driver), capture each ioctl result/readback, and only then mark the PR ready.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants