Skip to content

hw/xtensa/esp32s3: reset CPENABLE to 0xff to match silicon (QEMU-294)#155

Open
mandreev57 wants to merge 1 commit into
espressif:esp-developfrom
mandreev57:fix/xtensa-cpenable-reset
Open

hw/xtensa/esp32s3: reset CPENABLE to 0xff to match silicon (QEMU-294)#155
mandreev57 wants to merge 1 commit into
espressif:esp-developfrom
mandreev57:fix/xtensa-cpenable-reset

Conversation

@mandreev57

Copy link
Copy Markdown

Fixes #154.

ESP32-S3 (LX7) silicon resets CPENABLE to 0xff — directly
measured on ESP32-S3 with rsr.cpenable as the first instruction
in main (0xff on hardware, 0x00 under
esp-develop-9.2.2-20260417).

xtensa_cpu_reset_hold already writes CPENABLE = 0xff, but only in
the CONFIG_USER_ONLY branch, so qemu-system-xtensa boots with the
ISA default of 0. Guest firmware that assumes the silicon contract
hangs on the first floating-point instruction — Cp0Disabled (cause
32) re-raises through the user-exception vector, which itself spills
f0..f15 before CPENABLE is set (this is what xtensa-lx-rt 0.21
with float-save-restore does; that path is enabled by default in
esp-hal 1.0).

Approach

Rather than make the unconditional change in target/xtensa/cpu.c
— which would change the reset value for the upstream
sim/xtfpga/virt Xtensa boards too — this patch writes the
vendor reset value right after cpu_reset() in the ESP32-S3 SoC
reset handler (esp32s3_soc_reset). Scope is limited to the chip
where the silicon value has been directly measured.

ESP32 (LX6, hw/xtensa/esp32.c) and ESP32-S2 almost certainly behave
the same way — xtensa_cpu_reset_hold's user-mode branch sets
0xff unconditionally and the Espressif toolchain assumes it — but
I have not directly measured rsr.cpenable after reset on those
chips yet. The same one-line write should be added under each
corresponding cpu_reset() once that's confirmed. (hw/xtensa/esp32s2.c
does not exist in this fork today.)

Verification

Against the minimal repro in #154, the FP loop now completes instead
of hanging silently. No change for guest binaries that already set
CPENABLE explicitly.

ESP32-S3 (LX7) silicon resets CPENABLE to 0xff — verified directly
on ESP32-S3 hardware: an `rsr.cpenable` as the first instruction of
`main` reads 0xff on silicon, and 0x00 in qemu-system-xtensa
(esp-develop-9.2.2-20260417). Guest firmware that depends on the
silicon contract — including any exception path that spills f0..f15
before establishing CPENABLE — works on hardware but hangs in
emulation. xtensa-lx-rt 0.21 with `float-save-restore` (enabled by
default in esp-hal 1.0) does exactly that, so the first
floating-point op in a Rust ESP32-S3 binary re-raises Cp0Disabled
through the user-exception vector indefinitely.

target/xtensa/cpu.c writes CPENABLE = 0xff only inside the
CONFIG_USER_ONLY branch of xtensa_cpu_reset_hold. Rather than change
the generic Xtensa system-mode reset (which would also affect the
upstream sim/xtfpga/virt boards), restore the vendor reset value
right after cpu_reset() in the ESP32-S3 SoC reset handler. No impact
on non-Espressif Xtensa machines.

Reported and reproduced in espressif#154.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Mikhail Andreev <mikhail.andreev.57@gmail.com>
@github-actions github-actions Bot changed the title hw/xtensa/esp32s3: reset CPENABLE to 0xff to match silicon hw/xtensa/esp32s3: reset CPENABLE to 0xff to match silicon (QEMU-294) May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ESP32-S3: qemu-system-xtensa boots with CPENABLE = 0; first FP op recurses through the Cp0Disabled handler (QEMU-293)

2 participants