Skip to main content

x86defs/
snp.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! AMD SEV-SNP specific definitions.
5
6use 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
15// Interruption Information Field
16pub 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
21// Secrets page layout.
22pub const REG_TWEAK_BITMAP_OFFSET: usize = 0x100;
23pub const REG_TWEAK_BITMAP_SIZE: usize = 0x40;
24
25/// Value for the `msg_version` member in [`SNP_GUEST_REQ_MSG_VERSION`].
26/// Use 1 for now.
27pub 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/// A X64 selector register.
58#[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/// An X64 XMM register.
88#[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/// SEV secure AVIC control register
225#[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/// AVIC exit info1 for the incomplete IPI exit
237#[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/// AVIC exit info2 for the incomplete IPI exit
265#[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 Register.
278        APIC_ID = 0x2,
279        /// APIC Version Register.
280        VERSION = 0x3,
281        /// Task Priority Register
282        TPR = 0x8,
283        /// Arbitration Priority Register.
284        APR = 0x9,
285        /// Processor Priority Register.
286        PPR = 0xA,
287        /// End Of Interrupt Register.
288        EOI = 0xB,
289        /// Remote Read Register
290        REMOTE_READ = 0xC,
291        /// Logical Destination Register.
292        LDR = 0xD,
293        /// Destination Format Register.
294        DFR = 0xE,
295        /// Spurious Interrupt Vector.
296        SPURIOUS = 0xF,
297        /// In-Service Registers.
298        ISR0 = 0x10,
299        ISR1 = 0x11,
300        ISR2 = 0x12,
301        ISR3 = 0x13,
302        ISR4 = 0x14,
303        ISR5 = 0x15,
304        ISR6 = 0x16,
305        ISR7 = 0x17,
306        /// Trigger Mode Registers.
307        TMR0 = 0x18,
308        TMR1 = 0x19,
309        TMR2 = 0x1A,
310        TMR3 = 0x1B,
311        TMR4 = 0x1C,
312        TMR5 = 0x1D,
313        TMR6 = 0x1E,
314        TMR7 = 0x1F,
315        /// Interrupt Request Registers.
316        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 Status Register.
325        ERROR = 0x28,
326        /// ICR Low.
327        ICR_LOW = 0x30,
328        /// ICR High.
329        ICR_HIGH = 0x31,
330        /// LVT Timer Register.
331        TIMER_LVT = 0x32,
332        /// LVT Thermal Register.
333        THERMAL_LVT = 0x33,
334        /// LVT Performance Monitor Register.
335        PERFMON_LVT = 0x34,
336        /// LVT Local Int0 Register.
337        LINT0_LVT = 0x35,
338        /// LVT Local Int1 Register.
339        LINT1_LVT = 0x36,
340        /// LVT Error Register.
341        ERROR_LVT = 0x37,
342        /// Initial count Register.
343        INITIAL_COUNT = 0x38,
344        /// R/O Current count Register.
345        CURRENT_COUNT = 0x39,
346        /// Divide configuration Register.
347        DIVIDER = 0x3e,
348        /// Self IPI register, only present in x2APIC.
349        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/// AVIC SEV exit info1 for the no acceleration exit
364#[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/// SEV VMSA structure representing CPU state
379#[repr(C)]
380#[derive(Debug, Clone, IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
381pub struct SevVmsa {
382    // Selector Info
383    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    // Descriptor Table Info
391    pub gdtr: SevSelector,
392    pub ldtr: SevSelector,
393    pub idtr: SevSelector,
394    pub tr: SevSelector,
395
396    // CET
397    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    // Reserved, MBZ
404    pub vmsa_reserved1: [u8; 2],
405
406    // Virtual Machine Privilege Level
407    pub vmpl: u8,
408
409    // CPL
410    pub cpl: u8,
411
412    // Reserved, MBZ
413    pub vmsa_reserved2: u32,
414
415    // EFER
416    pub efer: u64,
417
418    // Reserved, MBZ
419    pub vmsa_reserved3: [u32; 26],
420
421    // XSS (offset 0x140)
422    pub xss: u64,
423
424    // Control registers
425    pub cr4: u64,
426    pub cr3: u64,
427    pub cr0: u64,
428
429    // Debug registers
430    pub dr7: u64,
431    pub dr6: u64,
432
433    // RFLAGS
434    pub rflags: u64,
435
436    // RIP
437    pub rip: u64,
438
439    // Additional saved debug registers
440    pub dr0: u64,
441    pub dr1: u64,
442    pub dr2: u64,
443    pub dr3: u64,
444
445    // Debug register address masks
446    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    // Reserved, MBZ
452    pub vmsa_reserved4: [u64; 3],
453
454    // RSP
455    pub rsp: u64,
456
457    // CET
458    pub s_cet: u64,
459    pub ssp: u64,
460    pub interrupt_ssp_table_addr: u64,
461
462    // RAX
463    pub rax: u64,
464
465    // SYSCALL config registers
466    pub star: u64,
467    pub lstar: u64,
468    pub cstar: u64,
469    pub sfmask: u64,
470
471    // KernelGsBase
472    pub kernel_gs_base: u64,
473
474    // SYSENTER config registers
475    pub sysenter_cs: u64,
476    pub sysenter_esp: u64,
477    pub sysenter_eip: u64,
478
479    // CR2
480    pub cr2: u64,
481
482    // Reserved, MBZ
483    pub vmsa_reserved5: [u64; 4],
484
485    // PAT
486    pub pat: u64,
487
488    // LBR MSRs
489    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    // Reserved, MBZ
496    pub vmsa_reserved6: [u64; 9],
497
498    // Speculation control MSR
499    pub spec_ctrl: u64,
500
501    // PKRU
502    pub pkru: u32,
503
504    // TSC_AUX
505    pub tsc_aux: u32,
506
507    // Reserved, MBZ
508    pub vmsa_reserved7: [u32; 4],
509
510    pub register_protection_nonce: u64,
511
512    // GPRs
513    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    // Reserved, MBZ
530    pub vmsa_reserved9: [u64; 2],
531
532    // Exit information following an automatic #VMEXIT
533    pub exit_info1: u64,
534    pub exit_info2: u64,
535    pub exit_int_info: u64,
536
537    // Software scratch register
538    pub next_rip: u64,
539
540    // SEV feature information
541    pub sev_features: SevFeatures,
542
543    // Virtual interrupt control
544    pub v_intr_cntrl: SevVirtualInterruptControl,
545
546    // Guest exiting error code
547    pub guest_error_code: u64,
548
549    // Virtual top of memory
550    pub virtual_tom: u64,
551
552    // TLB control.  Writing a zero to PCPU_ID will force a full TLB
553    // invalidation upon the next entry.
554    pub tlb_id: u64,
555    pub pcpu_id: u64,
556
557    // Event injection
558    pub event_inject: SevEventInjectInfo,
559
560    // XCR0
561    pub xcr0: u64,
562
563    // X87 state save valid bitmap
564    pub xsave_valid_bitmap: [u8; 16],
565
566    // X87 save state
567    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    // NOTE: Should be 80 bytes. Making it 10 u64 because no code uses it on a
578    // byte-level yet.
579    pub x87_registers: [u64; 10],
580
581    // XMM registers
582    pub xmm_registers: [SevXmmRegister; 16],
583
584    // YMM high registers
585    pub ymm_registers: [SevXmmRegister; 16],
586}
587
588#[repr(C)]
589#[derive(Debug, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
590/// Structure representing the SEV-ES AVIC IRR register.
591///
592/// If the UpdateIRR bit is set in the VMCB, the guest-controlled AllowedIRR mask
593/// is logically AND-ed with the host-controlled RequestedIRR and then is logically
594/// OR-ed into the IRR field in the Guest APIC Backing page.
595pub 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)]
603/// Structure representing the SEV-ES AVIC backing page.
604/// Specification: "AMD64 PPR Vol3 System Programming", 15.29.3  AVIC Backing Page.
605pub 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
647// Info codes for the GHCB MSR protocol.
648open_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/// GHCB layout for the secure enlightened Hyper-V hypercalls.
776#[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/// Struct representing GHCB hypercall parameters. These are located at the GHCB
788/// page starting at [`GHCB_PAGE_HYPERCALL_PARAMETERS_OFFSET`].
789#[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
799// Exit Codes.
800open_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        // SEV-ES software-defined exit codes
975        SNP_GUEST_REQUEST = 0x80000011,
976        SNP_EXTENDED_GUEST_REQUEST = 0x80000012,
977        HV_DOORBELL_PAGE = 0x80000014,
978
979        // SEV-SNP hardware error codes
980        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/// PSP data structures.
999#[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/// Structure describing the pages being read during SNP ID block measurement.
1026/// Each structure is hashed with the previous structures digest to create a final
1027/// measurement
1028#[repr(C)]
1029#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
1030pub struct SnpPageInfo {
1031    /// Set to the value of the previous page's launch digest
1032    pub digest_current: [u8; 48],
1033    /// Hash of page contents, if measured
1034    pub contents: [u8; 48],
1035    /// Size of the SnpPageInfo struct
1036    pub length: u16,
1037    /// type of page being measured, described by [`SnpPageType`]
1038    pub page_type: SnpPageType,
1039    /// imi_page_bit must match IMI_PAGE flag
1040    pub imi_page_bit: u8,
1041    /// All lower VMPL permissions are denied for SNP
1042    pub lower_vmpl_permissions: u32,
1043    /// The guest physical address at which this page data should be loaded; it
1044    /// must be aligned to a page size boundary.
1045    pub gpa: u64,
1046}
1047
1048open_enum::open_enum! {
1049    /// The type of page described by [`SnpPageInfo`]
1050    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1051    pub enum SnpPageType: u8 {
1052        /// Reserved
1053        RESERVED = 0x0,
1054        /// Normal data page
1055        NORMAL = 0x1,
1056        /// VMSA page
1057        VMSA = 0x2,
1058        /// Zero page
1059        ZERO = 0x3,
1060        /// Page encrypted, but not measured
1061        UNMEASURED = 0x4,
1062        /// Page storing guest secrets
1063        SECRETS = 0x5,
1064        /// Page to provide CPUID function values
1065        CPUID = 0x6,
1066    }
1067}
1068
1069/// Structure containing the completed SNP measurement of the IGVM file.
1070/// The signature of the hash of this struct is the id_key_signature for
1071/// `igvm_defs::IGVM_VHS_SNP_ID_BLOCK`.
1072#[repr(C)]
1073#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
1074pub struct SnpPspIdBlock {
1075    /// completed launch digest of IGVM file
1076    pub ld: [u8; 48],
1077    /// family id of the guest
1078    pub family_id: [u8; 16],
1079    /// image id of the guest
1080    pub image_id: [u8; 16],
1081    /// Version of the ID block format, must be 0x1
1082    pub version: u32,
1083    /// Software version of the guest
1084    pub guest_svn: u32,
1085    /// SNP Policy of the guest
1086    pub policy: u64,
1087}
1088
1089/// ECDSA signature in an SNP PSP ID authentication page.
1090#[repr(C)]
1091#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
1092pub struct SnpPspIdAuthSignature {
1093    /// ECDSA R component.
1094    pub r: [u8; 72],
1095    /// ECDSA S component.
1096    pub s: [u8; 72],
1097    /// Reserved bytes.
1098    pub reserved: [u8; 368],
1099}
1100
1101/// ECDSA public key in an SNP PSP ID authentication page.
1102#[repr(C)]
1103#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
1104pub struct SnpPspIdAuthPublicKey {
1105    /// Elliptic curve identifier.
1106    pub curve: u32,
1107    /// Public key X coordinate.
1108    pub qx: [u8; 72],
1109    /// Public key Y coordinate.
1110    pub qy: [u8; 72],
1111    /// Reserved bytes.
1112    pub reserved: [u8; 880],
1113}
1114
1115/// SNP PSP ID block authentication page.
1116///
1117/// This is the `ID_AUTH` structure supplied with `SNP_LAUNCH_FINISH`.
1118#[repr(C)]
1119#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
1120pub struct SnpPspIdAuth {
1121    /// Algorithm used by the ID key.
1122    pub id_key_algorithm: u32,
1123    /// Algorithm used by the author key.
1124    pub author_key_algorithm: u32,
1125    /// Reserved bytes.
1126    pub reserved0: [u8; 56],
1127    /// Signature of the ID block by the ID key.
1128    pub id_block_signature: SnpPspIdAuthSignature,
1129    /// ID public key.
1130    pub id_key: SnpPspIdAuthPublicKey,
1131    /// Reserved bytes.
1132    pub reserved1: [u8; 60],
1133    /// Signature of the ID key by the author key.
1134    pub id_key_signature: SnpPspIdAuthSignature,
1135    /// Author public key.
1136    pub author_key: SnpPspIdAuthPublicKey,
1137    /// Reserved bytes.
1138    pub reserved2: [u8; 892],
1139}
1140
1141const_assert_eq!(size_of::<SnpPspIdAuth>(), 4096);
1142
1143/// ECDSA signature components used by an SNP ID block.
1144#[derive(Debug, Clone, Copy, Eq, PartialEq)]
1145pub struct SnpIdBlockSignature {
1146    /// ECDSA R component.
1147    pub r: [u8; 72],
1148    /// ECDSA S component.
1149    pub s: [u8; 72],
1150}
1151
1152/// Public key used by an SNP ID block.
1153#[derive(Debug, Clone, Copy, Eq, PartialEq)]
1154pub struct SnpIdBlockPublicKey {
1155    /// Elliptic curve identifier.
1156    pub curve: u32,
1157    /// Public key X coordinate.
1158    pub qx: [u8; 72],
1159    /// Public key Y coordinate.
1160    pub qy: [u8; 72],
1161}
1162
1163#[bitfield(u64)]
1164#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
1165pub struct SevStatusMsr {
1166    pub sev_enabled: bool,
1167    pub es_enabled: bool,
1168    pub snp_enabled: bool,
1169    pub vtom: bool,
1170    pub reflect_vc: bool,
1171    pub restrict_injection: bool,
1172    pub alternate_injection: bool,
1173    pub debug_swap: bool,
1174    pub prevent_host_ibs: bool,
1175    pub snp_btb_isolation: bool,
1176    pub vmpl_sss: bool,
1177    pub secure_tsc: bool,
1178    pub vmgexit_param: bool,
1179    _rsvd3: bool,
1180    pub ibs_virt: bool,
1181    _rsvd5: bool,
1182    pub vmsa_reg_prot: bool,
1183    pub smt_prot: bool,
1184    pub secure_avic: bool,
1185    #[bits(4)]
1186    _reserved: u64,
1187    pub ibpb_on_entry: bool,
1188    #[bits(40)]
1189    _unused: u64,
1190}
1191
1192#[bitfield(u64)]
1193#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
1194pub struct SevInvlpgbRax {
1195    pub va_valid: bool,
1196    pub pcid_valid: bool,
1197    pub asid_valid: bool,
1198    pub global: bool,
1199    pub final_only: bool,
1200    pub nested: bool,
1201    #[bits(6)]
1202    reserved: u64,
1203    #[bits(52)]
1204    pub virtual_page_number: u64,
1205}
1206
1207#[bitfield(u32)]
1208#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
1209pub struct SevInvlpgbEdx {
1210    #[bits(16)]
1211    pub asid: u64,
1212    #[bits(12)]
1213    pub pcid: u64,
1214    #[bits(4)]
1215    reserved: u32,
1216}
1217
1218#[bitfield(u32)]
1219#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
1220pub struct SevInvlpgbEcx {
1221    #[bits(16)]
1222    pub additional_count: u64,
1223    #[bits(15)]
1224    reserved: u64,
1225    pub large_page: bool,
1226}
1227
1228#[bitfield(u64)]
1229pub struct MovCrxDrxInfo {
1230    #[bits(4)]
1231    pub gpr_number: u64,
1232    #[bits(59)]
1233    pub reserved: u64,
1234    pub mov_crx: bool,
1235}
1236
1237/// Request structure for the `SNP_GET_REPORT` request.
1238/// See `MSG_REPORT_REQ` in Table 21, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1239#[repr(C)]
1240#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1241pub struct SnpReportReq {
1242    /// Guest-provided data to be included in the attestation report.
1243    pub user_data: [u8; 64],
1244    /// The VMPL to put in the attestation report. Must be greater than
1245    /// or equal to the current VMPL and, at most, three.
1246    pub vmpl: u32,
1247    /// Reserved
1248    // TODO SNP: Support VLEK feature if needed
1249    pub rsvd: [u8; 28],
1250}
1251
1252pub const SNP_REPORT_RESP_DATA_SIZE: usize =
1253    size_of::<u32>() + size_of::<u32>() + 24 + size_of::<SnpReport>();
1254
1255/// Response structure for the `SNP_GET_REPORT` request.
1256/// See `MSG_REPORT_RSP` in Table 24, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1257#[repr(C)]
1258#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1259pub struct SnpReportResp {
1260    /// The status of key derivation operation.
1261    /// 0h: Success.
1262    /// 16h: Invalid parameters.
1263    /// 27h: Invalid key selection.
1264    pub status: u32,
1265    /// Size in bytes of the report.
1266    pub report_size: u32,
1267    /// Reserved
1268    pub _reserved0: [u8; 24],
1269    /// The attestation report generated by the firmware.
1270    pub report: SnpReport,
1271}
1272
1273/// Size of the [`SnpReport`].
1274pub const SNP_REPORT_SIZE: usize = 0x4a0;
1275
1276/// Size of `report_data` member in [`SnpReport`].
1277pub const SNP_REPORT_DATA_SIZE: usize = 64;
1278
1279/// Report structure.
1280/// See `ATTESTATION_REPORT` in Table 22, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1281#[repr(C)]
1282#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1283pub struct SnpReport {
1284    /// Version number of this attestation report.
1285    /// Set to 2h for this specification.
1286    pub version: u32,
1287    /// The guest SVN.
1288    pub guest_svn: u32,
1289    /// The guest policy.
1290    pub policy: u64,
1291    /// The family ID provided at launch.
1292    pub family: u128,
1293    /// The image ID provided at launch.
1294    pub image_id: u128,
1295    /// The request VMPL for the attestation
1296    /// report.
1297    pub vmpl: u32,
1298    /// The signature algorithm used to sign
1299    /// this report.
1300    pub signature_algo: u32,
1301    /// CurrentTcb.
1302    pub current_tcb: u64,
1303    /// Information about the platform.
1304    pub platform_info: u64,
1305    /// Flags
1306    pub flags: u32,
1307    /// Reserved
1308    pub _reserved0: u32,
1309    /// Guest-provided data.
1310    pub report_data: [u8; SNP_REPORT_DATA_SIZE],
1311    /// The measurement calculated at
1312    /// launch.
1313    pub measurement: [u8; 48],
1314    /// Data provided by the hypervisor at
1315    /// launch.
1316    pub host_data: [u8; 32],
1317    /// SHA-384 digest of the ID public key
1318    /// that signed the ID block provided in
1319    /// SNP_LAUNCH_FINISH.
1320    pub id_key_digest: [u8; 48],
1321    /// SHA-384 digest of the Author public
1322    /// key that certified the ID key, if
1323    /// provided in SNP_LAUNCH_FINISH.
1324    pub author_key_digest: [u8; 48],
1325    /// Report ID of this guest.
1326    pub report_id: [u8; 32],
1327    /// Report ID of this guest’s migration
1328    /// agent
1329    pub report_id_ma: [u8; 32],
1330    /// Reported TCB version used to derive
1331    /// the VCEK that signed this report.
1332    pub reported_tcb: u64,
1333    /// Reserved
1334    pub _reserved1: [u8; 24],
1335    /// If MaskChipId is set to 0, Identifier
1336    /// unique to the chip as output by
1337    /// GET_ID. Otherwise, set to 0h.
1338    pub chip_id: [u8; 64],
1339    /// CommittedTcb.
1340    pub committed_tcb: u64,
1341    /// The build number of CurrentVersion.
1342    pub current_build: u8,
1343    /// The minor number of CurrentVersion.
1344    pub current_minor: u8,
1345    /// The major number of CurrentVersion.
1346    pub current_major: u8,
1347    /// Reserved
1348    pub _reserved2: u8,
1349    /// The build number of CommittedVersion.
1350    pub committed_build: u8,
1351    /// The minor version of CommittedVersion.
1352    pub committed_minor: u8,
1353    /// The major version of CommittedVersion.
1354    pub committed_major: u8,
1355    /// Reserved
1356    pub _reserved3: u8,
1357    /// The CurrentTcb at the time the guest
1358    /// was launched or imported.
1359    pub launch_tcb: u64,
1360    /// Reserved
1361    pub _reserved4: [u8; 168],
1362    /// Signature of bytes inclusive of this report.
1363    pub signature: [u8; 512],
1364}
1365
1366static_assertions::const_assert_eq!(SNP_REPORT_SIZE, size_of::<SnpReport>());
1367
1368/// Request structure for the `SNP_GET_DERIVED_KEY` request.
1369/// See `MSG_KEY_REQ` in Table 18, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1370#[repr(C)]
1371#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1372pub struct SnpDerivedKeyReq {
1373    /// Selects the root key from which to derive the key.
1374    /// 0 indicates VCEK
1375    /// 1 indicates VMRK
1376    // TODO: Support VLEK feature if needed
1377    pub root_key_select: u32,
1378    /// Reserved
1379    pub rsvd: u32,
1380    /// Bitmask indicating which data will be mixed into the
1381    /// derived key.
1382    pub guest_field_select: u64,
1383    /// The VMPL to mix into the derived key. Must be greater
1384    /// than or equal to the current VMPL.
1385    pub vmpl: u32,
1386    /// The guest SVN to mix into the key. Must not exceed the
1387    /// guest SVN provided at launch in the ID block.
1388    pub guest_svn: u32,
1389    /// The TCB version to mix into the derived key. Must not
1390    /// exceed CommittedTcb.
1391    pub tcb_version: u64,
1392}
1393
1394/// Indicate which guest-selectable fields will be mixed into the key.
1395/// See `GUEST_FIELD_SELECT` in Table 19, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1396#[bitfield(u64)]
1397pub struct GuestFieldSelect {
1398    /// Indicate that the guest policy will be mixed into the key.
1399    pub guest_policy: bool,
1400    /// Indicate that the image ID of the guest will be mixed into the key.
1401    pub image_id: bool,
1402    /// Indicate the family ID of the guest will be mixed into the key.
1403    pub family_id: bool,
1404    /// Indicate the measurement of the guest during launch will be mixed into the key.
1405    pub measurement: bool,
1406    /// Indicate that the guest-provided SVN will be mixed into the key.
1407    pub guest_svn: bool,
1408    /// Indicate that the guest-provided TCB_VERSION will be mixed into the key.
1409    pub tcb_version: bool,
1410    /// Reserved
1411    #[bits(58)]
1412    pub _reserved: u64,
1413}
1414
1415/// See `DERIVED_KEY` in Table 20, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1416pub const SNP_DERIVED_KEY_SIZE: usize = 32;
1417
1418/// Response structure for the `SNP_GET_DERIVED_KEY` request.
1419/// See `MSG_KEY_RSP` in Table 20, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1420#[repr(C)]
1421#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1422pub struct SnpDerivedKeyResp {
1423    /// The status of key derivation operation.
1424    /// 0h: Success.
1425    /// 16h: Invalid parameters.
1426    /// 27h: Invalid key selection.
1427    pub status: u32,
1428    /// Reserved
1429    pub _reserved: [u8; 28],
1430    /// The requested derived key.
1431    pub derived_key: [u8; SNP_DERIVED_KEY_SIZE],
1432}
1433
1434static_assertions::const_assert_eq!(
1435    // The size of the response data defined by the SNP specification.
1436    64,
1437    size_of::<SnpDerivedKeyResp>()
1438);
1439
1440#[cfg(test)]
1441mod tests {
1442    use super::*;
1443    use zerocopy::FromZeros;
1444
1445    // ---- SecureAvicControl bitfield tests ----
1446
1447    #[test]
1448    fn secure_avic_control_default_is_zero() {
1449        let ctrl = SecureAvicControl::new();
1450        assert_eq!(ctrl.into_bits(), 0);
1451        assert_eq!(ctrl.secure_avic_en(), false);
1452        assert_eq!(ctrl.allowed_nmi(), false);
1453        assert_eq!(ctrl.guest_apic_backing_page_ptr(), 0);
1454    }
1455
1456    #[test]
1457    fn secure_avic_control_enable_bit() {
1458        let ctrl = SecureAvicControl::new().with_secure_avic_en(true);
1459        assert_eq!(ctrl.secure_avic_en(), true);
1460        assert_eq!(ctrl.into_bits() & 1, 1);
1461    }
1462
1463    #[test]
1464    fn secure_avic_control_allowed_nmi_bit() {
1465        let ctrl = SecureAvicControl::new().with_allowed_nmi(true);
1466        assert_eq!(ctrl.allowed_nmi(), true);
1467        assert_eq!(ctrl.into_bits() & 0b10, 0b10);
1468    }
1469
1470    #[test]
1471    fn secure_avic_control_page_ptr() {
1472        // The page pointer is in bits [63:12], representing a PFN.
1473        let pfn = 0xDEAD_BEEF_u64;
1474        let ctrl = SecureAvicControl::new()
1475            .with_secure_avic_en(true)
1476            .with_guest_apic_backing_page_ptr(pfn);
1477        assert_eq!(ctrl.guest_apic_backing_page_ptr(), pfn);
1478        assert_eq!(ctrl.secure_avic_en(), true);
1479        // The PFN should be in bits [63:12]
1480        assert_eq!(ctrl.into_bits() >> 12, pfn);
1481    }
1482
1483    #[test]
1484    fn secure_avic_control_roundtrip() {
1485        let raw = 0xABCD_1234_5678_9001_u64;
1486        let ctrl = SecureAvicControl::from(raw);
1487        assert_eq!(ctrl.into_bits(), raw);
1488    }
1489
1490    // ---- SevAvicNoAccelInfo bitfield tests ----
1491
1492    #[test]
1493    fn no_accel_info_register_number_extraction() {
1494        // Register number is in bits [11:4].
1495        let info = SevAvicNoAccelInfo::new().with_apic_register_number(SevAvicRegisterNumber::EOI);
1496        assert_eq!(info.apic_register_number(), SevAvicRegisterNumber::EOI);
1497        // EOI = 0xB, stored in bits [11:4]
1498        assert_eq!((info.into_bits() >> 4) & 0xFF, 0xB);
1499    }
1500
1501    #[test]
1502    fn no_accel_info_write_access_bit() {
1503        // Write access is bit 32.
1504        let info = SevAvicNoAccelInfo::new().with_write_access(true);
1505        assert!(info.write_access());
1506        assert_eq!(info.into_bits() & (1 << 32), 1 << 32);
1507
1508        let info_read = SevAvicNoAccelInfo::new().with_write_access(false);
1509        assert!(!info_read.write_access());
1510    }
1511
1512    #[test]
1513    fn no_accel_info_combined() {
1514        let info = SevAvicNoAccelInfo::new()
1515            .with_apic_register_number(SevAvicRegisterNumber::ICR_LOW)
1516            .with_write_access(true);
1517        assert_eq!(info.apic_register_number(), SevAvicRegisterNumber::ICR_LOW);
1518        assert!(info.write_access());
1519    }
1520
1521    #[test]
1522    fn no_accel_info_all_register_numbers_roundtrip() {
1523        let registers = [
1524            SevAvicRegisterNumber::APIC_ID,
1525            SevAvicRegisterNumber::VERSION,
1526            SevAvicRegisterNumber::TPR,
1527            SevAvicRegisterNumber::APR,
1528            SevAvicRegisterNumber::PPR,
1529            SevAvicRegisterNumber::EOI,
1530            SevAvicRegisterNumber::LDR,
1531            SevAvicRegisterNumber::DFR,
1532            SevAvicRegisterNumber::SPURIOUS,
1533            SevAvicRegisterNumber::ISR0,
1534            SevAvicRegisterNumber::ISR7,
1535            SevAvicRegisterNumber::TMR0,
1536            SevAvicRegisterNumber::TMR7,
1537            SevAvicRegisterNumber::IRR0,
1538            SevAvicRegisterNumber::IRR7,
1539            SevAvicRegisterNumber::ERROR,
1540            SevAvicRegisterNumber::ICR_LOW,
1541            SevAvicRegisterNumber::ICR_HIGH,
1542            SevAvicRegisterNumber::TIMER_LVT,
1543            SevAvicRegisterNumber::INITIAL_COUNT,
1544            SevAvicRegisterNumber::CURRENT_COUNT,
1545            SevAvicRegisterNumber::DIVIDER,
1546            SevAvicRegisterNumber::SELF_IPI,
1547        ];
1548        for reg in registers {
1549            let info = SevAvicNoAccelInfo::new().with_apic_register_number(reg);
1550            assert_eq!(
1551                info.apic_register_number(),
1552                reg,
1553                "register number roundtrip failed for {reg:#x?}"
1554            );
1555        }
1556    }
1557
1558    // ---- SevAvicIncompleteIpiInfo1/2 bitfield tests ----
1559
1560    #[test]
1561    fn incomplete_ipi_info1_icr_fields() {
1562        let icr_low = 0x0004_10FFu32;
1563        let icr_high = 0x0200_0000u32;
1564        let info = SevAvicIncompleteIpiInfo1::new()
1565            .with_icr_low(icr_low)
1566            .with_icr_high(icr_high);
1567        assert_eq!(info.icr_low(), icr_low);
1568        assert_eq!(info.icr_high(), icr_high);
1569        assert_eq!(info.into_bits(), icr_low as u64 | ((icr_high as u64) << 32));
1570    }
1571
1572    #[test]
1573    fn incomplete_ipi_info2_fields() {
1574        let info = SevAvicIncompleteIpiInfo2::new()
1575            .with_index(42)
1576            .with_failure(SevAvicIpiFailure::NOT_RUNNING);
1577        assert_eq!(info.index(), 42);
1578        assert_eq!(info.failure(), SevAvicIpiFailure::NOT_RUNNING);
1579    }
1580
1581    #[test]
1582    fn incomplete_ipi_info2_all_failure_codes() {
1583        let failures = [
1584            SevAvicIpiFailure::INVALID_TYPE,
1585            SevAvicIpiFailure::NOT_RUNNING,
1586            SevAvicIpiFailure::INVALID_TARGET,
1587            SevAvicIpiFailure::INVALID_BACKING_PAGE,
1588            SevAvicIpiFailure::INVALID_VECTOR,
1589            SevAvicIpiFailure::UNACCELERATED_IPI,
1590        ];
1591        for failure in failures {
1592            let info = SevAvicIncompleteIpiInfo2::new().with_failure(failure);
1593            assert_eq!(
1594                info.failure(),
1595                failure,
1596                "failure code roundtrip failed for {failure:#x?}"
1597            );
1598        }
1599    }
1600
1601    // ---- SevFeatures secure AVIC fields ----
1602
1603    #[test]
1604    fn sev_features_secure_avic_bit() {
1605        let features = SevFeatures::new().with_secure_avic(true);
1606        assert!(features.secure_avic());
1607        // secure_avic is bit 16 (0-indexed).
1608        assert_ne!(features.into_bits() & (1 << 16), 0);
1609    }
1610
1611    #[test]
1612    fn sev_features_guest_intercept_control_bit() {
1613        let features = SevFeatures::new().with_guest_intercept_control(true);
1614        assert!(features.guest_intercept_control());
1615        // guest_intercept_control is bit 13.
1616        assert_ne!(features.into_bits() & (1 << 13), 0);
1617    }
1618
1619    #[test]
1620    fn sev_features_secure_avic_with_no_alternate_injection() {
1621        // Secure AVIC and alternate injection are mutually exclusive per the
1622        // init_vmsa logic.
1623        let features = SevFeatures::new()
1624            .with_secure_avic(true)
1625            .with_guest_intercept_control(true)
1626            .with_alternate_injection(false);
1627        assert!(features.secure_avic());
1628        assert!(features.guest_intercept_control());
1629        assert!(!features.alternate_injection());
1630    }
1631
1632    #[test]
1633    fn sev_features_alternate_injection_without_secure_avic() {
1634        let features = SevFeatures::new()
1635            .with_alternate_injection(true)
1636            .with_secure_avic(false);
1637        assert!(features.alternate_injection());
1638        assert!(!features.secure_avic());
1639    }
1640
1641    // ---- SevStatusMsr secure AVIC field ----
1642
1643    #[test]
1644    fn sev_status_msr_secure_avic_bit() {
1645        let status = SevStatusMsr::new().with_secure_avic(true);
1646        assert!(status.secure_avic());
1647        // secure_avic is bit 18 in SevStatusMsr (after sev_enabled, es_enabled,
1648        // snp_enabled, vtom, reflect_vc, restrict_injection, alternate_injection,
1649        // debug_swap, prevent_host_ibs, snp_btb_isolation, vmpl_sss, secure_tsc,
1650        // vmgexit_param, _rsvd3, ibs_virt, _rsvd5, vmsa_reg_prot, smt_prot).
1651        assert_ne!(status.into_bits() & (1 << 18), 0);
1652    }
1653
1654    // ---- SevVirtualInterruptControl NMI fields ----
1655
1656    #[test]
1657    fn v_intr_cntrl_nmi_fields() {
1658        let ctrl = SevVirtualInterruptControl::new()
1659            .with_nmi(true)
1660            .with_nmi_mask(true)
1661            .with_nmi_enable(true);
1662        assert!(ctrl.nmi());
1663        assert!(ctrl.nmi_mask());
1664        assert!(ctrl.nmi_enable());
1665    }
1666
1667    // ---- SevAvicPage layout tests ----
1668
1669    #[test]
1670    fn sev_avic_page_size_is_4096() {
1671        // Already asserted at compile time, but verify at runtime too.
1672        assert_eq!(size_of::<SevAvicPage>(), 4096);
1673    }
1674
1675    #[test]
1676    fn sev_avic_irr_register_size() {
1677        // Each IRR register has value + allowed + reserved = 16 bytes,
1678        // same as a standard ApicRegisterValue.
1679        assert_eq!(
1680            size_of::<SevAvicIrrRegister>(),
1681            size_of::<ApicRegisterValue>()
1682        );
1683    }
1684
1685    #[test]
1686    fn sev_avic_page_field_offsets() {
1687        // Verify key field offsets match the APIC register map.
1688        // Each "register" is 16 bytes (128 bits per the AMD spec).
1689        let page = SevAvicPage::new_zeroed();
1690        let base = core::ptr::from_ref(&page) as usize;
1691
1692        // id is at register index 2 (offset 0x20)
1693        let id_offset = core::ptr::from_ref(&page.id) as usize - base;
1694        assert_eq!(id_offset, 2 * 16, "APIC ID offset");
1695
1696        // version is at register index 3 (offset 0x30)
1697        let version_offset = core::ptr::from_ref(&page.version) as usize - base;
1698        assert_eq!(version_offset, 3 * 16, "version offset");
1699
1700        // TPR is at register index 8 (offset 0x80)
1701        let tpr_offset = core::ptr::from_ref(&page.tpr) as usize - base;
1702        assert_eq!(tpr_offset, 8 * 16, "TPR offset");
1703
1704        // ISR starts at register index 0x10 (offset 0x100)
1705        let isr_offset = core::ptr::from_ref(&page.isr) as usize - base;
1706        assert_eq!(isr_offset, 0x10 * 16, "ISR offset");
1707
1708        // TMR starts at register index 0x18 (offset 0x180)
1709        let tmr_offset = core::ptr::from_ref(&page.tmr) as usize - base;
1710        assert_eq!(tmr_offset, 0x18 * 16, "TMR offset");
1711
1712        // IRR starts at register index 0x20 (offset 0x200)
1713        let irr_offset = core::ptr::from_ref(&page.irr) as usize - base;
1714        assert_eq!(irr_offset, 0x20 * 16, "IRR offset");
1715
1716        // ICR is at register index 0x30 (offset 0x300)
1717        let icr_offset = core::ptr::from_ref(&page.icr) as usize - base;
1718        assert_eq!(icr_offset, 0x30 * 16, "ICR offset");
1719    }
1720
1721    // ---- VMSA SecureAvicControl field offset test ----
1722
1723    #[test]
1724    fn vmsa_secure_avic_control_at_rsp_offset() {
1725        // In the VMSA, secure_avic_control occupies the RSP slot (between RBX and RBP).
1726        // Verify it's at the expected offset by checking it doesn't overlap GPRs.
1727        let vmsa = SevVmsa::new_zeroed();
1728        let base = core::ptr::from_ref(&vmsa) as usize;
1729        let rbx_offset = core::ptr::from_ref(&vmsa.rbx) as usize - base;
1730        let savic_offset = core::ptr::from_ref(&vmsa.secure_avic_control) as usize - base;
1731        let rbp_offset = core::ptr::from_ref(&vmsa.rbp) as usize - base;
1732
1733        // secure_avic_control should be right after rbx and before rbp.
1734        assert_eq!(savic_offset, rbx_offset + 8);
1735        assert_eq!(rbp_offset, savic_offset + 8);
1736    }
1737
1738    // ---- SevAvicRegisterNumber to x2APIC MSR mapping ----
1739
1740    #[test]
1741    fn avic_register_number_matches_apic_register_enum() {
1742        // The SevAvicRegisterNumber values should match the corresponding
1743        // x86defs::apic::ApicRegisterValue values, ensuring correct MSR computation.
1744        use crate::apic::ApicRegister;
1745        assert_eq!(SevAvicRegisterNumber::APIC_ID.0, ApicRegister::ID.0 as u32);
1746        assert_eq!(
1747            SevAvicRegisterNumber::VERSION.0,
1748            ApicRegister::VERSION.0 as u32
1749        );
1750        assert_eq!(SevAvicRegisterNumber::TPR.0, ApicRegister::TPR.0 as u32);
1751        assert_eq!(SevAvicRegisterNumber::EOI.0, ApicRegister::EOI.0 as u32);
1752        assert_eq!(SevAvicRegisterNumber::LDR.0, ApicRegister::LDR.0 as u32);
1753        assert_eq!(
1754            SevAvicRegisterNumber::SPURIOUS.0,
1755            ApicRegister::SVR.0 as u32
1756        );
1757        assert_eq!(SevAvicRegisterNumber::ISR0.0, ApicRegister::ISR0.0 as u32);
1758        assert_eq!(SevAvicRegisterNumber::TMR0.0, ApicRegister::TMR0.0 as u32);
1759        assert_eq!(SevAvicRegisterNumber::IRR0.0, ApicRegister::IRR0.0 as u32);
1760        assert_eq!(SevAvicRegisterNumber::ERROR.0, ApicRegister::ESR.0 as u32);
1761        assert_eq!(
1762            SevAvicRegisterNumber::ICR_LOW.0,
1763            ApicRegister::ICR0.0 as u32
1764        );
1765        assert_eq!(
1766            SevAvicRegisterNumber::ICR_HIGH.0,
1767            ApicRegister::ICR1.0 as u32
1768        );
1769        assert_eq!(
1770            SevAvicRegisterNumber::TIMER_LVT.0,
1771            ApicRegister::LVT_TIMER.0 as u32
1772        );
1773        assert_eq!(
1774            SevAvicRegisterNumber::INITIAL_COUNT.0,
1775            ApicRegister::TIMER_ICR.0 as u32
1776        );
1777        assert_eq!(
1778            SevAvicRegisterNumber::CURRENT_COUNT.0,
1779            ApicRegister::TIMER_CCR.0 as u32
1780        );
1781        assert_eq!(
1782            SevAvicRegisterNumber::DIVIDER.0,
1783            ApicRegister::TIMER_DCR.0 as u32
1784        );
1785        assert_eq!(
1786            SevAvicRegisterNumber::SELF_IPI.0,
1787            ApicRegister::SELF_IPI.0 as u32
1788        );
1789    }
1790
1791    #[test]
1792    fn avic_register_to_x2apic_msr() {
1793        // Verify the MSR computation: X2APIC_MSR_BASE + register_number.
1794        use crate::apic::X2APIC_MSR_BASE;
1795        let msr = X2APIC_MSR_BASE + SevAvicRegisterNumber::EOI.0;
1796        assert_eq!(msr, 0x80B); // EOI is register 0xB
1797
1798        let msr = X2APIC_MSR_BASE + SevAvicRegisterNumber::ICR_LOW.0;
1799        assert_eq!(msr, 0x830); // ICR_LOW is register 0x30
1800    }
1801
1802    // ---- SevExitCode AVIC constants ----
1803
1804    #[test]
1805    fn sev_exit_code_avic_values() {
1806        assert_eq!(SevExitCode::AVIC_INCOMPLETE_IPI.0, 0x401);
1807        assert_eq!(SevExitCode::AVIC_NOACCEL.0, 0x402);
1808    }
1809}