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