Coverage Report

Created: 2026-05-24 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/td-shim/td-shim-interface/src/metadata.rs
Line
Count
Source
1
// Copyright (c) 2020 Intel Corporation
2
//
3
// SPDX-License-Identifier: BSD-2-Clause-Patent
4
5
extern crate alloc;
6
7
use crate::td_uefi_pi::pi::guid::Guid;
8
use alloc::string::String;
9
use core::{ptr::slice_from_raw_parts, str::FromStr};
10
use scroll::{Pread, Pwrite};
11
12
/// TDX Metadata GUID defined in td-shim specification
13
pub const TDX_METADATA_GUID_STR: &str = "E9EAF9F3-168E-44D5-A8EB-7F4D8738F6AE";
14
pub const TDX_METADATA_GUID: Guid = Guid::from_fields(
15
    0xE9EAF9F3,
16
    0x168E,
17
    0x44D5,
18
    [0xA8, 0xEB, 0x7F, 0x4D, 0x87, 0x38, 0xF6, 0xAE],
19
);
20
21
/// 'TDVF' signature
22
pub const TDX_METADATA_SIGNATURE: u32 = 0x46564454;
23
/// Version of the `TdxMetadataDescriptor` structure. It must be 1.
24
pub const TDX_METADATA_VERSION: u32 = 1;
25
/// TdxMetadata Offset
26
pub const TDX_METADATA_OFFSET: u32 = 0x20;
27
/// TdxMetadata guid length
28
pub const TDX_METADATA_GUID_LEN: u32 = 16;
29
/// TdxMetadata description length
30
pub const TDX_METADATA_DESCRIPTOR_LEN: u32 = 16;
31
/// TdxMetadata section length
32
pub const TDX_METADATA_SECTION_LEN: u32 = 32;
33
34
/// Section type for EFI Boot Firmware Volume.
35
pub const TDX_METADATA_SECTION_TYPE_BFV: u32 = 0;
36
/// Section type for EFI Boot Configuration Volume.
37
pub const TDX_METADATA_SECTION_TYPE_CFV: u32 = 1;
38
/// Section type for EFI Hand-off Blob.
39
pub const TDX_METADATA_SECTION_TYPE_TD_HOB: u32 = 2;
40
/// Section type for stack, heap and mailbox.
41
pub const TDX_METADATA_SECTION_TYPE_TEMP_MEM: u32 = 3;
42
/// Section type for PermMem
43
pub const TDX_METADATA_SECTION_TYPE_PERM_MEM: u32 = 4;
44
/// Section type for kernel image.
45
pub const TDX_METADATA_SECTION_TYPE_PAYLOAD: u32 = 5;
46
/// Section type for kernel parameters.
47
pub const TDX_METADATA_SECTION_TYPE_PAYLOAD_PARAM: u32 = 6;
48
/// Section type for td info.
49
pub const TDX_METADATA_SECTION_TYPE_TD_INFO: u32 = 7;
50
/// Section type for TD Params.
51
pub const TDX_METADATA_SECTION_TYPE_TD_PARAMS: u32 = 8;
52
/// Max Section type
53
pub const TDX_METADATA_SECTION_TYPE_MAX: u32 = 9;
54
55
pub const TDX_METADATA_SECTION_TYPE_STRS: [&str; TDX_METADATA_SECTION_TYPE_MAX as usize] = [
56
    "BFV",
57
    "CFV",
58
    "TD_HOB",
59
    "TempMem",
60
    "PermMem",
61
    "Payload",
62
    "PayloadParam",
63
    "TdInfo",
64
    "TdParams",
65
];
66
67
/// Attribute flags for BFV.
68
pub const TDX_METADATA_ATTRIBUTES_EXTENDMR: u32 = 0x00000001;
69
pub const TDX_METADATA_ATTRIBUTES_PAGE_AUG: u32 = 0x00000002;
70
71
#[repr(C)]
72
#[derive(Debug, Pread, Pwrite)]
73
pub struct TdxMetadataDescriptor {
74
    pub signature: u32,
75
    pub length: u32,
76
    pub version: u32,
77
    pub number_of_section_entry: u32,
78
}
79
80
impl Default for TdxMetadataDescriptor {
81
0
    fn default() -> Self {
82
0
        TdxMetadataDescriptor {
83
0
            signature: TDX_METADATA_SIGNATURE,
84
0
            length: 16,
85
0
            version: 1,
86
0
            number_of_section_entry: 0,
87
0
        }
88
0
    }
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataDescriptor as core::default::Default>::default
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataDescriptor as core::default::Default>::default
89
}
90
91
impl TdxMetadataDescriptor {
92
0
    pub fn set_sections(&mut self, sections: u32) {
93
        // TdxMetadataDescriptor.length does not include TdxMetadata.guid, so "16 + 32 * sections"
94
        // instead of "32 + 32 * sections".
95
0
        assert!(sections < 0x10000);
96
0
        self.number_of_section_entry = sections;
97
0
        self.length = 16 + sections * 32;
98
0
    }
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataDescriptor>::set_sections
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataDescriptor>::set_sections
99
100
0
    pub fn is_valid(&self) -> bool {
101
        #[cfg(not(feature = "no-metadata-checks"))]
102
0
        if self.signature != TDX_METADATA_SIGNATURE {
103
0
            return false;
104
0
        }
105
106
0
        let len = self.length;
107
0
        if self.version != 1
108
0
            || self.number_of_section_entry == 0
109
0
            || len < 16
110
0
            || (len - 16) % 32 != 0
111
0
            || (len - 16) / 32 != self.number_of_section_entry
112
        {
113
0
            return false;
114
0
        }
115
116
0
        true
117
0
    }
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataDescriptor>::is_valid
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataDescriptor>::is_valid
118
119
0
    pub fn as_bytes(&self) -> &[u8] {
120
        unsafe {
121
0
            core::slice::from_raw_parts(
122
0
                self as *const TdxMetadataDescriptor as *const u8,
123
0
                core::mem::size_of::<Self>(),
124
0
            )
125
        }
126
0
    }
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataDescriptor>::as_bytes
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataDescriptor>::as_bytes
127
}
128
129
#[repr(C)]
130
#[derive(Clone, Copy, Debug, Default, Pwrite, Pread)]
131
pub struct TdxMetadataSection {
132
    pub data_offset: u32,
133
    pub raw_data_size: u32,
134
    pub memory_address: u64,
135
    pub memory_data_size: u64,
136
    pub r#type: u32,
137
    pub attributes: u32,
138
}
139
140
impl TdxMetadataSection {
141
0
    pub fn get_type_name(r#type: u32) -> Option<String> {
142
0
        if r#type >= TDX_METADATA_SECTION_TYPE_MAX {
143
0
            None
144
        } else {
145
0
            Some(String::from(
146
0
                TDX_METADATA_SECTION_TYPE_STRS[r#type as usize],
147
0
            ))
148
        }
149
0
    }
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataSection>::get_type_name
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataSection>::get_type_name
150
151
0
    pub fn as_bytes(&self) -> &[u8] {
152
        unsafe {
153
0
            core::slice::from_raw_parts(
154
0
                self as *const TdxMetadataSection as *const u8,
155
0
                core::mem::size_of::<Self>(),
156
0
            )
157
        }
158
0
    }
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataSection>::as_bytes
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataSection>::as_bytes
159
}
160
161
#[repr(C)]
162
#[derive(Pwrite, Pread)]
163
pub struct TdxMetadataGuid {
164
    pub guid: Guid,
165
}
166
167
impl TdxMetadataGuid {
168
    /// Check whether it's a valid
169
0
    pub fn is_valid(&self) -> bool {
170
0
        let metadata_guid = Guid::from_str(TDX_METADATA_GUID_STR).unwrap();
171
0
        metadata_guid == self.guid
172
0
    }
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataGuid>::is_valid
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataGuid>::is_valid
173
174
0
    pub fn as_bytes(&self) -> &[u8; 16] {
175
0
        self.guid.as_bytes()
176
0
    }
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataGuid>::as_bytes
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataGuid>::as_bytes
177
178
    /// Return TdxMetadataGuid based on the input buffer
179
    ///
180
    /// # Arguments
181
    ///
182
    /// * `buffer` - A buffer contains TdxMetadata guid.
183
0
    pub fn from_bytes(buffer: &[u8; 16]) -> Option<TdxMetadataGuid> {
184
0
        let guid = Guid::from_bytes(buffer);
185
0
        let metadata_guid = TdxMetadataGuid { guid };
186
0
        if metadata_guid.is_valid() {
187
0
            Some(metadata_guid)
188
        } else {
189
0
            None
190
        }
191
0
    }
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataGuid>::from_bytes
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataGuid>::from_bytes
192
}
193
194
impl Default for TdxMetadataGuid {
195
0
    fn default() -> Self {
196
0
        TdxMetadataGuid {
197
0
            guid: Guid::from_str(TDX_METADATA_GUID_STR).unwrap(),
198
0
        }
199
0
    }
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataGuid as core::default::Default>::default
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataGuid as core::default::Default>::default
200
}
201
202
#[derive(Debug)]
203
pub enum TdxMetadataError {
204
    InvalidSection,
205
}
206
207
0
pub fn validate_sections(sections: &[TdxMetadataSection]) -> Result<(), TdxMetadataError> {
208
0
    let mut bfv_cnt = 0;
209
0
    let mut bfv_start = 0;
210
0
    let mut bfv_end = 0;
211
0
    let mut hob_cnt = 0;
212
0
    let mut perm_mem_cnt = 0;
213
0
    let mut payload_cnt = 0;
214
0
    let mut payload_param_cnt = 0;
215
0
    let mut td_info_cnt = 0;
216
0
    let mut td_info_start = 0;
217
0
    let mut td_info_end = 0;
218
0
    let mut td_params_cnt = 0;
219
0
    let mut td_params_start = 0;
220
0
    let mut td_params_end = 0;
221
0
    let check_data_memory_fields =
222
0
        |data_offset: u32, data_size: u32, memory_address: u64, memory_size: u64| -> bool {
223
0
            if data_size == 0 && data_offset != 0 {
224
0
                return false;
225
0
            }
226
0
            if data_size != 0 && memory_size < data_size as u64 {
227
0
                return false;
228
0
            }
229
0
            if (memory_address & 0xfff) != 0 {
230
0
                return false;
231
0
            }
232
0
            true
233
0
        };
Unexecuted instantiation: td_shim_interface::metadata::validate_sections::{closure#0}
Unexecuted instantiation: td_shim_interface::metadata::validate_sections::{closure#0}
234
0
    for section in sections.iter() {
235
0
        match section.r#type {
236
            TDX_METADATA_SECTION_TYPE_BFV => {
237
                // A TD-Shim shall include at least one BFV and the reset vector shall be inside
238
                // of BFV. The RawDataSize of BFV must be non-zero.
239
0
                if bfv_cnt == i32::MAX {
240
0
                    return Err(TdxMetadataError::InvalidSection);
241
0
                }
242
0
                bfv_cnt += 1;
243
0
                if section.raw_data_size == 0 {
244
0
                    return Err(TdxMetadataError::InvalidSection);
245
0
                }
246
                #[cfg(not(feature = "no-metadata-checks"))]
247
0
                if section.attributes != TDX_METADATA_ATTRIBUTES_EXTENDMR {
248
0
                    return Err(TdxMetadataError::InvalidSection);
249
0
                }
250
0
                if !check_data_memory_fields(
251
0
                    section.data_offset,
252
0
                    section.raw_data_size,
253
0
                    section.memory_address,
254
0
                    section.memory_data_size,
255
0
                ) {
256
0
                    return Err(TdxMetadataError::InvalidSection);
257
0
                } else {
258
0
                    bfv_start = section.data_offset;
259
0
                    bfv_end = bfv_start + section.raw_data_size;
260
0
                }
261
            }
262
263
            TDX_METADATA_SECTION_TYPE_CFV => {
264
                // A TD-Shim may have zero, one or multiple CFVs. The RawDataSize of CFV must be
265
                // non-zero.
266
0
                if section.raw_data_size == 0 {
267
0
                    return Err(TdxMetadataError::InvalidSection);
268
0
                }
269
0
                if section.attributes != 0 {
270
0
                    return Err(TdxMetadataError::InvalidSection);
271
0
                }
272
0
                if !check_data_memory_fields(
273
0
                    section.data_offset,
274
0
                    section.raw_data_size,
275
0
                    section.memory_address,
276
0
                    section.memory_data_size,
277
0
                ) {
278
0
                    return Err(TdxMetadataError::InvalidSection);
279
0
                }
280
            }
281
282
            TDX_METADATA_SECTION_TYPE_TD_HOB => {
283
                // A TD-Shim may have zero or one TD_HOB section. The RawDataSize of TD_HOB must
284
                // be zero. If TD-Shim reports zero TD_HOB section, then TD-Shim shall report
285
                // all required memory in PermMem section.
286
0
                if hob_cnt == i32::MAX {
287
0
                    return Err(TdxMetadataError::InvalidSection);
288
0
                }
289
0
                hob_cnt += 1;
290
0
                if hob_cnt > 1 {
291
0
                    return Err(TdxMetadataError::InvalidSection);
292
0
                }
293
0
                if section.raw_data_size != 0 || section.data_offset != 0 {
294
0
                    return Err(TdxMetadataError::InvalidSection);
295
0
                }
296
0
                if section.attributes != 0 {
297
0
                    return Err(TdxMetadataError::InvalidSection);
298
0
                }
299
0
                if !check_data_memory_fields(
300
0
                    section.data_offset,
301
0
                    section.raw_data_size,
302
0
                    section.memory_address,
303
0
                    section.memory_data_size,
304
0
                ) {
305
0
                    return Err(TdxMetadataError::InvalidSection);
306
0
                }
307
            }
308
309
            TDX_METADATA_SECTION_TYPE_TEMP_MEM => {
310
                // The RawDataSize of TempMem must be zero.
311
0
                if section.raw_data_size != 0 || section.data_offset != 0 {
312
0
                    return Err(TdxMetadataError::InvalidSection);
313
0
                }
314
0
                if section.attributes != 0 {
315
0
                    return Err(TdxMetadataError::InvalidSection);
316
0
                }
317
0
                if !check_data_memory_fields(
318
0
                    section.data_offset,
319
0
                    section.raw_data_size,
320
0
                    section.memory_address,
321
0
                    section.memory_data_size,
322
0
                ) {
323
0
                    return Err(TdxMetadataError::InvalidSection);
324
0
                }
325
            }
326
327
            TDX_METADATA_SECTION_TYPE_PERM_MEM => {
328
                // A TD-Shim may have zero, one or multiple PermMem section. The RawDataSize of
329
                // PermMem must be zero. If a TD provides PermMem section, that means the TD
330
                // will own the memory allocation. VMM shall allocate the permanent memory for
331
                // this TD. TD will NOT use the system memory information in the TD HOB. Even if
332
                // VMM adds system memory information in the TD HOB, it will ne ignored.
333
0
                if perm_mem_cnt == i32::MAX {
334
0
                    return Err(TdxMetadataError::InvalidSection);
335
0
                }
336
0
                perm_mem_cnt += 1;
337
0
                if section.raw_data_size != 0 || section.data_offset != 0 {
338
0
                    return Err(TdxMetadataError::InvalidSection);
339
0
                }
340
                #[cfg(not(feature = "no-metadata-checks"))]
341
0
                if section.attributes != TDX_METADATA_ATTRIBUTES_PAGE_AUG {
342
0
                    return Err(TdxMetadataError::InvalidSection);
343
0
                }
344
0
                if !check_data_memory_fields(
345
0
                    section.data_offset,
346
0
                    section.raw_data_size,
347
0
                    section.memory_address,
348
0
                    section.memory_data_size,
349
0
                ) {
350
0
                    return Err(TdxMetadataError::InvalidSection);
351
0
                }
352
            }
353
354
            TDX_METADATA_SECTION_TYPE_PAYLOAD => {
355
                // A TD-Shim may have zero or one Payload. The RawDataSize of Payload must be
356
                // non-zero, if the whole image includes the Payload. Otherwise the RawDataSize
357
                // must be zero.
358
0
                if payload_cnt == i32::MAX {
359
0
                    return Err(TdxMetadataError::InvalidSection);
360
0
                }
361
0
                payload_cnt += 1;
362
0
                if payload_cnt > 1 {
363
0
                    return Err(TdxMetadataError::InvalidSection);
364
0
                }
365
                #[cfg(not(feature = "no-metadata-checks"))]
366
0
                if section.attributes & (!TDX_METADATA_ATTRIBUTES_EXTENDMR) != 0 {
367
0
                    return Err(TdxMetadataError::InvalidSection);
368
0
                }
369
0
                if !check_data_memory_fields(
370
0
                    section.data_offset,
371
0
                    section.raw_data_size,
372
0
                    section.memory_address,
373
0
                    section.memory_data_size,
374
0
                ) {
375
0
                    return Err(TdxMetadataError::InvalidSection);
376
0
                }
377
            }
378
379
            TDX_METADATA_SECTION_TYPE_PAYLOAD_PARAM => {
380
                // A TD-Shim may have zero or one PayloadParam. PayloadParam is present only if
381
                // the Payload is present.
382
0
                if payload_param_cnt == i32::MAX {
383
0
                    return Err(TdxMetadataError::InvalidSection);
384
0
                }
385
0
                payload_param_cnt += 1;
386
0
                if payload_param_cnt > 1 {
387
0
                    return Err(TdxMetadataError::InvalidSection);
388
0
                }
389
0
                if section.attributes != 0 {
390
0
                    return Err(TdxMetadataError::InvalidSection);
391
0
                }
392
0
                if !check_data_memory_fields(
393
0
                    section.data_offset,
394
0
                    section.raw_data_size,
395
0
                    section.memory_address,
396
0
                    section.memory_data_size,
397
0
                ) {
398
0
                    return Err(TdxMetadataError::InvalidSection);
399
0
                }
400
            }
401
402
            TDX_METADATA_SECTION_TYPE_TD_INFO => {
403
                // A TD-Shim may have zero or one TdInfo. If present, it shall be included in BFV section.
404
0
                if td_info_cnt == i32::MAX {
405
0
                    return Err(TdxMetadataError::InvalidSection);
406
0
                }
407
0
                td_info_cnt += 1;
408
0
                if td_info_cnt > 1 {
409
0
                    return Err(TdxMetadataError::InvalidSection);
410
0
                }
411
0
                if section.attributes != 0 {
412
0
                    return Err(TdxMetadataError::InvalidSection);
413
0
                }
414
0
                if section.raw_data_size == 0 {
415
0
                    return Err(TdxMetadataError::InvalidSection);
416
0
                } else {
417
0
                    td_info_start = section.data_offset;
418
0
                    td_info_end = td_info_start + section.raw_data_size;
419
0
                }
420
421
                // MemoryAddress and MemoryDataSize shall be zero.
422
0
                if section.memory_address != 0 || section.memory_data_size != 0 {
423
0
                    return Err(TdxMetadataError::InvalidSection);
424
0
                }
425
            }
426
427
            TDX_METADATA_SECTION_TYPE_TD_PARAMS => {
428
                // A TD-Shim may have zero or one TdParams. If present, it shall be included in BFV section.
429
0
                if td_params_cnt == i32::MAX {
430
0
                    return Err(TdxMetadataError::InvalidSection);
431
0
                }
432
0
                td_params_cnt += 1;
433
0
                if td_params_cnt > 1 {
434
0
                    return Err(TdxMetadataError::InvalidSection);
435
0
                }
436
0
                if section.attributes != 0 {
437
0
                    return Err(TdxMetadataError::InvalidSection);
438
0
                }
439
0
                if section.raw_data_size == 0 {
440
0
                    return Err(TdxMetadataError::InvalidSection);
441
0
                } else {
442
0
                    td_params_start = section.data_offset;
443
0
                    td_params_end = td_params_start + section.raw_data_size;
444
0
                }
445
446
                // MemoryAddress and MemoryDataSize shall be zero.
447
0
                if section.memory_address != 0 || section.memory_data_size != 0 {
448
0
                    return Err(TdxMetadataError::InvalidSection);
449
0
                }
450
            }
451
452
            _ => {
453
0
                return Err(TdxMetadataError::InvalidSection);
454
            }
455
        }
456
    }
457
458
    // A TD-Shim shall include at least one BFV
459
0
    if bfv_cnt == 0 {
460
0
        return Err(TdxMetadataError::InvalidSection);
461
0
    }
462
    // If TD-Shim reports zero TD_HOB section, then TD-Shim shall report
463
    // all required memory in PermMem section.
464
0
    if hob_cnt == 0 && perm_mem_cnt == 0 {
465
0
        return Err(TdxMetadataError::InvalidSection);
466
0
    }
467
    // PayloadParam is present only if the Payload is present.
468
0
    if payload_cnt == 0 && payload_param_cnt != 0 {
469
0
        return Err(TdxMetadataError::InvalidSection);
470
0
    }
471
472
    // TdInfo. If present, it shall be included in BFV section.
473
0
    if td_info_cnt != 0
474
0
        && (td_info_start < bfv_start || td_info_start >= bfv_end || td_info_end > bfv_end)
475
    {
476
0
        return Err(TdxMetadataError::InvalidSection);
477
0
    }
478
479
    // TdParams. If present, it shall be included in BFV section.
480
0
    if td_params_cnt != 0
481
0
        && (td_params_start < bfv_start || td_params_start >= bfv_end || td_params_end > bfv_end)
482
    {
483
0
        return Err(TdxMetadataError::InvalidSection);
484
0
    }
485
486
0
    Ok(())
487
0
}
Unexecuted instantiation: td_shim_interface::metadata::validate_sections
Unexecuted instantiation: td_shim_interface::metadata::validate_sections
488
489
#[repr(C)]
490
#[derive(Default, Pwrite, Pread)]
491
pub struct TdxMetadataPtr {
492
    pub ptr: u32,
493
}
494
495
impl TdxMetadataPtr {
496
0
    pub fn as_bytes(&self) -> &[u8] {
497
        unsafe {
498
0
            &*slice_from_raw_parts(
499
0
                self as *const TdxMetadataPtr as *const u8,
500
0
                core::mem::size_of::<Self>(),
501
0
            )
502
        }
503
0
    }
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataPtr>::as_bytes
Unexecuted instantiation: <td_shim_interface::metadata::TdxMetadataPtr>::as_bytes
504
}
505
506
#[cfg(test)]
507
mod tests {
508
    use super::*;
509
    use scroll::export::mem::size_of;
510
511
    #[test]
512
    fn ensure_data_struct_size() {
513
        assert_eq!(size_of::<TdxMetadataDescriptor>(), 16);
514
        assert_eq!(size_of::<TdxMetadataSection>(), 32);
515
        assert_eq!(size_of::<TdxMetadataGuid>(), 16);
516
        assert_eq!(size_of::<TdxMetadataPtr>(), 4);
517
    }
518
519
    #[test]
520
    fn test_tdx_metadata_descriptor() {
521
        let mut desc = TdxMetadataDescriptor::default();
522
523
        assert_eq!(desc.signature, TDX_METADATA_SIGNATURE);
524
        assert_eq!(desc.length, 16);
525
        assert_eq!(desc.version, 1);
526
        assert_eq!(desc.number_of_section_entry, 0);
527
        assert_eq!(desc.is_valid(), false);
528
529
        desc.set_sections(1);
530
        assert_eq!(desc.signature, TDX_METADATA_SIGNATURE);
531
        assert_eq!(desc.length, 48);
532
        assert_eq!(desc.version, 1);
533
        assert_eq!(desc.number_of_section_entry, 1);
534
        assert_eq!(desc.is_valid(), true);
535
    }
536
537
    #[test]
538
    fn test_tdx_metadata_guid() {
539
        let tdx_metadata_guid: [u8; 16] = [
540
            0xF3, 0xF9, 0xEA, 0xE9, 0x8e, 0x16, 0xD5, 0x44, 0xA8, 0xEB, 0x7F, 0x4D, 0x87, 0x38,
541
            0xF6, 0xAE,
542
        ];
543
        let invalid_tdx_metadata_guid: [u8; 16] = [
544
            0xE9, 0xEA, 0xF9, 0xF3, 0x16, 0x8e, 0x44, 0xD5, 0xA8, 0xEB, 0x7F, 0x4D, 0x87, 0x38,
545
            0xF6, 0xAE,
546
        ];
547
        let guid = TdxMetadataGuid::default();
548
549
        assert_eq!(&tdx_metadata_guid, guid.as_bytes());
550
        assert_eq!(&tdx_metadata_guid, TDX_METADATA_GUID.as_bytes());
551
        assert_eq!(guid.is_valid(), true);
552
553
        let guid_pread: TdxMetadataGuid = tdx_metadata_guid.pread(0).unwrap();
554
        assert_eq!(guid_pread.as_bytes(), guid.as_bytes());
555
556
        let guid = TdxMetadataGuid::from_bytes(&tdx_metadata_guid).unwrap();
557
        assert_eq!(guid.as_bytes(), &tdx_metadata_guid);
558
559
        assert!(TdxMetadataGuid::from_bytes(&invalid_tdx_metadata_guid).is_none());
560
    }
561
562
    #[test]
563
    fn test_tdx_metadata_section() {
564
        assert_eq!(TdxMetadataSection::get_type_name(0).unwrap(), "BFV");
565
        assert_eq!(TdxMetadataSection::get_type_name(1).unwrap(), "CFV");
566
        assert_eq!(TdxMetadataSection::get_type_name(2).unwrap(), "TD_HOB");
567
        assert_eq!(TdxMetadataSection::get_type_name(3).unwrap(), "TempMem");
568
        assert_eq!(TdxMetadataSection::get_type_name(4).unwrap(), "PermMem");
569
        assert_eq!(TdxMetadataSection::get_type_name(5).unwrap(), "Payload");
570
        assert_eq!(
571
            TdxMetadataSection::get_type_name(6).unwrap(),
572
            "PayloadParam"
573
        );
574
        assert_eq!(TdxMetadataSection::get_type_name(7).unwrap(), "TdInfo");
575
        assert_eq!(TdxMetadataSection::get_type_name(8).unwrap(), "TdParams");
576
577
        assert!(TdxMetadataSection::get_type_name(9).is_none());
578
    }
579
580
    #[test]
581
    fn test_validate_sections() {
582
        // empty sections at leaset one bfv section
583
        let sections = [];
584
        assert!(!validate_sections(&sections).is_ok());
585
586
        // init sections include all types
587
        let mut sections: [TdxMetadataSection; 7] = [TdxMetadataSection::default(); 7];
588
        // BFV
589
        sections[0] = TdxMetadataSection {
590
            data_offset: 0,
591
            raw_data_size: 0xf7e000,
592
            memory_address: 0xff082000,
593
            memory_data_size: 0xf7e000,
594
            attributes: 1,
595
            r#type: TDX_METADATA_SECTION_TYPE_BFV,
596
        };
597
        // CFV
598
        sections[1] = TdxMetadataSection {
599
            data_offset: 0,
600
            raw_data_size: 0x40000,
601
            memory_address: 0xff000000,
602
            memory_data_size: 0x40000,
603
            attributes: 0,
604
            r#type: TDX_METADATA_SECTION_TYPE_CFV,
605
        };
606
        // TD HOB
607
        sections[2] = TdxMetadataSection {
608
            data_offset: 0,
609
            raw_data_size: 0,
610
            memory_address: 0x820000,
611
            memory_data_size: 0x20000,
612
            attributes: 0,
613
            r#type: TDX_METADATA_SECTION_TYPE_TD_HOB,
614
        };
615
        // Temp memory
616
        sections[3] = TdxMetadataSection {
617
            data_offset: 0,
618
            raw_data_size: 0,
619
            memory_address: 0xFF040000,
620
            memory_data_size: 0x1000,
621
            attributes: 0,
622
            r#type: TDX_METADATA_SECTION_TYPE_TEMP_MEM,
623
        };
624
        // Payload
625
        sections[4] = TdxMetadataSection {
626
            data_offset: 0,
627
            raw_data_size: 0,
628
            memory_address: 0x1200000,
629
            memory_data_size: 0x8000000,
630
            attributes: 0,
631
            r#type: TDX_METADATA_SECTION_TYPE_PAYLOAD,
632
        };
633
        // PayloadParam
634
        sections[5] = TdxMetadataSection {
635
            data_offset: 0,
636
            raw_data_size: 0,
637
            memory_address: 0x1100000,
638
            memory_data_size: 0x100000,
639
            attributes: 0,
640
            r#type: TDX_METADATA_SECTION_TYPE_PAYLOAD_PARAM,
641
        };
642
        // TdInfo
643
        sections[6] = TdxMetadataSection {
644
            data_offset: 0,
645
            raw_data_size: 0x1000,
646
            memory_address: 0,
647
            memory_data_size: 0,
648
            attributes: 0,
649
            r#type: TDX_METADATA_SECTION_TYPE_TD_INFO,
650
        };
651
652
        assert!(validate_sections(&sections).is_ok());
653
654
        // test BFV
655
        // section.raw_data_size == 0
656
        sections[0].raw_data_size = 0;
657
        assert!(!validate_sections(&sections).is_ok());
658
        sections[0].raw_data_size = 0xf7e000;
659
        // section.attributes != TDX_METADATA_ATTRIBUTES_EXTENDMR
660
        sections[0].attributes = 0;
661
        assert!(!validate_sections(&sections).is_ok());
662
        sections[0].attributes = TDX_METADATA_ATTRIBUTES_EXTENDMR;
663
        // memory_data_size < raw_data_size
664
        sections[0].memory_data_size = sections[0].raw_data_size as u64 - 1;
665
        assert!(!validate_sections(&sections).is_ok());
666
        sections[0].memory_data_size += 1;
667
        // memory_address is not 4K align
668
        sections[0].memory_address += 1;
669
        assert!(!validate_sections(&sections).is_ok());
670
        sections[0].memory_address -= 1;
671
        // multiple CFV
672
        sections[3].r#type = TDX_METADATA_SECTION_TYPE_BFV;
673
        sections[3].attributes = TDX_METADATA_ATTRIBUTES_EXTENDMR;
674
        sections[3].raw_data_size = sections[3].memory_data_size as u32;
675
        assert!(validate_sections(&sections).is_ok());
676
        sections[3].r#type = TDX_METADATA_SECTION_TYPE_TEMP_MEM;
677
        sections[3].attributes = 0;
678
        sections[3].raw_data_size = 0;
679
680
        // test CFV
681
        // no CFV
682
        sections[1].r#type = TDX_METADATA_SECTION_TYPE_TEMP_MEM;
683
        sections[1].raw_data_size = 0;
684
        assert!(validate_sections(&sections).is_ok());
685
        sections[1].r#type = TDX_METADATA_SECTION_TYPE_CFV;
686
        // section.raw_data_size == 0
687
        assert!(!validate_sections(&sections).is_ok());
688
        sections[1].raw_data_size = 0x40000;
689
        // section.attributes != 0
690
        sections[1].attributes = 1;
691
        assert!(!validate_sections(&sections).is_ok());
692
        sections[1].attributes = 0;
693
        // memory_data_size < raw_data_size
694
        sections[1].memory_data_size = sections[1].raw_data_size as u64 - 1;
695
        assert!(!validate_sections(&sections).is_ok());
696
        sections[1].memory_data_size += 1;
697
        // memory_address is not 4K align
698
        sections[1].memory_address += 1;
699
        assert!(!validate_sections(&sections).is_ok());
700
        sections[1].memory_address -= 1;
701
        // multiple CFV
702
        sections[3].r#type = TDX_METADATA_SECTION_TYPE_CFV;
703
        sections[3].raw_data_size = sections[3].memory_data_size as u32;
704
        assert!(validate_sections(&sections).is_ok());
705
        sections[3].r#type = TDX_METADATA_SECTION_TYPE_TEMP_MEM;
706
        sections[3].raw_data_size = 0;
707
708
        // test TD HOB
709
        // no TD HOB and no PermMem
710
        sections[2].r#type = TDX_METADATA_SECTION_TYPE_TEMP_MEM;
711
        assert!(!validate_sections(&sections).is_ok());
712
        sections[2].r#type = TDX_METADATA_SECTION_TYPE_TD_HOB;
713
        // raw_data_size != 0
714
        sections[2].raw_data_size = 1;
715
        assert!(!validate_sections(&sections).is_ok());
716
        sections[2].raw_data_size = 0;
717
        // data_offset != 0
718
        sections[2].data_offset = 1;
719
        assert!(!validate_sections(&sections).is_ok());
720
        sections[2].data_offset = 0;
721
        // section.attributes != 0
722
        sections[2].attributes = 1;
723
        assert!(!validate_sections(&sections).is_ok());
724
        sections[2].attributes = 0;
725
        // memory_address is not 4K align
726
        sections[2].memory_address += 1;
727
        assert!(!validate_sections(&sections).is_ok());
728
        sections[2].memory_address -= 1;
729
        // multiple TD HOB
730
        sections[3].r#type = TDX_METADATA_SECTION_TYPE_TD_HOB;
731
        assert!(!validate_sections(&sections).is_ok());
732
        sections[3].r#type = TDX_METADATA_SECTION_TYPE_TEMP_MEM;
733
734
        // test TEMP MEM
735
        // no TEMP MEM already covered by upon test case
736
737
        // raw_data_size != 0
738
        sections[3].raw_data_size = 1;
739
        assert!(!validate_sections(&sections).is_ok());
740
        sections[3].raw_data_size = 0;
741
        // data_offset != 0
742
        sections[3].data_offset = 1;
743
        assert!(!validate_sections(&sections).is_ok());
744
        sections[3].data_offset = 0;
745
        // section.attributes != 0
746
        sections[3].attributes = 1;
747
        assert!(!validate_sections(&sections).is_ok());
748
        sections[3].attributes = 0;
749
        // memory_address is not 4K align
750
        sections[3].memory_address += 1;
751
        assert!(!validate_sections(&sections).is_ok());
752
        sections[3].memory_address -= 1;
753
        // multiple TEMP MEM already covered by CFV test
754
755
        // test PERM MEM
756
        // no TD HOB  one PERM MEM
757
        sections[2].r#type = TDX_METADATA_SECTION_TYPE_PERM_MEM;
758
        sections[2].attributes = TDX_METADATA_ATTRIBUTES_PAGE_AUG;
759
        assert!(validate_sections(&sections).is_ok());
760
        // raw_data_size != 0
761
        sections[2].raw_data_size = 1;
762
        assert!(!validate_sections(&sections).is_ok());
763
        sections[2].raw_data_size = 0;
764
        // data_offset != 0
765
        sections[2].data_offset = 1;
766
        assert!(!validate_sections(&sections).is_ok());
767
        sections[2].data_offset = 0;
768
        // section.attributes != 2
769
        sections[2].attributes = 0;
770
        assert!(!validate_sections(&sections).is_ok());
771
        sections[2].attributes = TDX_METADATA_ATTRIBUTES_EXTENDMR;
772
        assert!(!validate_sections(&sections).is_ok());
773
        sections[2].attributes = TDX_METADATA_ATTRIBUTES_PAGE_AUG;
774
        // memory_address is not 4K align
775
        sections[2].memory_address += 1;
776
        assert!(!validate_sections(&sections).is_ok());
777
        sections[2].memory_address -= 1;
778
        // both have TD HOB and PERM MEM
779
        sections[3].r#type = TDX_METADATA_SECTION_TYPE_TD_HOB;
780
        assert!(validate_sections(&sections).is_ok());
781
        sections[3].r#type = TDX_METADATA_SECTION_TYPE_TEMP_MEM;
782
        // multiple PERM MEM
783
        sections[3].r#type = TDX_METADATA_SECTION_TYPE_PERM_MEM;
784
        sections[3].attributes = TDX_METADATA_ATTRIBUTES_PAGE_AUG;
785
        assert!(validate_sections(&sections).is_ok());
786
        sections[3].r#type = TDX_METADATA_SECTION_TYPE_TEMP_MEM;
787
        sections[3].attributes = 0;
788
789
        // test PAYLAOD
790
        // no PAYLOAD but has PAYLOAD_PARAM
791
        sections[4].r#type = TDX_METADATA_SECTION_TYPE_TEMP_MEM;
792
        assert!(!validate_sections(&sections).is_ok());
793
        // no PAYLOAD and PAYLOAD_PARAM
794
        sections[5].r#type = TDX_METADATA_SECTION_TYPE_TEMP_MEM;
795
        assert!(validate_sections(&sections).is_ok());
796
        sections[4].r#type = TDX_METADATA_SECTION_TYPE_PAYLOAD;
797
        sections[5].r#type = TDX_METADATA_SECTION_TYPE_PAYLOAD_PARAM;
798
        // section.attributes == 1 means it is extended into MRTD
799
        sections[4].attributes = 1;
800
        assert!(validate_sections(&sections).is_ok());
801
        // section.attributes != 0 or 1
802
        sections[4].attributes = 2;
803
        assert!(!validate_sections(&sections).is_ok());
804
        sections[4].attributes = 0;
805
        // raw_data_size == 0 but data_offset != 0
806
        sections[4].data_offset = 1;
807
        assert!(!validate_sections(&sections).is_ok());
808
        sections[4].data_offset = 0;
809
        // memory_address is not 4K align
810
        sections[4].memory_address += 1;
811
        assert!(!validate_sections(&sections).is_ok());
812
        sections[4].memory_address -= 1;
813
        // multiple PAYLOAD
814
        sections[5].r#type = TDX_METADATA_SECTION_TYPE_PAYLOAD;
815
        assert!(!validate_sections(&sections).is_ok());
816
        sections[5].r#type = TDX_METADATA_SECTION_TYPE_PAYLOAD_PARAM;
817
818
        // test PAYLOAD_PARAM
819
        sections[5].r#type = TDX_METADATA_SECTION_TYPE_TEMP_MEM;
820
        assert!(validate_sections(&sections).is_ok());
821
        sections[5].r#type = TDX_METADATA_SECTION_TYPE_PAYLOAD_PARAM;
822
        // section.attributes != 0
823
        sections[5].attributes = 1;
824
        assert!(!validate_sections(&sections).is_ok());
825
        sections[5].attributes = 0;
826
        // memory_address is not 4K align
827
        sections[5].memory_address += 1;
828
        assert!(!validate_sections(&sections).is_ok());
829
        sections[5].memory_address -= 1;
830
        // multiple PAYLOAD_PARAM
831
        sections[3].r#type = TDX_METADATA_SECTION_TYPE_PAYLOAD_PARAM;
832
        assert!(!validate_sections(&sections).is_ok());
833
834
        // Invalid seciton type
835
        sections[5].r#type = TDX_METADATA_SECTION_TYPE_MAX;
836
        assert!(!validate_sections(&sections).is_ok());
837
    }
838
839
    #[test]
840
    fn test_tdxmetadataptr() {
841
        let ptr = TdxMetadataPtr { ptr: 0x1000 };
842
843
        assert_eq!(ptr.as_bytes(), 0x1000_i32.to_le_bytes())
844
    }
845
}