td_shim_interface/
metadata.rs

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