Skip to content

novatek: the mask ROM's Ethernet boot, DHCP and TFTP through nvt-eqos - #226

Merged
widgetii merged 2 commits into
masterfrom
novatek-rom-eth
Nov 4, 2026
Merged

widgetii merged 2 commits into
masterfrom
novatek-rom-eth

Conversation

@widgetii

@widgetii widgetii commented Nov 4, 2026

Copy link
Copy Markdown
Member

The second half of #225: the ROM fallback's Ethernet stage is now the NA51089 ROM's own DHCP and TFTP client, as read from the ROM dump and seen on an NT98562 on a real LAN.

ROM behaviour modelled:

  • MAC 00:00:00:xx:xx:xx, new every boot.
  • It takes only a broadcast offer and drops a unicast one.
  • One TFTP request for loader.bin from port 2962, sent to the offering MAC.
  • No timeout and no retransmission while it waits for data.
  • The console letters match silicon's.

Emulator change: a small nvt-eqos hook lets the ROM drive the MAC before any loader runs.

Tests:

The fallback's Ethernet stage (#225) sent nothing. It is now the NA51089
ROM's DHCP and TFTP client, as read from a dump of the ROM and seen on an
NT98562 on a real LAN:

- A MAC of 00:00:00 and three random bytes, new every boot.
  DHCPDISCOVER every 5 s.
- The first broadcast offer is taken; a unicast one, to an address it has
  not configured, is dropped, as silicon dropped dnsmasq's.
- DHCPREQUEST, the ACK, an ARP request for the next-server, then one
  TFTP read request for loader.bin from port 2962, to the offer's MAC.
- Then it waits for DATA from that server with no timeout and no
  retransmission, so a network DHCP server that wins the race holds it
  for good. A short block ends it, then the loader check.
- The letters are silicon's: aOfIP <ip> SRV <srv>, MSK, bS2, cAkS3S4,
  CD for ARP, t<block>, Dn, T.

The ROM drives nvt-eqos through a new hook: attached, every frame goes to
it instead of the rings, and it sends on the NIC's queue; it detaches
before the jump, and the loader brings the MAC up as before. Attaching
flushes the queue, or a tap backend that stopped polling while the MAC
could not receive never starts again.

defib's Ethernet recovery (OpenIPC/defib#170, #171) runs against it
unmodified over a tap: the ROM takes defib's offer, fetches loader.bin,
the real Ethernet loader then does its own DHCP and fetches the U-Boot
pack, and U-Boot from RAM answers at its prompt, on nt98562 and nt98566.
qemu-boot/test-novatek-recovery.sh gains that third way in, and CI runs
it (sudo for the tap and ports 67/69), with defib pinned to 74e1bcc.
test-novatek.py drives the ROM over a UDP socket netdev with no root: a
unicast offer dropped, a broadcast one taken, the ARP and the single
read request to the offering MAC, no retransmission while it waits, and
one short block running the loader. 802 checks pass.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Emulate Novatek mask ROM Ethernet recovery over DHCP and TFTP

✨ Enhancement 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Model the mask ROM’s DHCP and TFTP boot so Ethernet recovery can load a first-stage loader.
• Let the ROM use nvt-eqos before handing the MAC back to the loader.
• Cover packet behavior and defib recovery in tests, CI, and documentation.
Diagram

graph TD
  ROM["ROM fallback"] --> MAC["nvt-eqos hook"] --> DISC["DHCP discover"] --> OFFER{"Broadcast offer?"} -->|yes| REQ["DHCP request"] --> TFTP["ARP and TFTP"] --> SRAM["SRAM loader"] --> HANDOFF["Loader handoff"]
  OFFER -->|no| DISC
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Drive EQOS registers and DMA rings from the ROM model
  • ➕ Exercises the same MAC path used by the loader
  • ➕ Could model lower-level ROM hardware behavior more closely
  • ➖ Substantially expands the emulation surface
  • ➖ Adds register and descriptor complexity to a boot-stage protocol model

Recommendation: Keep the temporary nvt-eqos hook: it models the observable network exchange while preserving the loader’s existing MAC path after handoff. Register-level MAC operation is worth considering only if recovery needs hardware-level fidelity.

Files changed (9) +543 / -31

Enhancement (4) +359 / -4
novatek.cConnect the machine’s MAC to the boot ROM +6/-0

Connect the machine’s MAC to the boot ROM

• Retains the nvt-eqos device reference and links it to the ROM when creating the ROM device.

qemu/hw/arm/novatek.c

nvt-bootrom.cImplement mask ROM DHCP and TFTP boot +305/-4

Implement mask ROM DHCP and TFTP boot

• Adds Ethernet frame construction and a DHCP-to-TFTP recovery sequence, including the ROM’s broadcast-offer behavior, console output, and SRAM loader transfer. Attaches the ROM to the MAC during Ethernet boot and detaches on timeout, reset, or loader handoff.

qemu/hw/arm/nvt-bootrom.c

nvt-eqos.cProvide temporary ROM access to the MAC +32/-0

