1use crate::ApicRegisterValue;
7use crate::X64_PAGE_SIZE;
8use bitfield_struct::bitfield;
9use static_assertions::const_assert_eq;
10use zerocopy::FromBytes;
11use zerocopy::Immutable;
12use zerocopy::IntoBytes;
13use zerocopy::KnownLayout;
14
15pub const SEV_INTR_TYPE_EXT: u32 = 0;
17pub const SEV_INTR_TYPE_NMI: u32 = 2;
18pub const SEV_INTR_TYPE_EXCEPT: u32 = 3;
19pub const SEV_INTR_TYPE_SW: u32 = 4;
20
21pub const REG_TWEAK_BITMAP_OFFSET: usize = 0x100;
23pub const REG_TWEAK_BITMAP_SIZE: usize = 0x40;
24
25pub const SNP_GUEST_REQ_MSG_VERSION: u32 = 1;
28
29#[bitfield(u64)]
30#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
31pub struct SevEventInjectInfo {
32 pub vector: u8,
33 #[bits(3)]
34 pub interruption_type: u32,
35 pub deliver_error_code: bool,
36 #[bits(19)]
37 _rsvd1: u64,
38 pub valid: bool,
39 pub error_code: u32,
40}
41
42#[repr(u8)]
43#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
44pub enum Vmpl {
45 Vmpl0 = 0,
46 Vmpl1 = 1,
47 Vmpl2 = 2,
48 Vmpl3 = 3,
49}
50
51impl From<Vmpl> for u8 {
52 fn from(value: Vmpl) -> Self {
53 value as _
54 }
55}
56
57#[repr(C)]
59#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
60pub struct SevSelector {
61 pub selector: u16,
62 pub attrib: u16,
63 pub limit: u32,
64 pub base: u64,
65}
66
67impl SevSelector {
68 pub fn as_u128(&self) -> u128 {
69 ((self.base as u128) << 64)
70 | ((self.limit as u128) << 32)
71 | ((self.attrib as u128) << 16)
72 | self.selector as u128
73 }
74}
75
76impl From<u128> for SevSelector {
77 fn from(val: u128) -> Self {
78 SevSelector {
79 selector: val as u16,
80 attrib: (val >> 16) as u16,
81 limit: (val >> 32) as u32,
82 base: (val >> 64) as u64,
83 }
84 }
85}
86
87#[repr(C)]
89#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
90pub struct SevXmmRegister {
91 low: u64,
92 high: u64,
93}
94
95impl SevXmmRegister {
96 pub fn as_u128(&self) -> u128 {
97 ((self.high as u128) << 64) | self.low as u128
98 }
99}
100
101impl From<u128> for SevXmmRegister {
102 fn from(val: u128) -> Self {
103 SevXmmRegister {
104 low: val as u64,
105 high: (val >> 64) as u64,
106 }
107 }
108}
109
110#[bitfield(u64)]
111#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
112pub struct SevFeatures {
113 pub snp: bool,
114 pub vtom: bool,
115 pub reflect_vc: bool,
116 pub restrict_injection: bool,
117 pub alternate_injection: bool,
118 pub debug_swap: bool,
119 pub prevent_host_ibs: bool,
120 pub snp_btb_isolation: bool,
121 pub vmpl_isss: bool,
122 pub secure_tsc: bool,
123 pub vmgexit_param: bool,
124 pub pmc_virt: bool,
125 pub ibs_virt: bool,
126 pub guest_intercept_control: bool,
127 pub vmsa_reg_prot: bool,
128 pub smt_prot: bool,
129 pub secure_avic: bool,
130 #[bits(4)]
131 _reserved0: u64,
132 pub ibpb_on_entry: bool,
133 #[bits(41)]
134 _reserved1: u64,
135 pub allowed_sev_features_enable: bool,
136}
137
138#[bitfield(u64)]
139#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
140pub struct SevVirtualInterruptControl {
141 pub tpr: u8,
142 pub irq: bool,
143 pub gif: bool,
144 pub intr_shadow: bool,
145 pub nmi: bool,
146 pub nmi_mask: bool,
147 #[bits(3)]
148 _rsvd1: u64,
149 #[bits(4)]
150 pub priority: u64,
151 pub ignore_tpr: bool,
152 #[bits(5)]
153 _rsvd2: u64,
154 pub nmi_enable: bool,
155 #[bits(5)]
156 _rsvd3: u64,
157 pub vector: u8,
158 #[bits(23)]
159 _rsvd4: u64,
160 pub guest_busy: bool,
161}
162
163#[bitfield(u64)]
164#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
165pub struct SevRmpAdjust {
166 pub target_vmpl: u8,
167 pub enable_read: bool,
168 pub enable_write: bool,
169 pub enable_user_execute: bool,
170 pub enable_kernel_execute: bool,
171 #[bits(4)]
172 _rsvd1: u64,
173 pub vmsa: bool,
174 #[bits(47)]
175 _rsvd2: u64,
176}
177
178#[bitfield(u32)]
179#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
180pub struct SevIoAccessInfo {
181 pub read_access: bool,
182 #[bits(1)]
183 reserved1: u32,
184 pub string_access: bool,
185 pub rep_access: bool,
186 pub access_size8: bool,
187 pub access_size16: bool,
188 pub access_size32: bool,
189 pub address_size8: bool,
190 pub address_size16: bool,
191 pub address_size32: bool,
192 #[bits(3)]
193 pub effective_segment: u32,
194 #[bits(3)]
195 rsvd2: u32,
196 pub port: u16,
197}
198
199#[bitfield(u64)]
200#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
201pub struct SevNpfInfo {
202 pub present: bool,
203 pub is_write: bool,
204 pub user: bool,
205 pub reserved_bit_set: bool,
206 pub fetch: bool,
207 #[bits(1)]
208 rsvd5: u64,
209 pub shadow_stack: bool,
210 #[bits(24)]
211 rsvd7_31: u64,
212 pub rmp_failure: bool,
213 pub caused_by_gpa_access: bool,
214 pub caused_by_page_table_access: bool,
215 pub encrypted_access: bool,
216 pub rmp_size_mismatch: bool,
217 pub vmpl_violation: bool,
218 pub npt_supervisor_shadow_stack: bool,
219 #[bits(25)]
220 rsvd38_62: u64,
221 pub not_restartable: bool,
222}
223
224#[bitfield(u64)]
226#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
227pub struct SecureAvicControl {
228 pub secure_avic_en: bool,
229 pub allowed_nmi: bool,
230 #[bits(10)]
231 _rsvd: u64,
232 #[bits(52)]
233 pub guest_apic_backing_page_ptr: u64,
234}
235
236#[bitfield(u64)]
238pub struct SevAvicIncompleteIpiInfo1 {
239 pub icr_low: u32,
240 pub icr_high: u32,
241}
242
243open_enum::open_enum! {
244 pub enum SevAvicIpiFailure: u32 {
245 INVALID_TYPE = 0,
246 NOT_RUNNING = 1,
247 INVALID_TARGET = 2,
248 INVALID_BACKING_PAGE = 3,
249 INVALID_VECTOR = 4,
250 UNACCELERATED_IPI = 5,
251 }
252}
253
254impl SevAvicIpiFailure {
255 const fn into_bits(self) -> u32 {
256 self.0
257 }
258
259 const fn from_bits(bits: u32) -> Self {
260 Self(bits)
261 }
262}
263
264#[bitfield(u64)]
266pub struct SevAvicIncompleteIpiInfo2 {
267 #[bits(8)]
268 pub index: u32,
269 #[bits(24)]
270 _mbz: u32,
271 #[bits(32)]
272 pub failure: SevAvicIpiFailure,
273}
274
275open_enum::open_enum! {
276 pub enum SevAvicRegisterNumber: u32 {
277 APIC_ID = 0x2,
279 VERSION = 0x3,
281 TPR = 0x8,
283 APR = 0x9,
285 PPR = 0xA,
287 EOI = 0xB,
289 REMOTE_READ = 0xC,
291 LDR = 0xD,
293 DFR = 0xE,
295 SPURIOUS = 0xF,
297 ISR0 = 0x10,
299 ISR1 = 0x11,
300 ISR2 = 0x12,
301 ISR3 = 0x13,
302 ISR4 = 0x14,
303 ISR5 = 0x15,
304 ISR6 = 0x16,
305 ISR7 = 0x17,
306 TMR0 = 0x18,
308 TMR1 = 0x19,
309 TMR2 = 0x1A,
310 TMR3 = 0x1B,
311 TMR4 = 0x1C,
312 TMR5 = 0x1D,
313 TMR6 = 0x1E,
314 TMR7 = 0x1F,
315 IRR0 = 0x20,
317 IRR1 = 0x21,
318 IRR2 = 0x22,
319 IRR3 = 0x23,
320 IRR4 = 0x24,
321 IRR5 = 0x25,
322 IRR6 = 0x26,
323 IRR7 = 0x27,
324 ERROR = 0x28,
326 ICR_LOW = 0x30,
328 ICR_HIGH = 0x31,
330 TIMER_LVT = 0x32,
332 THERMAL_LVT = 0x33,
334 PERFMON_LVT = 0x34,
336 LINT0_LVT = 0x35,
338 LINT1_LVT = 0x36,
340 ERROR_LVT = 0x37,
342 INITIAL_COUNT = 0x38,
344 CURRENT_COUNT = 0x39,
346 DIVIDER = 0x3e,
348 SELF_IPI = 0x3f,
350 }
351}
352
353impl SevAvicRegisterNumber {
354 const fn into_bits(self) -> u32 {
355 self.0
356 }
357
358 const fn from_bits(bits: u32) -> Self {
359 Self(bits)
360 }
361}
362
363#[bitfield(u64)]
365pub struct SevAvicNoAccelInfo {
366 #[bits(4)]
367 _rsvd1: u64,
368 #[bits(8)]
369 pub apic_register_number: SevAvicRegisterNumber,
370 #[bits(20)]
371 _rsvd2: u64,
372 #[bits(1)]
373 pub write_access: bool,
374 #[bits(31)]
375 _rsvd3: u64,
376}
377
378#[repr(C)]
380#[derive(Debug, Clone, IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
381pub struct SevVmsa {
382 pub es: SevSelector,
384 pub cs: SevSelector,
385 pub ss: SevSelector,
386 pub ds: SevSelector,
387 pub fs: SevSelector,
388 pub gs: SevSelector,
389
390 pub gdtr: SevSelector,
392 pub ldtr: SevSelector,
393 pub idtr: SevSelector,
394 pub tr: SevSelector,
395
396 pub pl0_ssp: u64,
398 pub pl1_ssp: u64,
399 pub pl2_ssp: u64,
400 pub pl3_ssp: u64,
401 pub u_cet: u64,
402
403 pub vmsa_reserved1: [u8; 2],
405
406 pub vmpl: u8,
408
409 pub cpl: u8,
411
412 pub vmsa_reserved2: u32,
414
415 pub efer: u64,
417
418 pub vmsa_reserved3: [u32; 26],
420
421 pub xss: u64,
423
424 pub cr4: u64,
426 pub cr3: u64,
427 pub cr0: u64,
428
429 pub dr7: u64,
431 pub dr6: u64,
432
433 pub rflags: u64,
435
436 pub rip: u64,
438
439 pub dr0: u64,
441 pub dr1: u64,
442 pub dr2: u64,
443 pub dr3: u64,
444
445 pub dr0_addr_mask: u64,
447 pub dr1_addr_mask: u64,
448 pub dr2_addr_mask: u64,
449 pub dr3_addr_mask: u64,
450
451 pub vmsa_reserved4: [u64; 3],
453
454 pub rsp: u64,
456
457 pub s_cet: u64,
459 pub ssp: u64,
460 pub interrupt_ssp_table_addr: u64,
461
462 pub rax: u64,
464
465 pub star: u64,
467 pub lstar: u64,
468 pub cstar: u64,
469 pub sfmask: u64,
470
471 pub kernel_gs_base: u64,
473
474 pub sysenter_cs: u64,
476 pub sysenter_esp: u64,
477 pub sysenter_eip: u64,
478
479 pub cr2: u64,
481
482 pub vmsa_reserved5: [u64; 4],
484
485 pub pat: u64,
487
488 pub dbgctl: u64,
490 pub last_branch_from_ip: u64,
491 pub last_branch_to_ip: u64,
492 pub last_excp_from_ip: u64,
493 pub last_excp_to_ip: u64,
494
495 pub vmsa_reserved6: [u64; 9],
497
498 pub spec_ctrl: u64,
500
501 pub pkru: u32,
503
504 pub tsc_aux: u32,
506
507 pub vmsa_reserved7: [u32; 4],
509
510 pub register_protection_nonce: u64,
511
512 pub rcx: u64,
514 pub rdx: u64,
515 pub rbx: u64,
516 pub secure_avic_control: SecureAvicControl,
517 pub rbp: u64,
518 pub rsi: u64,
519 pub rdi: u64,
520 pub r8: u64,
521 pub r9: u64,
522 pub r10: u64,
523 pub r11: u64,
524 pub r12: u64,
525 pub r13: u64,
526 pub r14: u64,
527 pub r15: u64,
528
529 pub vmsa_reserved9: [u64; 2],
531
532 pub exit_info1: u64,
534 pub exit_info2: u64,
535 pub exit_int_info: u64,
536
537 pub next_rip: u64,
539
540 pub sev_features: SevFeatures,
542
543 pub v_intr_cntrl: SevVirtualInterruptControl,
545
546 pub guest_error_code: u64,
548
549 pub virtual_tom: u64,
551
552 pub tlb_id: u64,
555 pub pcpu_id: u64,
556
557 pub event_inject: SevEventInjectInfo,
559
560 pub xcr0: u64,
562
563 pub xsave_valid_bitmap: [u8; 16],
565
566 pub x87dp: u64,
568 pub mxcsr: u32,
569 pub x87_ftw: u16,
570 pub x87_fsw: u16,
571 pub x87_fcw: u16,
572 pub x87_op: u16,
573 pub x87_ds: u16,
574 pub x87_cs: u16,
575 pub x87_rip: u64,
576
577 pub x87_registers: [u64; 10],
580
581 pub xmm_registers: [SevXmmRegister; 16],
583
584 pub ymm_registers: [SevXmmRegister; 16],
586}
587
588#[repr(C)]
589#[derive(Debug, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
590pub struct SevAvicIrrRegister {
596 pub value: u32,
597 pub allowed: u32,
598 _reserved: [u32; 2],
599}
600
601#[repr(C)]
602#[derive(Debug, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
603pub struct SevAvicPage {
606 pub reserved_0: [ApicRegisterValue; 2],
607 pub id: ApicRegisterValue,
608 pub version: ApicRegisterValue,
609 pub reserved_4: [ApicRegisterValue; 4],
610 pub tpr: ApicRegisterValue,
611 pub apr: ApicRegisterValue,
612 pub ppr: ApicRegisterValue,
613 pub eoi: ApicRegisterValue,
614 pub rrd: ApicRegisterValue,
615 pub ldr: ApicRegisterValue,
616 pub dfr: ApicRegisterValue,
617 pub svr: ApicRegisterValue,
618 pub isr: [ApicRegisterValue; 8],
619 pub tmr: [ApicRegisterValue; 8],
620 pub irr: [SevAvicIrrRegister; 8],
621 pub esr: ApicRegisterValue,
622 pub reserved_29: [ApicRegisterValue; 6],
623 pub lvt_cmci: ApicRegisterValue,
624 pub icr: [ApicRegisterValue; 2],
625 pub lvt_timer: ApicRegisterValue,
626 pub lvt_thermal: ApicRegisterValue,
627 pub lvt_pmc: ApicRegisterValue,
628 pub lvt_lint0: ApicRegisterValue,
629 pub lvt_lint1: ApicRegisterValue,
630 pub lvt_error: ApicRegisterValue,
631 pub timer_icr: ApicRegisterValue,
632 pub timer_ccr: ApicRegisterValue,
633 pub reserved_3a: [ApicRegisterValue; 4],
634 pub timer_dcr: ApicRegisterValue,
635 pub self_ipi: ApicRegisterValue,
636 pub eafr: ApicRegisterValue,
637 pub eacr: ApicRegisterValue,
638 pub seoi: ApicRegisterValue,
639 pub reserved_44: [ApicRegisterValue; 0x5],
640 pub ier: [ApicRegisterValue; 8],
641 pub ei_lv_tr: [ApicRegisterValue; 3],
642 pub reserved_54: [ApicRegisterValue; 0xad],
643}
644
645const_assert_eq!(size_of::<SevAvicPage>(), 4096);
646
647open_enum::open_enum! {
649 pub enum GhcbInfo: u64 {
650 NORMAL = 0x000,
651 SEV_INFO_RESPONSE = 0x001,
652 SEV_INFO_REQUEST = 0x002,
653 AP_JUMP_TABLE = 0x003,
654 CPUID_REQUEST = 0x004,
655 CPUID_RESPONSE = 0x005,
656 PREFERRED_REQUEST = 0x010,
657 PREFERRED_RESPONSE = 0x011,
658 REGISTER_REQUEST = 0x012,
659 REGISTER_RESPONSE = 0x013,
660 PAGE_STATE_CHANGE = 0x014,
661 PAGE_STATE_UPDATED = 0x015,
662 UNREGISTER_REQUEST = 0x018,
663 UNREGISTER_RESPONSE = 0x019,
664 HYP_FEATURE_REQUEST = 0x080,
665 HYP_FEATURE_RESPONSE = 0x081,
666 SPECIAL_HYPERCALL = 0xF00,
667 SPECIAL_FAST_CALL = 0xF01,
668 HYPERCALL_OUTPUT = 0xF02,
669 SPECIAL_DBGPRINT = 0xF03,
670 SHUTDOWN_REQUEST = 0x100,
671 }
672}
673
674pub const GHCB_HYP_FEATURE_GHCB_UNREGISTER: u64 = 1 << 8;
676
677pub const GHCB_DATA_PAGE_STATE_PRIVATE: u64 = 0x001;
678pub const GHCB_DATA_PAGE_STATE_SHARED: u64 = 0x002;
679pub const GHCB_DATA_PAGE_STATE_PSMASH: u64 = 0x003;
680pub const GHCB_DATA_PAGE_STATE_UNSMASH: u64 = 0x004;
681pub const GHCB_DATA_PAGE_STATE_MASK: u64 = 0x00F;
682pub const GHCB_DATA_PAGE_STATE_LARGE_PAGE: u64 = 0x010;
683
684open_enum::open_enum! {
685 #[derive(FromBytes, IntoBytes)]
686 pub enum GhcbUsage: u32 {
687 BASE = 0,
688 HYPERCALL = 1,
689 VTL_RETURN = 2,
690 INVALID = !0,
691 }
692}
693
694impl GhcbUsage {
695 pub const fn into_bits(self) -> u32 {
696 self.0
697 }
698
699 pub const fn from_bits(bits: u32) -> Self {
700 Self(bits)
701 }
702}
703
704open_enum::open_enum! {
705 #[derive(FromBytes, IntoBytes)]
706 pub enum GhcbProtocolVersion: u16 {
707 V1 = 1,
708 V2 = 2,
709 }
710}
711
712impl GhcbProtocolVersion {
713 pub const fn into_bits(self) -> u16 {
714 self.0
715 }
716
717 pub const fn from_bits(bits: u16) -> Self {
718 Self(bits)
719 }
720}
721
722#[repr(C)]
723#[derive(Debug, Copy, Clone, IntoBytes, FromBytes)]
724pub struct GhcbSaveArea {
725 pub reserved_0x0: [u8; 203],
726 pub cpl: u8,
727 pub reserved_0xcc: [u8; 116],
728 pub xss: u64,
729 pub reserved_0x148: [u8; 24],
730 pub dr7: u64,
731 pub reserved_0x168: [u8; 16],
732 pub rip: u64,
733 pub reserved_0x180: [u8; 88],
734 pub rsp: u64,
735 pub reserved_0x1e0: [u8; 24],
736 pub rax: u64,
737 pub reserved_0x200: [u8; 264],
738 pub rcx: u64,
739 pub rdx: u64,
740 pub rbx: u64,
741 pub reserved_0x320: [u8; 8],
742 pub rbp: u64,
743 pub rsi: u64,
744 pub rdi: u64,
745 pub r8: u64,
746 pub r9: u64,
747 pub r10: u64,
748 pub r11: u64,
749 pub r12: u64,
750 pub r13: u64,
751 pub r14: u64,
752 pub r15: u64,
753 pub reserved_0x380: [u8; 16],
754 pub sw_exit_code: u64,
755 pub sw_exit_info1: u64,
756 pub sw_exit_info2: u64,
757 pub sw_scratch: u64,
758 pub reserved_0x3b0: [u8; 56],
759 pub xcr0: u64,
760 pub valid_bitmap0: u64,
761 pub valid_bitmap1: u64,
762 pub x87_state_gpa: u64,
763}
764
765#[repr(C, align(4096))]
766#[derive(Debug, Copy, Clone, IntoBytes, FromBytes)]
767pub struct GhcbPage {
768 pub save: GhcbSaveArea,
769 pub reserved_save: [u8; 2048 - size_of::<GhcbSaveArea>()],
770 pub shared_buffer: [u8; 2032],
771 pub reserved_0xff0: [u8; 10],
772 pub protocol_version: GhcbProtocolVersion,
773 pub ghcb_usage: GhcbUsage,
774}
775
776const _: () = assert!(size_of::<GhcbPage>() == X64_PAGE_SIZE as usize);
777
778pub const GHCB_PAGE_HV_HYPERCALL_DATA_SIZE: usize = 4072;
779
780#[repr(C, align(4096))]
782#[derive(Debug, Copy, Clone, IntoBytes, FromBytes)]
783pub struct GhcbPageHvHypercall {
784 pub data: [u8; GHCB_PAGE_HV_HYPERCALL_DATA_SIZE],
785 pub output_gpa: u64,
786 pub io: u64,
787 pub reserved: u64,
788}
789
790const _: () = assert!(size_of::<GhcbPageHvHypercall>() == X64_PAGE_SIZE as usize);
791
792#[repr(C)]
795#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
796pub struct GhcbHypercallParameters {
797 pub output_gpa: u64,
798 pub input_control: u64,
799}
800
801pub const GHCB_PAGE_HYPERCALL_PARAMETERS_OFFSET: usize = 4072;
802pub const GHCB_PAGE_HYPERCALL_OUTPUT_OFFSET: usize = 4080;
803
804open_enum::open_enum! {
806 pub enum SevExitCode: u64 {
807 CR0_READ = 0x0,
808 CR1_READ = 0x1,
809 CR2_READ = 0x2,
810 CR3_READ = 0x3,
811 CR4_READ = 0x4,
812 CR5_READ = 0x5,
813 CR6_READ = 0x6,
814 CR7_READ = 0x7,
815 CR8_READ = 0x8,
816 CR9_READ = 0x9,
817 CR10_READ = 0xa,
818 CR11_READ = 0xb,
819 CR12_READ = 0xc,
820 CR13_READ = 0xd,
821 CR14_READ = 0xe,
822 CR15_READ = 0xf,
823 CR0_WRITE = 0x10,
824 CR1_WRITE = 0x11,
825 CR2_WRITE = 0x12,
826 CR3_WRITE = 0x13,
827 CR4_WRITE = 0x14,
828 CR5_WRITE = 0x15,
829 CR6_WRITE = 0x16,
830 CR7_WRITE = 0x17,
831 CR8_WRITE = 0x18,
832 CR9_WRITE = 0x19,
833 CR10_WRITE = 0x1a,
834 CR11_WRITE = 0x1b,
835 CR12_WRITE = 0x1c,
836 CR13_WRITE = 0x1d,
837 CR14_WRITE = 0x1e,
838 CR15_WRITE = 0x1f,
839 DR0_READ = 0x20,
840 DR1_READ = 0x21,
841 DR2_READ = 0x22,
842 DR3_READ = 0x23,
843 DR4_READ = 0x24,
844 DR5_READ = 0x25,
845 DR6_READ = 0x26,
846 DR7_READ = 0x27,
847 DR8_READ = 0x28,
848 DR9_READ = 0x29,
849 DR10_READ = 0x2a,
850 DR11_READ = 0x2b,
851 DR12_READ = 0x2c,
852 DR13_READ = 0x2d,
853 DR14_READ = 0x2e,
854 DR15_READ = 0x2f,
855 DR0_WRITE = 0x30,
856 DR1_WRITE = 0x31,
857 DR2_WRITE = 0x32,
858 DR3_WRITE = 0x33,
859 DR4_WRITE = 0x34,
860 DR5_WRITE = 0x35,
861 DR6_WRITE = 0x36,
862 DR7_WRITE = 0x37,
863 DR8_WRITE = 0x38,
864 DR9_WRITE = 0x39,
865 DR10_WRITE = 0x3a,
866 DR11_WRITE = 0x3b,
867 DR12_WRITE = 0x3c,
868 DR13_WRITE = 0x3d,
869 DR14_WRITE = 0x3e,
870 DR15_WRITE = 0x3f,
871 EXCP0 = 0x40,
872 EXCP_DB = 0x41,
873 EXCP2 = 0x42,
874 EXCP3 = 0x43,
875 EXCP4 = 0x44,
876 EXCP5 = 0x45,
877 EXCP6 = 0x46,
878 EXCP7 = 0x47,
879 EXCP8 = 0x48,
880 EXCP9 = 0x49,
881 EXCP10 = 0x4a,
882 EXCP11 = 0x4b,
883 EXCP12 = 0x4c,
884 EXCP13 = 0x4d,
885 EXCP14 = 0x4e,
886 EXCP15 = 0x4f,
887 EXCP16 = 0x50,
888 EXCP17 = 0x51,
889 EXCP18 = 0x52,
890 EXCP19 = 0x53,
891 EXCP20 = 0x54,
892 EXCP21 = 0x55,
893 EXCP22 = 0x56,
894 EXCP23 = 0x57,
895 EXCP24 = 0x58,
896 EXCP25 = 0x59,
897 EXCP26 = 0x5a,
898 EXCP27 = 0x5b,
899 EXCP28 = 0x5c,
900 EXCP29 = 0x5d,
901 EXCP30 = 0x5e,
902 EXCP31 = 0x5f,
903 INTR = 0x60,
904 NMI = 0x61,
905 SMI = 0x62,
906 INIT = 0x63,
907 VINTR = 0x64,
908 CR0_SEL_WRITE = 0x65,
909 IDTR_READ = 0x66,
910 GDTR_READ = 0x67,
911 LDTR_READ = 0x68,
912 TR_READ = 0x69,
913 IDTR_WRITE = 0x6a,
914 GDTR_WRITE = 0x6b,
915 LDTR_WRITE = 0x6c,
916 TR_WRITE = 0x6d,
917 RDTSC = 0x6e,
918 RDPMC = 0x6f,
919 PUSHF = 0x70,
920 POPF = 0x71,
921 CPUID = 0x72,
922 RSM = 0x73,
923 IRET = 0x74,
924 SWINT = 0x75,
925 INVD = 0x76,
926 PAUSE = 0x77,
927 HLT = 0x78,
928 INVLPG = 0x79,
929 INVLPGA = 0x7a,
930 IOIO = 0x7b,
931 MSR = 0x7c,
932 TASK_SWITCH = 0x7d,
933 FERR_FREEZE = 0x7e,
934 SHUTDOWN = 0x7f,
935 VMRUN = 0x80,
936 VMMCALL = 0x81,
937 VMLOAD = 0x82,
938 VMSAVE = 0x83,
939 STGI = 0x84,
940 CLGI = 0x85,
941 SKINIT = 0x86,
942 RDTSCP = 0x87,
943 ICEBP = 0x88,
944 WBINVD = 0x89,
945 MONITOR = 0x8a,
946 MWAIT = 0x8b,
947 MWAIT_CONDITIONAL = 0x8c,
948 XSETBV = 0x8d,
949 RDPRU = 0x8e,
950 EFER_WRITE_TRAP = 0x8f,
951 CR0_WRITE_TRAP = 0x90,
952 CR1_WRITE_TRAP = 0x91,
953 CR2_WRITE_TRAP = 0x92,
954 CR3_WRITE_TRAP = 0x93,
955 CR4_WRITE_TRAP = 0x94,
956 CR5_WRITE_TRAP = 0x95,
957 CR6_WRITE_TRAP = 0x96,
958 CR7_WRITE_TRAP = 0x97,
959 CR8_WRITE_TRAP = 0x98,
960 CR9_WRITE_TRAP = 0x99,
961 CR10_WRITE_TRAP = 0x9a,
962 CR11_WRITE_TRAP = 0x9b,
963 CR12_WRITE_TRAP = 0x9c,
964 CR13_WRITE_TRAP = 0x9d,
965 CR14_WRITE_TRAP = 0x9e,
966 CR15_WRITE_TRAP = 0x9f,
967 INVLPGB = 0xa0,
968 ILLEGAL_INVLPGB = 0xa1,
969 INVPCID = 0xa2,
970 BUSLOCK = 0xa5,
971 IDLE_HLT = 0xa6,
972 NPF = 0x400,
973 AVIC_INCOMPLETE_IPI = 0x401,
974 AVIC_NOACCEL = 0x402,
975 VMGEXIT = 0x403,
976 PAGE_NOT_VALIDATED = 0x404,
977 NOT_RESTARTABLE = 0x406,
978
979 SNP_GUEST_REQUEST = 0x80000011,
981 SNP_EXTENDED_GUEST_REQUEST = 0x80000012,
982 HV_DOORBELL_PAGE = 0x80000014,
983
984 INVALID_VMCB = 0xffff_ffff_ffff_ffff,
986 VMSA_BUSY = 0xffff_ffff_ffff_fffe,
987 IDLE_REQUIRED = 0xffff_ffff_ffff_fffd,
988 INVALID_PMC = 0xffff_ffff_ffff_fffc,
989 }
990}
991
992#[bitfield(u64)]
993#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
994pub struct GhcbMsr {
995 #[bits(12)]
996 pub info: u64,
997 #[bits(40)]
998 pub pfn: u64,
999 #[bits(12)]
1000 pub extra_data: u64,
1001}
1002
1003#[repr(C)]
1005#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Clone, Copy)]
1006pub struct HvPspCpuidLeaf {
1007 pub eax_in: u32,
1008 pub ecx_in: u32,
1009 pub xfem_in: u64,
1010 pub xss_in: u64,
1011 pub eax_out: u32,
1012 pub ebx_out: u32,
1013 pub ecx_out: u32,
1014 pub edx_out: u32,
1015 pub reserved_z: u64,
1016}
1017
1018pub const HV_PSP_CPUID_LEAF_COUNT_MAX: usize = 64;
1019
1020#[repr(C)]
1021#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Clone, Copy)]
1022pub struct HvPspCpuidPage {
1023 pub count: u32,
1024 pub reserved_z1: u32,
1025 pub reserved_z2: u64,
1026 pub cpuid_leaf_info: [HvPspCpuidLeaf; HV_PSP_CPUID_LEAF_COUNT_MAX],
1027 pub reserved_z3: [u64; 126],
1028}
1029
1030#[repr(C)]
1034#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
1035pub struct SnpPageInfo {
1036 pub digest_current: [u8; 48],
1038 pub contents: [u8; 48],
1040 pub length: u16,
1042 pub page_type: SnpPageType,
1044 pub imi_page_bit: u8,
1046 pub lower_vmpl_permissions: u32,
1048 pub gpa: u64,
1051}
1052
1053open_enum::open_enum! {
1054 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1056 pub enum SnpPageType: u8 {
1057 RESERVED = 0x0,
1059 NORMAL = 0x1,
1061 VMSA = 0x2,
1063 ZERO = 0x3,
1065 UNMEASURED = 0x4,
1067 SECRETS = 0x5,
1069 CPUID = 0x6,
1071 }
1072}
1073
1074#[repr(C)]
1078#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
1079pub struct SnpPspIdBlock {
1080 pub ld: [u8; 48],
1082 pub family_id: [u8; 16],
1084 pub image_id: [u8; 16],
1086 pub version: u32,
1088 pub guest_svn: u32,
1090 pub policy: u64,
1092}
1093
1094#[repr(C)]
1096#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
1097pub struct SnpPspIdAuthSignature {
1098 pub r: [u8; 72],
1100 pub s: [u8; 72],
1102 pub reserved: [u8; 368],
1104}
1105
1106#[repr(C)]
1108#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
1109pub struct SnpPspIdAuthPublicKey {
1110 pub curve: u32,
1112 pub qx: [u8; 72],
1114 pub qy: [u8; 72],
1116 pub reserved: [u8; 880],
1118}
1119
1120#[repr(C)]
1124#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
1125pub struct SnpPspIdAuth {
1126 pub id_key_algorithm: u32,
1128 pub author_key_algorithm: u32,
1130 pub reserved0: [u8; 56],
1132 pub id_block_signature: SnpPspIdAuthSignature,
1134 pub id_key: SnpPspIdAuthPublicKey,
1136 pub reserved1: [u8; 60],
1138 pub id_key_signature: SnpPspIdAuthSignature,
1140 pub author_key: SnpPspIdAuthPublicKey,
1142 pub reserved2: [u8; 892],
1144}
1145
1146const_assert_eq!(size_of::<SnpPspIdAuth>(), 4096);
1147
1148#[derive(Debug, Clone, Copy, Eq, PartialEq)]
1150pub struct SnpIdBlockSignature {
1151 pub r: [u8; 72],
1153 pub s: [u8; 72],
1155}
1156
1157#[derive(Debug, Clone, Copy, Eq, PartialEq)]
1159pub struct SnpIdBlockPublicKey {
1160 pub curve: u32,
1162 pub qx: [u8; 72],
1164 pub qy: [u8; 72],
1166}
1167
1168#[bitfield(u64)]
1169#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
1170pub struct SevStatusMsr {
1171 pub sev_enabled: bool,
1172 pub es_enabled: bool,
1173 pub snp_enabled: bool,
1174 pub vtom: bool,
1175 pub reflect_vc: bool,
1176 pub restrict_injection: bool,
1177 pub alternate_injection: bool,
1178 pub debug_swap: bool,
1179 pub prevent_host_ibs: bool,
1180 pub snp_btb_isolation: bool,
1181 pub vmpl_sss: bool,
1182 pub secure_tsc: bool,
1183 pub vmgexit_param: bool,
1184 _rsvd3: bool,
1185 pub ibs_virt: bool,
1186 _rsvd5: bool,
1187 pub vmsa_reg_prot: bool,
1188 pub smt_prot: bool,
1189 pub secure_avic: bool,
1190 #[bits(4)]
1191 _reserved: u64,
1192 pub ibpb_on_entry: bool,
1193 #[bits(40)]
1194 _unused: u64,
1195}
1196
1197#[bitfield(u64)]
1198#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
1199pub struct SevInvlpgbRax {
1200 pub va_valid: bool,
1201 pub pcid_valid: bool,
1202 pub asid_valid: bool,
1203 pub global: bool,
1204 pub final_only: bool,
1205 pub nested: bool,
1206 #[bits(6)]
1207 reserved: u64,
1208 #[bits(52)]
1209 pub virtual_page_number: u64,
1210}
1211
1212#[bitfield(u32)]
1213#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
1214pub struct SevInvlpgbEdx {
1215 #[bits(16)]
1216 pub asid: u64,
1217 #[bits(12)]
1218 pub pcid: u64,
1219 #[bits(4)]
1220 reserved: u32,
1221}
1222
1223#[bitfield(u32)]
1224#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
1225pub struct SevInvlpgbEcx {
1226 #[bits(16)]
1227 pub additional_count: u64,
1228 #[bits(15)]
1229 reserved: u64,
1230 pub large_page: bool,
1231}
1232
1233#[bitfield(u64)]
1234pub struct MovCrxDrxInfo {
1235 #[bits(4)]
1236 pub gpr_number: u64,
1237 #[bits(59)]
1238 pub reserved: u64,
1239 pub mov_crx: bool,
1240}
1241
1242#[repr(C)]
1245#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1246pub struct SnpReportReq {
1247 pub user_data: [u8; 64],
1249 pub vmpl: u32,
1252 pub rsvd: [u8; 28],
1255}
1256
1257pub const SNP_REPORT_RESP_DATA_SIZE: usize =
1258 size_of::<u32>() + size_of::<u32>() + 24 + size_of::<SnpReport>();
1259
1260#[repr(C)]
1263#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1264pub struct SnpReportResp {
1265 pub status: u32,
1270 pub report_size: u32,
1272 pub _reserved0: [u8; 24],
1274 pub report: SnpReport,
1276}
1277
1278pub const SNP_REPORT_SIZE: usize = 0x4a0;
1280
1281pub const SNP_REPORT_DATA_SIZE: usize = 64;
1283
1284#[repr(C)]
1287#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1288pub struct SnpReport {
1289 pub version: u32,
1292 pub guest_svn: u32,
1294 pub policy: u64,
1296 pub family: u128,
1298 pub image_id: u128,
1300 pub vmpl: u32,
1303 pub signature_algo: u32,
1306 pub current_tcb: u64,
1308 pub platform_info: u64,
1310 pub flags: u32,
1312 pub _reserved0: u32,
1314 pub report_data: [u8; SNP_REPORT_DATA_SIZE],
1316 pub measurement: [u8; 48],
1319 pub host_data: [u8; 32],
1322 pub id_key_digest: [u8; 48],
1326 pub author_key_digest: [u8; 48],
1330 pub report_id: [u8; 32],
1332 pub report_id_ma: [u8; 32],
1335 pub reported_tcb: u64,
1338 pub _reserved1: [u8; 24],
1340 pub chip_id: [u8; 64],
1344 pub committed_tcb: u64,
1346 pub current_build: u8,
1348 pub current_minor: u8,
1350 pub current_major: u8,
1352 pub _reserved2: u8,
1354 pub committed_build: u8,
1356 pub committed_minor: u8,
1358 pub committed_major: u8,
1360 pub _reserved3: u8,
1362 pub launch_tcb: u64,
1365 pub _reserved4: [u8; 168],
1367 pub signature: [u8; 512],
1369}
1370
1371static_assertions::const_assert_eq!(SNP_REPORT_SIZE, size_of::<SnpReport>());
1372
1373#[repr(C)]
1376#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1377pub struct SnpDerivedKeyReq {
1378 pub root_key_select: u32,
1383 pub rsvd: u32,
1385 pub guest_field_select: u64,
1388 pub vmpl: u32,
1391 pub guest_svn: u32,
1394 pub tcb_version: u64,
1397}
1398
1399#[bitfield(u64)]
1402pub struct GuestFieldSelect {
1403 pub guest_policy: bool,
1405 pub image_id: bool,
1407 pub family_id: bool,
1409 pub measurement: bool,
1411 pub guest_svn: bool,
1413 pub tcb_version: bool,
1415 #[bits(58)]
1417 pub _reserved: u64,
1418}
1419
1420pub const SNP_DERIVED_KEY_SIZE: usize = 32;
1422
1423#[repr(C)]
1426#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1427pub struct SnpDerivedKeyResp {
1428 pub status: u32,
1433 pub _reserved: [u8; 28],
1435 pub derived_key: [u8; SNP_DERIVED_KEY_SIZE],
1437}
1438
1439static_assertions::const_assert_eq!(
1440 64,
1442 size_of::<SnpDerivedKeyResp>()
1443);
1444
1445#[cfg(test)]
1446mod tests {
1447 use super::*;
1448 use zerocopy::FromZeros;
1449
1450 #[test]
1453 fn secure_avic_control_default_is_zero() {
1454 let ctrl = SecureAvicControl::new();
1455 assert_eq!(ctrl.into_bits(), 0);
1456 assert_eq!(ctrl.secure_avic_en(), false);
1457 assert_eq!(ctrl.allowed_nmi(), false);
1458 assert_eq!(ctrl.guest_apic_backing_page_ptr(), 0);
1459 }
1460
1461 #[test]
1462 fn secure_avic_control_enable_bit() {
1463 let ctrl = SecureAvicControl::new().with_secure_avic_en(true);
1464 assert_eq!(ctrl.secure_avic_en(), true);
1465 assert_eq!(ctrl.into_bits() & 1, 1);
1466 }
1467
1468 #[test]
1469 fn secure_avic_control_allowed_nmi_bit() {
1470 let ctrl = SecureAvicControl::new().with_allowed_nmi(true);
1471 assert_eq!(ctrl.allowed_nmi(), true);
1472 assert_eq!(ctrl.into_bits() & 0b10, 0b10);
1473 }
1474
1475 #[test]
1476 fn secure_avic_control_page_ptr() {
1477 let pfn = 0xDEAD_BEEF_u64;
1479 let ctrl = SecureAvicControl::new()
1480 .with_secure_avic_en(true)
1481 .with_guest_apic_backing_page_ptr(pfn);
1482 assert_eq!(ctrl.guest_apic_backing_page_ptr(), pfn);
1483 assert_eq!(ctrl.secure_avic_en(), true);
1484 assert_eq!(ctrl.into_bits() >> 12, pfn);
1486 }
1487
1488 #[test]
1489 fn secure_avic_control_roundtrip() {
1490 let raw = 0xABCD_1234_5678_9001_u64;
1491 let ctrl = SecureAvicControl::from(raw);
1492 assert_eq!(ctrl.into_bits(), raw);
1493 }
1494
1495 #[test]
1498 fn no_accel_info_register_number_extraction() {
1499 let info = SevAvicNoAccelInfo::new().with_apic_register_number(SevAvicRegisterNumber::EOI);
1501 assert_eq!(info.apic_register_number(), SevAvicRegisterNumber::EOI);
1502 assert_eq!((info.into_bits() >> 4) & 0xFF, 0xB);
1504 }
1505
1506 #[test]
1507 fn no_accel_info_write_access_bit() {
1508 let info = SevAvicNoAccelInfo::new().with_write_access(true);
1510 assert!(info.write_access());
1511 assert_eq!(info.into_bits() & (1 << 32), 1 << 32);
1512
1513 let info_read = SevAvicNoAccelInfo::new().with_write_access(false);
1514 assert!(!info_read.write_access());
1515 }
1516
1517 #[test]
1518 fn no_accel_info_combined() {
1519 let info = SevAvicNoAccelInfo::new()
1520 .with_apic_register_number(SevAvicRegisterNumber::ICR_LOW)
1521 .with_write_access(true);
1522 assert_eq!(info.apic_register_number(), SevAvicRegisterNumber::ICR_LOW);
1523 assert!(info.write_access());
1524 }
1525
1526 #[test]
1527 fn no_accel_info_all_register_numbers_roundtrip() {
1528 let registers = [
1529 SevAvicRegisterNumber::APIC_ID,
1530 SevAvicRegisterNumber::VERSION,
1531 SevAvicRegisterNumber::TPR,
1532 SevAvicRegisterNumber::APR,
1533 SevAvicRegisterNumber::PPR,
1534 SevAvicRegisterNumber::EOI,
1535 SevAvicRegisterNumber::LDR,
1536 SevAvicRegisterNumber::DFR,
1537 SevAvicRegisterNumber::SPURIOUS,
1538 SevAvicRegisterNumber::ISR0,
1539 SevAvicRegisterNumber::ISR7,
1540 SevAvicRegisterNumber::TMR0,
1541 SevAvicRegisterNumber::TMR7,
1542 SevAvicRegisterNumber::IRR0,
1543 SevAvicRegisterNumber::IRR7,
1544 SevAvicRegisterNumber::ERROR,
1545 SevAvicRegisterNumber::ICR_LOW,
1546 SevAvicRegisterNumber::ICR_HIGH,
1547 SevAvicRegisterNumber::TIMER_LVT,
1548 SevAvicRegisterNumber::INITIAL_COUNT,
1549 SevAvicRegisterNumber::CURRENT_COUNT,
1550 SevAvicRegisterNumber::DIVIDER,
1551 SevAvicRegisterNumber::SELF_IPI,
1552 ];
1553 for reg in registers {
1554 let info = SevAvicNoAccelInfo::new().with_apic_register_number(reg);
1555 assert_eq!(
1556 info.apic_register_number(),
1557 reg,
1558 "register number roundtrip failed for {reg:#x?}"
1559 );
1560 }
1561 }
1562
1563 #[test]
1566 fn incomplete_ipi_info1_icr_fields() {
1567 let icr_low = 0x0004_10FFu32;
1568 let icr_high = 0x0200_0000u32;
1569 let info = SevAvicIncompleteIpiInfo1::new()
1570 .with_icr_low(icr_low)
1571 .with_icr_high(icr_high);
1572 assert_eq!(info.icr_low(), icr_low);
1573 assert_eq!(info.icr_high(), icr_high);
1574 assert_eq!(info.into_bits(), icr_low as u64 | ((icr_high as u64) << 32));
1575 }
1576
1577 #[test]
1578 fn incomplete_ipi_info2_fields() {
1579 let info = SevAvicIncompleteIpiInfo2::new()
1580 .with_index(42)
1581 .with_failure(SevAvicIpiFailure::NOT_RUNNING);
1582 assert_eq!(info.index(), 42);
1583 assert_eq!(info.failure(), SevAvicIpiFailure::NOT_RUNNING);
1584 }
1585
1586 #[test]
1587 fn incomplete_ipi_info2_all_failure_codes() {
1588 let failures = [
1589 SevAvicIpiFailure::INVALID_TYPE,
1590 SevAvicIpiFailure::NOT_RUNNING,
1591 SevAvicIpiFailure::INVALID_TARGET,
1592 SevAvicIpiFailure::INVALID_BACKING_PAGE,
1593 SevAvicIpiFailure::INVALID_VECTOR,
1594 SevAvicIpiFailure::UNACCELERATED_IPI,
1595 ];
1596 for failure in failures {
1597 let info = SevAvicIncompleteIpiInfo2::new().with_failure(failure);
1598 assert_eq!(
1599 info.failure(),
1600 failure,
1601 "failure code roundtrip failed for {failure:#x?}"
1602 );
1603 }
1604 }
1605
1606 #[test]
1609 fn sev_features_secure_avic_bit() {
1610 let features = SevFeatures::new().with_secure_avic(true);
1611 assert!(features.secure_avic());
1612 assert_ne!(features.into_bits() & (1 << 16), 0);
1614 }
1615
1616 #[test]
1617 fn sev_features_guest_intercept_control_bit() {
1618 let features = SevFeatures::new().with_guest_intercept_control(true);
1619 assert!(features.guest_intercept_control());
1620 assert_ne!(features.into_bits() & (1 << 13), 0);
1622 }
1623
1624 #[test]
1625 fn sev_features_secure_avic_with_no_alternate_injection() {
1626 let features = SevFeatures::new()
1629 .with_secure_avic(true)
1630 .with_guest_intercept_control(true)
1631 .with_alternate_injection(false);
1632 assert!(features.secure_avic());
1633 assert!(features.guest_intercept_control());
1634 assert!(!features.alternate_injection());
1635 }
1636
1637 #[test]
1638 fn sev_features_alternate_injection_without_secure_avic() {
1639 let features = SevFeatures::new()
1640 .with_alternate_injection(true)
1641 .with_secure_avic(false);
1642 assert!(features.alternate_injection());
1643 assert!(!features.secure_avic());
1644 }
1645
1646 #[test]
1649 fn sev_status_msr_secure_avic_bit() {
1650 let status = SevStatusMsr::new().with_secure_avic(true);
1651 assert!(status.secure_avic());
1652 assert_ne!(status.into_bits() & (1 << 18), 0);
1657 }
1658
1659 #[test]
1662 fn v_intr_cntrl_nmi_fields() {
1663 let ctrl = SevVirtualInterruptControl::new()
1664 .with_nmi(true)
1665 .with_nmi_mask(true)
1666 .with_nmi_enable(true);
1667 assert!(ctrl.nmi());
1668 assert!(ctrl.nmi_mask());
1669 assert!(ctrl.nmi_enable());
1670 }
1671
1672 #[test]
1675 fn sev_avic_page_size_is_4096() {
1676 assert_eq!(size_of::<SevAvicPage>(), 4096);
1678 }
1679
1680 #[test]
1681 fn sev_avic_irr_register_size() {
1682 assert_eq!(
1685 size_of::<SevAvicIrrRegister>(),
1686 size_of::<ApicRegisterValue>()
1687 );
1688 }
1689
1690 #[test]
1691 fn sev_avic_page_field_offsets() {
1692 let page = SevAvicPage::new_zeroed();
1695 let base = core::ptr::from_ref(&page) as usize;
1696
1697 let id_offset = core::ptr::from_ref(&page.id) as usize - base;
1699 assert_eq!(id_offset, 2 * 16, "APIC ID offset");
1700
1701 let version_offset = core::ptr::from_ref(&page.version) as usize - base;
1703 assert_eq!(version_offset, 3 * 16, "version offset");
1704
1705 let tpr_offset = core::ptr::from_ref(&page.tpr) as usize - base;
1707 assert_eq!(tpr_offset, 8 * 16, "TPR offset");
1708
1709 let isr_offset = core::ptr::from_ref(&page.isr) as usize - base;
1711 assert_eq!(isr_offset, 0x10 * 16, "ISR offset");
1712
1713 let tmr_offset = core::ptr::from_ref(&page.tmr) as usize - base;
1715 assert_eq!(tmr_offset, 0x18 * 16, "TMR offset");
1716
1717 let irr_offset = core::ptr::from_ref(&page.irr) as usize - base;
1719 assert_eq!(irr_offset, 0x20 * 16, "IRR offset");
1720
1721 let icr_offset = core::ptr::from_ref(&page.icr) as usize - base;
1723 assert_eq!(icr_offset, 0x30 * 16, "ICR offset");
1724 }
1725
1726 #[test]
1729 fn vmsa_secure_avic_control_at_rsp_offset() {
1730 let vmsa = SevVmsa::new_zeroed();
1733 let base = core::ptr::from_ref(&vmsa) as usize;
1734 let rbx_offset = core::ptr::from_ref(&vmsa.rbx) as usize - base;
1735 let savic_offset = core::ptr::from_ref(&vmsa.secure_avic_control) as usize - base;
1736 let rbp_offset = core::ptr::from_ref(&vmsa.rbp) as usize - base;
1737
1738 assert_eq!(savic_offset, rbx_offset + 8);
1740 assert_eq!(rbp_offset, savic_offset + 8);
1741 }
1742
1743 #[test]
1746 fn avic_register_number_matches_apic_register_enum() {
1747 use crate::apic::ApicRegister;
1750 assert_eq!(SevAvicRegisterNumber::APIC_ID.0, ApicRegister::ID.0 as u32);
1751 assert_eq!(
1752 SevAvicRegisterNumber::VERSION.0,
1753 ApicRegister::VERSION.0 as u32
1754 );
1755 assert_eq!(SevAvicRegisterNumber::TPR.0, ApicRegister::TPR.0 as u32);
1756 assert_eq!(SevAvicRegisterNumber::EOI.0, ApicRegister::EOI.0 as u32);
1757 assert_eq!(SevAvicRegisterNumber::LDR.0, ApicRegister::LDR.0 as u32);
1758 assert_eq!(
1759 SevAvicRegisterNumber::SPURIOUS.0,
1760 ApicRegister::SVR.0 as u32
1761 );
1762 assert_eq!(SevAvicRegisterNumber::ISR0.0, ApicRegister::ISR0.0 as u32);
1763 assert_eq!(SevAvicRegisterNumber::TMR0.0, ApicRegister::TMR0.0 as u32);
1764 assert_eq!(SevAvicRegisterNumber::IRR0.0, ApicRegister::IRR0.0 as u32);
1765 assert_eq!(SevAvicRegisterNumber::ERROR.0, ApicRegister::ESR.0 as u32);
1766 assert_eq!(
1767 SevAvicRegisterNumber::ICR_LOW.0,
1768 ApicRegister::ICR0.0 as u32
1769 );
1770 assert_eq!(
1771 SevAvicRegisterNumber::ICR_HIGH.0,
1772 ApicRegister::ICR1.0 as u32
1773 );
1774 assert_eq!(
1775 SevAvicRegisterNumber::TIMER_LVT.0,
1776 ApicRegister::LVT_TIMER.0 as u32
1777 );
1778 assert_eq!(
1779 SevAvicRegisterNumber::INITIAL_COUNT.0,
1780 ApicRegister::TIMER_ICR.0 as u32
1781 );
1782 assert_eq!(
1783 SevAvicRegisterNumber::CURRENT_COUNT.0,
1784 ApicRegister::TIMER_CCR.0 as u32
1785 );
1786 assert_eq!(
1787 SevAvicRegisterNumber::DIVIDER.0,
1788 ApicRegister::TIMER_DCR.0 as u32
1789 );
1790 assert_eq!(
1791 SevAvicRegisterNumber::SELF_IPI.0,
1792 ApicRegister::SELF_IPI.0 as u32
1793 );
1794 }
1795
1796 #[test]
1797 fn avic_register_to_x2apic_msr() {
1798 use crate::apic::X2APIC_MSR_BASE;
1800 let msr = X2APIC_MSR_BASE + SevAvicRegisterNumber::EOI.0;
1801 assert_eq!(msr, 0x80B); let msr = X2APIC_MSR_BASE + SevAvicRegisterNumber::ICR_LOW.0;
1804 assert_eq!(msr, 0x830); }
1806
1807 #[test]
1810 fn sev_exit_code_avic_values() {
1811 assert_eq!(SevExitCode::AVIC_INCOMPLETE_IPI.0, 0x401);
1812 assert_eq!(SevExitCode::AVIC_NOACCEL.0, 0x402);
1813 }
1814}