Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

snapshot.gno

2.63 Kb · 83 lines
 1package riscv
 2
 3import "gno.land/p/g1magld5ptgzaktqcexxq0pgq5lmdf0kz6re8hlv/x/vm/vmkit/v0"
 4
 5// Snapshot serializes the hart: registers, pc, status, and only the memory
 6// pages the guest has written.
 7//
 8// A 1 MiB address space serialized on every pause would make continuations
 9// cost more than re-running, which is exactly the kill criterion vmkit set for
10// them. The dirty bitmap is what avoids it: a guest that has touched two pages
11// pauses in about 8 KiB regardless of how much memory it was given.
12func (m *Machine) Snapshot() []byte {
13	if m.code == nil {
14		m.code = &code{}
15	}
16	w := vmkit.NewWriter(4096)
17	w.Uint32(snapMagic)
18	w.Byte(snapVersion)
19	for i := 0; i < 32; i++ {
20		w.Uint32(m.reg[i])
21	}
22	w.Uint32(m.pc)
23	w.Byte(byte(m.status))
24	w.String(m.trap)
25	w.Int(int64(m.outLen))
26	// The text segment's extent, so a restored hart knows which of its pages
27	// are code and can predecode them again. The code itself is not written:
28	// it is already in the memory pages, which WriteImage marked dirty.
29	w.Uint32(m.code.base)
30	w.Uint32(m.code.words)
31	m.mem.Snapshot(w)
32	return w.Out()
33}
34
35// Restore loads a snapshot. The program image is not carried separately: it
36// lives in the memory pages, which were marked dirty when it was written, so a
37// restored hart has its code without the instance storing it twice.
38func (m *Machine) Restore(b []byte) error {
39	r := vmkit.NewReader(b)
40	if r.Uint32() != snapMagic {
41		return vmkit.ErrBadSnapshot
42	}
43	if r.Byte() != snapVersion {
44		return vmkit.ErrBadSnapshot
45	}
46	var reg [32]uint32
47	for i := 0; i < 32; i++ {
48		reg[i] = r.Uint32()
49	}
50	pc := r.Uint32()
51	status := vmkit.Status(r.Byte())
52	trap := r.String()
53	outLen := int(r.Int())
54	base := r.Uint32()
55	words := r.Uint32()
56	if err := r.Err(); err != nil {
57		return err
58	}
59	// A text segment that does not fit in the address space is a snapshot this
60	// machine did not write, and predecoding it would index past the memory.
61	if base%4 != 0 || uint64(base)+uint64(words)*4 > uint64(MemSize) {
62		return vmkit.ErrBadSnapshot
63	}
64
65	mem := NewMemory()
66	if err := mem.Restore(r); err != nil {
67		return err
68	}
69	if err := r.Err(); err != nil {
70		return err
71	}
72
73	m.reg, m.pc, m.status, m.trap, m.outLen, m.mem = reg, pc, status, trap, outLen, mem
74	// Predecode again from the restored pages. This is the work a resume pays
75	// for, once, in exchange for not paying a fetch on every instruction after
76	// it, and it is why stores into the text segment trap: the arrays and the
77	// memory would otherwise be free to disagree.
78	m.code = predecode(base, mem.b[base:base+words*4])
79	// x0 is hardwired, and a snapshot that claims otherwise is not one this
80	// machine wrote.
81	m.reg[0] = 0
82	return nil
83}