Skip to content

espemu: eFuses, flash encryption, esp32c5, and a working hard reset (CII-251) - #431

Open
Harshal5 wants to merge 3 commits into
espressif:mainfrom
Harshal5:feat/espemu_efuse_and_encryption
Open

espemu: eFuses, flash encryption, esp32c5, and a working hard reset (CII-251)#431
Harshal5 wants to merge 3 commits into
espressif:mainfrom
Harshal5:feat/espemu_efuse_and_encryption

Conversation

@Harshal5

@Harshal5 Harshal5 commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Description

The qemu service can give a test an eFuse image, burn eFuses into it and boot an encrypted image. The esp-emu service could do none of that, and it had no dut.serial at all, so ESP-IDF tests that operate on device state had nothing to run against.

eFuses

--espemu-efuse-path gives the emulator an eFuse image, creating a blank QEMU-compatible one when the file does not exist.

execute_efuse_command() runs espefuse against a second emulator instance started in download mode with its UART on a socket. A second instance is needed because the first one is booted into the firmware, and pyserial's socket:// handler ignores modem control lines, so esptool cannot reset it into download mode.

Flash encryption

--encrypt and --keyfile encrypt the merged image the way the qemu service does, with one difference: the command is espsecure encrypt-flash-data --aes-xts. Every target the emulator supports encrypts flash with XTS-AES

esp32c5

esp-emu has accepted --chip esp32c5 for a while, but the service rejected the target before launching it, so every esp32c5 app was unrunnable under --embedded-services idf,espemu. Nothing else in the service is target specific — the flash image comes from the app's own flash arguments — so the target list was the only gap.

dut.serial.hard_reset()

ESP-IDF tests reach the chip through two channels: the console stream (dut.expect) and a control channel (dut.serial) that resets it, erases flash and burns eFuses. esp-emu now serves a control channel, so hard_reset() sends reset over it. The emulator process keeps running, so the dut's output stream, its expect history and its log all continue across the reset; relaunching the process would break all three.

The service checks esp-emu --help for --control-tcp before passing the flag, because an older binary exits on an unknown one. The operations that still need download mode raise NotImplementedError naming the operation that was wanted.

Validation

Run against ESP-IDF master with --embedded-services idf,espemu:

  • An encrypted image boots on an emulated target with the eFuses burned.
  • esp32c5 collects and passes the same esp_system and esp_hw_support cases as the other targets.
  • esp_driver_uart's test_uart_single_dev, which used to fail at setup on dut.serial, now resets the chip six times and runs through to its test content.

Dependency

hard_reset() needs an esp-emu build with --control-tcp, which no release carries yet. Without it the service behaves as it does today and dut.serial.hard_reset() raises with an explanation, so this can merge ahead of the emulator change.


Checklist

Before submitting a Pull Request, please ensure the following:

  • 🚨 This PR does not introduce breaking changes.
  • All CI checks (GH Actions) pass.
  • Documentation is updated as needed.
  • Tests are updated or added as necessary.
  • Code is well-commented, especially in complex areas.
  • Git history is clean — commits are squashed to the minimum necessary.

The qemu service can hand a test an eFuse image, burn eFuses into it and boot
an encrypted image; the esp-emu service could do none of that, so the ESP-IDF
tests that need a device state, rather than a peripheral, had nothing to run
against.

--espemu-efuse-path gives the emulator an eFuse image, creating a blank one
when the file does not exist. execute_efuse_command() runs espefuse against a
second instance started in download mode with its UART on a socket, since the
running one is booted into the firmware and a socket carries no reset lines.
--encrypt and --keyfile encrypt the merged image the same way the qemu service
does, with the current espsecure command name.
esp-emu has supported `--chip esp32c5` for a while, but the service rejected
the target before launching it:

    ValueError: esp-emu does not support target 'esp32c5'.
    Supported targets: esp32c3, esp32c6, esp32h2, esp32p4, esp32s31

so every esp32c5 app was unrunnable under `--embedded-services idf,espemu`.
Nothing else in the service is target specific — the flash image comes from
the app's own flash arguments — so the target list was the only gap.
@github-actions github-actions Bot changed the title espemu efuse and flash encryption espemu efuse and flash encryption (CII-251) Sep 1, 2026
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Title Coverage Tests Skipped Failures Errors Time
Qemu Coverage 7 0 💤 0 ❌ 0 🔥 24.763s ⏱️
3.14 X64 Coverage 123 20 💤 0 ❌ 0 🔥 15m 27s ⏱️
Espemu Coverage 4 0 💤 0 ❌ 0 🔥 4.838s ⏱️

ESP-IDF tests reach the chip through two channels: the console stream
(`dut.expect`) and a control channel (`dut.serial`) that resets it, erases
flash and burns eFuses. `EspEmuDut` extends the plain `Dut`, so `dut.serial`
did not exist and 48 cases in an ESP-IDF sweep died at setup with

    AttributeError: 'EspEmuDutWithIdfUnityDutMixin' object has no attribute 'serial'

40% of them only wanted a reset. esp-emu now serves a control channel, so
`hard_reset()` sends `reset` over it: the emulator process keeps running, so
the dut's stream, expect history and log all continue across the reset, which
relaunching the process would break.

The service asks `--help` whether the binary has the channel before passing
`--control-tcp`, since an older esp-emu exits on an unknown flag. The
operations that still need the emulator in download mode raise with the name
of what was wanted, so a test reports the operation it needed rather than a
missing attribute.
@Harshal5 Harshal5 changed the title espemu efuse and flash encryption (CII-251) espemu: eFuses, flash encryption, esp32c5, and a working hard reset (CII-251) Sep 2, 2026
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