Skip to content

arm: Add missing hflag update after writing PSTATE - #2386

Open
phverg wants to merge 2 commits into
unicorn-engine:devfrom
phverg:fix-aarch64-pstate-hflags
Open

arm: Add missing hflag update after writing PSTATE#2386
phverg wants to merge 2 commits into
unicorn-engine:devfrom
phverg:fix-aarch64-pstate-hflags

Conversation

@phverg

@phverg phverg commented Aug 11, 2026

Copy link
Copy Markdown

Summary

Fixes #2333.

uc_reg_write(UC_ARM64_REG_PSTATE, ...) called pstate_write() but did not refresh env->hflags. QEMU caches PSTATE-derived state (current exception level, SP selection, ...) in hflags, and MRS CurrentEL in particular is materialized as a translate-time constant from the TB flags. So after a user raises the exception level by writing PSTATE, MRS CurrentEL and a subsequent ERET still observed the stale level.

The fix mirrors the existing UC_ARM64_REG_CP_REG case (which already calls arm_rebuild_hflags()), and the merged AArch32 counterpart #2268 ("arm: Add missing hflag update after writing xpsr"). The arm_rebuild_hflags mechanism itself was introduced for cp-regs in #1844.

Before / after

Writing PSTATE to elevate to EL2, then executing MRS X0, CurrentEL:

  • Before: X0 = 0x4 (stale EL1).
  • After: X0 = 0x8 (EL2), matching the written PSTATE.

Testing

Added test_arm64_pstate_hflags_rebuild in tests/unit/test_arm64.c: it writes PSTATE to EL2 and asserts MRS CurrentEL reports EL2. The assertion fails on the unpatched tree (returns EL1) and passes with the fix. The full unit-test suite passes.

Scope

  • The other direct EL1 register writes in this switch (TTBR0/1, MAIR, PAR, VBAR) do not feed hflags, so they need no rebuild.
  • UC_ARM64_REG_CPACR_EL1 does feed the SVE-related hflags (SVEEXC_EL/ZCR_LEN); refreshing it is a separate, lower-impact concern that can be handled as a follow-up if desired.
  • Issue Missing arm_rebuild_hflags call after writing to UC_ARM64_REG_PSTATE? #2333 also mentions a secondary problem (a CurrentEL raw_read/fieldoffset assert); that is out of scope for this change.

phverg added 2 commits August 11, 2026 15:40
reg_write() for UC_ARM64_REG_PSTATE called pstate_write() but never
refreshed env->hflags. The hflags cache holds PSTATE-derived state such
as the current exception level, so after a user raises the EL by writing
PSTATE, MRS CurrentEL (which materializes the EL as a translate-time
constant from the TB flags) and a subsequent ERET still observed the
stale level. The sibling UC_ARM64_REG_CP_REG case already calls
arm_rebuild_hflags(); do the same after pstate_write(), matching the
AArch32 fix in unicorn-engine#2268.

Fixes unicorn-engine#2333.
Write PSTATE to raise the exception level to EL2 and check that MRS
CurrentEL observes EL2. Without the hflags rebuild the read returns the
stale EL1.
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.

1 participant