Patrick Lidstone
Self-hosted

Development log

Hibernation, and the copy that ran out from under itself

· Path OS

S3 keeps RAM powered. S4 does not, which means the contents of memory have to be somewhere else before the power goes, and back in exactly the right places afterwards.

The image is a run-length encoded copy of active memory written to a dedicated disk partition. Dedicated rather than a file, because an image that cannot be written has failed at the worst possible moment, and a partition reserved at install time is storage that is guaranteed to be there. Before the write, every core except the one doing the writing is quiesced, for the same reason a filesystem is not backed up while it is being modified.

The first attempt powered off, booted, and walked straight past its own image. That is the easy class of failure. The interesting one came later.

The copy that ran out from under itself

The checksum passed, so the image on disk was good, and then the restore died inside the assembly block that does the copy.

This is a design error rather than a slip. The frames being restored contain the page tables the fresh boot is currently running on. A rep movsb over them overwrites them while the processor is using them, so the mappings change underneath the copier part-way through the copy. Disabling interrupts does not help with that at all - there is no interrupt involved. The processor is walking a page table that the instruction it is executing is in the middle of overwriting.

The answer is to copy under a page table belonging to neither machine: a minimal set of mappings owned by the restore itself, so neither the outgoing boot's tables nor the incoming image's are live while the bytes move. The companion rule is to read nothing after CR3 moves, which sounds obvious written down and is easy to violate by accident, because any helper function touching a global is a read through the mappings you have just replaced.

Two smaller faults in the same area: the snapshot's runs were being shadowed by the live ones, and a modified input register sat inside a block that returns, so the compiler was entitled to assume it had not changed.

The order a restore has to happen in

A restored machine is a machine whose software state is perfect and whose hardware state is gone. Every driver has to say explicitly which of those it is dealing with, and S4 is not S3 with a longer sleep - it has to assume the old hardware context never existed, even though the structures describing it came back intact.

restore the image; keep application cores parked and device callbacks gated
  → recover platform, clocks and interrupt infrastructure
  → recover the disk
  → recover the display and repaint
  → recover USB, then Bluetooth
  → recover the wired network, then Wi-Fi
  → recover audio
  → release device callbacks and restart application cores

Each device finishes either ready or explicitly offline. A failed initialisation must never leave its old handle available to the polling loop, which is the mistake that turns one dead device into a hung machine. Dropping the dead handles outright is the rule, rather than merely declining to use them.

The display is where S4 differs most from S3. After S4 the firmware may already have brought the panel up, so replaying the pre-hibernate display registers over a working configuration is the wrong move. The fresh boot's framebuffer address, pitch, format and mode are captured outside the memory about to be overwritten and passed into the restored kernel, which then adopts them if they are usable.

USB gets cold-boot treatment rather than a resume: claim ownership from the firmware, halt and reset the controller, build fresh DMA rings, reset and enumerate the ports, assign addresses again, rebind the class drivers. A device staying physically plugged in does not make its old software handle valid.

The log that survives the power going off

All of this happens before the network exists, and the X1 has no serial port, so there was nothing to read. The console log is now also a ring buffer on the disk, which is the only instrument that survives the machine being powered off and started again.

That immediately earned its keep: the disk log's replay was broken, and the failed path went deaf, so the one case that most needed a record was the case producing none.

What is not built

All the cores come back by default now, and a restored machine on one core was the intermediate step rather than the goal. The awkward parts of device recovery are opt-in, which is an honest way of saying they are not trusted yet.

This is the X1 only. The partition layout assumes an installed machine with a hibernation area, and a machine without one declines to hibernate rather than improvising.