x86defs/
snp.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! AMD SEV-SNP specific definitions.
5
6use bitfield_struct::bitfield;
7use zerocopy::FromBytes;
8use zerocopy::Immutable;
9use zerocopy::IntoBytes;
10use zerocopy::KnownLayout;
11
12// Interruption Information Field
13pub const SEV_INTR_TYPE_EXT: u32 = 0;
14pub const SEV_INTR_TYPE_NMI: u32 = 2;
15pub const SEV_INTR_TYPE_EXCEPT: u32 = 3;
16pub const SEV_INTR_TYPE_SW: u32 = 4;
17
18// Secrets page layout.
19pub const REG_TWEAK_BITMAP_OFFSET: usize = 0x100;
20pub const REG_TWEAK_BITMAP_SIZE: usize = 0x40;
21
22/// Value for the `msg_version` member in [`SNP_GUEST_REQ_MSG_VERSION`].
23/// Use 1 for now.
24pub const SNP_GUEST_REQ_MSG_VERSION: u32 = 1;
25
26#[bitfield(u64)]
27#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
28pub struct SevEventInjectInfo {
29    pub vector: u8,
30    #[bits(3)]
31    pub interruption_type: u32,
32    pub deliver_error_code: bool,
33    #[bits(19)]
34    _rsvd1: u64,
35    pub valid: bool,
36    pub error_code: u32,
37}
38
39#[repr(u8)]
40#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
41pub enum Vmpl {
42    Vmpl0 = 0,
43    Vmpl1 = 1,
44    Vmpl2 = 2,
45    Vmpl3 = 3,
46}
47
48impl From<Vmpl> for u8 {
49    fn from(value: Vmpl) -> Self {
50        value as _
51    }
52}
53
54/// A X64 selector register.
55#[repr(C)]
56#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
57pub struct SevSelector {
58    pub selector: u16,
59    pub attrib: u16,
60    pub limit: u32,
61    pub base: u64,
62}
63
64impl SevSelector {
65    pub fn as_u128(&self) -> u128 {
66        ((self.base as u128) << 64)
67            | ((self.limit as u128) << 32)
68            | ((self.attrib as u128) << 16)
69            | self.selector as u128
70    }
71}
72
73impl From<u128> for SevSelector {
74    fn from(val: u128) -> Self {
75        SevSelector {
76            selector: val as u16,
77            attrib: (val >> 16) as u16,
78            limit: (val >> 32) as u32,
79            base: (val >> 64) as u64,
80        }
81    }
82}
83
84/// An X64 XMM register.
85#[repr(C)]
86#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
87pub struct SevXmmRegister {
88    low: u64,
89    high: u64,
90}
91
92impl SevXmmRegister {
93    pub fn as_u128(&self) -> u128 {
94        ((self.high as u128) << 64) | self.low as u128
95    }
96}
97
98impl From<u128> for SevXmmRegister {
99    fn from(val: u128) -> Self {
100        SevXmmRegister {
101            low: val as u64,
102            high: (val >> 64) as u64,
103        }
104    }
105}
106
107#[bitfield(u64)]
108#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
109pub struct SevFeatures {
110    pub snp: bool,
111    pub vtom: bool,
112    pub reflect_vc: bool,
113    pub restrict_injection: bool,
114    pub alternate_injection: bool,
115    pub debug_swap: bool,
116    pub prevent_host_ibs: bool,
117    pub snp_btb_isolation: bool,
118    pub vmpl_isss: bool,
119    pub secure_tsc: bool,
120    pub vmgexit_param: bool,
121    pub pmc_virt: bool,
122    pub ibs_virt: bool,
123    rsvd: bool,
124    pub vmsa_reg_prot: bool,
125    pub smt_prot: bool,
126    pub secure_avic: bool,
127    #[bits(4)]
128    _reserved: u64,
129    pub ibpb_on_entry: bool,
130    #[bits(42)]
131    _unused: u64,
132}
133
134#[bitfield(u64)]
135#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
136pub struct SevVirtualInterruptControl {
137    pub tpr: u8,
138    pub irq: bool,
139    pub gif: bool,
140    pub intr_shadow: bool,
141    #[bits(5)]
142    _rsvd1: u64,
143    #[bits(4)]
144    pub priority: u64,
145    pub ignore_tpr: bool,
146    #[bits(11)]
147    _rsvd2: u64,
148    pub vector: u8,
149    #[bits(23)]
150    _rsvd3: u64,
151    pub guest_busy: bool,
152}
153
154#[bitfield(u64)]
155#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
156pub struct SevRmpAdjust {
157    pub target_vmpl: u8,
158    pub enable_read: bool,
159    pub enable_write: bool,
160    pub enable_user_execute: bool,
161    pub enable_kernel_execute: bool,
162    #[bits(4)]
163    _rsvd1: u64,
164    pub vmsa: bool,
165    #[bits(47)]
166    _rsvd2: u64,
167}
168
169#[bitfield(u32)]
170#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
171pub struct SevIoAccessInfo {
172    pub read_access: bool,
173    #[bits(1)]
174    reserved1: u32,
175    pub string_access: bool,
176    pub rep_access: bool,
177    pub access_size8: bool,
178    pub access_size16: bool,
179    pub access_size32: bool,
180    pub address_size8: bool,
181    pub address_size16: bool,
182    pub address_size32: bool,
183    #[bits(3)]
184    pub effective_segment: u32,
185    #[bits(3)]
186    rsvd2: u32,
187    pub port: u16,
188}
189
190#[bitfield(u64)]
191#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
192pub struct SevNpfInfo {
193    pub present: bool,
194    pub is_write: bool,
195    pub user: bool,
196    pub reserved_bit_set: bool,
197    pub fetch: bool,
198    #[bits(1)]
199    rsvd5: u64,
200    pub shadow_stack: bool,
201    #[bits(24)]
202    rsvd7_31: u64,
203    pub rmp_failure: bool,
204    pub caused_by_gpa_access: bool,
205    pub caused_by_page_table_access: bool,
206    pub encrypted_access: bool,
207    pub rmp_size_mismatch: bool,
208    pub vmpl_violation: bool,
209    pub npt_supervisor_shadow_stack: bool,
210    #[bits(26)]
211    rsvd38_63: u64,
212}
213
214/// SEV VMSA structure representing CPU state
215#[repr(C)]
216#[derive(Debug, Clone, IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
217pub struct SevVmsa {
218    // Selector Info
219    pub es: SevSelector,
220    pub cs: SevSelector,
221    pub ss: SevSelector,
222    pub ds: SevSelector,
223    pub fs: SevSelector,
224    pub gs: SevSelector,
225
226    // Descriptor Table Info
227    pub gdtr: SevSelector,
228    pub ldtr: SevSelector,
229    pub idtr: SevSelector,
230    pub tr: SevSelector,
231
232    // CET
233    pub pl0_ssp: u64,
234    pub pl1_ssp: u64,
235    pub pl2_ssp: u64,
236    pub pl3_ssp: u64,
237    pub u_cet: u64,
238
239    // Reserved, MBZ
240    pub vmsa_reserved1: [u8; 2],
241
242    // Virtual Machine Privilege Level
243    pub vmpl: u8,
244
245    // CPL
246    pub cpl: u8,
247
248    // Reserved, MBZ
249    pub vmsa_reserved2: u32,
250
251    // EFER
252    pub efer: u64,
253
254    // Reserved, MBZ
255    pub vmsa_reserved3: [u32; 26],
256
257    // XSS (offset 0x140)
258    pub xss: u64,
259
260    // Control registers
261    pub cr4: u64,
262    pub cr3: u64,
263    pub cr0: u64,
264
265    // Debug registers
266    pub dr7: u64,
267    pub dr6: u64,
268
269    // RFLAGS
270    pub rflags: u64,
271
272    // RIP
273    pub rip: u64,
274
275    // Additional saved debug registers
276    pub dr0: u64,
277    pub dr1: u64,
278    pub dr2: u64,
279    pub dr3: u64,
280
281    // Debug register address masks
282    pub dr0_addr_mask: u64,
283    pub dr1_addr_mask: u64,
284    pub dr2_addr_mask: u64,
285    pub dr3_addr_mask: u64,
286
287    // Reserved, MBZ
288    pub vmsa_reserved4: [u64; 3],
289
290    // RSP
291    pub rsp: u64,
292
293    // CET
294    pub s_cet: u64,
295    pub ssp: u64,
296    pub interrupt_ssp_table_addr: u64,
297
298    // RAX
299    pub rax: u64,
300
301    // SYSCALL config registers
302    pub star: u64,
303    pub lstar: u64,
304    pub cstar: u64,
305    pub sfmask: u64,
306
307    // KernelGsBase
308    pub kernel_gs_base: u64,
309
310    // SYSENTER config registers
311    pub sysenter_cs: u64,
312    pub sysenter_esp: u64,
313    pub sysenter_eip: u64,
314
315    // CR2
316    pub cr2: u64,
317
318    // Reserved, MBZ
319    pub vmsa_reserved5: [u64; 4],
320
321    // PAT
322    pub pat: u64,
323
324    // LBR MSRs
325    pub dbgctl: u64,
326    pub last_branch_from_ip: u64,
327    pub last_branch_to_ip: u64,
328    pub last_excp_from_ip: u64,
329    pub last_excp_to_ip: u64,
330
331    // Reserved, MBZ
332    pub vmsa_reserved6: [u64; 9],
333
334    // Speculation control MSR
335    pub spec_ctrl: u64,
336
337    // PKRU
338    pub pkru: u32,
339
340    // TSC_AUX
341    pub tsc_aux: u32,
342
343    // Reserved, MBZ
344    pub vmsa_reserved7: [u32; 4],
345
346    pub register_protection_nonce: u64,
347
348    // GPRs
349    pub rcx: u64,
350    pub rdx: u64,
351    pub rbx: u64,
352    pub vmsa_reserved8: u64, // MBZ
353    pub rbp: u64,
354    pub rsi: u64,
355    pub rdi: u64,
356    pub r8: u64,
357    pub r9: u64,
358    pub r10: u64,
359    pub r11: u64,
360    pub r12: u64,
361    pub r13: u64,
362    pub r14: u64,
363    pub r15: u64,
364
365    // Reserved, MBZ
366    pub vmsa_reserved9: [u64; 2],
367
368    // Exit information following an automatic #VMEXIT
369    pub exit_info1: u64,
370    pub exit_info2: u64,
371    pub exit_int_info: u64,
372
373    // Software scratch register
374    pub next_rip: u64,
375
376    // SEV feature information
377    pub sev_features: SevFeatures,
378
379    // Virtual interrupt control
380    pub v_intr_cntrl: SevVirtualInterruptControl,
381
382    // Guest exiting error code
383    pub guest_error_code: u64,
384
385    // Virtual top of memory
386    pub virtual_tom: u64,
387
388    // TLB control.  Writing a zero to PCPU_ID will force a full TLB
389    // invalidation upon the next entry.
390    pub tlb_id: u64,
391    pub pcpu_id: u64,
392
393    // Event injection
394    pub event_inject: SevEventInjectInfo,
395
396    // XCR0
397    pub xcr0: u64,
398
399    // X87 state save valid bitmap
400    pub xsave_valid_bitmap: [u8; 16],
401
402    // X87 save state
403    pub x87dp: u64,
404    pub mxcsr: u32,
405    pub x87_ftw: u16,
406    pub x87_fsw: u16,
407    pub x87_fcw: u16,
408    pub x87_op: u16,
409    pub x87_ds: u16,
410    pub x87_cs: u16,
411    pub x87_rip: u64,
412
413    // NOTE: Should be 80 bytes. Making it 10 u64 because no code uses it on a
414    // byte-level yet.
415    pub x87_registers: [u64; 10],
416
417    // XMM registers
418    pub xmm_registers: [SevXmmRegister; 16],
419
420    // YMM high registers
421    pub ymm_registers: [SevXmmRegister; 16],
422}
423
424// Info codes for the GHCB MSR protocol.
425open_enum::open_enum! {
426    pub enum GhcbInfo: u64 {
427        NORMAL = 0x000,
428        SEV_INFO_RESPONSE = 0x001,
429        SEV_INFO_REQUEST = 0x002,
430        AP_JUMP_TABLE = 0x003,
431        CPUID_REQUEST = 0x004,
432        CPUID_RESPONSE = 0x005,
433        PREFERRED_REQUEST = 0x010,
434        PREFERRED_RESPONSE = 0x011,
435        REGISTER_REQUEST = 0x012,
436        REGISTER_RESPONSE = 0x013,
437        PAGE_STATE_CHANGE = 0x014,
438        PAGE_STATE_UPDATED = 0x015,
439        HYP_FEATURE_REQUEST = 0x080,
440        HYP_FEATURE_RESPONSE = 0x081,
441        SPECIAL_HYPERCALL = 0xF00,
442        SPECIAL_FAST_CALL = 0xF01,
443        HYPERCALL_OUTPUT = 0xF02,
444        SPECIAL_DBGPRINT = 0xF03,
445        SHUTDOWN_REQUEST = 0x100,
446    }
447}
448
449pub const GHCB_DATA_PAGE_STATE_PRIVATE: u64 = 0x001;
450pub const GHCB_DATA_PAGE_STATE_SHARED: u64 = 0x002;
451pub const GHCB_DATA_PAGE_STATE_PSMASH: u64 = 0x003;
452pub const GHCB_DATA_PAGE_STATE_UNSMASH: u64 = 0x004;
453pub const GHCB_DATA_PAGE_STATE_MASK: u64 = 0x00F;
454pub const GHCB_DATA_PAGE_STATE_LARGE_PAGE: u64 = 0x010;
455
456open_enum::open_enum! {
457    pub enum GhcbUsage: u32 {
458        BASE = 0,
459        HYPERCALL = 1,
460        VTL_RETURN = 2,
461    }
462}
463
464/// Struct representing GHCB hypercall parameters. These are located at the GHCB
465/// page starting at [`GHCB_PAGE_HYPERCALL_PARAMETERS_OFFSET`].
466#[repr(C)]
467#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
468pub struct GhcbHypercallParameters {
469    pub output_gpa: u64,
470    pub input_control: u64,
471}
472
473pub const GHCB_PAGE_HYPERCALL_PARAMETERS_OFFSET: usize = 4072;
474pub const GHCB_PAGE_HYPERCALL_OUTPUT_OFFSET: usize = 4080;
475
476// Exit Codes.
477open_enum::open_enum! {
478    pub enum SevExitCode: u64 {
479        CR0_READ = 0x0,
480        CR1_READ = 0x1,
481        CR2_READ = 0x2,
482        CR3_READ = 0x3,
483        CR4_READ = 0x4,
484        CR5_READ = 0x5,
485        CR6_READ = 0x6,
486        CR7_READ = 0x7,
487        CR8_READ = 0x8,
488        CR9_READ = 0x9,
489        CR10_READ = 0xa,
490        CR11_READ = 0xb,
491        CR12_READ = 0xc,
492        CR13_READ = 0xd,
493        CR14_READ = 0xe,
494        CR15_READ = 0xf,
495        CR0_WRITE = 0x10,
496        CR1_WRITE = 0x11,
497        CR2_WRITE = 0x12,
498        CR3_WRITE = 0x13,
499        CR4_WRITE = 0x14,
500        CR5_WRITE = 0x15,
501        CR6_WRITE = 0x16,
502        CR7_WRITE = 0x17,
503        CR8_WRITE = 0x18,
504        CR9_WRITE = 0x19,
505        CR10_WRITE = 0x1a,
506        CR11_WRITE = 0x1b,
507        CR12_WRITE = 0x1c,
508        CR13_WRITE = 0x1d,
509        CR14_WRITE = 0x1e,
510        CR15_WRITE = 0x1f,
511        DR0_READ = 0x20,
512        DR1_READ = 0x21,
513        DR2_READ = 0x22,
514        DR3_READ = 0x23,
515        DR4_READ = 0x24,
516        DR5_READ = 0x25,
517        DR6_READ = 0x26,
518        DR7_READ = 0x27,
519        DR8_READ = 0x28,
520        DR9_READ = 0x29,
521        DR10_READ = 0x2a,
522        DR11_READ = 0x2b,
523        DR12_READ = 0x2c,
524        DR13_READ = 0x2d,
525        DR14_READ = 0x2e,
526        DR15_READ = 0x2f,
527        DR0_WRITE = 0x30,
528        DR1_WRITE = 0x31,
529        DR2_WRITE = 0x32,
530        DR3_WRITE = 0x33,
531        DR4_WRITE = 0x34,
532        DR5_WRITE = 0x35,
533        DR6_WRITE = 0x36,
534        DR7_WRITE = 0x37,
535        DR8_WRITE = 0x38,
536        DR9_WRITE = 0x39,
537        DR10_WRITE = 0x3a,
538        DR11_WRITE = 0x3b,
539        DR12_WRITE = 0x3c,
540        DR13_WRITE = 0x3d,
541        DR14_WRITE = 0x3e,
542        DR15_WRITE = 0x3f,
543        EXCP0 = 0x40,
544        EXCP_DB = 0x41,
545        EXCP2 = 0x42,
546        EXCP3 = 0x43,
547        EXCP4 = 0x44,
548        EXCP5 = 0x45,
549        EXCP6 = 0x46,
550        EXCP7 = 0x47,
551        EXCP8 = 0x48,
552        EXCP9 = 0x49,
553        EXCP10 = 0x4a,
554        EXCP11 = 0x4b,
555        EXCP12 = 0x4c,
556        EXCP13 = 0x4d,
557        EXCP14 = 0x4e,
558        EXCP15 = 0x4f,
559        EXCP16 = 0x50,
560        EXCP17 = 0x51,
561        EXCP18 = 0x52,
562        EXCP19 = 0x53,
563        EXCP20 = 0x54,
564        EXCP21 = 0x55,
565        EXCP22 = 0x56,
566        EXCP23 = 0x57,
567        EXCP24 = 0x58,
568        EXCP25 = 0x59,
569        EXCP26 = 0x5a,
570        EXCP27 = 0x5b,
571        EXCP28 = 0x5c,
572        EXCP29 = 0x5d,
573        EXCP30 = 0x5e,
574        EXCP31 = 0x5f,
575        INTR = 0x60,
576        NMI = 0x61,
577        SMI = 0x62,
578        INIT = 0x63,
579        VINTR = 0x64,
580        CR0_SEL_WRITE = 0x65,
581        IDTR_READ = 0x66,
582        GDTR_READ = 0x67,
583        LDTR_READ = 0x68,
584        TR_READ = 0x69,
585        IDTR_WRITE = 0x6a,
586        GDTR_WRITE = 0x6b,
587        LDTR_WRITE = 0x6c,
588        TR_WRITE = 0x6d,
589        RDTSC = 0x6e,
590        RDPMC = 0x6f,
591        PUSHF = 0x70,
592        POPF = 0x71,
593        CPUID = 0x72,
594        RSM = 0x73,
595        IRET = 0x74,
596        SWINT = 0x75,
597        INVD = 0x76,
598        PAUSE = 0x77,
599        HLT = 0x78,
600        INVLPG = 0x79,
601        INVLPGA = 0x7a,
602        IOIO = 0x7b,
603        MSR = 0x7c,
604        TASK_SWITCH = 0x7d,
605        FERR_FREEZE = 0x7e,
606        SHUTDOWN = 0x7f,
607        VMRUN = 0x80,
608        VMMCALL = 0x81,
609        VMLOAD = 0x82,
610        VMSAVE = 0x83,
611        STGI = 0x84,
612        CLGI = 0x85,
613        SKINIT = 0x86,
614        RDTSCP = 0x87,
615        ICEBP = 0x88,
616        WBINVD = 0x89,
617        MONITOR = 0x8a,
618        MWAIT = 0x8b,
619        MWAIT_CONDITIONAL = 0x8c,
620        XSETBV = 0x8d,
621        RDPRU = 0x8e,
622        EFER_WRITE_TRAP = 0x8f,
623        CR0_WRITE_TRAP = 0x90,
624        CR1_WRITE_TRAP = 0x91,
625        CR2_WRITE_TRAP = 0x92,
626        CR3_WRITE_TRAP = 0x93,
627        CR4_WRITE_TRAP = 0x94,
628        CR5_WRITE_TRAP = 0x95,
629        CR6_WRITE_TRAP = 0x96,
630        CR7_WRITE_TRAP = 0x97,
631        CR8_WRITE_TRAP = 0x98,
632        CR9_WRITE_TRAP = 0x99,
633        CR10_WRITE_TRAP = 0x9a,
634        CR11_WRITE_TRAP = 0x9b,
635        CR12_WRITE_TRAP = 0x9c,
636        CR13_WRITE_TRAP = 0x9d,
637        CR14_WRITE_TRAP = 0x9e,
638        CR15_WRITE_TRAP = 0x9f,
639        INVLPGB = 0xa0,
640        ILLEGAL_INVLPGB = 0xa1,
641        INVPCID = 0xa2,
642        BUSLOCK = 0xa5,
643        IDLE_HLT = 0xa6,
644        NPF = 0x400,
645        AVIC_INCOMPLETE_IPI = 0x401,
646        AVIC_NOACCEL = 0x402,
647        VMGEXIT = 0x403,
648        PAGE_NOT_VALIDATED = 0x404,
649
650        // SEV-ES software-defined exit codes
651        SNP_GUEST_REQUEST = 0x80000011,
652        SNP_EXTENDED_GUEST_REQUEST = 0x80000012,
653        HV_DOORBELL_PAGE = 0x80000014,
654
655        // SEV-SNP hardware error codes
656        INVALID_VMCB = 0xffff_ffff_ffff_ffff,
657        VMSA_BUSY = 0xffff_ffff_ffff_fffe,
658        IDLE_REQUIRED = 0xffff_ffff_ffff_fffd,
659        INVALID_PMC = 0xffff_ffff_ffff_fffc,
660    }
661}
662
663#[bitfield(u64)]
664#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
665pub struct GhcbMsr {
666    #[bits(12)]
667    pub info: u64,
668    #[bits(40)]
669    pub pfn: u64,
670    #[bits(12)]
671    pub extra_data: u64,
672}
673
674/// PSP data structures.
675#[repr(C)]
676#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Clone, Copy)]
677pub struct HvPspCpuidLeaf {
678    pub eax_in: u32,
679    pub ecx_in: u32,
680    pub xfem_in: u64,
681    pub xss_in: u64,
682    pub eax_out: u32,
683    pub ebx_out: u32,
684    pub ecx_out: u32,
685    pub edx_out: u32,
686    pub reserved_z: u64,
687}
688
689pub const HV_PSP_CPUID_LEAF_COUNT_MAX: usize = 64;
690
691#[repr(C)]
692#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Clone, Copy)]
693pub struct HvPspCpuidPage {
694    pub count: u32,
695    pub reserved_z1: u32,
696    pub reserved_z2: u64,
697    pub cpuid_leaf_info: [HvPspCpuidLeaf; HV_PSP_CPUID_LEAF_COUNT_MAX],
698    pub reserved_z3: [u64; 126],
699}
700
701/// Structure describing the pages being read during SNP ID block measurement.
702/// Each structure is hashed with the previous structures digest to create a final
703/// measurement
704#[repr(C)]
705#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
706pub struct SnpPageInfo {
707    /// Set to the value of the previous page's launch digest
708    pub digest_current: [u8; 48],
709    /// Hash of page contents, if measured
710    pub contents: [u8; 48],
711    /// Size of the SnpPageInfo struct
712    pub length: u16,
713    /// type of page being measured, described by [`SnpPageType`]
714    pub page_type: SnpPageType,
715    /// imi_page_bit must match IMI_PAGE flag
716    pub imi_page_bit: u8,
717    /// All lower VMPL permissions are denied for SNP
718    pub lower_vmpl_permissions: u32,
719    /// The guest physical address at which this page data should be loaded; it
720    /// must be aligned to a page size boundary.
721    pub gpa: u64,
722}
723
724open_enum::open_enum! {
725    /// The type of page described by [`SnpPageInfo`]
726    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
727    pub enum SnpPageType: u8 {
728        /// Reserved
729        RESERVED = 0x0,
730        /// Normal data page
731        NORMAL = 0x1,
732        /// VMSA page
733        VMSA = 0x2,
734        /// Zero page
735        ZERO = 0x3,
736        /// Page encrypted, but not measured
737        UNMEASURED = 0x4,
738        /// Page storing guest secrets
739        SECRETS = 0x5,
740        /// Page to provide CPUID function values
741        CPUID = 0x6,
742    }
743}
744
745/// Structure containing the completed SNP measurement of the IGVM file.
746/// The signature of the hash of this struct is the id_key_signature for
747/// `igvm_defs::IGVM_VHS_SNP_ID_BLOCK`.
748#[repr(C)]
749#[derive(Debug, Clone, Copy, IntoBytes, Immutable, KnownLayout, FromBytes)]
750pub struct SnpPspIdBlock {
751    /// completed launch digest of IGVM file
752    pub ld: [u8; 48],
753    /// family id of the guest
754    pub family_id: [u8; 16],
755    /// image id of the guest
756    pub image_id: [u8; 16],
757    /// Version of the ID block format, must be 0x1
758    pub version: u32,
759    /// Software version of the guest
760    pub guest_svn: u32,
761    /// SNP Policy of the guest
762    pub policy: u64,
763}
764
765#[bitfield(u64)]
766#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
767pub struct SevStatusMsr {
768    pub sev_enabled: bool,
769    pub es_enabled: bool,
770    pub snp_enabled: bool,
771    pub vtom: bool,
772    pub reflect_vc: bool,
773    pub restrict_injection: bool,
774    pub alternate_injection: bool,
775    pub debug_swap: bool,
776    pub prevent_host_ibs: bool,
777    pub snp_btb_isolation: bool,
778    pub _rsvd1: bool,
779    pub secure_tsc: bool,
780    pub _rsvd2: bool,
781    pub _rsvd3: bool,
782    pub _rsvd4: bool,
783    pub _rsvd5: bool,
784    pub vmsa_reg_prot: bool,
785    #[bits(6)]
786    _reserved: u64,
787    pub ibpb_on_entry: bool,
788    #[bits(40)]
789    _unused: u64,
790}
791
792#[bitfield(u64)]
793#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
794pub struct SevInvlpgbRax {
795    pub va_valid: bool,
796    pub pcid_valid: bool,
797    pub asid_valid: bool,
798    pub global: bool,
799    pub final_only: bool,
800    pub nested: bool,
801    #[bits(6)]
802    reserved: u64,
803    #[bits(52)]
804    pub virtual_page_number: u64,
805}
806
807#[bitfield(u32)]
808#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
809pub struct SevInvlpgbEdx {
810    #[bits(16)]
811    pub asid: u64,
812    #[bits(12)]
813    pub pcid: u64,
814    #[bits(4)]
815    reserved: u32,
816}
817
818#[bitfield(u32)]
819#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
820pub struct SevInvlpgbEcx {
821    #[bits(16)]
822    pub additional_count: u64,
823    #[bits(15)]
824    reserved: u64,
825    pub large_page: bool,
826}
827
828#[bitfield(u64)]
829pub struct MovCrxDrxInfo {
830    #[bits(4)]
831    pub gpr_number: u64,
832    #[bits(59)]
833    pub reserved: u64,
834    pub mov_crx: bool,
835}
836
837/// Request structure for the `SNP_GET_REPORT` request.
838/// See `MSG_REPORT_REQ` in Table 21, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
839#[repr(C)]
840#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
841pub struct SnpReportReq {
842    /// Guest-provided data to be included in the attestation report.
843    pub user_data: [u8; 64],
844    /// The VMPL to put in the attestation report. Must be greater than
845    /// or equal to the current VMPL and, at most, three.
846    pub vmpl: u32,
847    /// Reserved
848    // TODO SNP: Support VLEK feature if needed
849    pub rsvd: [u8; 28],
850}
851
852pub const SNP_REPORT_RESP_DATA_SIZE: usize =
853    size_of::<u32>() + size_of::<u32>() + 24 + size_of::<SnpReport>();
854
855/// Response structure for the `SNP_GET_REPORT` request.
856/// See `MSG_REPORT_RSP` in Table 24, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
857#[repr(C)]
858#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
859pub struct SnpReportResp {
860    /// The status of key derivation operation.
861    /// 0h: Success.
862    /// 16h: Invalid parameters.
863    /// 27h: Invalid key selection.
864    pub status: u32,
865    /// Size in bytes of the report.
866    pub report_size: u32,
867    /// Reserved
868    pub _reserved0: [u8; 24],
869    /// The attestation report generated by the firmware.
870    pub report: SnpReport,
871}
872
873/// Size of the [`SnpReport`].
874pub const SNP_REPORT_SIZE: usize = 0x4a0;
875
876/// Size of `report_data` member in [`SnpReport`].
877pub const SNP_REPORT_DATA_SIZE: usize = 64;
878
879/// Report structure.
880/// See `ATTESTATION_REPORT` in Table 22, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
881#[repr(C)]
882#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
883pub struct SnpReport {
884    /// Version number of this attestation report.
885    /// Set to 2h for this specification.
886    pub version: u32,
887    /// The guest SVN.
888    pub guest_svn: u32,
889    /// The guest policy.
890    pub policy: u64,
891    /// The family ID provided at launch.
892    pub family: u128,
893    /// The image ID provided at launch.
894    pub image_id: u128,
895    /// The request VMPL for the attestation
896    /// report.
897    pub vmpl: u32,
898    /// The signature algorithm used to sign
899    /// this report.
900    pub signature_algo: u32,
901    /// CurrentTcb.
902    pub current_tcb: u64,
903    /// Information about the platform.
904    pub platform_info: u64,
905    /// Flags
906    pub flags: u32,
907    /// Reserved
908    pub _reserved0: u32,
909    /// Guest-provided data.
910    pub report_data: [u8; SNP_REPORT_DATA_SIZE],
911    /// The measurement calculated at
912    /// launch.
913    pub measurement: [u8; 48],
914    /// Data provided by the hypervisor at
915    /// launch.
916    pub host_data: [u8; 32],
917    /// SHA-384 digest of the ID public key
918    /// that signed the ID block provided in
919    /// SNP_LAUNCH_FINISH.
920    pub id_key_digest: [u8; 48],
921    /// SHA-384 digest of the Author public
922    /// key that certified the ID key, if
923    /// provided in SNP_LAUNCH_FINISH.
924    pub author_key_digest: [u8; 48],
925    /// Report ID of this guest.
926    pub report_id: [u8; 32],
927    /// Report ID of this guest’s migration
928    /// agent
929    pub report_id_ma: [u8; 32],
930    /// Reported TCB version used to derive
931    /// the VCEK that signed this report.
932    pub reported_tcb: u64,
933    /// Reserved
934    pub _reserved1: [u8; 24],
935    /// If MaskChipId is set to 0, Identifier
936    /// unique to the chip as output by
937    /// GET_ID. Otherwise, set to 0h.
938    pub chip_id: [u8; 64],
939    /// CommittedTcb.
940    pub committed_tcb: u64,
941    /// The build number of CurrentVersion.
942    pub current_build: u8,
943    /// The minor number of CurrentVersion.
944    pub current_minor: u8,
945    /// The major number of CurrentVersion.
946    pub current_major: u8,
947    /// Reserved
948    pub _reserved2: u8,
949    /// The build number of CommittedVersion.
950    pub committed_build: u8,
951    /// The minor version of CommittedVersion.
952    pub committed_minor: u8,
953    /// The major version of CommittedVersion.
954    pub committed_major: u8,
955    /// Reserved
956    pub _reserved3: u8,
957    /// The CurrentTcb at the time the guest
958    /// was launched or imported.
959    pub launch_tcb: u64,
960    /// Reserved
961    pub _reserved4: [u8; 168],
962    /// Signature of bytes inclusive of this report.
963    pub signature: [u8; 512],
964}
965
966static_assertions::const_assert_eq!(SNP_REPORT_SIZE, size_of::<SnpReport>());
967
968/// Request structure for the `SNP_GET_DERIVED_KEY` request.
969/// See `MSG_KEY_REQ` in Table 18, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
970#[repr(C)]
971#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
972pub struct SnpDerivedKeyReq {
973    /// Selects the root key from which to derive the key.
974    /// 0 indicates VCEK
975    /// 1 indicates VMRK
976    // TODO: Support VLEK feature if needed
977    pub root_key_select: u32,
978    /// Reserved
979    pub rsvd: u32,
980    /// Bitmask indicating which data will be mixed into the
981    /// derived key.
982    pub guest_field_select: u64,
983    /// The VMPL to mix into the derived key. Must be greater
984    /// than or equal to the current VMPL.
985    pub vmpl: u32,
986    /// The guest SVN to mix into the key. Must not exceed the
987    /// guest SVN provided at launch in the ID block.
988    pub guest_svn: u32,
989    /// The TCB version to mix into the derived key. Must not
990    /// exceed CommittedTcb.
991    pub tcb_version: u64,
992}
993
994/// Indicate which guest-selectable fields will be mixed into the key.
995/// See `GUEST_FIELD_SELECT` in Table 19, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
996#[bitfield(u64)]
997pub struct GuestFieldSelect {
998    /// Indicate that the guest policy will be mixed into the key.
999    pub guest_policy: bool,
1000    /// Indicate that the image ID of the guest will be mixed into the key.
1001    pub image_id: bool,
1002    /// Indicate the family ID of the guest will be mixed into the key.
1003    pub family_id: bool,
1004    /// Indicate the measurement of the guest during launch will be mixed into the key.
1005    pub measurement: bool,
1006    /// Indicate that the guest-provided SVN will be mixed into the key.
1007    pub guest_svn: bool,
1008    /// Indicate that the guest-provided TCB_VERSION will be mixed into the key.
1009    pub tcb_version: bool,
1010    /// Reserved
1011    #[bits(58)]
1012    pub _reserved: u64,
1013}
1014
1015/// See `DERIVED_KEY` in Table 20, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1016pub const SNP_DERIVED_KEY_SIZE: usize = 32;
1017
1018/// Response structure for the `SNP_GET_DERIVED_KEY` request.
1019/// See `MSG_KEY_RSP` in Table 20, "SEV Secure Nested Paging Firmware ABI specification", Revision 1.55.
1020#[repr(C)]
1021#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
1022pub struct SnpDerivedKeyResp {
1023    /// The status of key derivation operation.
1024    /// 0h: Success.
1025    /// 16h: Invalid parameters.
1026    /// 27h: Invalid key selection.
1027    pub status: u32,
1028    /// Reserved
1029    pub _reserved: [u8; 28],
1030    /// The requested derived key.
1031    pub derived_key: [u8; SNP_DERIVED_KEY_SIZE],
1032}
1033
1034static_assertions::const_assert_eq!(
1035    // The size of the response data defined by the SNP specification.
1036    64,
1037    size_of::<SnpDerivedKeyResp>()
1038);