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        UNREGISTER_REQUEST = 0x018,
663        UNREGISTER_RESPONSE = 0x019,
664        HYP_FEATURE_REQUEST = 0x080,
665        HYP_FEATURE_RESPONSE = 0x081,
666        SPECIAL_HYPERCALL = 0xF00,
667        SPECIAL_FAST_CALL = 0xF01,
668        HYPERCALL_OUTPUT = 0xF02,
669        SPECIAL_DBGPRINT = 0xF03,
670        SHUTDOWN_REQUEST = 0x100,
671    }
672}
673
674/// GHCB 2.04 feature bitmap bit for unregistering the current GHCB GPA.
675pub const GHCB_HYP_FEATURE_GHCB_UNREGISTER: u64 = 1 << 8;
676
677pub const GHCB_DATA_PAGE_STATE_PRIVATE: u64 = 0x001;
678pub const GHCB_DATA_PAGE_STATE_SHARED: u64 = 0x002;
679pub const GHCB_DATA_PAGE_STATE_PSMASH: u64 = 0x003;
680pub const GHCB_DATA_PAGE_STATE_UNSMASH: u64 = 0x004;
681pub const GHCB_DATA_PAGE_STATE_MASK: u64 = 0x00F;
682pub const GHCB_DATA_PAGE_STATE_LARGE_PAGE: u64 = 0x010;
683
684open_enum::open_enum! {
685    #[derive(FromBytes, IntoBytes)]
686    pub enum GhcbUsage: u32 {
687        BASE = 0,
688        HYPERCALL = 1,
689        VTL_RETURN = 2,
690        INVALID = !0,
691    }
692}
693
694impl GhcbUsage {
695    pub const fn into_bits(self) -> u32 {
696        self.0
697    }
698
699    pub const fn from_bits(bits: u32) -> Self {
700        Self(bits)
701    }
702}
703
704open_enum::open_enum! {
705    #[derive(FromBytes, IntoBytes)]
706    pub enum GhcbProtocolVersion: u16 {
707        V1 = 1,
708        V2 = 2,
709    }
710}
711
712impl GhcbProtocolVersion {
713    pub const fn into_bits(self) -> u16 {
714        self.0
715    }
716
717    pub const fn from_bits(bits: u16) -> Self {
718        Self(bits)
719    }
720}
721
722#[repr(C)]
723#[derive(Debug, Copy, Clone, IntoBytes, FromBytes)]
724pub struct GhcbSaveArea {
725    pub reserved_0x0: [u8; 203],
726    pub cpl: u8,
727    pub reserved_0xcc: [u8; 116],
728    pub xss: u64,
729    pub reserved_0x148: [u8; 24],
730    pub dr7: u64,
731    pub reserved_0x168: [u8; 16],
732    pub rip: u64,
733    pub reserved_0x180: [u8; 88],
734    pub rsp: u64,
735    pub reserved_0x1e0: [u8; 24],
736    pub rax: u64,
737    pub reserved_0x200: [u8; 264],
738    pub rcx: u64,
739    pub rdx: u64,
740    pub rbx: u64,
741    pub reserved_0x320: [u8; 8],
742    pub rbp: u64,
743    pub rsi: u64,
744    pub rdi: u64,
745    pub r8: u64,
746    pub r9: u64,
747    pub r10: u64,
748    pub r11: u64,
749    pub r12: u64,
750    pub r13: u64,
751    pub r14: u64,
752    pub r15: u64,
753    pub reserved_0x380: [u8; 16],
754    pub sw_exit_code: u64,
755    pub sw_exit_info1: u64,
756    pub sw_exit_info2: u64,
757    pub sw_scratch: u64,
758    pub reserved_0x3b0: [u8; 56],
759    pub xcr0: u64,
760    pub valid_bitmap0: u64,
761    pub valid_bitmap1: u64,
762    pub x87_state_gpa: u64,
763}
764
765#[repr(C, align(4096))]
766#[derive(Debug, Copy, Clone, IntoBytes, FromBytes)]
767pub struct GhcbPage {
768    pub save: GhcbSaveArea,
769    pub reserved_save: [u8; 2048 - size_of::<GhcbSaveArea>()],
770    pub shared_buffer: [u8; 2032],
771    pub reserved_0xff0: [u8; 10],
772    pub protocol_version: GhcbProtocolVersion,
773    pub ghcb_usage: GhcbUsage,
774}
775
776const _: () = assert!(size_of::<GhcbPage>() == X64_PAGE_SIZE as usize);
777
778pub const GHCB_PAGE_HV_HYPERCALL_DATA_SIZE: usize = 4072;
779
780/// GHCB layout for the secure enlightened Hyper-V hypercalls.
781#[repr(C, align(4096))]
782#[derive(Debug, Copy, Clone, IntoBytes, FromBytes)]
783pub struct GhcbPageHvHypercall {
784    pub data: [u8; GHCB_PAGE_HV_HYPERCALL_DATA_SIZE],
785    pub output_gpa: u64,
786    pub io: u64,
787    pub reserved: u64,
788}
789
790const _: () = assert!(size_of::<GhcbPageHvHypercall>() == X64_PAGE_SIZE as usize);
791
792/// Struct representing GHCB hypercall parameters. These are located at the GHCB
793/// page starting at [`GHCB_PAGE_HYPERCALL_PARAMETERS_OFFSET`].
794#[repr(C)]
795#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
796pub struct GhcbHypercallParameters {
797    pub output_gpa: u64,
798    pub input_control: u64,
799}
800
801pub const GHCB_PAGE_HYPERCALL_PARAMETERS_OFFSET: usize = 4072;
802pub const GHCB_PAGE_HYPERCALL_OUTPUT_OFFSET: usize = 4080;
803
804// Exit Codes.
805open_enum::open_enum! {
806    pub enum SevExitCode: u64 {
807        CR0_READ = 0x0,
808        CR1_READ = 0x1,
809        CR2_READ = 0x2,
810        CR3_READ = 0x3,
811        CR4_READ = 0x4,
812        CR5_READ = 0x5,
813        CR6_READ = 0x6,
814        CR7_READ = 0x7,
815        CR8_READ = 0x8,
816        CR9_READ = 0x9,
817        CR10_READ = 0xa,
818        CR11_READ = 0xb,
819        CR12_READ = 0xc,
820        CR13_READ = 0xd,
821        CR14_READ = 0xe,
822        CR15_READ = 0xf,
823        CR0_WRITE = 0x10,
824        CR1_WRITE = 0x11,
825        CR2_WRITE = 0x12,
826        CR3_WRITE = 0x13,
827        CR4_WRITE = 0x14,
828        CR5_WRITE = 0x15,
829        CR6_WRITE = 0x16,
830        CR7_WRITE = 0x17,
831        CR8_WRITE = 0x18,
832        CR9_WRITE = 0x19,
833        CR10_WRITE = 0x1a,
834        CR11_WRITE = 0x1b,
835        CR12_WRITE = 0x1c,
836        CR13_WRITE = 0x1d,
837        CR14_WRITE = 0x1e,
838        CR15_WRITE = 0x1f,
839        DR0_READ = 0x20,
840        DR1_READ = 0x21,
841        DR2_READ = 0x22,
842        DR3_READ = 0x23,
843        DR4_READ = 0x24,
844        DR5_READ = 0x25,
845        DR6_READ = 0x26,
846        DR7_READ = 0x27,
847        DR8_READ = 0x28,
848        DR9_READ = 0x29,
849        DR10_READ = 0x2a,
850        DR11_READ = 0x2b,
851        DR12_READ = 0x2c,
852        DR13_READ = 0x2d,
853        DR14_READ = 0x2e,
854        DR15_READ = 0x2f,
855        DR0_WRITE = 0x30,
856        DR1_WRITE = 0x31,
857        DR2_WRITE = 0x32,
858        DR3_WRITE = 0x33,
859        DR4_WRITE = 0x34,
860        DR5_WRITE = 0x35,
861        DR6_WRITE = 0x36,
862        DR7_WRITE = 0x37,
863        DR8_WRITE = 0x38,
864        DR9_WRITE = 0x39,
865        DR10_WRITE = 0x3a,
866        DR11_WRITE = 0x3b,
867        DR12_WRITE = 0x3c,
868        DR13_WRITE = 0x3d,
869        DR14_WRITE = 0x3e,
870        DR15_WRITE = 0x3f,
871        EXCP0 = 0x40,
872        EXCP_DB = 0x41,
873        EXCP2 = 0x42,
874        EXCP3 = 0x43,
875        EXCP4 = 0x44,
876        EXCP5 = 0x45,
877        EXCP6 = 0x46,
878        EXCP7 = 0x47,
879        EXCP8 = 0x48,
880        EXCP9 = 0x49,
881        EXCP10 = 0x4a,
882        EXCP11 = 0x4b,
883        EXCP12 = 0x4c,
884        EXCP13 = 0x4d,
885        EXCP14 = 0x4e,
886        EXCP15 = 0x4f,
887        EXCP16 = 0x50,
888        EXCP17 = 0x51,
889        EXCP18 = 0x52,
890        EXCP19 = 0x53,
891        EXCP20 = 0x54,
892        EXCP21 = 0x55,
893        EXCP22 = 0x56,
894        EXCP23 = 0x57,
895        EXCP24 = 0x58,
896        EXCP25 = 0x59,
897        EXCP26 = 0x5a,
898        EXCP27 = 0x5b,
899        EXCP28 = 0x5c,
900        EXCP29 = 0x5d,
901        EXCP30 = 0x5e,
902        EXCP31 = 0x5f,
903        INTR = 0x60,
904        NMI = 0x61,
905        SMI = 0x62,
906        INIT = 0x63,
907        VINTR = 0x64,
908        CR0_SEL_WRITE = 0x65,
909        IDTR_READ = 0x66,
910        GDTR_READ = 0x67,
911        LDTR_READ = 0x68,
912        TR_READ = 0x69,
913        IDTR_WRITE = 0x6a,
914        GDTR_WRITE = 0x6b,
915        LDTR_WRITE = 0x6c,
916        TR_WRITE = 0x6d,
917        RDTSC = 0x6e,
918        RDPMC = 0x6f,
919        PUSHF = 0x70,
920        POPF = 0x71,
921        CPUID = 0x72,
922        RSM = 0x73,
923        IRET = 0x74,
924        SWINT = 0x75,
925        INVD = 0x76,
926        PAUSE = 0x77,
927        HLT = 0x78,
928        INVLPG = 0x79,
929        INVLPGA = 0x7a,
930        IOIO = 0x7b,
931        MSR = 0x7c,
932        TASK_SWITCH = 0x7d,
933        FERR_FREEZE = 0x7e,
934        SHUTDOWN = 0x7f,
935        VMRUN = 0x80,
936        VMMCALL = 0x81,
937        VMLOAD = 0x82,
938        VMSAVE = 0x83,
939        STGI = 0x84,
940        CLGI = 0x85,
941        SKINIT = 0x86,
942        RDTSCP = 0x87,
943        ICEBP = 0x88,
944        WBINVD = 0x89,
945        MONITOR = 0x8a,
946        MWAIT = 0x8b,
947        MWAIT_CONDITIONAL = 0x8c,
948        XSETBV = 0x8d,
949        RDPRU = 0x8e,
950        EFER_WRITE_TRAP = 0x8f,
951        CR0_WRITE_TRAP = 0x90,
952        CR1_WRITE_TRAP = 0x91,
953        CR2_WRITE_TRAP = 0x92,
954        CR3_WRITE_TRAP = 0x93,
955        CR4_WRITE_TRAP = 0x94,
956        CR5_WRITE_TRAP = 0x95,
957        CR6_WRITE_TRAP = 0x96,
958        CR7_WRITE_TRAP = 0x97,
959        CR8_WRITE_TRAP = 0x98,
960        CR9_WRITE_TRAP = 0x99,
961        CR10_WRITE_TRAP = 0x9a,
962        CR11_WRITE_TRAP = 0x9b,
963        CR12_WRITE_TRAP = 0x9c,
964        CR13_WRITE_TRAP = 0x9d,
965        CR14_WRITE_TRAP = 0x9e,
966        CR15_WRITE_TRAP = 0x9f,
967        INVLPGB = 0xa0,
968        ILLEGAL_INVLPGB = 0xa1,
969        INVPCID = 0xa2,
970        BUSLOCK = 0xa5,
971        IDLE_HLT = 0xa6,
972        NPF = 0x400,
973        AVIC_INCOMPLETE_IPI = 0x401,
974        AVIC_NOACCEL = 0x402,
975        VMGEXIT = 0x403,
976        PAGE_NOT_VALIDATED = 0x404,
977        NOT_RESTARTABLE = 0x406,
978
979        // SEV-ES software-defined exit codes
980        SNP_GUEST_REQUEST = 0x80000011,
981        SNP_EXTENDED_GUEST_REQUEST = 0x80000012,
982        HV_DOORBELL_PAGE = 0x80000014,
983
984        // SEV-SNP hardware error codes
985        INVALID_VMCB = 0xffff_ffff_ffff_ffff,
986        VMSA_BUSY = 0xffff_ffff_ffff_fffe,
987        IDLE_REQUIRED = 0xffff_ffff_ffff_fffd,
988        INVALID_PMC = 0xffff_ffff_ffff_fffc,
989    }
990}
991
992#[bitfield(u64)]
993#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
994pub struct GhcbMsr {
995    #[bits(12)]
996    pub info: u64,
997    #[bits(40)]
998    pub pfn: u64,
999    #[bits(12)]
1000    pub extra_data: u64,
1001}
1002
1003/// PSP data structures.
1004#[repr(C)]
1005#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Clone, Copy)]
1006pub struct HvPspCpuidLeaf {
1007    pub eax_in: u32,
1008    pub ecx_in: u32,
1009    pub xfem_in: u64,
1010    pub xss_in: u64,
1011    pub eax_out: u32,
1012    pub ebx_out: u32,
1013    pub ecx_out: u32,
1014    pub edx_out: u32,
1015    pub reserved_z: u64,
1016}
1017
1018pub const HV_PSP_CPUID_LEAF_COUNT_MAX: usize = 64;
1019
1020#[repr(C)]
1021#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Clone, Copy)]
1022pub struct HvPspCpuidPage {
1023    pub count: u32,
1024    pub reserved_z1: u32,
1025    pub reserved_z2: u64,
1026    pub cpuid_leaf_info: [HvPspCpuidLeaf; HV_PSP_CPUID_LEAF_COUNT_MAX],
1027    pub reserved_z3: [u64; 126],
1028}
1029
1030/// Structure describing the pages being read during SNP ID block measurement.
1031/// Each structure is hashed with the previous structures digest to create a final
1032/// measurement
1033#[repr(C)]
1034#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
1035pub struct SnpPageInfo {
1036    /// Set to the value of the previous page's launch digest
1037    pub digest_current: [u8; 48],
1038    /// Hash of page contents, if measured
1039    pub contents: [u8; 48],
1040    /// Size of the SnpPageInfo struct
1041    pub length: u16,
1042    /// type of page being measured, described by [`SnpPageType`]
1043    pub page_type: SnpPageType,
1044    /// imi_page_bit must match IMI_PAGE flag
1045    pub imi_page_bit: u8,
1046    /// All lower VMPL permissions are denied for SNP
1047    pub lower_vmpl_permissions: u32,
1048    /// The guest physical address at which this page data should be loaded; it
1049    /// must be aligned to a page size boundary.
1050    pub gpa: u64,
1051}
1052
1053open_enum::open_enum! {
1054    /// The type of page described by [`SnpPageInfo`]
1055    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1056    pub enum SnpPageType: u8 {
1057        /// Reserved
1058        RESERVED = 0x0,
1059        /// Normal data page
1060        NORMAL = 0x1,
1061        /// VMSA page
1062        VMSA = 0x2,
1063        /// Zero page
1064        ZERO = 0x3,
1065        /// Page encrypted, but not measured
1066        UNMEASURED = 0x4,
1067        /// Page storing guest secrets
1068        SECRETS = 0x5,
1069        /// Page to provide CPUID function values
1070        CPUID = 0x6,
1071    }
1072}
1073
1074/// Structure containing the completed SNP measurement of the IGVM file.
1075/// The signature of the hash of this struct is the id_key_signature for
1076/// `igvm_defs::IGVM_VHS_SNP_ID_BLOCK`.
1077#[repr(C)]
1078#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
1079pub struct SnpPspIdBlock {
1080    /// completed launch digest of IGVM file
1081    pub ld: [u8; 48],
1082    /// family id of the guest
1083    pub family_id: [u8; 16],
1084    /// image id of the guest
1085    pub image_id: [u8; 16],
1086    /// Version of the ID block format, must be 0x1
1087    pub version: u32,
1088    /// Software version of the guest
1089    pub guest_svn: u32,
1090    /// SNP Policy of the guest
1091    pub policy: u64,
1092}
1093
1094/// ECDSA signature in an SNP PSP ID authentication page.
1095#[repr(C)]
1096#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
1097pub struct SnpPspIdAuthSignature {
1098    /// ECDSA R component.
1099    pub r: [u8; 72],
1100    /// ECDSA S component.
1101    pub s: [u8; 72],
1102    /// Reserved bytes.
1103    pub reserved: [u8; 368],
1104}
1105
1106/// ECDSA public key in an SNP PSP ID authentication page.
1107#[repr(C)]
1108#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
1109pub struct SnpPspIdAuthPublicKey {
1110    /// Elliptic curve identifier.
1111    pub curve: u32,
1112    /// Public key X coordinate.
1113    pub qx: [u8; 72],
1114    /// Public key Y coordinate.
1115    pub qy: [u8; 72],
1116    /// Reserved bytes.
1117    pub reserved: [u8; 880],
1118}
1119
1120/// SNP PSP ID block authentication page.
1121///
1122/// This is the `ID_AUTH` structure supplied with `SNP_LAUNCH_FINISH`.
1123#[repr(C)]
1124#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
1125pub struct SnpPspIdAuth {
1126    /// Algorithm used by the ID key.
1127    pub id_key_algorithm: u32,
1128    /// Algorithm used by the author key.
1129    pub author_key_algorithm: u32,
1130    /// Reserved bytes.
1131    pub reserved0: [u8; 56],
1132    /// Signature of the ID block by the ID key.
1133    pub id_block_signature: SnpPspIdAuthSignature,
1134    /// ID public key.
1135    pub id_key: SnpPspIdAuthPublicKey,
1136    /// Reserved bytes.
1137    pub reserved1: [u8; 60],
1138    /// Signature of the ID key by the author key.
1139    pub id_key_signature: SnpPspIdAuthSignature,
1140    /// Author public key.
1141    pub author_key: SnpPspIdAuthPublicKey,
1142    /// Reserved bytes.
1143    pub reserved2: [u8; 892],
1144}
1145
1146const_assert_eq!(size_of::<SnpPspIdAuth>(), 4096);
1147
1148/// ECDSA signature components used by an SNP ID block.
1149#[derive(Debug, Clone, Copy, Eq, PartialEq)]
1150pub struct SnpIdBlockSignature {
1151    /// ECDSA R component.
1152    pub r: [u8; 72],
1153    /// ECDSA S component.
1154    pub s: [u8; 72],
1155}
1156
1157/// Public key used by an SNP ID block.
1158#[derive(Debug, Clone, Copy, Eq, PartialEq)]
1159pub struct SnpIdBlockPublicKey {
1160    /// Elliptic curve identifier.
1161    pub curve: u32,
1162    /// Public key X coordinate.
1163    pub qx: [u8; 72],
1164    /// Public key Y coordinate.
1165    pub qy: [u8; 72],
1166}
1167
1168#[bitfield(u64)]
1169#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
1170pub struct SevStatusMsr {
1171    pub sev_enabled: bool,
1172    pub es_enabled: bool,
1173    pub snp_enabled: bool,
1174    pub vtom: bool,
1175    pub reflect_vc: bool,
1176    pub restrict_injection: bool,
1177    pub alternate_injection: bool,
1178    pub debug_swap: bool,
1179    pub prevent_host_ibs: bool,
1180    pub snp_btb_isolation: bool,
1181    pub vmpl_sss: bool,
1182    pub secure_tsc: bool,
1183    pub vmgexit_param: bool,
1184    _rsvd3: bool,
1185    pub ibs_virt: bool,
1186    _rsvd5: bool,
1187    pub vmsa_reg_prot: bool,
1188    pub smt_prot: bool,
1189    pub secure_avic: bool,
1190    #[bits(4)]
1191    _reserved: u64,
1192    pub ibpb_on_entry: bool,
1193    #[bits(40)]
1194    _unused: u64,
1195}
1196
1197#[bitfield(u64)]
1198#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
1199pub struct SevInvlpgbRax {
1200    pub va_valid: bool,
1201    pub pcid_valid: bool,
1202    pub asid_valid: bool,
1203    pub global: bool,
1204    pub final_only: bool,
1205    pub nested: bool,
1206    #[bits(6)]
1207    reserved: u64,
1208    #[bits(52)]
1209    pub virtual_page_number: u64,
1210}
1211
1212#[bitfield(u32)]
1213#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
1214pub struct SevInvlpgbEdx {
1215    #[bits(16)]
1216    pub asid: u64,
1217    #[bits(12)]
1218    pub pcid: u64,
1219    #[bits(4)]
1220    reserved: u32,
1221}
1222
1223#[bitfield(u32)]
1224#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
1225pub struct SevInvlpgbEcx {
1226    #[bits(16)]
1227    pub additional_count: u64,
1228    #[bits(15)]
1229    reserved: u64,
1230    pub large_page: bool,
1231}
1232
1233#[bitfield(u64)]
1234pub struct MovCrxDrxInfo {
1235    #[bits(4)]
1236    pub gpr_number: u64,
1237    #[bits(59)]
1238    pub reserved: u64,
1239    pub mov_crx: bool,
1240}
1241
1242/// Request structure for the `SNP_GET_REPORT` request.
1243/// See `MSG_REPORT_REQ` in Table 21, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1244#[repr(C)]
1245#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1246pub struct SnpReportReq {
1247    /// Guest-provided data to be included in the attestation report.
1248    pub user_data: [u8; 64],
1249    /// The VMPL to put in the attestation report. Must be greater than
1250    /// or equal to the current VMPL and, at most, three.
1251    pub vmpl: u32,
1252    /// Reserved
1253    // TODO SNP: Support VLEK feature if needed
1254    pub rsvd: [u8; 28],
1255}
1256
1257pub const SNP_REPORT_RESP_DATA_SIZE: usize =
1258    size_of::<u32>() + size_of::<u32>() + 24 + size_of::<SnpReport>();
1259
1260/// Response structure for the `SNP_GET_REPORT` request.
1261/// See `MSG_REPORT_RSP` in Table 24, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1262#[repr(C)]
1263#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1264pub struct SnpReportResp {
1265    /// The status of key derivation operation.
1266    /// 0h: Success.
1267    /// 16h: Invalid parameters.
1268    /// 27h: Invalid key selection.
1269    pub status: u32,
1270    /// Size in bytes of the report.
1271    pub report_size: u32,
1272    /// Reserved
1273    pub _reserved0: [u8; 24],
1274    /// The attestation report generated by the firmware.
1275    pub report: SnpReport,
1276}
1277
1278/// Size of the [`SnpReport`].
1279pub const SNP_REPORT_SIZE: usize = 0x4a0;
1280
1281/// Size of `report_data` member in [`SnpReport`].
1282pub const SNP_REPORT_DATA_SIZE: usize = 64;
1283
1284/// Report structure.
1285/// See `ATTESTATION_REPORT` in Table 22, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1286#[repr(C)]
1287#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1288pub struct SnpReport {
1289    /// Version number of this attestation report.
1290    /// Set to 2h for this specification.
1291    pub version: u32,
1292    /// The guest SVN.
1293    pub guest_svn: u32,
1294    /// The guest policy.
1295    pub policy: u64,
1296    /// The family ID provided at launch.
1297    pub family: u128,
1298    /// The image ID provided at launch.
1299    pub image_id: u128,
1300    /// The request VMPL for the attestation
1301    /// report.
1302    pub vmpl: u32,
1303    /// The signature algorithm used to sign
1304    /// this report.
1305    pub signature_algo: u32,
1306    /// CurrentTcb.
1307    pub current_tcb: u64,
1308    /// Information about the platform.
1309    pub platform_info: u64,
1310    /// Flags
1311    pub flags: u32,
1312    /// Reserved
1313    pub _reserved0: u32,
1314    /// Guest-provided data.
1315    pub report_data: [u8; SNP_REPORT_DATA_SIZE],
1316    /// The measurement calculated at
1317    /// launch.
1318    pub measurement: [u8; 48],
1319    /// Data provided by the hypervisor at
1320    /// launch.
1321    pub host_data: [u8; 32],
1322    /// SHA-384 digest of the ID public key
1323    /// that signed the ID block provided in
1324    /// SNP_LAUNCH_FINISH.
1325    pub id_key_digest: [u8; 48],
1326    /// SHA-384 digest of the Author public
1327    /// key that certified the ID key, if
1328    /// provided in SNP_LAUNCH_FINISH.
1329    pub author_key_digest: [u8; 48],
1330    /// Report ID of this guest.
1331    pub report_id: [u8; 32],
1332    /// Report ID of this guest’s migration
1333    /// agent
1334    pub report_id_ma: [u8; 32],
1335    /// Reported TCB version used to derive
1336    /// the VCEK that signed this report.
1337    pub reported_tcb: u64,
1338    /// Reserved
1339    pub _reserved1: [u8; 24],
1340    /// If MaskChipId is set to 0, Identifier
1341    /// unique to the chip as output by
1342    /// GET_ID. Otherwise, set to 0h.
1343    pub chip_id: [u8; 64],
1344    /// CommittedTcb.
1345    pub committed_tcb: u64,
1346    /// The build number of CurrentVersion.
1347    pub current_build: u8,
1348    /// The minor number of CurrentVersion.
1349    pub current_minor: u8,
1350    /// The major number of CurrentVersion.
1351    pub current_major: u8,
1352    /// Reserved
1353    pub _reserved2: u8,
1354    /// The build number of CommittedVersion.
1355    pub committed_build: u8,
1356    /// The minor version of CommittedVersion.
1357    pub committed_minor: u8,
1358    /// The major version of CommittedVersion.
1359    pub committed_major: u8,
1360    /// Reserved
1361    pub _reserved3: u8,
1362    /// The CurrentTcb at the time the guest
1363    /// was launched or imported.
1364    pub launch_tcb: u64,
1365    /// Reserved
1366    pub _reserved4: [u8; 168],
1367    /// Signature of bytes inclusive of this report.
1368    pub signature: [u8; 512],
1369}
1370
1371static_assertions::const_assert_eq!(SNP_REPORT_SIZE, size_of::<SnpReport>());
1372
1373/// Request structure for the `SNP_GET_DERIVED_KEY` request.
1374/// See `MSG_KEY_REQ` in Table 18, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1375#[repr(C)]
1376#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1377pub struct SnpDerivedKeyReq {
1378    /// Selects the root key from which to derive the key.
1379    /// 0 indicates VCEK
1380    /// 1 indicates VMRK
1381    // TODO: Support VLEK feature if needed
1382    pub root_key_select: u32,
1383    /// Reserved
1384    pub rsvd: u32,
1385    /// Bitmask indicating which data will be mixed into the
1386    /// derived key.
1387    pub guest_field_select: u64,
1388    /// The VMPL to mix into the derived key. Must be greater
1389    /// than or equal to the current VMPL.
1390    pub vmpl: u32,
1391    /// The guest SVN to mix into the key. Must not exceed the
1392    /// guest SVN provided at launch in the ID block.
1393    pub guest_svn: u32,
1394    /// The TCB version to mix into the derived key. Must not
1395    /// exceed CommittedTcb.
1396    pub tcb_version: u64,
1397}
1398
1399/// Indicate which guest-selectable fields will be mixed into the key.
1400/// See `GUEST_FIELD_SELECT` in Table 19, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1401#[bitfield(u64)]
1402pub struct GuestFieldSelect {
1403    /// Indicate that the guest policy will be mixed into the key.
1404    pub guest_policy: bool,
1405    /// Indicate that the image ID of the guest will be mixed into the key.
1406    pub image_id: bool,
1407    /// Indicate the family ID of the guest will be mixed into the key.
1408    pub family_id: bool,
1409    /// Indicate the measurement of the guest during launch will be mixed into the key.
1410    pub measurement: bool,
1411    /// Indicate that the guest-provided SVN will be mixed into the key.
1412    pub guest_svn: bool,
1413    /// Indicate that the guest-provided TCB_VERSION will be mixed into the key.
1414    pub tcb_version: bool,
1415    /// Reserved
1416    #[bits(58)]
1417    pub _reserved: u64,
1418}
1419
1420/// See `DERIVED_KEY` in Table 20, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1421pub const SNP_DERIVED_KEY_SIZE: usize = 32;
1422
1423/// Response structure for the `SNP_GET_DERIVED_KEY` request.
1424/// See `MSG_KEY_RSP` in Table 20, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1425#[repr(C)]
1426#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1427pub struct SnpDerivedKeyResp {
1428    /// The status of key derivation operation.
1429    /// 0h: Success.
1430    /// 16h: Invalid parameters.
1431    /// 27h: Invalid key selection.
1432    pub status: u32,
1433    /// Reserved
1434    pub _reserved: [u8; 28],
1435    /// The requested derived key.
1436    pub derived_key: [u8; SNP_DERIVED_KEY_SIZE],
1437}
1438
1439static_assertions::const_assert_eq!(
1440    // The size of the response data defined by the SNP specification.
1441    64,
1442    size_of::<SnpDerivedKeyResp>()
1443);
1444
1445#[cfg(test)]
1446mod tests {
1447    use super::*;
1448    use zerocopy::FromZeros;
1449
1450    // ---- SecureAvicControl bitfield tests ----
1451
1452    #[test]
1453    fn secure_avic_control_default_is_zero() {
1454        let ctrl = SecureAvicControl::new();
1455        assert_eq!(ctrl.into_bits(), 0);
1456        assert_eq!(ctrl.secure_avic_en(), false);
1457        assert_eq!(ctrl.allowed_nmi(), false);
1458        assert_eq!(ctrl.guest_apic_backing_page_ptr(), 0);
1459    }
1460
1461    #[test]
1462    fn secure_avic_control_enable_bit() {
1463        let ctrl = SecureAvicControl::new().with_secure_avic_en(true);
1464        assert_eq!(ctrl.secure_avic_en(), true);
1465        assert_eq!(ctrl.into_bits() & 1, 1);
1466    }
1467
1468    #[test]
1469    fn secure_avic_control_allowed_nmi_bit() {
1470        let ctrl = SecureAvicControl::new().with_allowed_nmi(true);
1471        assert_eq!(ctrl.allowed_nmi(), true);
1472        assert_eq!(ctrl.into_bits() & 0b10, 0b10);
1473    }
1474
1475    #[test]
1476    fn secure_avic_control_page_ptr() {
1477        // The page pointer is in bits [63:12], representing a PFN.
1478        let pfn = 0xDEAD_BEEF_u64;
1479        let ctrl = SecureAvicControl::new()
1480            .with_secure_avic_en(true)
1481            .with_guest_apic_backing_page_ptr(pfn);
1482        assert_eq!(ctrl.guest_apic_backing_page_ptr(), pfn);
1483        assert_eq!(ctrl.secure_avic_en(), true);
1484        // The PFN should be in bits [63:12]
1485        assert_eq!(ctrl.into_bits() >> 12, pfn);
1486    }
1487
1488    #[test]
1489    fn secure_avic_control_roundtrip() {
1490        let raw = 0xABCD_1234_5678_9001_u64;
1491        let ctrl = SecureAvicControl::from(raw);
1492        assert_eq!(ctrl.into_bits(), raw);
1493    }
1494
1495    // ---- SevAvicNoAccelInfo bitfield tests ----
1496
1497    #[test]
1498    fn no_accel_info_register_number_extraction() {
1499        // Register number is in bits [11:4].
1500        let info = SevAvicNoAccelInfo::new().with_apic_register_number(SevAvicRegisterNumber::EOI);
1501        assert_eq!(info.apic_register_number(), SevAvicRegisterNumber::EOI);
1502        // EOI = 0xB, stored in bits [11:4]
1503        assert_eq!((info.into_bits() >> 4) & 0xFF, 0xB);
1504    }
1505
1506    #[test]
1507    fn no_accel_info_write_access_bit() {
1508        // Write access is bit 32.
1509        let info = SevAvicNoAccelInfo::new().with_write_access(true);
1510        assert!(info.write_access());
1511        assert_eq!(info.into_bits() & (1 << 32), 1 << 32);
1512
1513        let info_read = SevAvicNoAccelInfo::new().with_write_access(false);
1514        assert!(!info_read.write_access());
1515    }
1516
1517    #[test]
1518    fn no_accel_info_combined() {
1519        let info = SevAvicNoAccelInfo::new()
1520            .with_apic_register_number(SevAvicRegisterNumber::ICR_LOW)
1521            .with_write_access(true);
1522        assert_eq!(info.apic_register_number(), SevAvicRegisterNumber::ICR_LOW);
1523        assert!(info.write_access());
1524    }
1525
1526    #[test]
1527    fn no_accel_info_all_register_numbers_roundtrip() {
1528        let registers = [
1529            SevAvicRegisterNumber::APIC_ID,
1530            SevAvicRegisterNumber::VERSION,
1531            SevAvicRegisterNumber::TPR,
1532            SevAvicRegisterNumber::APR,
1533            SevAvicRegisterNumber::PPR,
1534            SevAvicRegisterNumber::EOI,
1535            SevAvicRegisterNumber::LDR,
1536            SevAvicRegisterNumber::DFR,
1537            SevAvicRegisterNumber::SPURIOUS,
1538            SevAvicRegisterNumber::ISR0,
1539            SevAvicRegisterNumber::ISR7,
1540            SevAvicRegisterNumber::TMR0,
1541            SevAvicRegisterNumber::TMR7,
1542            SevAvicRegisterNumber::IRR0,
1543            SevAvicRegisterNumber::IRR7,
1544            SevAvicRegisterNumber::ERROR,
1545            SevAvicRegisterNumber::ICR_LOW,
1546            SevAvicRegisterNumber::ICR_HIGH,
1547            SevAvicRegisterNumber::TIMER_LVT,
1548            SevAvicRegisterNumber::INITIAL_COUNT,
1549            SevAvicRegisterNumber::CURRENT_COUNT,
1550            SevAvicRegisterNumber::DIVIDER,
1551            SevAvicRegisterNumber::SELF_IPI,
1552        ];
1553        for reg in registers {
1554            let info = SevAvicNoAccelInfo::new().with_apic_register_number(reg);
1555            assert_eq!(
1556                info.apic_register_number(),
1557                reg,
1558                "register number roundtrip failed for {reg:#x?}"
1559            );
1560        }
1561    }
1562
1563    // ---- SevAvicIncompleteIpiInfo1/2 bitfield tests ----
1564
1565    #[test]
1566    fn incomplete_ipi_info1_icr_fields() {
1567        let icr_low = 0x0004_10FFu32;
1568        let icr_high = 0x0200_0000u32;
1569        let info = SevAvicIncompleteIpiInfo1::new()
1570            .with_icr_low(icr_low)
1571            .with_icr_high(icr_high);
1572        assert_eq!(info.icr_low(), icr_low);
1573        assert_eq!(info.icr_high(), icr_high);
1574        assert_eq!(info.into_bits(), icr_low as u64 | ((icr_high as u64) << 32));
1575    }
1576
1577    #[test]
1578    fn incomplete_ipi_info2_fields() {
1579        let info = SevAvicIncompleteIpiInfo2::new()
1580            .with_index(42)
1581            .with_failure(SevAvicIpiFailure::NOT_RUNNING);
1582        assert_eq!(info.index(), 42);
1583        assert_eq!(info.failure(), SevAvicIpiFailure::NOT_RUNNING);
1584    }
1585
1586    #[test]
1587    fn incomplete_ipi_info2_all_failure_codes() {
1588        let failures = [
1589            SevAvicIpiFailure::INVALID_TYPE,
1590            SevAvicIpiFailure::NOT_RUNNING,
1591            SevAvicIpiFailure::INVALID_TARGET,
1592            SevAvicIpiFailure::INVALID_BACKING_PAGE,
1593            SevAvicIpiFailure::INVALID_VECTOR,
1594            SevAvicIpiFailure::UNACCELERATED_IPI,
1595        ];
1596        for failure in failures {
1597            let info = SevAvicIncompleteIpiInfo2::new().with_failure(failure);
1598            assert_eq!(
1599                info.failure(),
1600                failure,
1601                "failure code roundtrip failed for {failure:#x?}"
1602            );
1603        }
1604    }
1605
1606    // ---- SevFeatures secure AVIC fields ----
1607
1608    #[test]
1609    fn sev_features_secure_avic_bit() {
1610        let features = SevFeatures::new().with_secure_avic(true);
1611        assert!(features.secure_avic());
1612        // secure_avic is bit 16 (0-indexed).
1613        assert_ne!(features.into_bits() & (1 << 16), 0);
1614    }
1615
1616    #[test]
1617    fn sev_features_guest_intercept_control_bit() {
1618        let features = SevFeatures::new().with_guest_intercept_control(true);
1619        assert!(features.guest_intercept_control());
1620        // guest_intercept_control is bit 13.
1621        assert_ne!(features.into_bits() & (1 << 13), 0);
1622    }
1623
1624    #[test]
1625    fn sev_features_secure_avic_with_no_alternate_injection() {
1626        // Secure AVIC and alternate injection are mutually exclusive per the
1627        // init_vmsa logic.
1628        let features = SevFeatures::new()
1629            .with_secure_avic(true)
1630            .with_guest_intercept_control(true)
1631            .with_alternate_injection(false);
1632        assert!(features.secure_avic());
1633        assert!(features.guest_intercept_control());
1634        assert!(!features.alternate_injection());
1635    }
1636
1637    #[test]
1638    fn sev_features_alternate_injection_without_secure_avic() {
1639        let features = SevFeatures::new()
1640            .with_alternate_injection(true)
1641            .with_secure_avic(false);
1642        assert!(features.alternate_injection());
1643        assert!(!features.secure_avic());
1644    }
1645
1646    // ---- SevStatusMsr secure AVIC field ----
1647
1648    #[test]
1649    fn sev_status_msr_secure_avic_bit() {
1650        let status = SevStatusMsr::new().with_secure_avic(true);
1651        assert!(status.secure_avic());
1652        // secure_avic is bit 18 in SevStatusMsr (after sev_enabled, es_enabled,
1653        // snp_enabled, vtom, reflect_vc, restrict_injection, alternate_injection,
1654        // debug_swap, prevent_host_ibs, snp_btb_isolation, vmpl_sss, secure_tsc,
1655        // vmgexit_param, _rsvd3, ibs_virt, _rsvd5, vmsa_reg_prot, smt_prot).
1656        assert_ne!(status.into_bits() & (1 << 18), 0);
1657    }
1658
1659    // ---- SevVirtualInterruptControl NMI fields ----
1660
1661    #[test]
1662    fn v_intr_cntrl_nmi_fields() {
1663        let ctrl = SevVirtualInterruptControl::new()
1664            .with_nmi(true)
1665            .with_nmi_mask(true)
1666            .with_nmi_enable(true);
1667        assert!(ctrl.nmi());
1668        assert!(ctrl.nmi_mask());
1669        assert!(ctrl.nmi_enable());
1670    }
1671
1672    // ---- SevAvicPage layout tests ----
1673
1674    #[test]
1675    fn sev_avic_page_size_is_4096() {
1676        // Already asserted at compile time, but verify at runtime too.
1677        assert_eq!(size_of::<SevAvicPage>(), 4096);
1678    }
1679
1680    #[test]
1681    fn sev_avic_irr_register_size() {
1682        // Each IRR register has value + allowed + reserved = 16 bytes,
1683        // same as a standard ApicRegisterValue.
1684        assert_eq!(
1685            size_of::<SevAvicIrrRegister>(),
1686            size_of::<ApicRegisterValue>()
1687        );
1688    }
1689
1690    #[test]
1691    fn sev_avic_page_field_offsets() {
1692        // Verify key field offsets match the APIC register map.
1693        // Each "register" is 16 bytes (128 bits per the AMD spec).
1694        let page = SevAvicPage::new_zeroed();
1695        let base = core::ptr::from_ref(&page) as usize;
1696
1697        // id is at register index 2 (offset 0x20)
1698        let id_offset = core::ptr::from_ref(&page.id) as usize - base;
1699        assert_eq!(id_offset, 2 * 16, "APIC ID offset");
1700
1701        // version is at register index 3 (offset 0x30)
1702        let version_offset = core::ptr::from_ref(&page.version) as usize - base;
1703        assert_eq!(version_offset, 3 * 16, "version offset");
1704
1705        // TPR is at register index 8 (offset 0x80)
1706        let tpr_offset = core::ptr::from_ref(&page.tpr) as usize - base;
1707        assert_eq!(tpr_offset, 8 * 16, "TPR offset");
1708
1709        // ISR starts at register index 0x10 (offset 0x100)
1710        let isr_offset = core::ptr::from_ref(&page.isr) as usize - base;
1711        assert_eq!(isr_offset, 0x10 * 16, "ISR offset");
1712
1713        // TMR starts at register index 0x18 (offset 0x180)
1714        let tmr_offset = core::ptr::from_ref(&page.tmr) as usize - base;
1715        assert_eq!(tmr_offset, 0x18 * 16, "TMR offset");
1716
1717        // IRR starts at register index 0x20 (offset 0x200)
1718        let irr_offset = core::ptr::from_ref(&page.irr) as usize - base;
1719        assert_eq!(irr_offset, 0x20 * 16, "IRR offset");
1720
1721        // ICR is at register index 0x30 (offset 0x300)
1722        let icr_offset = core::ptr::from_ref(&page.icr) as usize - base;
1723        assert_eq!(icr_offset, 0x30 * 16, "ICR offset");
1724    }
1725
1726    // ---- VMSA SecureAvicControl field offset test ----
1727
1728    #[test]
1729    fn vmsa_secure_avic_control_at_rsp_offset() {
1730        // In the VMSA, secure_avic_control occupies the RSP slot (between RBX and RBP).
1731        // Verify it's at the expected offset by checking it doesn't overlap GPRs.
1732        let vmsa = SevVmsa::new_zeroed();
1733        let base = core::ptr::from_ref(&vmsa) as usize;
1734        let rbx_offset = core::ptr::from_ref(&vmsa.rbx) as usize - base;
1735        let savic_offset = core::ptr::from_ref(&vmsa.secure_avic_control) as usize - base;
1736        let rbp_offset = core::ptr::from_ref(&vmsa.rbp) as usize - base;
1737
1738        // secure_avic_control should be right after rbx and before rbp.
1739        assert_eq!(savic_offset, rbx_offset + 8);
1740        assert_eq!(rbp_offset, savic_offset + 8);
1741    }
1742
1743    // ---- SevAvicRegisterNumber to x2APIC MSR mapping ----
1744
1745    #[test]
1746    fn avic_register_number_matches_apic_register_enum() {
1747        // The SevAvicRegisterNumber values should match the corresponding
1748        // x86defs::apic::ApicRegisterValue values, ensuring correct MSR computation.
1749        use crate::apic::ApicRegister;
1750        assert_eq!(SevAvicRegisterNumber::APIC_ID.0, ApicRegister::ID.0 as u32);
1751        assert_eq!(
1752            SevAvicRegisterNumber::VERSION.0,
1753            ApicRegister::VERSION.0 as u32
1754        );
1755        assert_eq!(SevAvicRegisterNumber::TPR.0, ApicRegister::TPR.0 as u32);
1756        assert_eq!(SevAvicRegisterNumber::EOI.0, ApicRegister::EOI.0 as u32);
1757        assert_eq!(SevAvicRegisterNumber::LDR.0, ApicRegister::LDR.0 as u32);
1758        assert_eq!(
1759            SevAvicRegisterNumber::SPURIOUS.0,
1760            ApicRegister::SVR.0 as u32
1761        );
1762        assert_eq!(SevAvicRegisterNumber::ISR0.0, ApicRegister::ISR0.0 as u32);
1763        assert_eq!(SevAvicRegisterNumber::TMR0.0, ApicRegister::TMR0.0 as u32);
1764        assert_eq!(SevAvicRegisterNumber::IRR0.0, ApicRegister::IRR0.0 as u32);
1765        assert_eq!(SevAvicRegisterNumber::ERROR.0, ApicRegister::ESR.0 as u32);
1766        assert_eq!(
1767            SevAvicRegisterNumber::ICR_LOW.0,
1768            ApicRegister::ICR0.0 as u32
1769        );
1770        assert_eq!(
1771            SevAvicRegisterNumber::ICR_HIGH.0,
1772            ApicRegister::ICR1.0 as u32
1773        );
1774        assert_eq!(
1775            SevAvicRegisterNumber::TIMER_LVT.0,
1776            ApicRegister::LVT_TIMER.0 as u32
1777        );
1778        assert_eq!(
1779            SevAvicRegisterNumber::INITIAL_COUNT.0,
1780            ApicRegister::TIMER_ICR.0 as u32
1781        );
1782        assert_eq!(
1783            SevAvicRegisterNumber::CURRENT_COUNT.0,
1784            ApicRegister::TIMER_CCR.0 as u32
1785        );
1786        assert_eq!(
1787            SevAvicRegisterNumber::DIVIDER.0,
1788            ApicRegister::TIMER_DCR.0 as u32
1789        );
1790        assert_eq!(
1791            SevAvicRegisterNumber::SELF_IPI.0,
1792            ApicRegister::SELF_IPI.0 as u32
1793        );
1794    }
1795
1796    #[test]
1797    fn avic_register_to_x2apic_msr() {
1798        // Verify the MSR computation: X2APIC_MSR_BASE + register_number.
1799        use crate::apic::X2APIC_MSR_BASE;
1800        let msr = X2APIC_MSR_BASE + SevAvicRegisterNumber::EOI.0;
1801        assert_eq!(msr, 0x80B); // EOI is register 0xB
1802
1803        let msr = X2APIC_MSR_BASE + SevAvicRegisterNumber::ICR_LOW.0;
1804        assert_eq!(msr, 0x830); // ICR_LOW is register 0x30
1805    }
1806
1807    // ---- SevExitCode AVIC constants ----
1808
1809    #[test]
1810    fn sev_exit_code_avic_values() {
1811        assert_eq!(SevExitCode::AVIC_INCOMPLETE_IPI.0, 0x401);
1812        assert_eq!(SevExitCode::AVIC_NOACCEL.0, 0x402);
1813    }
1814}