Skip to content

Machine snapshots: serialize RAM, harts and devices - #317

Open
zmarlon wants to merge 6 commits into
LekKit:stagingfrom
zmarlon:staging
Open

zmarlon wants to merge 6 commits into
LekKit:stagingfrom
zmarlon:staging

Conversation

@zmarlon

@zmarlon zmarlon commented Sep 12, 2026

Copy link
Copy Markdown

The snapshot container and the device suspend callback were already in
place, but nothing walked a machine to drive them, so snapshots couldn't
actually be taken.

rvvm_machine_snapshot() serializes RAM, the harts and every device, in
whichever direction the snapshot was opened. RAM size, hart count, XLEN and
the timebase are stored and checked, so a snapshot only resumes into a
machine it fits. TLB and compiled blocks are dropped on resume since
they're just caches over guest memory.

Legacy MMIO devices gained the suspend callback the region API already had,
so the existing implementations take part. I added suspend for three more
that a typical machine needs: PCI config state including BAR placement,
NVMe queues, and the OpenCores I2C controller. -loadsnap and -savesnap make
it usable from the CLI.

Tested by booting a Linux guest with a framebuffer, NVMe disks and PCIe,
saving it, rebuilding an identical machine and restoring: the guest carries
on from where it left off.

Snapshot sections, device suspend callbacks and several device
implementations were already in place, but nothing walked a machine to
drive them.

rvvm_machine_snapshot() serializes RAM, every hart and every device in a
fixed section order, in whichever direction the snapshot was opened. Hart
state covers registers, FPU and vector state, CSRs, translation and
privilege mode, LR/SC reservation, AIA register files, timer comparators
and raised interrupts. Address translation and compiled blocks are caches
over guest memory and are dropped on resume.

RAM size, hart count and XLEN are stored and checked, so a snapshot only
resumes into the machine layout it was taken from.

Legacy MMIO devices gain the suspend callback the region device API
already had, forwarded through the region wrapper, which lets existing
device implementations participate.
Command, status, interrupt line, bridge windows, power management, MSI
and MSI-X state of every function, and the address each BAR is mapped at,
so that regions are placed back where the guest expects them on resume.
Submission and completion queues, controller configuration, interrupt
mask and temperature threshold. IO workers are drained first, so queues
are not read or overwritten while commands are in flight.

The backing block device is not part of a snapshot and must be restored
to a matching state by the caller.
Resume a machine from a snapshot before it is started, and write one out
after it shuts down.
Resuming skips the machine reset, which is the only place the timer
frequency is set up. Harts then waited in WFI for a timer that never
advanced, leaving the guest frozen with its display intact.

The timebase now travels in the snapshot, and the machine section carries
a version so that a snapshot of an older layout is rejected rather than
misread.
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