1#![expect(missing_docs)]
7#![forbid(unsafe_code)]
8#![no_std]
9
10use bitfield_struct::bitfield;
11use core::ops::Index;
12use core::ops::IndexMut;
13#[cfg(feature = "inspect")]
14use inspect::Inspect;
15use open_enum::open_enum;
16use static_assertions::const_assert;
17use zerocopy::FromBytes;
18use zerocopy::Immutable;
19use zerocopy::IntoBytes;
20use zerocopy::KnownLayout;
21
22pub const VMGS_DEFAULT_CAPACITY: u64 = 0x400000;
30
31open_enum! {
32 #[cfg_attr(feature = "inspect", derive(Inspect))]
34 #[cfg_attr(feature = "inspect", inspect(debug))]
35 pub enum FileId: u32 {
36 FILE_TABLE = 0,
37 BIOS_NVRAM = 1,
38 TPM_PPI = 2,
39 TPM_NVRAM = 3,
40 RTC_SKEW = 4,
41 ATTEST = 5,
42 KEY_PROTECTOR = 6,
43 VM_UNIQUE_ID = 7,
44 GUEST_FIRMWARE = 8,
45 CUSTOM_UEFI = 9,
46 GUEST_WATCHDOG = 10,
47 HW_KEY_PROTECTOR = 11,
48 GUEST_SECRET_KEY = 13,
49
50 EXTENDED_FILE_TABLE = 63,
51 }
52}
53
54pub const VMGS_VERSION_2_0: u32 = 0x00020000;
55pub const VMGS_VERSION_3_0: u32 = 0x00030000;
56
57pub const VMGS_SIGNATURE: u64 = u64::from_le_bytes(*b"GUESTRTS"); pub const VMGS_BYTES_PER_BLOCK: u32 = 4096;
60
61const VMGS_MAX_CAPACITY_BLOCKS: u64 = 0x100000000;
62pub const VMGS_MAX_CAPACITY_BYTES: u64 = VMGS_MAX_CAPACITY_BLOCKS * VMGS_BYTES_PER_BLOCK as u64;
63
64pub const VMGS_MIN_FILE_BLOCK_OFFSET: u32 = 2;
65pub const VMGS_FILE_COUNT: usize = 64;
66pub const VMGS_MAX_FILE_SIZE_BLOCKS: u64 = 0xFFFFFFFF;
67pub const VMGS_MAX_FILE_SIZE_BYTES: u64 = VMGS_MAX_FILE_SIZE_BLOCKS * VMGS_BYTES_PER_BLOCK as u64;
68
69pub const VMGS_NONCE_SIZE: usize = 12; pub const VMGS_NONCE_RANDOM_SEED_SIZE: usize = 4;
71pub const VMGS_AUTHENTICATION_TAG_SIZE: usize = 16;
72pub const VMGS_ENCRYPTION_KEY_SIZE: usize = 32;
73
74pub type VmgsNonce = [u8; VMGS_NONCE_SIZE];
75pub type VmgsAuthTag = [u8; VMGS_AUTHENTICATION_TAG_SIZE];
76pub type VmgsDatastoreKey = [u8; VMGS_ENCRYPTION_KEY_SIZE];
77
78#[repr(C)]
79#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
80pub struct VmgsFileEntry {
81 pub offset: u32,
83 pub allocation_size: u32,
84 pub valid_data_size: u64,
85
86 pub nonce: VmgsNonce,
88 pub authentication_tag: VmgsAuthTag,
89
90 pub reserved: [u8; 20],
91}
92
93const_assert!(size_of::<VmgsFileEntry>() == 64);
94
95impl Index<FileId> for [VmgsFileEntry] {
96 type Output = VmgsFileEntry;
97
98 fn index(&self, file_id: FileId) -> &Self::Output {
99 &self[file_id.0 as usize]
100 }
101}
102
103impl IndexMut<FileId> for [VmgsFileEntry] {
104 fn index_mut(&mut self, file_id: FileId) -> &mut Self::Output {
105 &mut self[file_id.0 as usize]
106 }
107}
108
109#[repr(C)]
110#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
111pub struct VmgsExtendedFileEntry {
112 pub attributes: FileAttribute,
113 pub encryption_key: VmgsDatastoreKey,
114
115 pub reserved: [u8; 28],
116}
117
118const_assert!(size_of::<VmgsExtendedFileEntry>() == 64);
119
120impl Index<FileId> for [VmgsExtendedFileEntry] {
121 type Output = VmgsExtendedFileEntry;
122
123 fn index(&self, file_id: FileId) -> &Self::Output {
124 &self[file_id.0 as usize]
125 }
126}
127
128impl IndexMut<FileId> for [VmgsExtendedFileEntry] {
129 fn index_mut(&mut self, file_id: FileId) -> &mut Self::Output {
130 &mut self[file_id.0 as usize]
131 }
132}
133
134#[repr(C)]
135#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
136#[cfg_attr(feature = "inspect", derive(Inspect))]
137pub struct VmgsEncryptionKey {
138 pub nonce: VmgsNonce,
139 pub reserved: u32,
140 pub authentication_tag: VmgsAuthTag,
141 pub encryption_key: VmgsDatastoreKey,
142}
143
144const_assert!(size_of::<VmgsEncryptionKey>() == 64);
145
146#[repr(C)]
147#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
148pub struct VmgsHeader {
149 pub signature: u64,
151 pub version: u32,
152 pub checksum: u32,
153 pub sequence: u32,
154 pub header_size: u32,
155
156 pub file_table_offset: u32,
158 pub file_table_size: u32,
159
160 pub encryption_algorithm: EncryptionAlgorithm,
162 pub reserved: u16,
163 pub metadata_keys: [VmgsEncryptionKey; 2],
164 pub reserved_1: u32,
165}
166
167const_assert!(size_of::<VmgsHeader>() == 168);
168
169#[repr(C)]
170#[derive(Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes, Debug)]
171pub struct VmgsFileTable {
172 pub entries: [VmgsFileEntry; VMGS_FILE_COUNT],
173}
174
175const_assert!(size_of::<VmgsFileTable>() == 4096);
176const_assert!(size_of::<VmgsFileTable>() as u32 % VMGS_BYTES_PER_BLOCK == 0);
177pub const VMGS_FILE_TABLE_BLOCK_SIZE: u32 =
178 size_of::<VmgsFileTable>() as u32 / VMGS_BYTES_PER_BLOCK;
179
180#[repr(C)]
181#[derive(Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]
182pub struct VmgsExtendedFileTable {
183 pub entries: [VmgsExtendedFileEntry; VMGS_FILE_COUNT],
184}
185
186const_assert!(size_of::<VmgsExtendedFileTable>() == 4096);
187const_assert!(size_of::<VmgsExtendedFileTable>() as u32 % VMGS_BYTES_PER_BLOCK == 0);
188pub const VMGS_EXTENDED_FILE_TABLE_BLOCK_SIZE: u32 =
189 size_of::<VmgsExtendedFileTable>() as u32 / VMGS_BYTES_PER_BLOCK;
190
191#[cfg_attr(feature = "inspect", derive(Inspect))]
193#[bitfield(u32)]
194#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)]
195pub struct FileAttribute {
196 pub encrypted: bool,
197 pub authenticated: bool,
198 #[bits(30)]
199 _reserved: u32,
200}
201
202open_enum! {
203 #[cfg_attr(feature = "inspect", derive(Inspect))]
205 #[cfg_attr(feature = "inspect", inspect(debug))]
206 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
207 pub enum EncryptionAlgorithm: u16 {
208 NONE = 0,
210 AES_GCM = 1,
212 }
213}