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, }); } }