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 HYP_FEATURE_REQUEST = 0x080,
663 HYP_FEATURE_RESPONSE = 0x081,
664 SPECIAL_HYPERCALL = 0xF00,
665 SPECIAL_FAST_CALL = 0xF01,
666 HYPERCALL_OUTPUT = 0xF02,
667 SPECIAL_DBGPRINT = 0xF03,
668 SHUTDOWN_REQUEST = 0x100,
669 }
670}
671
672pub const GHCB_DATA_PAGE_STATE_PRIVATE: u64 = 0x001;
673pub const GHCB_DATA_PAGE_STATE_SHARED: u64 = 0x002;
674pub const GHCB_DATA_PAGE_STATE_PSMASH: u64 = 0x003;
675pub const GHCB_DATA_PAGE_STATE_UNSMASH: u64 = 0x004;
676pub const GHCB_DATA_PAGE_STATE_MASK: u64 = 0x00F;
677pub const GHCB_DATA_PAGE_STATE_LARGE_PAGE: u64 = 0x010;
678
679open_enum::open_enum! {
680 #[derive(FromBytes, IntoBytes)]
681 pub enum GhcbUsage: u32 {
682 BASE = 0,
683 HYPERCALL = 1,
684 VTL_RETURN = 2,
685 INVALID = !0,
686 }
687}
688
689impl GhcbUsage {
690 pub const fn into_bits(self) -> u32 {
691 self.0
692 }
693
694 pub const fn from_bits(bits: u32) -> Self {
695 Self(bits)
696 }
697}
698
699open_enum::open_enum! {
700 #[derive(FromBytes, IntoBytes)]
701 pub enum GhcbProtocolVersion: u16 {
702 V1 = 1,
703 V2 = 2,
704 }
705}
706
707impl GhcbProtocolVersion {
708 pub const fn into_bits(self) -> u16 {
709 self.0
710 }
711
712 pub const fn from_bits(bits: u16) -> Self {
713 Self(bits)
714 }
715}
716
717#[repr(C)]
718#[derive(Debug, Copy, Clone, IntoBytes, FromBytes)]
719pub struct GhcbSaveArea {
720 pub reserved_0x0: [u8; 203],
721 pub cpl: u8,
722 pub reserved_0xcc: [u8; 116],
723 pub xss: u64,
724 pub reserved_0x148: [u8; 24],
725 pub dr7: u64,
726 pub reserved_0x168: [u8; 16],
727 pub rip: u64,
728 pub reserved_0x180: [u8; 88],
729 pub rsp: u64,
730 pub reserved_0x1e0: [u8; 24],
731 pub rax: u64,
732 pub reserved_0x200: [u8; 264],
733 pub rcx: u64,
734 pub rdx: u64,
735 pub rbx: u64,
736 pub reserved_0x320: [u8; 8],
737 pub rbp: u64,
738 pub rsi: u64,
739 pub rdi: u64,
740 pub r8: u64,
741 pub r9: u64,
742 pub r10: u64,
743 pub r11: u64,
744 pub r12: u64,
745 pub r13: u64,
746 pub r14: u64,
747 pub r15: u64,
748 pub reserved_0x380: [u8; 16],
749 pub sw_exit_code: u64,
750 pub sw_exit_info1: u64,
751 pub sw_exit_info2: u64,
752 pub sw_scratch: u64,
753 pub reserved_0x3b0: [u8; 56],
754 pub xcr0: u64,
755 pub valid_bitmap0: u64,
756 pub valid_bitmap1: u64,
757 pub x87_state_gpa: u64,
758}
759
760#[repr(C, align(4096))]
761#[derive(Debug, Copy, Clone, IntoBytes, FromBytes)]
762pub struct GhcbPage {
763 pub save: GhcbSaveArea,
764 pub reserved_save: [u8; 2048 - size_of::<GhcbSaveArea>()],
765 pub shared_buffer: [u8; 2032],
766 pub reserved_0xff0: [u8; 10],
767 pub protocol_version: GhcbProtocolVersion,
768 pub ghcb_usage: GhcbUsage,
769}
770
771const _: () = assert!(size_of::<GhcbPage>() == X64_PAGE_SIZE as usize);
772
773pub const GHCB_PAGE_HV_HYPERCALL_DATA_SIZE: usize = 4072;
774
775#[repr(C, align(4096))]
777#[derive(Debug, Copy, Clone, IntoBytes, FromBytes)]
778pub struct GhcbPageHvHypercall {
779 pub data: [u8; GHCB_PAGE_HV_HYPERCALL_DATA_SIZE],
780 pub output_gpa: u64,
781 pub io: u64,
782 pub reserved: u64,
783}
784
785const _: () = assert!(size_of::<GhcbPageHvHypercall>() == X64_PAGE_SIZE as usize);
786
787#[repr(C)]
790#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
791pub struct GhcbHypercallParameters {
792 pub output_gpa: u64,
793 pub input_control: u64,
794}
795
796pub const GHCB_PAGE_HYPERCALL_PARAMETERS_OFFSET: usize = 4072;
797pub const GHCB_PAGE_HYPERCALL_OUTPUT_OFFSET: usize = 4080;
798
799open_enum::open_enum! {
801 pub enum SevExitCode: u64 {
802 CR0_READ = 0x0,
803 CR1_READ = 0x1,
804 CR2_READ = 0x2,
805 CR3_READ = 0x3,
806 CR4_READ = 0x4,
807 CR5_READ = 0x5,
808 CR6_READ = 0x6,
809 CR7_READ = 0x7,
810 CR8_READ = 0x8,
811 CR9_READ = 0x9,
812 CR10_READ = 0xa,
813 CR11_READ = 0xb,
814 CR12_READ = 0xc,
815 CR13_READ = 0xd,
816 CR14_READ = 0xe,
817 CR15_READ = 0xf,
818 CR0_WRITE = 0x10,
819 CR1_WRITE = 0x11,
820 CR2_WRITE = 0x12,
821 CR3_WRITE = 0x13,
822 CR4_WRITE = 0x14,
823 CR5_WRITE = 0x15,
824 CR6_WRITE = 0x16,
825 CR7_WRITE = 0x17,
826 CR8_WRITE = 0x18,
827 CR9_WRITE = 0x19,
828 CR10_WRITE = 0x1a,
829 CR11_WRITE = 0x1b,
830 CR12_WRITE = 0x1c,
831 CR13_WRITE = 0x1d,
832 CR14_WRITE = 0x1e,
833 CR15_WRITE = 0x1f,
834 DR0_READ = 0x20,
835 DR1_READ = 0x21,
836 DR2_READ = 0x22,
837 DR3_READ = 0x23,
838 DR4_READ = 0x24,
839 DR5_READ = 0x25,
840 DR6_READ = 0x26,
841 DR7_READ = 0x27,
842 DR8_READ = 0x28,
843 DR9_READ = 0x29,
844 DR10_READ = 0x2a,
845 DR11_READ = 0x2b,
846 DR12_READ = 0x2c,
847 DR13_READ = 0x2d,
848 DR14_READ = 0x2e,
849 DR15_READ = 0x2f,
850 DR0_WRITE = 0x30,
851 DR1_WRITE = 0x31,
852 DR2_WRITE = 0x32,
853 DR3_WRITE = 0x33,
854 DR4_WRITE = 0x34,
855 DR5_WRITE = 0x35,
856 DR6_WRITE = 0x36,
857 DR7_WRITE = 0x37,
858 DR8_WRITE = 0x38,
859 DR9_WRITE = 0x39,
860 DR10_WRITE = 0x3a,
861 DR11_WRITE = 0x3b,
862 DR12_WRITE = 0x3c,
863 DR13_WRITE = 0x3d,
864 DR14_WRITE = 0x3e,
865 DR15_WRITE = 0x3f,
866 EXCP0 = 0x40,
867 EXCP_DB = 0x41,
868 EXCP2 = 0x42,
869 EXCP3 = 0x43,
870 EXCP4 = 0x44,
871 EXCP5 = 0x45,
872 EXCP6 = 0x46,
873 EXCP7 = 0x47,
874 EXCP8 = 0x48,
875 EXCP9 = 0x49,
876 EXCP10 = 0x4a,
877 EXCP11 = 0x4b,
878 EXCP12 = 0x4c,
879 EXCP13 = 0x4d,
880 EXCP14 = 0x4e,
881 EXCP15 = 0x4f,
882 EXCP16 = 0x50,
883 EXCP17 = 0x51,
884 EXCP18 = 0x52,
885 EXCP19 = 0x53,
886 EXCP20 = 0x54,
887 EXCP21 = 0x55,
888 EXCP22 = 0x56,
889 EXCP23 = 0x57,
890 EXCP24 = 0x58,
891 EXCP25 = 0x59,
892 EXCP26 = 0x5a,
893 EXCP27 = 0x5b,
894 EXCP28 = 0x5c,
895 EXCP29 = 0x5d,
896 EXCP30 = 0x5e,
897 EXCP31 = 0x5f,
898 INTR = 0x60,
899 NMI = 0x61,
900 SMI = 0x62,
901 INIT = 0x63,
902 VINTR = 0x64,
903 CR0_SEL_WRITE = 0x65,
904 IDTR_READ = 0x66,
905 GDTR_READ = 0x67,
906 LDTR_READ = 0x68,
907 TR_READ = 0x69,
908 IDTR_WRITE = 0x6a,
909 GDTR_WRITE = 0x6b,
910 LDTR_WRITE = 0x6c,
911 TR_WRITE = 0x6d,
912 RDTSC = 0x6e,
913 RDPMC = 0x6f,
914 PUSHF = 0x70,
915 POPF = 0x71,
916 CPUID = 0x72,
917 RSM = 0x73,
918 IRET = 0x74,
919 SWINT = 0x75,
920 INVD = 0x76,
921 PAUSE = 0x77,
922 HLT = 0x78,
923 INVLPG = 0x79,
924 INVLPGA = 0x7a,
925 IOIO = 0x7b,
926 MSR = 0x7c,
927 TASK_SWITCH = 0x7d,
928 FERR_FREEZE = 0x7e,
929 SHUTDOWN = 0x7f,
930 VMRUN = 0x80,
931 VMMCALL = 0x81,
932 VMLOAD = 0x82,
933 VMSAVE = 0x83,
934 STGI = 0x84,
935 CLGI = 0x85,
936 SKINIT = 0x86,
937 RDTSCP = 0x87,
938 ICEBP = 0x88,
939 WBINVD = 0x89,
940 MONITOR = 0x8a,
941 MWAIT = 0x8b,
942 MWAIT_CONDITIONAL = 0x8c,
943 XSETBV = 0x8d,
944 RDPRU = 0x8e,
945 EFER_WRITE_TRAP = 0x8f,
946 CR0_WRITE_TRAP = 0x90,
947 CR1_WRITE_TRAP = 0x91,
948 CR2_WRITE_TRAP = 0x92,
949 CR3_WRITE_TRAP = 0x93,
950 CR4_WRITE_TRAP = 0x94,
951 CR5_WRITE_TRAP = 0x95,
952 CR6_WRITE_TRAP = 0x96,
953 CR7_WRITE_TRAP = 0x97,
954 CR8_WRITE_TRAP = 0x98,
955 CR9_WRITE_TRAP = 0x99,
956 CR10_WRITE_TRAP = 0x9a,
957 CR11_WRITE_TRAP = 0x9b,
958 CR12_WRITE_TRAP = 0x9c,
959 CR13_WRITE_TRAP = 0x9d,
960 CR14_WRITE_TRAP = 0x9e,
961 CR15_WRITE_TRAP = 0x9f,
962 INVLPGB = 0xa0,
963 ILLEGAL_INVLPGB = 0xa1,
964 INVPCID = 0xa2,
965 BUSLOCK = 0xa5,
966 IDLE_HLT = 0xa6,
967 NPF = 0x400,
968 AVIC_INCOMPLETE_IPI = 0x401,
969 AVIC_NOACCEL = 0x402,
970 VMGEXIT = 0x403,
971 PAGE_NOT_VALIDATED = 0x404,
972 NOT_RESTARTABLE = 0x406,
973
974 SNP_GUEST_REQUEST = 0x80000011,
976 SNP_EXTENDED_GUEST_REQUEST = 0x80000012,
977 HV_DOORBELL_PAGE = 0x80000014,
978
979 INVALID_VMCB = 0xffff_ffff_ffff_ffff,
981 VMSA_BUSY = 0xffff_ffff_ffff_fffe,
982 IDLE_REQUIRED = 0xffff_ffff_ffff_fffd,
983 INVALID_PMC = 0xffff_ffff_ffff_fffc,
984 }
985}
986
987#[bitfield(u64)]
988#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
989pub struct GhcbMsr {
990 #[bits(12)]
991 pub info: u64,
992 #[bits(40)]
993 pub pfn: u64,
994 #[bits(12)]
995 pub extra_data: u64,
996}
997
998#[repr(C)]
1000#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Clone, Copy)]
1001pub struct HvPspCpuidLeaf {
1002 pub eax_in: u32,
1003 pub ecx_in: u32,
1004 pub xfem_in: u64,
1005 pub xss_in: u64,
1006 pub eax_out: u32,
1007 pub ebx_out: u32,
1008 pub ecx_out: u32,
1009 pub edx_out: u32,
1010 pub reserved_z: u64,
1011}
1012
1013pub const HV_PSP_CPUID_LEAF_COUNT_MAX: usize = 64;
1014
1015#[repr(C)]
1016#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Clone, Copy)]
1017pub struct HvPspCpuidPage {
1018 pub count: u32,
1019 pub reserved_z1: u32,
1020 pub reserved_z2: u64,
1021 pub cpuid_leaf_info: [HvPspCpuidLeaf; HV_PSP_CPUID_LEAF_COUNT_MAX],
1022 pub reserved_z3: [u64; 126],
1023}
1024
1025#[repr(C)]
1029#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
1030pub struct SnpPageInfo {
1031 pub digest_current: [u8; 48],
1033 pub contents: [u8; 48],
1035 pub length: u16,
1037 pub page_type: SnpPageType,
1039 pub imi_page_bit: u8,
1041 pub lower_vmpl_permissions: u32,
1043 pub gpa: u64,
1046}
1047
1048open_enum::open_enum! {
1049 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1051 pub enum SnpPageType: u8 {
1052 RESERVED = 0x0,
1054 NORMAL = 0x1,
1056 VMSA = 0x2,
1058 ZERO = 0x3,
1060 UNMEASURED = 0x4,
1062 SECRETS = 0x5,
1064 CPUID = 0x6,
1066 }
1067}
1068
1069#[repr(C)]
1073#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
1074pub struct SnpPspIdBlock {
1075 pub ld: [u8; 48],
1077 pub family_id: [u8; 16],
1079 pub image_id: [u8; 16],
1081 pub version: u32,
1083 pub guest_svn: u32,
1085 pub policy: u64,
1087}
1088
1089#[derive(Debug, Clone, Copy, Eq, PartialEq)]
1091pub struct SnpIdBlockSignature {
1092 pub r: [u8; 72],
1094 pub s: [u8; 72],
1096}
1097
1098#[derive(Debug, Clone, Copy, Eq, PartialEq)]
1100pub struct SnpIdBlockPublicKey {
1101 pub curve: u32,
1103 pub qx: [u8; 72],
1105 pub qy: [u8; 72],
1107}
1108
1109#[bitfield(u64)]
1110#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
1111pub struct SevStatusMsr {
1112 pub sev_enabled: bool,
1113 pub es_enabled: bool,
1114 pub snp_enabled: bool,
1115 pub vtom: bool,
1116 pub reflect_vc: bool,
1117 pub restrict_injection: bool,
1118 pub alternate_injection: bool,
1119 pub debug_swap: bool,
1120 pub prevent_host_ibs: bool,
1121 pub snp_btb_isolation: bool,
1122 pub vmpl_sss: bool,
1123 pub secure_tsc: bool,
1124 pub vmgexit_param: bool,
1125 _rsvd3: bool,
1126 pub ibs_virt: bool,
1127 _rsvd5: bool,
1128 pub vmsa_reg_prot: bool,
1129 pub smt_prot: bool,
1130 pub secure_avic: bool,
1131 #[bits(4)]
1132 _reserved: u64,
1133 pub ibpb_on_entry: bool,
1134 #[bits(40)]
1135 _unused: u64,
1136}
1137
1138#[bitfield(u64)]
1139#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
1140pub struct SevInvlpgbRax {
1141 pub va_valid: bool,
1142 pub pcid_valid: bool,
1143 pub asid_valid: bool,
1144 pub global: bool,
1145 pub final_only: bool,
1146 pub nested: bool,
1147 #[bits(6)]
1148 reserved: u64,
1149 #[bits(52)]
1150 pub virtual_page_number: u64,
1151}
1152
1153#[bitfield(u32)]
1154#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
1155pub struct SevInvlpgbEdx {
1156 #[bits(16)]
1157 pub asid: u64,
1158 #[bits(12)]
1159 pub pcid: u64,
1160 #[bits(4)]
1161 reserved: u32,
1162}
1163
1164#[bitfield(u32)]
1165#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
1166pub struct SevInvlpgbEcx {
1167 #[bits(16)]
1168 pub additional_count: u64,
1169 #[bits(15)]
1170 reserved: u64,
1171 pub large_page: bool,
1172}
1173
1174#[bitfield(u64)]
1175pub struct MovCrxDrxInfo {
1176 #[bits(4)]
1177 pub gpr_number: u64,
1178 #[bits(59)]
1179 pub reserved: u64,
1180 pub mov_crx: bool,
1181}
1182
1183#[repr(C)]
1186#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1187pub struct SnpReportReq {
1188 pub user_data: [u8; 64],
1190 pub vmpl: u32,
1193 pub rsvd: [u8; 28],
1196}
1197
1198pub const SNP_REPORT_RESP_DATA_SIZE: usize =
1199 size_of::<u32>() + size_of::<u32>() + 24 + size_of::<SnpReport>();
1200
1201#[repr(C)]
1204#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1205pub struct SnpReportResp {
1206 pub status: u32,
1211 pub report_size: u32,
1213 pub _reserved0: [u8; 24],
1215 pub report: SnpReport,
1217}
1218
1219pub const SNP_REPORT_SIZE: usize = 0x4a0;
1221
1222pub const SNP_REPORT_DATA_SIZE: usize = 64;
1224
1225#[repr(C)]
1228#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1229pub struct SnpReport {
1230 pub version: u32,
1233 pub guest_svn: u32,
1235 pub policy: u64,
1237 pub family: u128,
1239 pub image_id: u128,
1241 pub vmpl: u32,
1244 pub signature_algo: u32,
1247 pub current_tcb: u64,
1249 pub platform_info: u64,
1251 pub flags: u32,
1253 pub _reserved0: u32,
1255 pub report_data: [u8; SNP_REPORT_DATA_SIZE],
1257 pub measurement: [u8; 48],
1260 pub host_data: [u8; 32],
1263 pub id_key_digest: [u8; 48],
1267 pub author_key_digest: [u8; 48],
1271 pub report_id: [u8; 32],
1273 pub report_id_ma: [u8; 32],
1276 pub reported_tcb: u64,
1279 pub _reserved1: [u8; 24],
1281 pub chip_id: [u8; 64],
1285 pub committed_tcb: u64,
1287 pub current_build: u8,
1289 pub current_minor: u8,
1291 pub current_major: u8,
1293 pub _reserved2: u8,
1295 pub committed_build: u8,
1297 pub committed_minor: u8,
1299 pub committed_major: u8,
1301 pub _reserved3: u8,
1303 pub launch_tcb: u64,
1306 pub _reserved4: [u8; 168],
1308 pub signature: [u8; 512],
1310}
1311
1312static_assertions::const_assert_eq!(SNP_REPORT_SIZE, size_of::<SnpReport>());
1313
1314#[repr(C)]
1317#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1318pub struct SnpDerivedKeyReq {
1319 pub root_key_select: u32,
1324 pub rsvd: u32,
1326 pub guest_field_select: u64,
1329 pub vmpl: u32,
1332 pub guest_svn: u32,
1335 pub tcb_version: u64,
1338}
1339
1340#[bitfield(u64)]
1343pub struct GuestFieldSelect {
1344 pub guest_policy: bool,
1346 pub image_id: bool,
1348 pub family_id: bool,
1350 pub measurement: bool,
1352 pub guest_svn: bool,
1354 pub tcb_version: bool,
1356 #[bits(58)]
1358 pub _reserved: u64,
1359}
1360
1361pub const SNP_DERIVED_KEY_SIZE: usize = 32;
1363
1364#[repr(C)]
1367#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1368pub struct SnpDerivedKeyResp {
1369 pub status: u32,
1374 pub _reserved: [u8; 28],
1376 pub derived_key: [u8; SNP_DERIVED_KEY_SIZE],
1378}
1379
1380static_assertions::const_assert_eq!(
1381 64,
1383 size_of::<SnpDerivedKeyResp>()
1384);
1385
1386#[cfg(test)]
1387mod tests {
1388 use super::*;
1389 use zerocopy::FromZeros;
1390
1391 #[test]
1394 fn secure_avic_control_default_is_zero() {
1395 let ctrl = SecureAvicControl::new();
1396 assert_eq!(ctrl.into_bits(), 0);
1397 assert_eq!(ctrl.secure_avic_en(), false);
1398 assert_eq!(ctrl.allowed_nmi(), false);
1399 assert_eq!(ctrl.guest_apic_backing_page_ptr(), 0);
1400 }
1401
1402 #[test]
1403 fn secure_avic_control_enable_bit() {
1404 let ctrl = SecureAvicControl::new().with_secure_avic_en(true);
1405 assert_eq!(ctrl.secure_avic_en(), true);
1406 assert_eq!(ctrl.into_bits() & 1, 1);
1407 }
1408
1409 #[test]
1410 fn secure_avic_control_allowed_nmi_bit() {
1411 let ctrl = SecureAvicControl::new().with_allowed_nmi(true);
1412 assert_eq!(ctrl.allowed_nmi(), true);
1413 assert_eq!(ctrl.into_bits() & 0b10, 0b10);
1414 }
1415
1416 #[test]
1417 fn secure_avic_control_page_ptr() {
1418 let pfn = 0xDEAD_BEEF_u64;
1420 let ctrl = SecureAvicControl::new()
1421 .with_secure_avic_en(true)
1422 .with_guest_apic_backing_page_ptr(pfn);
1423 assert_eq!(ctrl.guest_apic_backing_page_ptr(), pfn);
1424 assert_eq!(ctrl.secure_avic_en(), true);
1425 assert_eq!(ctrl.into_bits() >> 12, pfn);
1427 }
1428
1429 #[test]
1430 fn secure_avic_control_roundtrip() {
1431 let raw = 0xABCD_1234_5678_9001_u64;
1432 let ctrl = SecureAvicControl::from(raw);
1433 assert_eq!(ctrl.into_bits(), raw);
1434 }
1435
1436 #[test]
1439 fn no_accel_info_register_number_extraction() {
1440 let info = SevAvicNoAccelInfo::new().with_apic_register_number(SevAvicRegisterNumber::EOI);
1442 assert_eq!(info.apic_register_number(), SevAvicRegisterNumber::EOI);
1443 assert_eq!((info.into_bits() >> 4) & 0xFF, 0xB);
1445 }
1446
1447 #[test]
1448 fn no_accel_info_write_access_bit() {
1449 let info = SevAvicNoAccelInfo::new().with_write_access(true);
1451 assert!(info.write_access());
1452 assert_eq!(info.into_bits() & (1 << 32), 1 << 32);
1453
1454 let info_read = SevAvicNoAccelInfo::new().with_write_access(false);
1455 assert!(!info_read.write_access());
1456 }
1457
1458 #[test]
1459 fn no_accel_info_combined() {
1460 let info = SevAvicNoAccelInfo::new()
1461 .with_apic_register_number(SevAvicRegisterNumber::ICR_LOW)
1462 .with_write_access(true);
1463 assert_eq!(info.apic_register_number(), SevAvicRegisterNumber::ICR_LOW);
1464 assert!(info.write_access());
1465 }
1466
1467 #[test]
1468 fn no_accel_info_all_register_numbers_roundtrip() {
1469 let registers = [
1470 SevAvicRegisterNumber::APIC_ID,
1471 SevAvicRegisterNumber::VERSION,
1472 SevAvicRegisterNumber::TPR,
1473 SevAvicRegisterNumber::APR,
1474 SevAvicRegisterNumber::PPR,
1475 SevAvicRegisterNumber::EOI,
1476 SevAvicRegisterNumber::LDR,
1477 SevAvicRegisterNumber::DFR,
1478 SevAvicRegisterNumber::SPURIOUS,
1479 SevAvicRegisterNumber::ISR0,
1480 SevAvicRegisterNumber::ISR7,
1481 SevAvicRegisterNumber::TMR0,
1482 SevAvicRegisterNumber::TMR7,
1483 SevAvicRegisterNumber::IRR0,
1484 SevAvicRegisterNumber::IRR7,
1485 SevAvicRegisterNumber::ERROR,
1486 SevAvicRegisterNumber::ICR_LOW,
1487 SevAvicRegisterNumber::ICR_HIGH,
1488 SevAvicRegisterNumber::TIMER_LVT,
1489 SevAvicRegisterNumber::INITIAL_COUNT,
1490 SevAvicRegisterNumber::CURRENT_COUNT,
1491 SevAvicRegisterNumber::DIVIDER,
1492 SevAvicRegisterNumber::SELF_IPI,
1493 ];
1494 for reg in registers {
1495 let info = SevAvicNoAccelInfo::new().with_apic_register_number(reg);
1496 assert_eq!(
1497 info.apic_register_number(),
1498 reg,
1499 "register number roundtrip failed for {reg:#x?}"
1500 );
1501 }
1502 }
1503
1504 #[test]
1507 fn incomplete_ipi_info1_icr_fields() {
1508 let icr_low = 0x0004_10FFu32;
1509 let icr_high = 0x0200_0000u32;
1510 let info = SevAvicIncompleteIpiInfo1::new()
1511 .with_icr_low(icr_low)
1512 .with_icr_high(icr_high);
1513 assert_eq!(info.icr_low(), icr_low);
1514 assert_eq!(info.icr_high(), icr_high);
1515 assert_eq!(info.into_bits(), icr_low as u64 | ((icr_high as u64) << 32));
1516 }
1517
1518 #[test]
1519 fn incomplete_ipi_info2_fields() {
1520 let info = SevAvicIncompleteIpiInfo2::new()
1521 .with_index(42)
1522 .with_failure(SevAvicIpiFailure::NOT_RUNNING);
1523 assert_eq!(info.index(), 42);
1524 assert_eq!(info.failure(), SevAvicIpiFailure::NOT_RUNNING);
1525 }
1526
1527 #[test]
1528 fn incomplete_ipi_info2_all_failure_codes() {
1529 let failures = [
1530 SevAvicIpiFailure::INVALID_TYPE,
1531 SevAvicIpiFailure::NOT_RUNNING,
1532 SevAvicIpiFailure::INVALID_TARGET,
1533 SevAvicIpiFailure::INVALID_BACKING_PAGE,
1534 SevAvicIpiFailure::INVALID_VECTOR,
1535 SevAvicIpiFailure::UNACCELERATED_IPI,
1536 ];
1537 for failure in failures {
1538 let info = SevAvicIncompleteIpiInfo2::new().with_failure(failure);
1539 assert_eq!(
1540 info.failure(),
1541 failure,
1542 "failure code roundtrip failed for {failure:#x?}"
1543 );
1544 }
1545 }
1546
1547 #[test]
1550 fn sev_features_secure_avic_bit() {
1551 let features = SevFeatures::new().with_secure_avic(true);
1552 assert!(features.secure_avic());
1553 assert_ne!(features.into_bits() & (1 << 16), 0);
1555 }
1556
1557 #[test]
1558 fn sev_features_guest_intercept_control_bit() {
1559 let features = SevFeatures::new().with_guest_intercept_control(true);
1560 assert!(features.guest_intercept_control());
1561 assert_ne!(features.into_bits() & (1 << 13), 0);
1563 }
1564
1565 #[test]
1566 fn sev_features_secure_avic_with_no_alternate_injection() {
1567 let features = SevFeatures::new()
1570 .with_secure_avic(true)
1571 .with_guest_intercept_control(true)
1572 .with_alternate_injection(false);
1573 assert!(features.secure_avic());
1574 assert!(features.guest_intercept_control());
1575 assert!(!features.alternate_injection());
1576 }
1577
1578 #[test]
1579 fn sev_features_alternate_injection_without_secure_avic() {
1580 let features = SevFeatures::new()
1581 .with_alternate_injection(true)
1582 .with_secure_avic(false);
1583 assert!(features.alternate_injection());
1584 assert!(!features.secure_avic());
1585 }
1586
1587 #[test]
1590 fn sev_status_msr_secure_avic_bit() {
1591 let status = SevStatusMsr::new().with_secure_avic(true);
1592 assert!(status.secure_avic());
1593 assert_ne!(status.into_bits() & (1 << 18), 0);
1598 }
1599
1600 #[test]
1603 fn v_intr_cntrl_nmi_fields() {
1604 let ctrl = SevVirtualInterruptControl::new()
1605 .with_nmi(true)
1606 .with_nmi_mask(true)
1607 .with_nmi_enable(true);
1608 assert!(ctrl.nmi());
1609 assert!(ctrl.nmi_mask());
1610 assert!(ctrl.nmi_enable());
1611 }
1612
1613 #[test]
1616 fn sev_avic_page_size_is_4096() {
1617 assert_eq!(size_of::<SevAvicPage>(), 4096);
1619 }
1620
1621 #[test]
1622 fn sev_avic_irr_register_size() {
1623 assert_eq!(
1626 size_of::<SevAvicIrrRegister>(),
1627 size_of::<ApicRegisterValue>()
1628 );
1629 }
1630
1631 #[test]
1632 fn sev_avic_page_field_offsets() {
1633 let page = SevAvicPage::new_zeroed();
1636 let base = core::ptr::from_ref(&page) as usize;
1637
1638 let id_offset = core::ptr::from_ref(&page.id) as usize - base;
1640 assert_eq!(id_offset, 2 * 16, "APIC ID offset");
1641
1642 let version_offset = core::ptr::from_ref(&page.version) as usize - base;
1644 assert_eq!(version_offset, 3 * 16, "version offset");
1645
1646 let tpr_offset = core::ptr::from_ref(&page.tpr) as usize - base;
1648 assert_eq!(tpr_offset, 8 * 16, "TPR offset");
1649
1650 let isr_offset = core::ptr::from_ref(&page.isr) as usize - base;
1652 assert_eq!(isr_offset, 0x10 * 16, "ISR offset");
1653
1654 let tmr_offset = core::ptr::from_ref(&page.tmr) as usize - base;
1656 assert_eq!(tmr_offset, 0x18 * 16, "TMR offset");
1657
1658 let irr_offset = core::ptr::from_ref(&page.irr) as usize - base;
1660 assert_eq!(irr_offset, 0x20 * 16, "IRR offset");
1661
1662 let icr_offset = core::ptr::from_ref(&page.icr) as usize - base;
1664 assert_eq!(icr_offset, 0x30 * 16, "ICR offset");
1665 }
1666
1667 #[test]
1670 fn vmsa_secure_avic_control_at_rsp_offset() {
1671 let vmsa = SevVmsa::new_zeroed();
1674 let base = core::ptr::from_ref(&vmsa) as usize;
1675 let rbx_offset = core::ptr::from_ref(&vmsa.rbx) as usize - base;
1676 let savic_offset = core::ptr::from_ref(&vmsa.secure_avic_control) as usize - base;
1677 let rbp_offset = core::ptr::from_ref(&vmsa.rbp) as usize - base;
1678
1679 assert_eq!(savic_offset, rbx_offset + 8);
1681 assert_eq!(rbp_offset, savic_offset + 8);
1682 }
1683
1684 #[test]
1687 fn avic_register_number_matches_apic_register_enum() {
1688 use crate::apic::ApicRegister;
1691 assert_eq!(SevAvicRegisterNumber::APIC_ID.0, ApicRegister::ID.0 as u32);
1692 assert_eq!(
1693 SevAvicRegisterNumber::VERSION.0,
1694 ApicRegister::VERSION.0 as u32
1695 );
1696 assert_eq!(SevAvicRegisterNumber::TPR.0, ApicRegister::TPR.0 as u32);
1697 assert_eq!(SevAvicRegisterNumber::EOI.0, ApicRegister::EOI.0 as u32);
1698 assert_eq!(SevAvicRegisterNumber::LDR.0, ApicRegister::LDR.0 as u32);
1699 assert_eq!(
1700 SevAvicRegisterNumber::SPURIOUS.0,
1701 ApicRegister::SVR.0 as u32
1702 );
1703 assert_eq!(SevAvicRegisterNumber::ISR0.0, ApicRegister::ISR0.0 as u32);
1704 assert_eq!(SevAvicRegisterNumber::TMR0.0, ApicRegister::TMR0.0 as u32);
1705 assert_eq!(SevAvicRegisterNumber::IRR0.0, ApicRegister::IRR0.0 as u32);
1706 assert_eq!(SevAvicRegisterNumber::ERROR.0, ApicRegister::ESR.0 as u32);
1707 assert_eq!(
1708 SevAvicRegisterNumber::ICR_LOW.0,
1709 ApicRegister::ICR0.0 as u32
1710 );
1711 assert_eq!(
1712 SevAvicRegisterNumber::ICR_HIGH.0,
1713 ApicRegister::ICR1.0 as u32
1714 );
1715 assert_eq!(
1716 SevAvicRegisterNumber::TIMER_LVT.0,
1717 ApicRegister::LVT_TIMER.0 as u32
1718 );
1719 assert_eq!(
1720 SevAvicRegisterNumber::INITIAL_COUNT.0,
1721 ApicRegister::TIMER_ICR.0 as u32
1722 );
1723 assert_eq!(
1724 SevAvicRegisterNumber::CURRENT_COUNT.0,
1725 ApicRegister::TIMER_CCR.0 as u32
1726 );
1727 assert_eq!(
1728 SevAvicRegisterNumber::DIVIDER.0,
1729 ApicRegister::TIMER_DCR.0 as u32
1730 );
1731 assert_eq!(
1732 SevAvicRegisterNumber::SELF_IPI.0,
1733 ApicRegister::SELF_IPI.0 as u32
1734 );
1735 }
1736
1737 #[test]
1738 fn avic_register_to_x2apic_msr() {
1739 use crate::apic::X2APIC_MSR_BASE;
1741 let msr = X2APIC_MSR_BASE + SevAvicRegisterNumber::EOI.0;
1742 assert_eq!(msr, 0x80B); let msr = X2APIC_MSR_BASE + SevAvicRegisterNumber::ICR_LOW.0;
1745 assert_eq!(msr, 0x830); }
1747
1748 #[test]
1751 fn sev_exit_code_avic_values() {
1752 assert_eq!(SevExitCode::AVIC_INCOMPLETE_IPI.0, 0x401);
1753 assert_eq!(SevExitCode::AVIC_NOACCEL.0, 0x402);
1754 }
1755}