Provide temporary ROM access to the MAC

• Routes received frames to the ROM callback instead of DMA rings while attached and lets the ROM transmit on the NIC queue. Flushes queued packets when attachment changes so a paused backend can resume receiving.

qemu/hw/net/nvt-eqos.c

nvt-bootrom.hDeclare ROM network state and MAC hook +16/-0

Declare ROM network state and MAC hook

• Adds the callback and send interfaces used by nvt-eqos, plus the ROM state needed to track DHCP and TFTP transfers.

qemu/include/hw/arm/nvt-bootrom.h

Documentation (2) +30 / -7
CLAUDE.mdDocument ROM Ethernet boot support +2/-2

Document ROM Ethernet boot support

• Updates the repository guidance to describe DHCP/TFTP through nvt-eqos and recovery with defib’s NIC mode.

CLAUDE.md

novatek.mdDescribe ROM network behavior and Ethernet recovery +28/-5

Describe ROM network behavior and Ethernet recovery

• Documents the ROM’s DHCP offer handling, TFTP transfer, console output, and behavior without a server. Adds a tap-based defib recovery example.

docs/novatek.md

Other (3) +154 / -20
ci.ymlRun Ethernet recovery with a pinned defib version +6/-4

Run Ethernet recovery with a pinned defib version

• Renames the recovery job to include Ethernet and pins a defib commit with NIC recovery support. The existing recovery script now exercises the additional path in CI.

.github/workflows/ci.yml

test-novatek-recovery.shExercise defib recovery over a tap device +37/-14

Exercise defib recovery over a tap device

• Adds Ethernet as a third recovery path alongside the two UART paths. Configures a tap device, runs defib in NIC mode, and checks that U-Boot answers at its prompt.

qemu-boot/test-novatek-recovery.sh

test-novatek.pyTest ROM Ethernet packets without a tap device +111/-2

Test ROM Ethernet packets without a tap device

• Adds a UDP socket-backed network test for DHCP offer selection, ARP and TFTP requests, waiting without retransmission, console output, and loader handoff. Extends the serial test helper to accept network arguments.

qemu/tests/test-novatek.py

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Recovery stalls with a separate TFTP server ✓ Resolved
Description
eth_dhcp() writes s->srv_ip into DHCPREQUEST option 54, although the offer parser sets that
value from the BOOTP next-server field whenever it is nonzero. If the next-server differs from the
DHCP server identified by the offer’s option 54, the request identifies the wrong DHCP server; a
server that rejects it leaves recovery retrying discovery instead of reaching TFTP.

2. Existing tap settings are left changed ✓ Resolved
Description
The Ethernet test path assigns 192.168.77.1/24 and brings $TAP up even when the interface
already existed, while cleanup() acts on it only when this invocation created it. Running the
default recovery test with a pre-existing nvt-rec0, or with a caller-supplied TAP, leaves that
interface’s address and link state modified after the test.

Grey Divider

Tip of the day
💡 Did you know, you can commit Qodo's fix in one click with committable suggestions (GitHub & GitLab)

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

…s a caller's tap alone

Review follow-ups:

- The ROM's DHCPREQUEST carries the offer's own server identifier
  (option 54) and no longer the next-server, which may be a separate TFTP
  host; the next-server stays the one TFTP is asked.
- test-novatek-recovery.sh changes a pre-existing tap only by adding its
  address if missing, and takes back just that; a tap it made, it
  deletes.
@widgetii
widgetii merged commit 9d8b48c into master Nov 4, 2026
43 checks passed
@widgetii
widgetii deleted the novatek-rom-eth branch November 4, 2026 14:42
widgetii added a commit that referenced this pull request Nov 4, 2026
…eading of a capture (#227)

The Ethernet stage (#226) dropped unicast offers and named the offer's
option 54 in its DHCPREQUEST. The reconstruction of NA51089's ROM
(OpenIPC/opennovatek, re/net.c, net_run 0x3384..0x3e7c) shows otherwise,
and the lab run behind the unicast claim had dnsmasq lose the race by
arriving 3 s late (its ping check), not by being unicast. Now, as the ROM:

- An offer is taken on its xid alone, broadcast or unicast, of any
  message type, if yiaddr and siaddr share a subnet (option 1, else /24);
  otherwise the ROM keeps waiting and asks again in 5 s. "b" follows
  every frame in that state.
- The DHCPREQUEST names siaddr as the server, not option 54 (which #226's
  review had asked for: wrong for this ROM). Its letters are "S2a"; an
  NT98562's capture lacks that "a", likely lost to the ROM's unwaited UART
  writes.
- Any reply with the xid counts as the ACK, a NAK included.
- ARP requests for its address are answered ("Darp"); before, the model
  never answered.

test_rom_eth now checks an off-subnet offer being passed over, a unicast
offer taken, siaddr named in the REQUEST although option 54 differs, and
the ARP answer. 804 checks pass; defib burn --nic still recovers a blank
nt98566 over a tap.
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