Skip to main content

hvdef/
save_restore.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Hypervisor save/restore chunk definitions.
5//!
6//! Structures for serializing VM processor state into the hypervisor's
7//! partition state chunk stream.
8
9use crate::AlignedU128;
10use crate::HvX64SegmentRegister;
11use crate::HvX64TableRegister;
12use core::mem::size_of;
13use open_enum::open_enum;
14use zerocopy::FromBytes;
15use zerocopy::Immutable;
16use zerocopy::IntoBytes;
17use zerocopy::KnownLayout;
18
19// ============================================================
20// Chunk IDs
21// ============================================================
22
23open_enum! {
24    /// Save/restore chunk IDs.
25    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
26    pub enum VmSaveChunkId: u32 {
27
28        // Framing
29        PROLOG                      = 0x0000_0000,
30        EPILOG                      = 0xF000_0000,
31
32        // Partition-level (0x2xxxxxxx)
33        PROCESSOR_CPUID_DATA        = 0x2000_0000,
34        OS_ID                       = 0x2000_1000,
35        PARTITION_VTL               = 0x2000_8000,
36        PARTITION_VSM_CONFIG        = 0x2000_A000,
37
38        // Per-VP (0x3xxxxxxx)
39        VP_INDICES                  = 0x3000_0000,
40        VP                          = 0x3000_1000,
41        VP_CORE                     = 0x3000_3000,
42        VP_GP_REGISTERS             = 0x3000_5000,
43        VP_FP_REGISTERS             = 0x3000_6000,
44        VP_VTL_CONTROL_REGISTERS    = 0x3000_7000,
45        VP_DEBUG_REGISTERS          = 0x3000_8000,
46        VP_SEGMENT_REGISTERS        = 0x3000_9000,
47        VP_TABLE_REGISTERS          = 0x3000_A000,
48        VP_VIRTUAL_MSRS             = 0x3000_B000,
49        VP_XSAVE_CONTROL_REGISTERS  = 0x3000_D000,
50        VP_XSAVE_STATE              = 0x3000_E100,
51        VP_SYNIC_APIC_STATE         = 0x3000_F000,
52        VP_SYNIC_MSRS               = 0x3001_0000,
53        VP_VTL_CONTROL_PAGE         = 0x3001_8000,
54        VP_VTL                      = 0x3001_A000,
55        VP_NESTED_BASE              = 0x3002_1000,
56        VP_NESTED_CURRENT_VMCS      = 0x3002_3000,
57    }
58}
59
60// ============================================================
61// Chunk Header
62// ============================================================
63
64/// Header prefixed to every chunk in the partition state blob.
65///
66/// 16 bytes, aligned to 16. Each chunk occupies
67/// `size_of::<VmSaveChunkHeader>() + data_length` bytes with no
68/// inter-chunk padding.
69#[repr(C, align(16))]
70#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
71pub struct VmSaveChunkHeader {
72    pub id: VmSaveChunkId,
73    pub data_length: u32,
74    pub _padding: [u8; 8],
75}
76
77static_assertions::const_assert_eq!(size_of::<VmSaveChunkHeader>(), 16);
78
79// ============================================================
80// Processor Vendor
81// ============================================================
82
83open_enum! {
84    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
85    pub enum HvProcessorVendor: u32 {
86        AMD     = 0x0000,
87        INTEL   = 0x0001,
88        HYGON   = 0x0002,
89        ARM     = 0x0010,
90    }
91}
92
93// ============================================================
94// Prolog / Epilog
95// ============================================================
96
97/// Undefined tag value written to the prolog.
98pub const VM_SAVE_CHUNK_TAG_UNDEFINED: u32 = 0x5054_6475; // 'duTP'
99
100/// Prolog chunk — always 4080 bytes total.
101#[repr(C)]
102#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
103pub struct ObSaveChunkProlog {
104    pub header: VmSaveChunkHeader,
105    pub undefined_tag: u32,
106    pub is_summary_save_state: u8,
107    pub _padding: [u8; 3],
108    pub vendor: HvProcessorVendor,
109    pub _reserved: [u8; 4052],
110}
111
112pub const OB_SAVE_CHUNK_PROLOG_SIZE: usize = 4080;
113static_assertions::const_assert_eq!(size_of::<ObSaveChunkProlog>(), OB_SAVE_CHUNK_PROLOG_SIZE);
114
115/// Epilog chunk — header only, no data.
116#[repr(C)]
117#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
118pub struct ObSaveChunkEpilog {
119    pub header: VmSaveChunkHeader,
120}
121
122// ============================================================
123// VP / VTL markers
124// ============================================================
125
126/// Per-VP marker chunk.
127#[repr(C)]
128#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
129pub struct ObSaveChunkVp {
130    pub header: VmSaveChunkHeader,
131    pub vp_index: u32,
132    pub _padding: [u8; 12],
133}
134
135/// Per-VTL marker chunk within a VP.
136#[repr(C)]
137#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
138pub struct ObSaveChunkVtl {
139    pub header: VmSaveChunkHeader,
140    pub vtl: u8,
141    pub _padding: [u8; 15],
142}
143
144/// Partition-level VTL marker (same layout as per-VP VTL marker).
145pub type ObSaveChunkPartitionVtl = ObSaveChunkVtl;
146
147// ============================================================
148// OsId
149// ============================================================
150
151/// OsId chunk — contains the guest OS identification.
152#[repr(C)]
153#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
154pub struct PtSaveChunkOsId {
155    pub header: VmSaveChunkHeader,
156    pub os_id: u64,
157    pub _padding: [u8; 8],
158}
159
160// ============================================================
161// x64 Register Chunks
162// ============================================================
163
164/// General purpose registers (x64).
165#[repr(C)]
166#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
167pub struct VpX64SaveChunkGpRegisters {
168    pub header: VmSaveChunkHeader,
169    pub rax: u64,
170    pub rcx: u64,
171    pub rdx: u64,
172    pub rbx: u64,
173    pub rsp: u64,
174    pub rbp: u64,
175    pub rsi: u64,
176    pub rdi: u64,
177    pub r8: u64,
178    pub r9: u64,
179    pub r10: u64,
180    pub r11: u64,
181    pub r12: u64,
182    pub r13: u64,
183    pub r14: u64,
184    pub r15: u64,
185    pub rip: u64,
186    pub rflags: u64,
187}
188
189/// Control registers (x64).
190#[repr(C)]
191#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
192pub struct SynicX64SaveChunkControlRegisters {
193    pub header: VmSaveChunkHeader,
194    pub cr0: u64,
195    pub cr2: u64,
196    pub cr3: u64,
197    pub cr4: u64,
198    pub cr8: u64,
199    pub efer: u64,
200}
201
202/// Debug registers (x64).
203#[repr(C)]
204#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
205pub struct VpX64SaveChunkDebugRegisters {
206    pub header: VmSaveChunkHeader,
207    pub dr0: u64,
208    pub dr1: u64,
209    pub dr2: u64,
210    pub dr3: u64,
211    pub dr6: u64,
212    pub dr7: u64,
213}
214
215/// Segment registers (x64).
216#[repr(C)]
217#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
218pub struct VpX64SaveChunkSegmentRegisters {
219    pub header: VmSaveChunkHeader,
220    pub es: HvX64SegmentRegister,
221    pub cs: HvX64SegmentRegister,
222    pub ss: HvX64SegmentRegister,
223    pub ds: HvX64SegmentRegister,
224    pub fs: HvX64SegmentRegister,
225    pub gs: HvX64SegmentRegister,
226    pub ldtr: HvX64SegmentRegister,
227    pub tr: HvX64SegmentRegister,
228    pub cpl: u8,
229    pub _padding: [u8; 15],
230}
231
232/// Table registers (x64) — IDTR and GDTR.
233#[repr(C)]
234#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
235pub struct VpX64SaveChunkTableRegisters {
236    pub header: VmSaveChunkHeader,
237    pub idtr: HvX64TableRegister,
238    pub gdtr: HvX64TableRegister,
239}
240
241/// Floating-point / SSE / MMX registers (x64).
242#[repr(C)]
243#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
244pub struct VpX64SaveChunkFpRegisters {
245    pub header: VmSaveChunkHeader,
246    pub xmm: [AlignedU128; 16],
247    pub fp_mmx: [AlignedU128; 8],
248    pub fp_control_status: AlignedU128,
249    pub xmm_control_status: AlignedU128,
250}
251
252// ============================================================
253// XSAVE Control Registers
254// ============================================================
255
256/// XSAVE control registers (x64).
257///
258/// Contains the XSAVE Feature Enabled Mask (XFEM/XCR0) register.
259/// Only XCR0 is currently implemented; Xcr1–Xcr7 are reserved.
260#[repr(C)]
261#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
262pub struct VpX64SaveChunkXsaveControlRegisters {
263    pub header: VmSaveChunkHeader,
264    /// XCR0 (XFEATURE_ENABLED_MASK / XFEM).
265    pub xfem: u64,
266    pub _reserved: [u64; 7],
267}
268
269// ============================================================
270// ARM64 Register Chunks
271// ============================================================
272
273/// General purpose registers (ARM64).
274#[repr(C)]
275#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
276pub struct VpArm64SaveChunkGpRegisters {
277    pub header: VmSaveChunkHeader,
278    pub x: [u64; 29],
279    pub x_fp: u64,
280    pub x_lr: u64,
281    pub elr_el2: u64,
282    pub spsr_el2: u64,
283    pub esr_el1: u64,
284    pub spsr_el1: u64,
285    pub far_el1: u64,
286    pub par_el1: u64,
287    pub elr_el1: u64,
288    pub sp_el0: u64,
289    pub sp_el1: u64,
290    pub afsr0_el1: u64,
291    pub afsr1_el1: u64,
292}
293
294/// Control registers (ARM64).
295#[repr(C)]
296#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
297pub struct SynicArm64SaveChunkControlRegisters {
298    pub header: VmSaveChunkHeader,
299    pub vmpidr_el2: u64,
300    pub vpidr_el2: u64,
301    pub sctlr_el1: u64,
302    pub actlr_el1: u64,
303    pub tcr_el1: u64,
304    pub mair_el1: u64,
305    pub tpidr_el1: u64,
306    pub amair_el1: u64,
307    pub tpidrro_el0: u64,
308    pub tpidr_el0: u64,
309    pub contextidr_el1: u64,
310    pub cpacr_el1: u64,
311    pub csselr_el1: u64,
312    pub cntk_ctl_el1: u64,
313    pub cntv_cval_el0: u64,
314    pub cntv_ctl_el0: u64,
315}
316
317/// Table registers (ARM64) — TTBR0, TTBR1, VBAR.
318#[repr(C)]
319#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
320pub struct VpArm64SaveChunkTableRegisters {
321    pub header: VmSaveChunkHeader,
322    pub ttbr0_el1: u64,
323    pub ttbr1_el1: u64,
324    pub vbar_el1: u64,
325    pub _padding: [u8; 8],
326}
327
328/// Floating-point / SIMD registers (ARM64).
329#[repr(C)]
330#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
331pub struct VpArm64SaveChunkFpRegisters {
332    pub header: VmSaveChunkHeader,
333    pub q: [AlignedU128; 32],
334    pub fpsr: u64,
335    pub fpcr: u64,
336}
337
338// ============================================================
339// VP VTL Control Page
340// ============================================================
341
342/// Size of VTL control data in the VP assist page.
343pub const VSM_SAVE_VP_VTL_CONTROL_BYTES: usize = 24;
344
345/// VP VTL control page chunk.
346///
347/// Contains the VTL control contents from the VP assist page and
348/// whether the VTL is runnable.
349#[repr(C)]
350#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
351pub struct VsmSaveChunkVpVtlControlPage {
352    pub header: VmSaveChunkHeader,
353    pub vp_assist_page_vtl_control_contents: [u8; VSM_SAVE_VP_VTL_CONTROL_BYTES],
354    pub vtl_is_runnable: u8,
355    pub _padding: [u8; 7],
356}