From 346ca9733543c9ce68f1533c502a09bb092f3fc0 Mon Sep 17 00:00:00 2001 From: Jiaqi Gao Date: Thu, 9 May 2024 10:37:15 -0400 Subject: [PATCH 1/4] td-shim-interface: align `xxHeader2` types with `xxHeader` types Align the definition, implementation and derive of the `FfsFileHeader2` and `CommonSectionHeader2` with `FfsFileHeader` and `CommonSectionHeader`. Signed-off-by: Jiaqi Gao --- td-shim-interface/src/td_uefi_pi/pi/fv.rs | 57 ++++++++++++++--------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/td-shim-interface/src/td_uefi_pi/pi/fv.rs b/td-shim-interface/src/td_uefi_pi/pi/fv.rs index e4d8b578..30527247 100644 --- a/td-shim-interface/src/td_uefi_pi/pi/fv.rs +++ b/td-shim-interface/src/td_uefi_pi/pi/fv.rs @@ -30,7 +30,6 @@ //! Firmware file sections are separate discrete “parts” within certain file types. use core::mem::size_of; use core::ptr::slice_from_raw_parts; -use r_efi::efi::Guid; use scroll::{Pread, Pwrite}; pub type FvbAttributes2 = u32; @@ -267,10 +266,7 @@ impl FfsFileHeader { // Validate the checksum of the FfsFileHeader pub fn validate_checksum(&self) -> bool { - let sum = sum8(self.as_bytes()); - sum ^ ((EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID) - + FFS_FIXED_CHECKSUM) - == 0 + ffs_header_validate_checksum(self.as_bytes()) } } @@ -284,10 +280,10 @@ impl FfsFileHeader { /// Type field in the header, either EFI_FFS_FILE_HEADER or EFI_FFS_FILE_HEADER2. /// If the file length is bigger than 16MB, EFI_FFS_FILE_HEADER2 must be used. #[repr(C)] -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Pread, Pwrite, Default)] pub struct FfsFileHeader2 { - pub name: Guid, - pub integrity_check: u16, + pub name: [u8; 16], // Guid, + pub integrity_check: Checksum, pub r#type: FvFileType, pub attributes: FfsFileAttributes, pub size: [u8; 3], @@ -296,9 +292,33 @@ pub struct FfsFileHeader2 { } impl FfsFileHeader2 { + // Calculate and update the checksum of the FfsFileHeader + pub fn update_checksum(&mut self) { + // Clear the existing one before we calculate the checksum + self.integrity_check.header = 0; + self.integrity_check.file = 0; + self.state = 0; + self.integrity_check.header = (u8::MAX - sum8(self.as_bytes())).wrapping_add(1); + + self.integrity_check.file = FFS_FIXED_CHECKSUM; + self.state = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID; + } + pub fn as_bytes(&self) -> &[u8] { unsafe { &*slice_from_raw_parts(self as *const Self as *const u8, size_of::()) } } + + // Validate the checksum of the FfsFileHeader + pub fn validate_checksum(&self) -> bool { + ffs_header_validate_checksum(self.as_bytes()) + } +} + +fn ffs_header_validate_checksum(bytes: &[u8]) -> bool { + let sum = sum8(bytes); + sum ^ ((EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID) + + FFS_FIXED_CHECKSUM) + == 0 } /// Firmware File Section Types defined in [UEFI-PI], section 2.1.5.1 @@ -339,7 +359,7 @@ impl CommonSectionHeader { /// Section Header 2 for files larger than 16Mb, define in [UEFI-PI Spec] section 2.2.4 #[repr(C)] -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Pread, Pwrite, Default)] pub struct CommonSectionHeader2 { pub size: [u8; 3], pub r#type: SectionType, @@ -385,21 +405,16 @@ mod tests { header.update_checksum(); assert_eq!(header.integrity_check.header, 0x10); - assert!(header.validate_checksum()); + assert!(ffs_header_validate_checksum(header.as_bytes())); - header.name = *Guid::from_fields( - 0x00000001, - 0x0000, - 0x0000, - 0x00, - 0x00, - &[0x02, 0x00, 0x00, 0x00, 0x00, 0x01], - ) - .as_bytes(); - assert!(!header.validate_checksum()); + header.name = [ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x01, + ]; + assert!(!ffs_header_validate_checksum(header.as_bytes())); header.update_checksum(); assert_eq!(header.integrity_check.header, 0xC); - assert!(header.validate_checksum()); + assert!(ffs_header_validate_checksum(header.as_bytes())); } #[test] From 20375cd50cfec8ee93ab87b0f8a7f0ee63ce9abd Mon Sep 17 00:00:00 2001 From: Jiaqi Gao Date: Fri, 10 May 2024 01:41:51 -0400 Subject: [PATCH 2/4] td-shim-interface: support large ffs header and section header Add support for parsing ffs and sections that have size larger than 16MiB. Signed-off-by: Jiaqi Gao --- td-shim-interface/src/td_uefi_pi/fv.rs | 119 ++++++++++++++++++++----- 1 file changed, 97 insertions(+), 22 deletions(-) diff --git a/td-shim-interface/src/td_uefi_pi/fv.rs b/td-shim-interface/src/td_uefi_pi/fv.rs index 8c9f8797..c84df8e9 100644 --- a/td-shim-interface/src/td_uefi_pi/fv.rs +++ b/td-shim-interface/src/td_uefi_pi/fv.rs @@ -58,10 +58,10 @@ pub fn get_image_from_fv( let files = Files::parse(fv_data, fv_header.header_length as usize)?; for (file_header, file_data) in files { - if !validate_ffs_file_header(file_header) { + if !file_header.validate() { return None; } - if file_header.r#type == fv_file_type { + if file_header.r#type() == fv_file_type { return get_image_from_sections(file_data, section_type); } } @@ -78,10 +78,10 @@ pub fn get_file_from_fv( let files = Files::parse(fv_data, fv_header.header_length as usize)?; for (file_header, file_data) in files { - if !validate_ffs_file_header(file_header) { + if !file_header.validate() { return None; } - if file_header.r#type == fv_file_type && &file_header.name == file_name.as_bytes() { + if file_header.r#type() == fv_file_type && file_header.name() == file_name.as_bytes() { return Some(file_data); } } @@ -93,7 +93,7 @@ fn get_image_from_sections(sections_data: &[u8], section_type: SectionType) -> O let sections = Sections::parse(sections_data, 0)?; for (section_header, section_data) in sections { - if section_header.r#type == section_type { + if section_header.r#type() == section_type { return Some(section_data); } } @@ -101,6 +101,20 @@ fn get_image_from_sections(sections_data: &[u8], section_type: SectionType) -> O None } +enum CommonSectionHeaderType { + Header(CommonSectionHeader), + Header2(CommonSectionHeader2), +} + +impl CommonSectionHeaderType { + fn r#type(&self) -> FvFileType { + match self { + Self::Header(header) => header.r#type, + Self::Header2(header2) => header2.r#type, + } + } +} + struct Sections<'a> { buffer: &'a [u8], } @@ -118,17 +132,32 @@ impl<'a> Sections<'a> { } impl<'a> Iterator for Sections<'a> { - type Item = (CommonSectionHeader, &'a [u8]); + type Item = (CommonSectionHeaderType, &'a [u8]); fn next(&mut self) -> Option { - const HEADER_SIZE: usize = core::mem::size_of::(); let header: CommonSectionHeader = self.buffer.pread(0).ok()?; - let section_size = header.size[0] as usize - + ((header.size[1] as usize) << 8) - + ((header.size[2] as usize) << 16); - section_size.checked_sub(HEADER_SIZE)?; + let is_large_section = header.size == [0xff, 0xff, 0xff]; + + let (section_size, section_header, header_size) = if is_large_section { + let header2: CommonSectionHeader2 = self.buffer.pread(0).ok()?; + ( + header2.extended_size as usize, + CommonSectionHeaderType::Header2(header2), + core::mem::size_of::(), + ) + } else { + ( + header.size[0] as usize + + ((header.size[1] as usize) << 8) + + ((header.size[2] as usize) << 16), + CommonSectionHeaderType::Header(header), + core::mem::size_of::(), + ) + }; + + section_size.checked_sub(header_size)?; self.buffer.len().checked_sub(section_size)?; - let buf = &self.buffer[HEADER_SIZE..section_size]; + let buf = &self.buffer[header_size..section_size]; // Align to 4 bytes. let section_size = (section_size + 3) & !3; @@ -138,7 +167,39 @@ impl<'a> Iterator for Sections<'a> { self.buffer = &self.buffer[0..0]; } - Some((header, buf)) + Some((section_header, buf)) + } +} + +enum FfsFileHeaderType { + Header(FfsFileHeader), + Header2(FfsFileHeader2), +} + +impl FfsFileHeaderType { + fn r#type(&self) -> FvFileType { + match self { + FfsFileHeaderType::Header(header) => header.r#type, + FfsFileHeaderType::Header2(header2) => header2.r#type, + } + } + + fn name(&self) -> &[u8] { + match self { + FfsFileHeaderType::Header(header) => &header.name, + FfsFileHeaderType::Header2(header2) => &header2.name, + } + } + + // Validate Ffs File header + fn validate(&self) -> bool { + // Do the sanity check for Ffs header. + // Verify the header integrity, + // + match self { + FfsFileHeaderType::Header(header) => header.validate_checksum(), + FfsFileHeaderType::Header2(header2) => header2.validate_checksum(), + } } } @@ -159,18 +220,32 @@ impl<'a> Files<'a> { } impl<'a> Iterator for Files<'a> { - type Item = (FfsFileHeader, &'a [u8]); + type Item = (FfsFileHeaderType, &'a [u8]); fn next(&mut self) -> Option { - const HEADER_SIZE: usize = core::mem::size_of::(); - let header: FfsFileHeader = self.buffer.pread(0).ok()?; - let data_size = header.size[0] as usize - + ((header.size[1] as usize) << 8) - + ((header.size[2] as usize) << 16); - data_size.checked_sub(HEADER_SIZE)?; + let is_large_file = header.attributes & FFS_ATTRIB_LARGE_FILE != 0; + + let (data_size, ffs_header, header_size) = if is_large_file { + let header2: FfsFileHeader2 = self.buffer.pread(0).ok()?; + ( + header2.extended_size as usize, + FfsFileHeaderType::Header2(header2), + core::mem::size_of::(), + ) + } else { + ( + header.size[0] as usize + + ((header.size[1] as usize) << 8) + + ((header.size[2] as usize) << 16), + FfsFileHeaderType::Header(header), + core::mem::size_of::(), + ) + }; + + data_size.checked_sub(header_size)?; self.buffer.len().checked_sub(data_size)?; - let buf = &self.buffer[HEADER_SIZE..data_size]; + let buf = &self.buffer[header_size..data_size]; // Align to 8 bytes. let data_size = (data_size + 7) & !7; @@ -180,7 +255,7 @@ impl<'a> Iterator for Files<'a> { self.buffer = &self.buffer[0..0]; } - Some((header, buf)) + Some((ffs_header, buf)) } } From aa6f83f0d221a37cfcfc332fb5d3fef34b7f44a9 Mon Sep 17 00:00:00 2001 From: Jiaqi Gao Date: Fri, 10 May 2024 03:38:01 -0400 Subject: [PATCH 3/4] td-layout: support large payload Update the `td-layout` with `td-layout-config`. Signed-off-by: Jiaqi Gao --- td-layout/src/build_time.rs | 14 +++++++++----- td-layout/src/memslice.rs | 14 ++++++++++++-- td-layout/src/runtime/exec.rs | 5 +++++ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/td-layout/src/build_time.rs b/td-layout/src/build_time.rs index f05a9f9d..54c5bf76 100644 --- a/td-layout/src/build_time.rs +++ b/td-layout/src/build_time.rs @@ -7,6 +7,8 @@ /* Image Layout +----------------------------------------+ <- 0x0 +| LARGE_PAYLOAD | (0x0) 0 B ++----------------------------------------+ <- 0x0 | CONFIG | (0x40000) 256 kB +----------------------------------------+ <- 0x40000 | MAILBOX | (0x1000) 4 kB @@ -29,6 +31,10 @@ Image size: 0x1000000 (16 MB) */ // Image Layout Configuration +pub const TD_SHIM_FIRMWARE_SIZE: u32 = 0x1000000; + +pub const TD_SHIM_LARGE_PAYLOAD_OFFSET: u32 = 0x0; +pub const TD_SHIM_LARGE_PAYLOAD_SIZE: u32 = 0x0; // 0 B pub const TD_SHIM_CONFIG_OFFSET: u32 = 0x0; pub const TD_SHIM_CONFIG_SIZE: u32 = 0x40000; // 256 kB @@ -57,16 +63,14 @@ pub const TD_SHIM_IPL_SIZE: u32 = 0x349000; // 3.29 MB pub const TD_SHIM_RESET_VECTOR_OFFSET: u32 = 0xFF8000; pub const TD_SHIM_RESET_VECTOR_SIZE: u32 = 0x8000; // 32 kB -// Offset when Loading into Memory -pub const TD_SHIM_FIRMWARE_BASE: u32 = 0xFF000000; -pub const TD_SHIM_FIRMWARE_SIZE: u32 = 0x1000000; - // TD_SHIM_SEC_INFO_OFFSET equals to firmware size - metadata pointer offset - // OVMF GUID table size - SEC Core information size. pub const TD_SHIM_SEC_CORE_INFO_OFFSET: u32 = 0xFFFFAC; pub const TD_SHIM_SEC_CORE_INFO_BASE: u32 = 0xFFFFFFAC; -// Base Address after Loaded into Memory +// Rom Configuration + +pub const TD_SHIM_FIRMWARE_BASE: u32 = 0xFF000000; pub const TD_SHIM_CONFIG_BASE: u32 = 0xFF000000; pub const TD_SHIM_MAILBOX_BASE: u32 = 0xFF040000; pub const TD_SHIM_TEMP_STACK_BASE: u32 = 0xFF041000; diff --git a/td-layout/src/memslice.rs b/td-layout/src/memslice.rs index 120228d6..3251c4ca 100644 --- a/td-layout/src/memslice.rs +++ b/td-layout/src/memslice.rs @@ -2,7 +2,10 @@ // // SPDX-License-Identifier: BSD-2-Clause-Patent -use crate::build_time::*; +use crate::{ + build_time::*, + runtime::exec::{LARGE_PAYLOAD_BASE, LARGE_PAYLOAD_SIZE}, +}; use core::fmt::Display; /// Type of build time and runtime memory regions. @@ -16,6 +19,8 @@ pub enum SliceType { ShimPayload, /// The `TD_MAILBOX` region in image file MailBox, + /// The `Large PAYLOAD` region in runtime memory layout + LargePayload, /// The `PAYLOAD` region in runtime memory layout Payload, /// The `Kernel Parameter` region in runtime memory layout @@ -41,6 +46,7 @@ impl SliceType { SliceType::TdHob => "TdHob", SliceType::ShimPayload => "ShimPayload", SliceType::MailBox => "MailBox", + SliceType::LargePayload => "LargePayload", SliceType::Payload => "Payload", SliceType::PayloadParameter => "PayloadParameter", SliceType::PayloadHob => "PayloadHob", @@ -73,6 +79,10 @@ pub fn get_mem_slice<'a>(t: SliceType) -> &'a [u8] { TD_SHIM_PAYLOAD_BASE as *const u8, TD_SHIM_PAYLOAD_SIZE as usize, ), + SliceType::LargePayload => core::slice::from_raw_parts( + LARGE_PAYLOAD_BASE as *const u8, + LARGE_PAYLOAD_SIZE as usize, + ), SliceType::MailBox => core::slice::from_raw_parts( TD_SHIM_MAILBOX_BASE as *const u8, TD_SHIM_MAILBOX_SIZE as usize, @@ -94,7 +104,7 @@ pub unsafe fn get_mem_slice_mut<'a>(t: SliceType) -> &'a mut [u8] { TD_SHIM_MAILBOX_BASE as *const u8 as *mut u8, TD_SHIM_MAILBOX_SIZE as usize, ), - SliceType::Config | SliceType::ShimPayload => { + SliceType::Config | SliceType::ShimPayload | SliceType::LargePayload => { panic!("get_mem_slice_mut: read only") } _ => panic!("get_mem_slice_mut: not support"), diff --git a/td-layout/src/runtime/exec.rs b/td-layout/src/runtime/exec.rs index 789350bb..6affa7c2 100644 --- a/td-layout/src/runtime/exec.rs +++ b/td-layout/src/runtime/exec.rs @@ -20,6 +20,8 @@ Top of Low Memory: 0x80000000 +----------------------------------------+ <- 0x7DDDE000 | FREE | (0x7D5BE000) 1.96 GB +----------------------------------------+ <- 0x820000 +| LARGE_PAYLOAD | (0x0) 0 B ++----------------------------------------+ <- 0x820000 | TD_HOB | (0x20000) 128 kB +----------------------------------------+ <- 0x800000 | BOOTLOADER | (0x800000) 8 MB @@ -34,6 +36,8 @@ pub const BOOTLOADER_BASE: usize = 0x0; pub const BOOTLOADER_SIZE: usize = 0x800000; // 8 MB pub const TD_HOB_BASE: usize = 0x800000; pub const TD_HOB_SIZE: usize = 0x20000; // 128 kB +pub const LARGE_PAYLOAD_BASE: usize = 0x820000; +pub const LARGE_PAYLOAD_SIZE: usize = 0x0; // 0 B pub const ACPI_SIZE: usize = 0x100000; // 1 MB pub const PAYLOAD_SIZE: usize = 0x2000000; // 32 MB pub const PAYLOAD_PAGE_TABLE_SIZE: usize = 0x20000; // 128 kB @@ -44,6 +48,7 @@ pub const MEMORY_LAYOUT_CONFIG: &[(&'static str, usize, &'static str)] = &[ // (name of memory region, region size, region type) ("Bootloader", 0x800000, "Memory"), ("TdHob", 0x20000, "Memory"), + ("LargePayload", 0x0, "Memory"), ("Acpi", 0x100000, "Acpi"), ("Payload", 0x2000000, "Reserved"), ("PayloadPageTable", 0x20000, "Reserved"), From 6efea8cb3ea52f18cb82a90a8aafe6e504e0acc0 Mon Sep 17 00:00:00 2001 From: Jiaqi Gao Date: Fri, 10 May 2024 03:56:49 -0400 Subject: [PATCH 4/4] td-shim-tools: support large payload Use `FfsFileHeader2` and `CommonSectionHeader2` for payload FV. If payload binary is larger than the `Payload` region size, then it will be treated as a large payload and it will be packaged in the start of the image and loaded into physical memory as indicated by metadata. Signed-off-by: Jiaqi Gao --- td-shim-tools/src/linker.rs | 233 ++++++++++++++++++++-------------- td-shim-tools/src/metadata.rs | 57 ++++++--- 2 files changed, 180 insertions(+), 110 deletions(-) diff --git a/td-shim-tools/src/linker.rs b/td-shim-tools/src/linker.rs index 0b6a3b49..3929f3c8 100644 --- a/td-shim-tools/src/linker.rs +++ b/td-shim-tools/src/linker.rs @@ -10,9 +10,10 @@ use log::trace; use r_efi::base::Guid; use scroll::Pwrite; use td_layout::build_time::{ - TD_SHIM_FIRMWARE_BASE, TD_SHIM_FIRMWARE_SIZE, TD_SHIM_IPL_OFFSET, TD_SHIM_IPL_SIZE, - TD_SHIM_MAILBOX_OFFSET, TD_SHIM_METADATA_OFFSET, TD_SHIM_PAYLOAD_BASE, TD_SHIM_PAYLOAD_OFFSET, - TD_SHIM_PAYLOAD_SIZE, TD_SHIM_RESET_VECTOR_SIZE, TD_SHIM_SEC_CORE_INFO_OFFSET, + TD_SHIM_FIRMWARE_SIZE, TD_SHIM_IPL_BASE, TD_SHIM_IPL_OFFSET, TD_SHIM_IPL_SIZE, + TD_SHIM_LARGE_PAYLOAD_OFFSET, TD_SHIM_LARGE_PAYLOAD_SIZE, TD_SHIM_MAILBOX_OFFSET, + TD_SHIM_METADATA_OFFSET, TD_SHIM_PAYLOAD_BASE, TD_SHIM_PAYLOAD_OFFSET, TD_SHIM_PAYLOAD_SIZE, + TD_SHIM_RESET_VECTOR_OFFSET, TD_SHIM_RESET_VECTOR_SIZE, TD_SHIM_SEC_CORE_INFO_OFFSET, }; use td_layout::mailbox::TdxMpWakeupMailbox; use td_loader::{elf, pe}; @@ -24,8 +25,8 @@ use td_shim::reset_vector::{ResetVectorHeader, ResetVectorParams}; use td_shim::write_u24; use td_shim_interface::metadata::{TdxMetadataGuid, TdxMetadataPtr}; use td_shim_interface::td_uefi_pi::pi::fv::{ - FfsFileHeader, FVH_REVISION, FVH_SIGNATURE, FV_FILETYPE_DXE_CORE, FV_FILETYPE_SECURITY_CORE, - SECTION_PE32, + CommonSectionHeader2, FfsFileHeader, FfsFileHeader2, FFS_ATTRIB_LARGE_FILE, FVH_REVISION, + FVH_SIGNATURE, FV_FILETYPE_DXE_CORE, FV_FILETYPE_SECURITY_CORE, SECTION_PE32, }; use crate::metadata::{default_metadata_sections, MetadataSections, TdxMetadata}; @@ -33,8 +34,6 @@ use crate::{InputData, OutputFile}; pub const MAX_IPL_CONTENT_SIZE: usize = TD_SHIM_IPL_SIZE as usize - size_of::() - size_of::(); -pub const MAX_PAYLOAD_CONTENT_SIZE: usize = - TD_SHIM_PAYLOAD_SIZE as usize - size_of::(); pub const MAX_METADATA_CONFIG_SIZE: usize = 1024 * 1024; pub const OVMF_TABLE_FOOTER_GUID: Guid = Guid::from_fields( @@ -73,80 +72,6 @@ impl Default for FvHeaderByte { } impl FvHeaderByte { - pub fn build_tdx_payload_fv_header() -> Self { - let mut hdr = Self::default(); - let fv_header_size = (size_of::()) as usize; - - let mut tdx_payload_fv_header = FvHeader::default(); - tdx_payload_fv_header.fv_header.fv_length = TD_SHIM_PAYLOAD_SIZE as u64; - tdx_payload_fv_header.fv_header.signature = FVH_SIGNATURE; - tdx_payload_fv_header.fv_header.header_length = size_of::() as u16; - tdx_payload_fv_header.fv_header.revision = FVH_REVISION; - tdx_payload_fv_header.fv_header.update_checksum(); - - tdx_payload_fv_header.fv_block_map[0].num_blocks = (TD_SHIM_PAYLOAD_SIZE as u32) / 0x1000; - tdx_payload_fv_header.fv_block_map[0].length = 0x1000; - tdx_payload_fv_header.fv_ext_header.fv_name.copy_from_slice( - Guid::from_fields( - 0x7cb8bdc9, - 0xf8eb, - 0x4f34, - 0xaa, - 0xea, - &[0x3e, 0xe4, 0xaf, 0x65, 0x16, 0xa1], - ) - .as_bytes(), - ); - tdx_payload_fv_header.fv_ext_header.ext_header_size = 0x14; - // Safe to unwrap() because space is enough. - let res = hdr.data.pwrite(tdx_payload_fv_header, 0).unwrap(); - assert_eq!(res, 120); - - let mut tdx_payload_fv_ffs_header = FvFfsFileHeader::default(); - tdx_payload_fv_ffs_header.ffs_header.name.copy_from_slice( - Guid::from_fields( - 0xa8f75d7c, - 0x8b85, - 0x49b6, - 0x91, - 0x3e, - &[0xaf, 0x99, 0x61, 0x55, 0x73, 0x08], - ) - .as_bytes(), - ); - tdx_payload_fv_ffs_header.ffs_header.r#type = FV_FILETYPE_DXE_CORE; - tdx_payload_fv_ffs_header.ffs_header.attributes = 0x00; - write_u24( - TD_SHIM_PAYLOAD_SIZE - fv_header_size as u32, - &mut tdx_payload_fv_ffs_header.ffs_header.size, - ); - tdx_payload_fv_ffs_header.ffs_header.update_checksum(); - // Safe to unwrap() because space is enough. - let res = hdr - .data - .pwrite(tdx_payload_fv_ffs_header, fv_header_size) - .unwrap(); - assert_eq!(res, 24); - - let mut tdx_payload_fv_ffs_section_header = FvFfsSectionHeader::default(); - write_u24( - TD_SHIM_PAYLOAD_SIZE - fv_header_size as u32 - size_of::() as u32, - &mut tdx_payload_fv_ffs_section_header.section_header.size, - ); - tdx_payload_fv_ffs_section_header.section_header.r#type = SECTION_PE32; - // Safe to unwrap() because space is enough. - let res = hdr - .data - .pwrite( - tdx_payload_fv_ffs_section_header, - fv_header_size + size_of::(), - ) - .unwrap(); - assert_eq!(res, 4); - - hdr - } - // Build internal payload header pub fn build_tdx_ipl_fv_header() -> Self { let mut hdr = Self::default(); @@ -222,19 +147,117 @@ impl FvHeaderByte { } } -pub type PayloadFvHeaderByte = FvHeaderByte; +#[repr(C, align(4))] +pub struct FvHeader2Byte { + pub data: [u8; size_of::() + + size_of::() + + size_of::()], +} + +impl Default for FvHeader2Byte { + fn default() -> Self { + Self { + data: [0u8; size_of::() + + size_of::() + + size_of::()], + } + } +} + +impl FvHeader2Byte { + pub fn build_tdx_payload_fv_header(is_large_payload: bool) -> Self { + let mut hdr = Self::default(); + let fv_header_size = (size_of::()) as usize; + + let mut tdx_payload_fv_header = FvHeader::default(); + let payload_region_size = if is_large_payload { + TD_SHIM_LARGE_PAYLOAD_SIZE + } else { + TD_SHIM_PAYLOAD_SIZE + }; + tdx_payload_fv_header.fv_header.fv_length = payload_region_size as u64; + tdx_payload_fv_header.fv_header.signature = FVH_SIGNATURE; + tdx_payload_fv_header.fv_header.header_length = size_of::() as u16; + tdx_payload_fv_header.fv_header.revision = FVH_REVISION; + tdx_payload_fv_header.fv_header.update_checksum(); + + tdx_payload_fv_header.fv_block_map[0].num_blocks = payload_region_size / 0x1000; + tdx_payload_fv_header.fv_block_map[0].length = 0x1000; + tdx_payload_fv_header.fv_ext_header.fv_name.copy_from_slice( + Guid::from_fields( + 0x7cb8bdc9, + 0xf8eb, + 0x4f34, + 0xaa, + 0xea, + &[0x3e, 0xe4, 0xaf, 0x65, 0x16, 0xa1], + ) + .as_bytes(), + ); + tdx_payload_fv_header.fv_ext_header.ext_header_size = 0x14; + // Safe to unwrap() because space is enough. + let res = hdr.data.pwrite(tdx_payload_fv_header, 0).unwrap(); + assert_eq!(res, 120); + + let mut tdx_payload_fv_ffs_header = FfsFileHeader2::default(); + tdx_payload_fv_ffs_header.name.copy_from_slice( + Guid::from_fields( + 0xa8f75d7c, + 0x8b85, + 0x49b6, + 0x91, + 0x3e, + &[0xaf, 0x99, 0x61, 0x55, 0x73, 0x08], + ) + .as_bytes(), + ); + tdx_payload_fv_ffs_header.r#type = FV_FILETYPE_DXE_CORE; + tdx_payload_fv_ffs_header.attributes = FFS_ATTRIB_LARGE_FILE; + tdx_payload_fv_ffs_header.extended_size = + payload_region_size as u32 - fv_header_size as u32; + tdx_payload_fv_ffs_header.update_checksum(); + // Safe to unwrap() because space is enough. + let res = hdr + .data + .pwrite(tdx_payload_fv_ffs_header, fv_header_size) + .unwrap(); + assert_eq!(res, 28); + + let mut tdx_payload_fv_ffs_section_header = CommonSectionHeader2::default(); + tdx_payload_fv_ffs_section_header + .size + .copy_from_slice(&[0xff, 0xff, 0xff]); + tdx_payload_fv_ffs_section_header.extended_size = + TD_SHIM_PAYLOAD_SIZE - fv_header_size as u32 - size_of::() as u32; + tdx_payload_fv_ffs_section_header.r#type = SECTION_PE32; + // Safe to unwrap() because space is enough. + let res = hdr + .data + .pwrite( + tdx_payload_fv_ffs_section_header, + fv_header_size + size_of::(), + ) + .unwrap(); + assert_eq!(res, 8); + + hdr + } +} + +pub type PayloadFvHeaderByte = FvHeader2Byte; pub type IplFvHeaderByte = FvHeaderByte; pub fn build_tdx_metadata( path: Option<&str>, payload_type: PayloadType, + is_large_payload: bool, ) -> io::Result { let sections = if let Some(path) = path { let metadata_config = fs::read(path)?; serde_json::from_slice::(metadata_config.as_slice()) .map_err(|e| io::Error::new(io::ErrorKind::Other, e))? } else { - default_metadata_sections(payload_type) + default_metadata_sections(payload_type, is_large_payload) }; TdxMetadata::new(sections).ok_or(io::Error::new( @@ -361,18 +384,33 @@ impl TdShimLinker { "mailbox content", )?; + let mut is_large_payload = false; if let Some(payload_name) = payload_name { - let payload_bin = - InputData::new(payload_name, 0..=MAX_PAYLOAD_CONTENT_SIZE, "payload")?; - let payload_header = PayloadFvHeaderByte::build_tdx_payload_fv_header(); + let max_payload_size = core::cmp::max(TD_SHIM_PAYLOAD_SIZE, TD_SHIM_LARGE_PAYLOAD_SIZE) + as usize + - size_of::(); + let payload_bin = InputData::new(payload_name, 0..=max_payload_size, "payload")?; + is_large_payload = payload_bin.as_bytes().len() > TD_SHIM_PAYLOAD_SIZE as usize; + + // If the payload image size greater than the size of payload region, it will be loaded + // into the large payload region. + // is_large_payload = payload_bin.as_bytes().len() + // > TD_SHIM_PAYLOAD_SIZE as usize - size_of::(); + let payload_offset = if is_large_payload { + TD_SHIM_LARGE_PAYLOAD_OFFSET + } else { + TD_SHIM_PAYLOAD_OFFSET + }; + + let payload_header = PayloadFvHeaderByte::build_tdx_payload_fv_header(is_large_payload); output_file.seek_and_write( - TD_SHIM_PAYLOAD_OFFSET as u64, + payload_offset as u64, &payload_header.data, "payload header", )?; if self.payload_relocation { - let mut payload_reloc_buf = vec![0x0u8; MAX_PAYLOAD_CONTENT_SIZE]; + let mut payload_reloc_buf = vec![0x0u8; max_payload_size]; let reloc = pe::relocate( &payload_bin.data, &mut payload_reloc_buf, @@ -386,9 +424,9 @@ impl TdShimLinker { } else { output_file.write(&payload_bin.data, "payload content")?; } - } + }; - let metadata = build_tdx_metadata(metadata_name, self.payload_type)?; + let metadata = build_tdx_metadata(metadata_name, self.payload_type, is_large_payload)?; let pos = TD_SHIM_METADATA_OFFSET as u64; output_file.seek_and_write(pos, &metadata.to_vec(), "metadata")?; @@ -409,18 +447,25 @@ impl TdShimLinker { 0x100000 ); let entry_point = (reloc.0 - 0x100000) as u32; - let current_pos = output_file.current_pos()?; let reset_vector_info = ResetVectorParams { entry_point, - img_base: TD_SHIM_FIRMWARE_BASE + current_pos as u32, + img_base: TD_SHIM_IPL_BASE + size_of::() as u32, img_size: ipl_bin.data.len() as u32, }; output_file.write(&ipl_reloc_buf, "internal payload content")?; let reset_vector_header = ResetVectorHeader::build_tdx_reset_vector_header(); - output_file.write(reset_vector_header.as_bytes(), "reset vector header")?; - output_file.write(&reset_vector_bin.data, "reset vector content")?; + output_file.seek_and_write( + TD_SHIM_RESET_VECTOR_OFFSET as u64 - size_of::() as u64, + reset_vector_header.as_bytes(), + "reset vector header", + )?; + output_file.seek_and_write( + TD_SHIM_RESET_VECTOR_OFFSET as u64, + &reset_vector_bin.data, + "reset vector content", + )?; let current_pos = output_file.current_pos()?; assert_eq!(current_pos, TD_SHIM_FIRMWARE_SIZE as u64); diff --git a/td-shim-tools/src/metadata.rs b/td-shim-tools/src/metadata.rs index ab1c5ad5..ce3dd5f1 100644 --- a/td-shim-tools/src/metadata.rs +++ b/td-shim-tools/src/metadata.rs @@ -6,13 +6,15 @@ use serde::de::Error; use serde::{de, Deserialize}; use std::{mem::size_of, vec::Vec}; use td_layout::build_time::*; +use td_layout::runtime::exec::LARGE_PAYLOAD_BASE; use td_layout::runtime::*; use td_shim_interface::metadata::{ - TdxMetadataDescriptor, TDX_METADATA_GUID, TDX_METADATA_SECTION_TYPE_BFV, - TDX_METADATA_SECTION_TYPE_CFV, TDX_METADATA_SECTION_TYPE_PAYLOAD, - TDX_METADATA_SECTION_TYPE_PAYLOAD_PARAM, TDX_METADATA_SECTION_TYPE_PERM_MEM, - TDX_METADATA_SECTION_TYPE_TD_HOB, TDX_METADATA_SECTION_TYPE_TD_INFO, - TDX_METADATA_SECTION_TYPE_TEMP_MEM, TDX_METADATA_SIGNATURE, TDX_METADATA_VERSION, + TdxMetadataDescriptor, TDX_METADATA_ATTRIBUTES_EXTENDMR, TDX_METADATA_GUID, + TDX_METADATA_SECTION_TYPE_BFV, TDX_METADATA_SECTION_TYPE_CFV, + TDX_METADATA_SECTION_TYPE_PAYLOAD, TDX_METADATA_SECTION_TYPE_PAYLOAD_PARAM, + TDX_METADATA_SECTION_TYPE_PERM_MEM, TDX_METADATA_SECTION_TYPE_TD_HOB, + TDX_METADATA_SECTION_TYPE_TD_INFO, TDX_METADATA_SECTION_TYPE_TEMP_MEM, TDX_METADATA_SIGNATURE, + TDX_METADATA_VERSION, }; use td_shim_interface::td_uefi_pi::pi::guid::Guid; @@ -101,8 +103,6 @@ impl MetadataSections { } fn basic_metadata_sections(payload_type: PayloadType) -> MetadataSections { - use td_shim_interface::metadata::TDX_METADATA_ATTRIBUTES_EXTENDMR; - let mut metadata_sections = MetadataSections::new(); // BFV @@ -182,7 +182,10 @@ fn basic_metadata_sections(payload_type: PayloadType) -> MetadataSections { metadata_sections } -pub fn default_metadata_sections(payload_type: PayloadType) -> MetadataSections { +pub fn default_metadata_sections( + payload_type: PayloadType, + is_large_payload: bool, +) -> MetadataSections { let mut metadata_sections = basic_metadata_sections(payload_type); if payload_type == PayloadType::Linux { @@ -226,16 +229,38 @@ pub fn default_metadata_sections(payload_type: PayloadType) -> MetadataSections attributes: 0, }); - if cfg!(feature = "exec-payload-section") { - println!("default_metadata_sections_exec_payload"); + if cfg!(feature = "exec-payload-section") || is_large_payload { + let (data_offset, raw_data_size, memory_address) = if is_large_payload { + ( + TD_SHIM_LARGE_PAYLOAD_OFFSET, + TD_SHIM_LARGE_PAYLOAD_SIZE, + LARGE_PAYLOAD_BASE as u64, + ) + } else { + ( + TD_SHIM_PAYLOAD_OFFSET, + TD_SHIM_PAYLOAD_SIZE, + TD_SHIM_PAYLOAD_BASE as u64, + ) + }; + + let (r#type, attributes) = if cfg!(feature = "exec-payload-section") { + (TDX_METADATA_SECTION_TYPE_PAYLOAD, 0) + } else { + ( + TDX_METADATA_SECTION_TYPE_BFV, + TDX_METADATA_ATTRIBUTES_EXTENDMR, + ) + }; + // payload image metadata_sections.add(TdxMetadataSection { - data_offset: TD_SHIM_PAYLOAD_OFFSET, - raw_data_size: TD_SHIM_PAYLOAD_SIZE, - memory_address: TD_SHIM_PAYLOAD_BASE as u64, - memory_data_size: TD_SHIM_PAYLOAD_SIZE as u64, - r#type: TDX_METADATA_SECTION_TYPE_PAYLOAD, - attributes: 0, + data_offset, + raw_data_size, + memory_address, + memory_data_size: raw_data_size as u64, + r#type, + attributes, }); } }