vbs_defs/lib.rs
1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4// Virtualization Based Security (VBS) platform definitions defined by Hyper-V
5
6#![expect(missing_docs)]
7#![forbid(unsafe_code)]
8#![allow(non_camel_case_types)]
9
10use bitfield_struct::bitfield;
11use igvm_defs::PAGE_SIZE_4K;
12use open_enum::open_enum;
13use static_assertions::const_assert;
14use zerocopy::Immutable;
15use zerocopy::IntoBytes;
16use zerocopy::KnownLayout;
17
18pub const VBS_VP_CHUNK_SIZE_BYTES: usize = PAGE_SIZE_4K as usize + size_of::<VpGpaPageChunk>();
19
20/// Structure containing the completed VBS boot measurement of the IGVM file.
21/// The signature of the hash of this struct is the signature for [`igvm_defs::IGVM_VHS_VBS_MEASUREMENT`]
22#[repr(C)]
23#[derive(IntoBytes, Immutable, KnownLayout, Debug)]
24pub struct VBS_VM_BOOT_MEASUREMENT_SIGNED_DATA {
25 /// The version of the signature structure
26 pub version: u32,
27 /// The user supplied product id
28 pub product_id: u32,
29 /// The uesr supplied module id
30 pub module_id: u32,
31 /// The user supplied svn
32 pub security_version: u32,
33 /// Security policy for the guest
34 pub security_policy: VBS_POLICY_FLAGS,
35 /// Algorithm that created the boot digest hash
36 pub boot_digest_algo: u32,
37 /// Algorithm that produces the signature
38 pub signing_algo: u32,
39 /// VBS Boot digest
40 pub boot_measurement_digest: [u8; 32],
41}
42
43/// Chunk that is measured to generate digest. These consist of a 16 byte header followed by data.
44/// This needs c style alignment to generate a consistent measurement.
45/// Defined by the following struct in C:
46/// ``` ignore
47/// typedef struct _VBS_VM_BOOT_MEASUREMENT_CHUNK
48/// {
49/// UINT32 ByteCount;
50/// VBS_VM_BOOT_MEASUREMENT_CHUNK_TYPE Type;
51/// UINT64 Reserved;
52///
53/// union
54/// {
55/// VBS_VM_BOOT_MEASUREMENT_CHUNK_VP_REGISTER VpRegister;
56/// VBS_VM_BOOT_MEASUREMENT_CHUNK_VP_VTL_ENABLED VpVtlEnabled;
57/// VBS_VM_BOOT_MEASUREMENT_CHUNK_GPA_PAGE GpaPage;
58/// } u;
59/// } VBS_VM_BOOT_MEASUREMENT_CHUNK, *PVBS_VM_BOOT_MEASUREMENT_CHUNK;
60/// ```
61///
62/// Structure describing the chunk to be measured
63#[repr(C)]
64#[derive(IntoBytes, Immutable, KnownLayout)]
65pub struct VbsChunkHeader {
66 /// The full size to be measured
67 pub byte_count: u32,
68 pub chunk_type: BootMeasurementType,
69 pub reserved: u64,
70}
71
72/// Structure describing the register being measured. Will be padded to [`VBS_VP_CHUNK_SIZE_BYTES`] when hashed to generate digest
73#[repr(C)]
74#[derive(IntoBytes, Immutable, KnownLayout)]
75pub struct VbsRegisterChunk {
76 pub header: VbsChunkHeader,
77 pub reserved: u32,
78 pub vtl: u8,
79 pub reserved2: u8,
80 pub reserved3: u16,
81 pub reserved4: u32,
82 pub name: u32,
83 pub value: [u8; 16],
84}
85const_assert!(size_of::<VbsRegisterChunk>() <= VBS_VP_CHUNK_SIZE_BYTES);
86
87/// Structure describing the page to be measured.
88/// Page data is hashed after struct to generate digest, if not a full page, measurable data will be padded to [`VBS_VP_CHUNK_SIZE_BYTES`]
89#[repr(C)]
90#[derive(IntoBytes, Immutable, KnownLayout)]
91pub struct VpGpaPageChunk {
92 pub header: VbsChunkHeader,
93 pub metadata: u64,
94 pub page_number: u64,
95}
96
97open_enum! {
98#[derive(IntoBytes, Immutable, KnownLayout)]
99pub enum BootMeasurementType: u32 {
100 VP_REGISTER = 0,
101 VP_VTL_ENABLED = 1,
102 VP_GPA_PAGE = 2,
103}
104}
105
106/// Flags indicating read and write acceptance of a GPA Page and whether it is
107/// to be measured in the digest
108#[bitfield(u64)]
109pub struct VBS_VM_GPA_PAGE_BOOT_METADATA {
110 #[bits(2)]
111 pub acceptance: u64,
112 #[bits(1)]
113 pub data_unmeasured: bool,
114 #[bits(61)]
115 reserved: u64,
116}
117
118/// Flags defining the security policy for the guest
119#[bitfield(u32)]
120#[derive(IntoBytes, Immutable, KnownLayout)]
121pub struct VBS_POLICY_FLAGS {
122 /// Guest supports debugging
123 #[bits(1)]
124 pub debug: bool,
125 #[bits(31)]
126 reserved: u32,
127}
128pub const VM_GPA_PAGE_READABLE: u64 = 0x1;
129pub const VM_GPA_PAGE_WRITABLE: u64 = 0x2;