1#[cfg(guest_arch = "aarch64")]
7pub use Aarch64Register as Register;
8#[cfg(guest_arch = "x86_64")]
9pub use X86Register as Register;
10
11#[derive(Debug, PartialEq, Eq, Clone, Copy)]
14pub enum BootPageAcceptance {
15 Exclusive,
18 ExclusiveUnmeasured,
21 VpContext,
23 SecretsPage,
26 CpuidPage,
28 CpuidExtendedStatePage,
30 Shared,
32}
33
34#[derive(Debug, PartialEq, Eq)]
36pub enum IsolationType {
37 None,
39 Vbs,
41 Snp,
43 Tdx,
45}
46
47#[derive(Debug, PartialEq, Eq)]
50pub enum StartupMemoryType {
51 Ram,
53 Vtl2ProtectableRam,
56}
57
58#[derive(Copy, Clone, Debug, PartialEq, Eq)]
60pub struct TableRegister {
61 pub base: u64,
62 pub limit: u16,
63}
64
65impl From<igvm::registers::TableRegister> for TableRegister {
66 fn from(value: igvm::registers::TableRegister) -> Self {
67 Self {
68 base: value.base,
69 limit: value.limit,
70 }
71 }
72}
73
74impl From<TableRegister> for igvm::registers::TableRegister {
75 fn from(value: TableRegister) -> Self {
76 Self {
77 base: value.base,
78 limit: value.limit,
79 }
80 }
81}
82
83#[derive(Copy, Clone, Debug, PartialEq, Eq)]
85pub struct SegmentRegister {
86 pub base: u64,
87 pub limit: u32,
88 pub selector: u16,
89 pub attributes: u16,
90}
91
92impl From<igvm::registers::SegmentRegister> for SegmentRegister {
93 fn from(value: igvm::registers::SegmentRegister) -> Self {
94 Self {
95 base: value.base,
96 limit: value.limit,
97 selector: value.selector,
98 attributes: value.attributes,
99 }
100 }
101}
102
103impl From<SegmentRegister> for igvm::registers::SegmentRegister {
104 fn from(value: SegmentRegister) -> Self {
105 Self {
106 base: value.base,
107 limit: value.limit,
108 selector: value.selector,
109 attributes: value.attributes,
110 }
111 }
112}
113
114#[derive(Debug, Clone, Copy, PartialEq, Eq)]
116pub enum X86Register {
117 Gdtr(TableRegister),
118 Idtr(TableRegister),
119 Ds(SegmentRegister),
120 Es(SegmentRegister),
121 Fs(SegmentRegister),
122 Gs(SegmentRegister),
123 Ss(SegmentRegister),
124 Cs(SegmentRegister),
125 Tr(SegmentRegister),
126 Cr0(u64),
127 Cr3(u64),
128 Cr4(u64),
129 Efer(u64),
130 Pat(u64),
131 Rbp(u64),
132 Rip(u64),
133 Rsi(u64),
134 Rsp(u64),
135 R8(u64),
136 R9(u64),
137 R10(u64),
138 R11(u64),
139 R12(u64),
140 Rflags(u64),
141 MtrrDefType(u64),
142 MtrrPhysBase0(u64),
143 MtrrPhysMask0(u64),
144 MtrrPhysBase1(u64),
145 MtrrPhysMask1(u64),
146 MtrrPhysBase2(u64),
147 MtrrPhysMask2(u64),
148 MtrrPhysBase3(u64),
149 MtrrPhysMask3(u64),
150 MtrrPhysBase4(u64),
151 MtrrPhysMask4(u64),
152 MtrrFix64k00000(u64),
153 MtrrFix16k80000(u64),
154 MtrrFix4kE0000(u64),
156 MtrrFix4kE8000(u64),
157 MtrrFix4kF0000(u64),
158 MtrrFix4kF8000(u64),
159}
160
161impl From<igvm::registers::X86Register> for X86Register {
162 fn from(value: igvm::registers::X86Register) -> Self {
163 use igvm::registers::X86Register as igvm_reg;
164 match value {
165 igvm_reg::Gdtr(v) => X86Register::Gdtr(v.into()),
166 igvm_reg::Idtr(v) => X86Register::Idtr(v.into()),
167 igvm_reg::Ds(v) => X86Register::Ds(v.into()),
168 igvm_reg::Es(v) => X86Register::Es(v.into()),
169 igvm_reg::Fs(v) => X86Register::Fs(v.into()),
170 igvm_reg::Gs(v) => X86Register::Gs(v.into()),
171 igvm_reg::Ss(v) => X86Register::Ss(v.into()),
172 igvm_reg::Cs(v) => X86Register::Cs(v.into()),
173 igvm_reg::Tr(v) => X86Register::Tr(v.into()),
174 igvm_reg::Cr0(v) => X86Register::Cr0(v),
175 igvm_reg::Cr3(v) => X86Register::Cr3(v),
176 igvm_reg::Cr4(v) => X86Register::Cr4(v),
177 igvm_reg::Efer(v) => X86Register::Efer(v),
178 igvm_reg::Pat(v) => X86Register::Pat(v),
179 igvm_reg::Rbp(v) => X86Register::Rbp(v),
180 igvm_reg::Rip(v) => X86Register::Rip(v),
181 igvm_reg::Rsi(v) => X86Register::Rsi(v),
182 igvm_reg::Rsp(v) => X86Register::Rsp(v),
183 igvm_reg::R8(v) => X86Register::R8(v),
184 igvm_reg::R9(v) => X86Register::R9(v),
185 igvm_reg::R10(v) => X86Register::R10(v),
186 igvm_reg::R11(v) => X86Register::R11(v),
187 igvm_reg::R12(v) => X86Register::R12(v),
188 igvm_reg::Rflags(v) => X86Register::Rflags(v),
189 igvm_reg::MtrrDefType(v) => X86Register::MtrrDefType(v),
190 igvm_reg::MtrrPhysBase0(v) => X86Register::MtrrPhysBase0(v),
191 igvm_reg::MtrrPhysMask0(v) => X86Register::MtrrPhysMask0(v),
192 igvm_reg::MtrrPhysBase1(v) => X86Register::MtrrPhysBase1(v),
193 igvm_reg::MtrrPhysMask1(v) => X86Register::MtrrPhysMask1(v),
194 igvm_reg::MtrrPhysBase2(v) => X86Register::MtrrPhysBase2(v),
195 igvm_reg::MtrrPhysMask2(v) => X86Register::MtrrPhysMask2(v),
196 igvm_reg::MtrrPhysBase3(v) => X86Register::MtrrPhysBase3(v),
197 igvm_reg::MtrrPhysMask3(v) => X86Register::MtrrPhysMask3(v),
198 igvm_reg::MtrrPhysBase4(v) => X86Register::MtrrPhysBase4(v),
199 igvm_reg::MtrrPhysMask4(v) => X86Register::MtrrPhysMask4(v),
200 igvm_reg::MtrrFix64k00000(v) => X86Register::MtrrFix64k00000(v),
201 igvm_reg::MtrrFix16k80000(v) => X86Register::MtrrFix16k80000(v),
202 igvm_reg::MtrrFix4kE0000(v) => X86Register::MtrrFix4kE0000(v),
203 igvm_reg::MtrrFix4kE8000(v) => X86Register::MtrrFix4kE8000(v),
204 igvm_reg::MtrrFix4kF0000(v) => X86Register::MtrrFix4kF0000(v),
205 igvm_reg::MtrrFix4kF8000(v) => X86Register::MtrrFix4kF8000(v),
206 }
207 }
208}
209
210impl From<X86Register> for igvm::registers::X86Register {
211 fn from(value: X86Register) -> Self {
212 use igvm::registers::X86Register as igvm_reg;
213 match value {
214 X86Register::Gdtr(v) => igvm_reg::Gdtr(v.into()),
215 X86Register::Idtr(v) => igvm_reg::Idtr(v.into()),
216 X86Register::Ds(v) => igvm_reg::Ds(v.into()),
217 X86Register::Es(v) => igvm_reg::Es(v.into()),
218 X86Register::Fs(v) => igvm_reg::Fs(v.into()),
219 X86Register::Gs(v) => igvm_reg::Gs(v.into()),
220 X86Register::Ss(v) => igvm_reg::Ss(v.into()),
221 X86Register::Cs(v) => igvm_reg::Cs(v.into()),
222 X86Register::Tr(v) => igvm_reg::Tr(v.into()),
223 X86Register::Cr0(v) => igvm_reg::Cr0(v),
224 X86Register::Cr3(v) => igvm_reg::Cr3(v),
225 X86Register::Cr4(v) => igvm_reg::Cr4(v),
226 X86Register::Efer(v) => igvm_reg::Efer(v),
227 X86Register::Pat(v) => igvm_reg::Pat(v),
228 X86Register::Rbp(v) => igvm_reg::Rbp(v),
229 X86Register::Rip(v) => igvm_reg::Rip(v),
230 X86Register::Rsi(v) => igvm_reg::Rsi(v),
231 X86Register::Rsp(v) => igvm_reg::Rsp(v),
232 X86Register::R8(v) => igvm_reg::R8(v),
233 X86Register::R9(v) => igvm_reg::R9(v),
234 X86Register::R10(v) => igvm_reg::R10(v),
235 X86Register::R11(v) => igvm_reg::R11(v),
236 X86Register::R12(v) => igvm_reg::R12(v),
237 X86Register::Rflags(v) => igvm_reg::Rflags(v),
238 X86Register::MtrrDefType(v) => igvm_reg::MtrrDefType(v),
239 X86Register::MtrrPhysBase0(v) => igvm_reg::MtrrPhysBase0(v),
240 X86Register::MtrrPhysMask0(v) => igvm_reg::MtrrPhysMask0(v),
241 X86Register::MtrrPhysBase1(v) => igvm_reg::MtrrPhysBase1(v),
242 X86Register::MtrrPhysMask1(v) => igvm_reg::MtrrPhysMask1(v),
243 X86Register::MtrrPhysBase2(v) => igvm_reg::MtrrPhysBase2(v),
244 X86Register::MtrrPhysMask2(v) => igvm_reg::MtrrPhysMask2(v),
245 X86Register::MtrrPhysBase3(v) => igvm_reg::MtrrPhysBase3(v),
246 X86Register::MtrrPhysMask3(v) => igvm_reg::MtrrPhysMask3(v),
247 X86Register::MtrrPhysBase4(v) => igvm_reg::MtrrPhysBase4(v),
248 X86Register::MtrrPhysMask4(v) => igvm_reg::MtrrPhysMask4(v),
249 X86Register::MtrrFix64k00000(v) => igvm_reg::MtrrFix64k00000(v),
250 X86Register::MtrrFix16k80000(v) => igvm_reg::MtrrFix16k80000(v),
251 X86Register::MtrrFix4kE0000(v) => igvm_reg::MtrrFix4kE0000(v),
252 X86Register::MtrrFix4kE8000(v) => igvm_reg::MtrrFix4kE8000(v),
253 X86Register::MtrrFix4kF0000(v) => igvm_reg::MtrrFix4kF0000(v),
254 X86Register::MtrrFix4kF8000(v) => igvm_reg::MtrrFix4kF8000(v),
255 }
256 }
257}
258
259#[derive(Debug, Clone, Copy, PartialEq, Eq)]
260pub enum Aarch64Register {
261 Pc(u64),
262 X0(u64),
263 X1(u64),
264 X2(u64),
265 X3(u64),
266 X4(u64),
267 X5(u64),
268 X6(u64),
269 X7(u64),
270 Cpsr(u64),
271 VbarEl1(u64),
272 Ttbr0El1(u64),
273 Ttbr1El1(u64),
274 MairEl1(u64),
275 SctlrEl1(u64),
276 TcrEl1(u64),
277}
278
279impl From<igvm::registers::AArch64Register> for Aarch64Register {
280 fn from(value: igvm::registers::AArch64Register) -> Self {
281 use igvm::registers::AArch64Register as igvm_reg;
282 match value {
283 igvm_reg::Pc(v) => Aarch64Register::Pc(v),
284 igvm_reg::X0(v) => Aarch64Register::X0(v),
285 igvm_reg::X1(v) => Aarch64Register::X1(v),
286 igvm_reg::X2(v) => Aarch64Register::X2(v),
287 igvm_reg::X3(v) => Aarch64Register::X3(v),
288 igvm_reg::X4(v) => Aarch64Register::X4(v),
289 igvm_reg::X5(v) => Aarch64Register::X5(v),
290 igvm_reg::X6(v) => Aarch64Register::X6(v),
291 igvm_reg::X7(v) => Aarch64Register::X7(v),
292 igvm_reg::Cpsr(v) => Aarch64Register::Cpsr(v),
293 igvm_reg::SctlrEl1(v) => Aarch64Register::SctlrEl1(v),
294 igvm_reg::TcrEl1(v) => Aarch64Register::TcrEl1(v),
295 igvm_reg::MairEl1(v) => Aarch64Register::MairEl1(v),
296 igvm_reg::VbarEl1(v) => Aarch64Register::VbarEl1(v),
297 igvm_reg::Ttbr0El1(v) => Aarch64Register::Ttbr0El1(v),
298 igvm_reg::Ttbr1El1(v) => Aarch64Register::Ttbr1El1(v),
299 }
300 }
301}
302
303impl From<Aarch64Register> for igvm::registers::AArch64Register {
304 fn from(value: Aarch64Register) -> Self {
305 use igvm::registers::AArch64Register as igvm_reg;
306 match value {
307 Aarch64Register::Pc(v) => igvm_reg::Pc(v),
308 Aarch64Register::X0(v) => igvm_reg::X0(v),
309 Aarch64Register::X1(v) => igvm_reg::X1(v),
310 Aarch64Register::X2(v) => igvm_reg::X2(v),
311 Aarch64Register::X3(v) => igvm_reg::X3(v),
312 Aarch64Register::X4(v) => igvm_reg::X4(v),
313 Aarch64Register::X5(v) => igvm_reg::X5(v),
314 Aarch64Register::X6(v) => igvm_reg::X6(v),
315 Aarch64Register::X7(v) => igvm_reg::X7(v),
316 Aarch64Register::Cpsr(v) => igvm_reg::Cpsr(v),
317 Aarch64Register::SctlrEl1(v) => igvm_reg::SctlrEl1(v),
318 Aarch64Register::TcrEl1(v) => igvm_reg::TcrEl1(v),
319 Aarch64Register::MairEl1(v) => igvm_reg::MairEl1(v),
320 Aarch64Register::VbarEl1(v) => igvm_reg::VbarEl1(v),
321 Aarch64Register::Ttbr0El1(v) => igvm_reg::Ttbr0El1(v),
322 Aarch64Register::Ttbr1El1(v) => igvm_reg::Ttbr1El1(v),
323 }
324 }
325}
326
327#[derive(Debug)]
329pub struct IsolationConfig {
330 pub paravisor_present: bool,
332
333 pub isolation_type: IsolationType,
335
336 pub shared_gpa_boundary_bits: Option<u8>,
338}
339
340#[derive(Debug, Default)]
341pub struct CpuidResult {
342 pub eax: u32,
343 pub ebx: u32,
344 pub ecx: u32,
345 pub edx: u32,
346}
347
348impl IsolationConfig {
349 pub fn get_cpuid(&self) -> CpuidResult {
351 let eax = if self.paravisor_present { 1 } else { 0 };
353
354 let mut ebx = 0;
355 match self.isolation_type {
356 IsolationType::None => {}
357 IsolationType::Vbs => ebx = hvdef::HvPartitionIsolationType::VBS.0 as _,
358 IsolationType::Snp => ebx = hvdef::HvPartitionIsolationType::SNP.0 as _,
359 IsolationType::Tdx => ebx = hvdef::HvPartitionIsolationType::TDX.0 as _,
360 }
361
362 match self.shared_gpa_boundary_bits {
363 None => {}
364 Some(bits) => {
365 ebx |= 1 << 5;
366 ebx |= ((bits & 0x3F) as u32) << 6;
367 }
368 }
369
370 CpuidResult {
371 eax,
372 ebx,
373 ecx: 0,
374 edx: 0,
375 }
376 }
377}
378
379#[derive(Debug)]
380pub enum IgvmParameterType {
381 VpCount,
382 Srat,
383 Madt,
384 MmioRanges,
385 MemoryMap,
386 CommandLine,
387 Slit,
388 Pptt,
389 DeviceTree,
390}
391
392#[repr(transparent)]
393#[derive(Debug, Clone, Copy)]
394pub struct ParameterAreaIndex(pub u32);
395
396#[derive(Debug, Clone, Copy, PartialEq, Eq)]
397pub enum GuestArchKind {
398 X86_64,
399 Aarch64,
400}
401
402pub trait GuestArch {
403 fn arch() -> GuestArchKind;
404}
405
406impl GuestArch for X86Register {
407 fn arch() -> GuestArchKind {
408 GuestArchKind::X86_64
409 }
410}
411
412impl GuestArch for Aarch64Register {
413 fn arch() -> GuestArchKind {
414 GuestArchKind::Aarch64
415 }
416}
417
418pub trait ImageLoad<R>
419where
420 R: GuestArch,
421{
422 fn isolation_config(&self) -> IsolationConfig;
425
426 fn create_parameter_area(
432 &mut self,
433 page_base: u64,
434 page_count: u32,
435 debug_tag: &str,
436 ) -> anyhow::Result<ParameterAreaIndex>;
437
438 fn create_parameter_area_with_data(
444 &mut self,
445 page_base: u64,
446 page_count: u32,
447 debug_tag: &str,
448 initial_data: &[u8],
449 ) -> anyhow::Result<ParameterAreaIndex>;
450
451 fn import_parameter(
457 &mut self,
458 parameter_area: ParameterAreaIndex,
459 byte_offset: u32,
460 parameter_type: IgvmParameterType,
461 ) -> anyhow::Result<()>;
462
463 fn import_pages(
469 &mut self,
470 page_base: u64,
471 page_count: u64,
472 debug_tag: &'static str,
473 acceptance: BootPageAcceptance,
474 data: &[u8],
475 ) -> anyhow::Result<()>;
476
477 fn import_vp_register(&mut self, register: R) -> anyhow::Result<()>;
479
480 fn verify_startup_memory_available(
482 &mut self,
483 page_base: u64,
484 page_count: u64,
485 memory_type: StartupMemoryType,
486 ) -> anyhow::Result<()>;
487
488 fn set_vp_context_page(&mut self, page_base: u64) -> anyhow::Result<()>;
492
493 fn relocation_region(
495 &mut self,
496 gpa: u64,
497 size_bytes: u64,
498 relocation_alignment: u64,
499 minimum_relocation_gpa: u64,
500 maximum_relocation_gpa: u64,
501 apply_rip_offset: bool,
502 apply_gdtr_offset: bool,
503 vp_index: u16,
504 ) -> anyhow::Result<()>;
505
506 fn page_table_relocation(
508 &mut self,
509 page_table_gpa: u64,
510 size_pages: u64,
511 used_pages: u64,
512 vp_index: u16,
513 ) -> anyhow::Result<()>;
514
515 fn set_imported_regions_config_page(&mut self, page_base: u64);
525
526 fn set_expected_page_hashes_config_page(&mut self, _page_base: u64) {}
539}