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 components used by an SNP ID block.
1090#[derive(Debug, Clone, Copy, Eq, PartialEq)]
1091pub struct SnpIdBlockSignature {
1092    /// ECDSA R component.
1093    pub r: [u8; 72],
1094    /// ECDSA S component.
1095    pub s: [u8; 72],
1096}
1097
1098/// Public key used by an SNP ID block.
1099#[derive(Debug, Clone, Copy, Eq, PartialEq)]
1100pub struct SnpIdBlockPublicKey {
1101    /// Elliptic curve identifier.
1102    pub curve: u32,
1103    /// Public key X coordinate.
1104    pub qx: [u8; 72],
1105    /// Public key Y coordinate.
1106    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/// Request structure for the `SNP_GET_REPORT` request.
1184/// See `MSG_REPORT_REQ` in Table 21, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1185#[repr(C)]
1186#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1187pub struct SnpReportReq {
1188    /// Guest-provided data to be included in the attestation report.
1189    pub user_data: [u8; 64],
1190    /// The VMPL to put in the attestation report. Must be greater than
1191    /// or equal to the current VMPL and, at most, three.
1192    pub vmpl: u32,
1193    /// Reserved
1194    // TODO SNP: Support VLEK feature if needed
1195    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/// Response structure for the `SNP_GET_REPORT` request.
1202/// See `MSG_REPORT_RSP` in Table 24, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1203#[repr(C)]
1204#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1205pub struct SnpReportResp {
1206    /// The status of key derivation operation.
1207    /// 0h: Success.
1208    /// 16h: Invalid parameters.
1209    /// 27h: Invalid key selection.
1210    pub status: u32,
1211    /// Size in bytes of the report.
1212    pub report_size: u32,
1213    /// Reserved
1214    pub _reserved0: [u8; 24],
1215    /// The attestation report generated by the firmware.
1216    pub report: SnpReport,
1217}
1218
1219/// Size of the [`SnpReport`].
1220pub const SNP_REPORT_SIZE: usize = 0x4a0;
1221
1222/// Size of `report_data` member in [`SnpReport`].
1223pub const SNP_REPORT_DATA_SIZE: usize = 64;
1224
1225/// Report structure.
1226/// See `ATTESTATION_REPORT` in Table 22, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1227#[repr(C)]
1228#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1229pub struct SnpReport {
1230    /// Version number of this attestation report.
1231    /// Set to 2h for this specification.
1232    pub version: u32,
1233    /// The guest SVN.
1234    pub guest_svn: u32,
1235    /// The guest policy.
1236    pub policy: u64,
1237    /// The family ID provided at launch.
1238    pub family: u128,
1239    /// The image ID provided at launch.
1240    pub image_id: u128,
1241    /// The request VMPL for the attestation
1242    /// report.
1243    pub vmpl: u32,
1244    /// The signature algorithm used to sign
1245    /// this report.
1246    pub signature_algo: u32,
1247    /// CurrentTcb.
1248    pub current_tcb: u64,
1249    /// Information about the platform.
1250    pub platform_info: u64,
1251    /// Flags
1252    pub flags: u32,
1253    /// Reserved
1254    pub _reserved0: u32,
1255    /// Guest-provided data.
1256    pub report_data: [u8; SNP_REPORT_DATA_SIZE],
1257    /// The measurement calculated at
1258    /// launch.
1259    pub measurement: [u8; 48],
1260    /// Data provided by the hypervisor at
1261    /// launch.
1262    pub host_data: [u8; 32],
1263    /// SHA-384 digest of the ID public key
1264    /// that signed the ID block provided in
1265    /// SNP_LAUNCH_FINISH.
1266    pub id_key_digest: [u8; 48],
1267    /// SHA-384 digest of the Author public
1268    /// key that certified the ID key, if
1269    /// provided in SNP_LAUNCH_FINISH.
1270    pub author_key_digest: [u8; 48],
1271    /// Report ID of this guest.
1272    pub report_id: [u8; 32],
1273    /// Report ID of this guest’s migration
1274    /// agent
1275    pub report_id_ma: [u8; 32],
1276    /// Reported TCB version used to derive
1277    /// the VCEK that signed this report.
1278    pub reported_tcb: u64,
1279    /// Reserved
1280    pub _reserved1: [u8; 24],
1281    /// If MaskChipId is set to 0, Identifier
1282    /// unique to the chip as output by
1283    /// GET_ID. Otherwise, set to 0h.
1284    pub chip_id: [u8; 64],
1285    /// CommittedTcb.
1286    pub committed_tcb: u64,
1287    /// The build number of CurrentVersion.
1288    pub current_build: u8,
1289    /// The minor number of CurrentVersion.
1290    pub current_minor: u8,
1291    /// The major number of CurrentVersion.
1292    pub current_major: u8,
1293    /// Reserved
1294    pub _reserved2: u8,
1295    /// The build number of CommittedVersion.
1296    pub committed_build: u8,
1297    /// The minor version of CommittedVersion.
1298    pub committed_minor: u8,
1299    /// The major version of CommittedVersion.
1300    pub committed_major: u8,
1301    /// Reserved
1302    pub _reserved3: u8,
1303    /// The CurrentTcb at the time the guest
1304    /// was launched or imported.
1305    pub launch_tcb: u64,
1306    /// Reserved
1307    pub _reserved4: [u8; 168],
1308    /// Signature of bytes inclusive of this report.
1309    pub signature: [u8; 512],
1310}
1311
1312static_assertions::const_assert_eq!(SNP_REPORT_SIZE, size_of::<SnpReport>());
1313
1314/// Request structure for the `SNP_GET_DERIVED_KEY` request.
1315/// See `MSG_KEY_REQ` in Table 18, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1316#[repr(C)]
1317#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1318pub struct SnpDerivedKeyReq {
1319    /// Selects the root key from which to derive the key.
1320    /// 0 indicates VCEK
1321    /// 1 indicates VMRK
1322    // TODO: Support VLEK feature if needed
1323    pub root_key_select: u32,
1324    /// Reserved
1325    pub rsvd: u32,
1326    /// Bitmask indicating which data will be mixed into the
1327    /// derived key.
1328    pub guest_field_select: u64,
1329    /// The VMPL to mix into the derived key. Must be greater
1330    /// than or equal to the current VMPL.
1331    pub vmpl: u32,
1332    /// The guest SVN to mix into the key. Must not exceed the
1333    /// guest SVN provided at launch in the ID block.
1334    pub guest_svn: u32,
1335    /// The TCB version to mix into the derived key. Must not
1336    /// exceed CommittedTcb.
1337    pub tcb_version: u64,
1338}
1339
1340/// Indicate which guest-selectable fields will be mixed into the key.
1341/// See `GUEST_FIELD_SELECT` in Table 19, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1342#[bitfield(u64)]
1343pub struct GuestFieldSelect {
1344    /// Indicate that the guest policy will be mixed into the key.
1345    pub guest_policy: bool,
1346    /// Indicate that the image ID of the guest will be mixed into the key.
1347    pub image_id: bool,
1348    /// Indicate the family ID of the guest will be mixed into the key.
1349    pub family_id: bool,
1350    /// Indicate the measurement of the guest during launch will be mixed into the key.
1351    pub measurement: bool,
1352    /// Indicate that the guest-provided SVN will be mixed into the key.
1353    pub guest_svn: bool,
1354    /// Indicate that the guest-provided TCB_VERSION will be mixed into the key.
1355    pub tcb_version: bool,
1356    /// Reserved
1357    #[bits(58)]
1358    pub _reserved: u64,
1359}
1360
1361/// See `DERIVED_KEY` in Table 20, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1362pub const SNP_DERIVED_KEY_SIZE: usize = 32;
1363
1364/// Response structure for the `SNP_GET_DERIVED_KEY` request.
1365/// See `MSG_KEY_RSP` in Table 20, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1366#[repr(C)]
1367#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1368pub struct SnpDerivedKeyResp {
1369    /// The status of key derivation operation.
1370    /// 0h: Success.
1371    /// 16h: Invalid parameters.
1372    /// 27h: Invalid key selection.
1373    pub status: u32,
1374    /// Reserved
1375    pub _reserved: [u8; 28],
1376    /// The requested derived key.
1377    pub derived_key: [u8; SNP_DERIVED_KEY_SIZE],
1378}
1379
1380static_assertions::const_assert_eq!(
1381    // The size of the response data defined by the SNP specification.
1382    64,
1383    size_of::<SnpDerivedKeyResp>()
1384);
1385
1386#[cfg(test)]
1387mod tests {
1388    use super::*;
1389    use zerocopy::FromZeros;
1390
1391    // ---- SecureAvicControl bitfield tests ----
1392
1393    #[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        // The page pointer is in bits [63:12], representing a PFN.
1419        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        // The PFN should be in bits [63:12]
1426        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    // ---- SevAvicNoAccelInfo bitfield tests ----
1437
1438    #[test]
1439    fn no_accel_info_register_number_extraction() {
1440        // Register number is in bits [11:4].
1441        let info = SevAvicNoAccelInfo::new().with_apic_register_number(SevAvicRegisterNumber::EOI);
1442        assert_eq!(info.apic_register_number(), SevAvicRegisterNumber::EOI);
1443        // EOI = 0xB, stored in bits [11:4]
1444        assert_eq!((info.into_bits() >> 4) & 0xFF, 0xB);
1445    }
1446
1447    #[test]
1448    fn no_accel_info_write_access_bit() {
1449        // Write access is bit 32.
1450        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    // ---- SevAvicIncompleteIpiInfo1/2 bitfield tests ----
1505
1506    #[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    // ---- SevFeatures secure AVIC fields ----
1548
1549    #[test]
1550    fn sev_features_secure_avic_bit() {
1551        let features = SevFeatures::new().with_secure_avic(true);
1552        assert!(features.secure_avic());
1553        // secure_avic is bit 16 (0-indexed).
1554        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        // guest_intercept_control is bit 13.
1562        assert_ne!(features.into_bits() & (1 << 13), 0);
1563    }
1564
1565    #[test]
1566    fn sev_features_secure_avic_with_no_alternate_injection() {
1567        // Secure AVIC and alternate injection are mutually exclusive per the
1568        // init_vmsa logic.
1569        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    // ---- SevStatusMsr secure AVIC field ----
1588
1589    #[test]
1590    fn sev_status_msr_secure_avic_bit() {
1591        let status = SevStatusMsr::new().with_secure_avic(true);
1592        assert!(status.secure_avic());
1593        // secure_avic is bit 18 in SevStatusMsr (after sev_enabled, es_enabled,
1594        // snp_enabled, vtom, reflect_vc, restrict_injection, alternate_injection,
1595        // debug_swap, prevent_host_ibs, snp_btb_isolation, vmpl_sss, secure_tsc,
1596        // vmgexit_param, _rsvd3, ibs_virt, _rsvd5, vmsa_reg_prot, smt_prot).
1597        assert_ne!(status.into_bits() & (1 << 18), 0);
1598    }
1599
1600    // ---- SevVirtualInterruptControl NMI fields ----
1601
1602    #[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    // ---- SevAvicPage layout tests ----
1614
1615    #[test]
1616    fn sev_avic_page_size_is_4096() {
1617        // Already asserted at compile time, but verify at runtime too.
1618        assert_eq!(size_of::<SevAvicPage>(), 4096);
1619    }
1620
1621    #[test]
1622    fn sev_avic_irr_register_size() {
1623        // Each IRR register has value + allowed + reserved = 16 bytes,
1624        // same as a standard ApicRegisterValue.
1625        assert_eq!(
1626            size_of::<SevAvicIrrRegister>(),
1627            size_of::<ApicRegisterValue>()
1628        );
1629    }
1630
1631    #[test]
1632    fn sev_avic_page_field_offsets() {
1633        // Verify key field offsets match the APIC register map.
1634        // Each "register" is 16 bytes (128 bits per the AMD spec).
1635        let page = SevAvicPage::new_zeroed();
1636        let base = core::ptr::from_ref(&page) as usize;
1637
1638        // id is at register index 2 (offset 0x20)
1639        let id_offset = core::ptr::from_ref(&page.id) as usize - base;
1640        assert_eq!(id_offset, 2 * 16, "APIC ID offset");
1641
1642        // version is at register index 3 (offset 0x30)
1643        let version_offset = core::ptr::from_ref(&page.version) as usize - base;
1644        assert_eq!(version_offset, 3 * 16, "version offset");
1645
1646        // TPR is at register index 8 (offset 0x80)
1647        let tpr_offset = core::ptr::from_ref(&page.tpr) as usize - base;
1648        assert_eq!(tpr_offset, 8 * 16, "TPR offset");
1649
1650        // ISR starts at register index 0x10 (offset 0x100)
1651        let isr_offset = core::ptr::from_ref(&page.isr) as usize - base;
1652        assert_eq!(isr_offset, 0x10 * 16, "ISR offset");
1653
1654        // TMR starts at register index 0x18 (offset 0x180)
1655        let tmr_offset = core::ptr::from_ref(&page.tmr) as usize - base;
1656        assert_eq!(tmr_offset, 0x18 * 16, "TMR offset");
1657
1658        // IRR starts at register index 0x20 (offset 0x200)
1659        let irr_offset = core::ptr::from_ref(&page.irr) as usize - base;
1660        assert_eq!(irr_offset, 0x20 * 16, "IRR offset");
1661
1662        // ICR is at register index 0x30 (offset 0x300)
1663        let icr_offset = core::ptr::from_ref(&page.icr) as usize - base;
1664        assert_eq!(icr_offset, 0x30 * 16, "ICR offset");
1665    }
1666
1667    // ---- VMSA SecureAvicControl field offset test ----
1668
1669    #[test]
1670    fn vmsa_secure_avic_control_at_rsp_offset() {
1671        // In the VMSA, secure_avic_control occupies the RSP slot (between RBX and RBP).
1672        // Verify it's at the expected offset by checking it doesn't overlap GPRs.
1673        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        // secure_avic_control should be right after rbx and before rbp.
1680        assert_eq!(savic_offset, rbx_offset + 8);
1681        assert_eq!(rbp_offset, savic_offset + 8);
1682    }
1683
1684    // ---- SevAvicRegisterNumber to x2APIC MSR mapping ----
1685
1686    #[test]
1687    fn avic_register_number_matches_apic_register_enum() {
1688        // The SevAvicRegisterNumber values should match the corresponding
1689        // x86defs::apic::ApicRegisterValue values, ensuring correct MSR computation.
1690        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        // Verify the MSR computation: X2APIC_MSR_BASE + register_number.
1740        use crate::apic::X2APIC_MSR_BASE;
1741        let msr = X2APIC_MSR_BASE + SevAvicRegisterNumber::EOI.0;
1742        assert_eq!(msr, 0x80B); // EOI is register 0xB
1743
1744        let msr = X2APIC_MSR_BASE + SevAvicRegisterNumber::ICR_LOW.0;
1745        assert_eq!(msr, 0x830); // ICR_LOW is register 0x30
1746    }
1747
1748    // ---- SevExitCode AVIC constants ----
1749
1750    #[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}