From fa964f68d65c2e61d6ab8be23d7cbec19397f720 Mon Sep 17 00:00:00 2001 From: haowx Date: Fri, 18 Mar 2022 01:58:40 +0800 Subject: [PATCH] td-shim: Migration acpi event_log fv reset_vector and secure_boot files Signed-off-by: haowx --- td-shim/src/acpi.rs | 187 ++++++++++++++++++++++++ td-shim/src/event_log.rs | 274 ++++++++++++++++++++++++++++++++++++ td-shim/src/fv.rs | 104 ++++++++++++++ td-shim/src/lib.rs | 102 ++++++++++++++ td-shim/src/reset_vector.rs | 83 +++++++++++ td-shim/src/secure_boot.rs | 96 +++++++++++++ 6 files changed, 846 insertions(+) create mode 100644 td-shim/src/acpi.rs create mode 100644 td-shim/src/event_log.rs create mode 100644 td-shim/src/fv.rs create mode 100644 td-shim/src/reset_vector.rs create mode 100644 td-shim/src/secure_boot.rs diff --git a/td-shim/src/acpi.rs b/td-shim/src/acpi.rs new file mode 100644 index 00000000..d0d2ef8a --- /dev/null +++ b/td-shim/src/acpi.rs @@ -0,0 +1,187 @@ +// Copyright (c) 2021 Intel Corporation +// Copyright (c) 2022 Alibaba Cloud +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +use core::mem::size_of; +use zerocopy::{AsBytes, FromBytes}; + +pub const ACPI_TABLES_MAX_NUM: usize = 20; +pub const ACPI_RSDP_REVISION: u8 = 2; + +pub fn calculate_checksum(data: &[u8]) -> u8 { + (255 - data.iter().fold(0u8, |acc, x| acc.wrapping_add(*x))).wrapping_add(1) +} + +#[repr(packed)] +#[derive(Default, AsBytes, FromBytes)] +pub struct Rsdp { + pub signature: [u8; 8], + pub checksum: u8, + pub oem_id: [u8; 6], + pub revision: u8, + pub _rsdt_addr: u32, + pub length: u32, + pub xsdt_addr: u64, + pub extended_checksum: u8, + pub _reserved: [u8; 3], +} + +impl Rsdp { + pub fn new(xsdt_addr: u64) -> Rsdp { + let mut rsdp = Rsdp { + signature: *b"RSD PTR ", + checksum: 0, + oem_id: *b"INTEL ", + revision: ACPI_RSDP_REVISION, + length: size_of::() as u32, + xsdt_addr, + ..Default::default() + }; + rsdp.checksum(); + rsdp + } + + pub fn set_xsdt(&mut self, xsdt: u64) { + self.xsdt_addr = xsdt; + self.checksum(); + } + + fn checksum(&mut self) { + self.checksum = 0; + self.extended_checksum = 0; + self.checksum = calculate_checksum(&self.as_bytes()[0..20]); + self.extended_checksum = calculate_checksum(self.as_bytes()); + } +} + +#[repr(C, packed)] +#[derive(Default, AsBytes, FromBytes)] +pub struct GenericSdtHeader { + pub signature: [u8; 4], + pub length: u32, + pub revision: u8, + pub checksum: u8, + pub oem_id: [u8; 6], + pub oem_table_id: u64, + pub oem_revision: u32, + pub creator_id: u32, + pub creator_revision: u32, +} + +impl GenericSdtHeader { + pub fn new(signature: &[u8; 4], length: u32, revision: u8) -> Self { + GenericSdtHeader { + signature: *signature, + length, + revision, + checksum: 0, + oem_id: *b"INTEL ", + oem_table_id: u64::from_le_bytes(*b"SHIM "), + oem_revision: 1, + creator_id: u32::from_le_bytes(*b"SHIM"), + creator_revision: 1, + } + } + + pub fn set_checksum(&mut self, checksum: u8) { + self.checksum = checksum; + } +} + +#[repr(C, packed)] +#[derive(Default, AsBytes, FromBytes)] +pub struct Xsdt { + pub header: GenericSdtHeader, + pub tables: [u64; ACPI_TABLES_MAX_NUM], +} + +impl Xsdt { + pub fn new() -> Self { + Xsdt { + header: GenericSdtHeader::new(b"XSDT", size_of::() as u32, 1), + tables: [0; ACPI_TABLES_MAX_NUM], + } + } + + pub fn add_table(&mut self, addr: u64) { + let table_num = + (self.header.length as usize - size_of::()) / size_of::(); + if table_num < ACPI_TABLES_MAX_NUM { + self.tables[table_num] = addr as u64; + self.header.length += size_of::() as u32; + } else { + log::error!("too many ACPI tables, max {}", ACPI_TABLES_MAX_NUM); + } + } + + pub fn checksum(&mut self) { + self.header.set_checksum(0); + self.header.set_checksum(calculate_checksum( + &self.as_bytes()[..self.header.length as usize], + )); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_calculate_checksum() { + let mut buf = [0xac; 8]; + buf[7] = 0; + buf[7] = calculate_checksum(&buf); + let sum = buf.iter().fold(0u8, |s, v| s.wrapping_add(*v)); + assert_eq!(sum, 0); + + buf[3] = 0xcd; + buf[6] = 0x1c; + buf[4] = 0; + buf[4] = calculate_checksum(&buf); + let sum = buf.iter().fold(0u8, |s, v| s.wrapping_add(*v)); + assert_eq!(sum, 0); + } + + #[test] + fn test_rsdp() { + let mut rsdp = Rsdp::new(0xabcd1234); + let sum = rsdp.as_bytes()[0..20] + .iter() + .fold(0u8, |s, v| s.wrapping_add(*v)); + assert_eq!(sum, 0); + let sum = rsdp.as_bytes().iter().fold(0u8, |s, v| s.wrapping_add(*v)); + assert_eq!(sum, 0); + + rsdp.set_xsdt(0xdeadbeaf); + let sum = rsdp.as_bytes()[0..20] + .iter() + .fold(0u8, |s, v| s.wrapping_add(*v)); + assert_eq!(sum, 0); + let sum = rsdp.as_bytes().iter().fold(0u8, |s, v| s.wrapping_add(*v)); + assert_eq!(sum, 0); + } + + #[test] + fn test_xsdt() { + let mut xsdt = Xsdt::new(); + assert_eq!(xsdt.header.length as usize, size_of::()); + for idx in 0..ACPI_TABLES_MAX_NUM { + xsdt.add_table(idx as u64); + assert_eq!( + xsdt.header.length as usize, + size_of::() + (idx + 1) * 8 + ); + } + + xsdt.add_table(100); + assert_eq!( + xsdt.header.length as usize, + size_of::() + ACPI_TABLES_MAX_NUM * 8 + ); + xsdt.add_table(101); + assert_eq!( + xsdt.header.length as usize, + size_of::() + ACPI_TABLES_MAX_NUM * 8 + ); + } +} diff --git a/td-shim/src/event_log.rs b/td-shim/src/event_log.rs new file mode 100644 index 00000000..3d1a423b --- /dev/null +++ b/td-shim/src/event_log.rs @@ -0,0 +1,274 @@ +// Copyright (c) 2020 Intel Corporation +// Copyright (c) 2022 Alibaba Cloud +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +use core::mem::size_of; + +use scroll::{ctx, Endian, Pread, Pwrite}; +use zerocopy::{AsBytes, FromBytes}; + +use crate::acpi::{calculate_checksum, GenericSdtHeader}; + +pub const SHA384_DIGEST_SIZE: usize = 48; +pub const TPML_ALG_SHA384: u16 = 0xc; +pub const TPML_DIGEST_VALUES_PACKED_SIZE: usize = 54; +pub const PCR_DIGEST_NUM: usize = 1; +pub const PCR_EVENT_HEADER_SIZE: usize = 66; + +pub const EV_EFI_EVENT_BASE: u32 = 0x80000000; +pub const EV_PLATFORM_CONFIG_FLAGS: u32 = EV_EFI_EVENT_BASE + 0x0000000A; +pub const EV_EFI_HANDOFF_TABLES2: u32 = EV_EFI_EVENT_BASE + 0xB; + +#[repr(C)] +#[derive(Default, Debug, Pread, Pwrite, AsBytes, FromBytes)] +pub struct Guid { + pub data1: u32, + pub data2: u32, + pub data3: u32, + pub data4: u32, +} + +pub const TD_LOG_EFI_HANDOFF_TABLE_GUID: Guid = Guid { + data1: 0xf706dd8f, + data2: 0x11e9eebe, + data3: 0xa7e41499, + data4: 0x51e6daa0, +}; + +#[repr(C)] +#[derive(Default, Debug, Pread, Pwrite)] +pub struct TdHandoffTable { + pub guid: Guid, + pub table: u64, // should be usize, usize can't be derived by pwrite, but tdx only support 64bit +} + +#[repr(C)] +#[derive(Default, Debug, Pwrite)] +pub struct TdHandoffTablePointers { + pub table_descripion_size: u8, + pub table_description: [u8; 8], + pub number_of_tables: u64, + pub table_entry: [TdHandoffTable; 1], +} + +#[repr(C)] +#[derive(Debug)] +pub struct TpmuHa { + pub sha384: [u8; SHA384_DIGEST_SIZE], +} + +impl Default for TpmuHa { + fn default() -> Self { + TpmuHa { + sha384: [0; SHA384_DIGEST_SIZE], + } + } +} + +impl<'a> ctx::TryFromCtx<'a, Endian> for TpmuHa { + type Error = scroll::Error; + + fn try_from_ctx(src: &'a [u8], _endian: Endian) -> Result<(Self, usize), Self::Error> { + let mut sha384: [u8; SHA384_DIGEST_SIZE] = [0; SHA384_DIGEST_SIZE]; + sha384.copy_from_slice(&src[0..SHA384_DIGEST_SIZE]); + Ok((TpmuHa { sha384 }, sha384.len())) + } +} + +impl ctx::TryIntoCtx for &TpmuHa { + type Error = scroll::Error; + + fn try_into_ctx(self, this: &mut [u8], _endian: Endian) -> Result { + if this.len() < SHA384_DIGEST_SIZE { + return Err(scroll::Error::BadOffset(SHA384_DIGEST_SIZE)); + } + + this[0..SHA384_DIGEST_SIZE].copy_from_slice(&self.sha384); + Ok(SHA384_DIGEST_SIZE) + } +} + +#[repr(C)] +#[derive(Default, Debug, Pread, Pwrite)] +pub struct TpmtHa { + pub hash_alg: u16, + pub digest: TpmuHa, +} + +#[repr(C)] +#[derive(Default, Debug)] +pub struct TpmlDigestValues { + pub count: u32, + pub digests: [TpmtHa; PCR_DIGEST_NUM], +} + +impl<'a> ctx::TryFromCtx<'a, Endian> for TpmlDigestValues { + type Error = scroll::Error; + + fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { + let offset = &mut 0; + let count = src.gread_with::(offset, endian)?; + let mut digests: [TpmtHa; PCR_DIGEST_NUM] = [TpmtHa::default(); PCR_DIGEST_NUM]; + src.gread_inout_with(offset, &mut digests, endian)?; + + Ok((TpmlDigestValues { count, digests }, *offset)) + } +} + +impl ctx::TryIntoCtx for &TpmlDigestValues { + type Error = scroll::Error; + + fn try_into_ctx(self, this: &mut [u8], endian: Endian) -> Result { + let type_size = TPML_DIGEST_VALUES_PACKED_SIZE; + if this.len() < type_size { + return Err(scroll::Error::BadOffset(type_size)); + } + + let offset = &mut 0; + this.gwrite_with::(self.count, offset, endian)?; + for index in 0..PCR_DIGEST_NUM { + this.gwrite_with::<&TpmtHa>(&self.digests[index], offset, endian)?; + } + + Ok(*offset) + } +} + +#[repr(C)] +#[derive(Default, Debug, Pread, Pwrite)] +pub struct TcgPcrEvent2Header { + pub pcr_index: u32, + pub event_type: u32, + pub digest: TpmlDigestValues, + pub event_size: u32, +} + +#[repr(C, packed)] +#[derive(Default, AsBytes, FromBytes)] +pub struct Tdel { + pub header: GenericSdtHeader, + pub reserved: u32, + pub laml: u64, + pub lasa: u64, +} + +impl Tdel { + pub fn new(laml: u64, lasa: u64) -> Tdel { + let mut tdel = Tdel { + header: GenericSdtHeader::new(b"TDEL", size_of::() as u32, 1), + laml, + lasa, + ..Default::default() + }; + tdel.checksum(); + tdel + } + + pub fn checksum(&mut self) { + self.header.checksum = 0; + self.header + .set_checksum(calculate_checksum(self.as_bytes())); + } +} + +pub struct TdEventDumper<'a> { + area: &'a mut [u8], + size: usize, +} + +impl<'a> TdEventDumper<'a> { + pub fn new(td_event_mem: &'static mut [u8], size: usize) -> Self { + TdEventDumper { + area: td_event_mem, + size, + } + } + + pub fn dump_event_log(&self) { + let mut offset = 0; + + while offset < self.size as usize { + if let Some(td_event_header) = self.read_header(offset) { + offset += PCR_EVENT_HEADER_SIZE; + let td_event_size = td_event_header.event_size as usize; + if td_event_size + offset <= self.area.len() { + let td_event_data = &self.area[offset..offset + td_event_size]; + Self::dump_event(&td_event_header, td_event_data); + } + offset = offset.saturating_add(td_event_size); + } else { + break; + } + } + } + + fn dump_event(td_event_header: &TcgPcrEvent2Header, _td_event_data: &[u8]) { + let pcr_index = td_event_header.pcr_index; + let event_type = td_event_header.event_type; + let event_size = td_event_header.event_size; + + log::info!("TD Event:\n"); + log::info!(" PcrIndex - {}\n", pcr_index); + log::info!(" EventType - 0x{:x}\n", event_type); + + for i in 0..td_event_header.digest.count { + let hash_alg = td_event_header.digest.digests[i as usize].hash_alg; + log::info!(" HashAlgo : 0x{:x}\n", hash_alg); + log::info!( + " Digest({}): {:x?}\n", + i, + td_event_header.digest.digests[i as usize].digest + ); + } + + log::info!(" EventSize - 0x{:x}\n", event_size); + log::info!("\n"); + } + + fn read_header(&self, offset: usize) -> Option { + if let Ok(v) = self.area.pread::(offset) { + Some(v) + } else { + None + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_struct_size() { + assert_eq!(size_of::(), SHA384_DIGEST_SIZE); + assert_eq!(size_of::(), SHA384_DIGEST_SIZE + 2); + //assert_eq!(size_of::(), PCR_EVENT_HEADER_SIZE); + assert_eq!(size_of::(), 56); + } + + #[test] + fn test_tpml_digest_value() { + let value = TpmlDigestValues { + count: 0, + digests: Default::default(), + }; + let mut buf = [0u8; TPML_DIGEST_VALUES_PACKED_SIZE]; + + buf.pwrite(&value, 0).unwrap(); + } + + #[test] + fn test_tcg_pcr_event2_header() { + let hdr = TcgPcrEvent2Header { + pcr_index: 0, + event_type: 0, + digest: TpmlDigestValues { + count: 0, + digests: Default::default(), + }, + event_size: 0, + }; + let mut buf = [0u8; PCR_EVENT_HEADER_SIZE]; + buf.pwrite(&hdr, 0).unwrap(); + } +} diff --git a/td-shim/src/fv.rs b/td-shim/src/fv.rs new file mode 100644 index 00000000..6484f605 --- /dev/null +++ b/td-shim/src/fv.rs @@ -0,0 +1,104 @@ +// Copyright (c) 2021 Intel Corporation +// Copyright (c) 2022 Alibaba Cloud +// +// SPDX-License-Identifier: BSD-2-Clause-Patent + +use core::mem::size_of; +use core::ptr::slice_from_raw_parts; + +use r_efi::efi::Guid; +use scroll::{Pread, Pwrite}; +use td_uefi_pi::pi::fv::{ + CommonSectionHeader, FfsFileHeader, FirmwareVolumeExtHeader, FirmwareVolumeHeader, FvBlockMap, + FIRMWARE_FILE_SYSTEM2_GUID, FVH_SIGNATURE, FV_FILETYPE_FFS_PAD, +}; + +use crate::write_u24; + +/// Firmware volume header. +#[repr(C, align(4))] +#[derive(Copy, Clone, Debug, Pwrite)] +pub struct FvHeader { + pub fv_header: FirmwareVolumeHeader, + pub fv_block_map: [FvBlockMap; 2], + pub pad_ffs_header: FfsFileHeader, + pub fv_ext_header: FirmwareVolumeExtHeader, + pad: [u8; 4], +} + +impl FvHeader { + pub fn as_bytes(&self) -> &[u8] { + unsafe { &*slice_from_raw_parts(self as *const Self as *const u8, size_of::()) } + } +} + +impl Default for FvHeader { + fn default() -> Self { + let mut header_sz = [0u8; 3]; + write_u24(0x2c, &mut header_sz); + + FvHeader { + fv_header: FirmwareVolumeHeader { + zero_vector: [0u8; 16], + file_system_guid: *FIRMWARE_FILE_SYSTEM2_GUID.as_bytes(), + fv_length: 0, + signature: FVH_SIGNATURE, + attributes: 0x0004f6ff, + header_length: 0x0048, + checksum: 0, + ext_header_offset: 0x0060, + reserved: 0x00, + revision: 0x02, + }, + fv_block_map: [FvBlockMap::default(); 2], + pad_ffs_header: FfsFileHeader { + name: *Guid::from_fields( + 0x00000000, + 0x0000, + 0x0000, + 0x00, + 0x00, + &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00], + ) + .as_bytes(), + integrity_check: 0xaae4, + r#type: FV_FILETYPE_FFS_PAD, + attributes: 0x00, + size: header_sz, + state: 0x07u8, + }, + fv_ext_header: FirmwareVolumeExtHeader { + fv_name: [0u8; 16], + ext_header_size: 0, + }, + pad: [0u8; 4], + } + } +} + +/// Firmware volume file header. +#[repr(C, align(4))] +#[derive(Copy, Clone, Debug, Pread, Pwrite, Default)] +pub struct FvFfsFileHeader { + pub ffs_header: FfsFileHeader, +} + +impl FvFfsFileHeader { + pub fn as_bytes(&self) -> &[u8] { + unsafe { &*slice_from_raw_parts(self as *const Self as *const u8, size_of::()) } + } +} + +/// Firmware volume file section header. +#[repr(C, align(4))] +#[derive(Copy, Clone, Debug, Pread, Pwrite, Default)] +pub struct FvFfsSectionHeader { + pub section_header: CommonSectionHeader, +} + +pub type PayloadFvHeader = FvHeader; +pub type PayloadFvFfsHeader = FvFfsFileHeader; +pub type PayloadFvFfsSectionHeader = FvFfsSectionHeader; +pub type IplFvHeader = PayloadFvHeader; +pub type IplFvFfsHeader = PayloadFvFfsHeader; +pub type IplFvFfsSectionHeader = FvFfsSectionHeader; diff --git a/td-shim/src/lib.rs b/td-shim/src/lib.rs index 4b470e46..edb11594 100644 --- a/td-shim/src/lib.rs +++ b/td-shim/src/lib.rs @@ -3,3 +3,105 @@ // SPDX-License-Identifier: BSD-2-Clause-Patent #![no_std] + +use scroll::{Pread, Pwrite}; + +use td_uefi_pi::pi; + +pub mod acpi; +pub mod event_log; +pub mod fv; +pub mod reset_vector; +pub mod secure_boot; + +pub const TD_ACPI_TABLE_HOB_GUID: [u8; 16] = [ + 0x70, 0x58, 0x0c, 0x6a, 0xed, 0xd4, 0xf4, 0x44, 0xa1, 0x35, 0xdd, 0x23, 0x8b, 0x6f, 0xc, 0x8d, +]; + +pub const TD_KERNEL_INFO_HOB_GUID: [u8; 16] = [ + 0x12, 0xa4, 0x6f, 0xb9, 0x1f, 0x46, 0xe3, 0x4b, 0x8c, 0xd, 0xad, 0x80, 0x5a, 0x49, 0x7a, 0xc0, +]; + +#[repr(u32)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum TdKernelInfoHobType { + /// Payload Binary is a PE/COFF or ELF executable image as payload. + /// + /// Entrypoint can be found by parsing the image header. This type image does not follow + /// Linux boot protocol. A payload HOB is used to pass data from TdShim to payload. + ExecutablePayload = 0, + + /// Payload Binary is bzImage, follow Linux boot protocol. + /// + /// The first 512 bytes are boot_param. (zero page). The entrypoint is start address of loaded + /// 64bit Linux kernel plus 0x200 + BzImage, + + /// Payload Binary is VMM loaded vmLinux, follow Linux boot protocol. + /// + /// The entrypoint is defined at HOB_PAYLOAD_INFO_TABLE.Entrypoint. + RawVmLinux, + + /// Unknown Image type + UnknownImage = u32::MAX, +} + +impl From<&TdKernelInfoHobType> for u32 { + fn from(v: &TdKernelInfoHobType) -> Self { + *v as u32 + } +} + +impl From for TdKernelInfoHobType { + fn from(v: u32) -> Self { + match v { + 0 => TdKernelInfoHobType::ExecutablePayload, + 1 => TdKernelInfoHobType::BzImage, + 2 => TdKernelInfoHobType::RawVmLinux, + _ => TdKernelInfoHobType::UnknownImage, + } + } +} + +#[derive(Pwrite)] +pub struct ConfigurationTable { + pub guid: event_log::Guid, + pub table: u64, // should be usize, usize can't be derived by pwrite, but tdx only support 64bit +} + +#[derive(Pwrite)] +pub struct TdxHandoffTablePointers { + pub table_descripion_size: u8, + pub table_description: [u8; 8], + pub number_of_tables: u64, + pub table_entry: [ConfigurationTable; 1], +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Pwrite, Pread)] +pub struct HobTemplate { + pub handoff_info_table: pi::hob::HandoffInfoTable, + pub firmware_volume: pi::hob::FirmwareVolume, + pub cpu: pi::hob::Cpu, + pub payload: pi::hob::MemoryAllocation, + pub page_table: pi::hob::MemoryAllocation, + pub stack: pi::hob::MemoryAllocation, + pub memory_above_1m: pi::hob::ResourceDescription, + pub memory_blow_1m: pi::hob::ResourceDescription, + pub end_off_hob: pi::hob::Header, +} + +#[repr(C)] +#[derive(Default, Clone, Copy, Pread, Pwrite)] +pub struct PayloadInfo { + pub image_type: u32, + pub entry_point: u64, +} + +/// Write three bytes from an integer value into the buffer. +pub fn write_u24(data: u32, buf: &mut [u8]) { + assert!(data < 0xffffff); + buf[0] = (data & 0xFF) as u8; + buf[1] = ((data >> 8) & 0xFF) as u8; + buf[2] = ((data >> 16) & 0xFF) as u8; +} diff --git a/td-shim/src/reset_vector.rs b/td-shim/src/reset_vector.rs new file mode 100644 index 00000000..e6cc7711 --- /dev/null +++ b/td-shim/src/reset_vector.rs @@ -0,0 +1,83 @@ +// Copyright (c) 2021 Intel Corporation +// Copyright (c) 2022 Alibaba Cloud +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +use core::mem::size_of; +use core::ptr::slice_from_raw_parts; + +use r_efi::efi::Guid; +use scroll::{Pread, Pwrite}; +use td_layout::build_time::TD_SHIM_RESET_VECTOR_SIZE; +use td_uefi_pi::pi::fv::{CommonSectionHeader, FfsFileHeader, FV_FILETYPE_RAW, SECTION_RAW}; + +use crate::write_u24; + +/// File header for the ResetVector region. +/// +/// The `ResetVectorHeader` is stored at the end of the IPL region, so the total size of the +/// reset vector file is `TD_SHIM_RESET_VECTOR_SIZE + size_of::()`. +#[repr(C, align(4))] +#[derive(Debug, Default, Pwrite)] +pub struct ResetVectorHeader { + pub ffs_header: FfsFileHeader, + pub section_header_pad: CommonSectionHeader, + pad: [u8; 8], + pub section_header_reset_vector: CommonSectionHeader, +} + +impl ResetVectorHeader { + pub fn build_tdx_reset_vector_header() -> Self { + let mut tdx_reset_vector_header = ResetVectorHeader::default(); + + tdx_reset_vector_header.ffs_header.name.copy_from_slice( + Guid::from_fields( + 0x1ba0062e, + 0xc779, + 0x4582, + 0x85, + 0x66, + &[0x33, 0x6a, 0xe8, 0xf7, 0x8f, 0x09], + ) + .as_bytes(), + ); + tdx_reset_vector_header.ffs_header.integrity_check = 0xaa5a; + tdx_reset_vector_header.ffs_header.r#type = FV_FILETYPE_RAW; + tdx_reset_vector_header.ffs_header.attributes = 0x08; + write_u24( + TD_SHIM_RESET_VECTOR_SIZE + size_of::() as u32, + &mut tdx_reset_vector_header.ffs_header.size, + ); + tdx_reset_vector_header.ffs_header.state = 0x07u8; + + write_u24(0x0c, &mut tdx_reset_vector_header.section_header_pad.size); + tdx_reset_vector_header.section_header_pad.r#type = SECTION_RAW; + + tdx_reset_vector_header.pad = [0u8; 8]; + + write_u24( + TD_SHIM_RESET_VECTOR_SIZE + size_of::() as u32, + &mut tdx_reset_vector_header.section_header_reset_vector.size, + ); + tdx_reset_vector_header.section_header_reset_vector.r#type = SECTION_RAW; + + tdx_reset_vector_header + } + + pub fn as_bytes(&self) -> &[u8] { + unsafe { &*slice_from_raw_parts(self as *const Self as *const u8, size_of::()) } + } +} + +#[repr(C, align(4))] +#[derive(Debug, Pread, Pwrite)] +pub struct ResetVectorParams { + pub entry_point: u32, // rust entry point + pub img_base: u32, // rust ipl bin base + pub img_size: u32, // rust ipl bin size +} + +impl ResetVectorParams { + pub fn as_bytes(&self) -> &[u8] { + unsafe { &*slice_from_raw_parts(self as *const Self as *const u8, size_of::()) } + } +} diff --git a/td-shim/src/secure_boot.rs b/td-shim/src/secure_boot.rs new file mode 100644 index 00000000..bfa33fd4 --- /dev/null +++ b/td-shim/src/secure_boot.rs @@ -0,0 +1,96 @@ +// Copyright (c) 2021 Intel Corporation +// Copyright (c) 2022 Alibaba Cloud +// +// SPDX-License-Identifier: BSD-2-Clause-Patent + +//! Constants and structs to enable secure boot for td-shim. +//! +//! A customized secure boot protocol is designed for td-shim, please refer to `doc/secure_boot.md` +//! for details. + +use core::mem::size_of; +use core::ptr::slice_from_raw_parts; + +use r_efi::efi::Guid; +use scroll::{Pread, Pwrite}; + +/// GUID for secure boot trust anchor in the Configuration Firmware Volume (CFV). +pub const CFV_FFS_HEADER_TRUST_ANCHOR_GUID: Guid = Guid::from_fields( + 0x77a2742e, + 0x9340, + 0x4ac9, + 0x8f, + 0x85, + &[0xb7, 0xb9, 0x78, 0x58, 0x0, 0x21], +); // {77A2742E-9340-4AC9-8F85-B7B978580021} + +/// GUID for secure boot pubkey hash file in the Configuration Firmware Volume (CFV). +pub const CFV_FILE_HEADER_PUBKEY_GUID: Guid = Guid::from_fields( + 0xbe8f65a3, + 0xa83b, + 0x415c, + 0xa1, + 0xfb, + &[0xf7, 0x8e, 0x10, 0x5e, 0x82, 0x4e], +); // {BE8F65A3-A83B-415C-A1FB-F78E105E824E} + +pub const PUBKEY_FILE_STRUCT_VERSION_V1: u32 = 0x01; +pub const PUBKEY_HASH_ALGORITHM_SHA384: u64 = 1; + +#[repr(C, align(4))] +#[derive(Debug, Default, Pread, Pwrite)] +pub struct CfvPubKeyFileHeader { + pub type_guid: [u8; 16], + pub struct_version: u32, + pub length: u32, + pub hash_algorithm: u64, + pub _reserved: u32, + pub _pad: u32, +} + +impl CfvPubKeyFileHeader { + pub fn as_bytes(&self) -> &[u8] { + unsafe { &*slice_from_raw_parts(self as *const Self as *const u8, size_of::()) } + } +} + +/// GUID for signed payload. +pub const SIGNED_PAYLOAD_FILE_HEADER_GUID: Guid = Guid::from_fields( + 0xFCF2D558, + 0x9DF5, + 0x4F4D, + 0xB0, + 0xD7, + &[0x3e, 0x4b, 0x79, 0x8a, 0xb0, 0x66], +); // {FCF2D558-9DF5-4F4D-B0D7-3E4B798AB066} + +pub const PAYLOAD_SIGN_ECDSA_NIST_P384_SHA384: u32 = 1; +pub const PAYLOAD_SIGN_RSA_PSS_3072_SHA384: u32 = 2; +pub const PAYLOAD_SIGN_RSA_EXPONENT_SIZE: usize = 8; +pub const PAYLOAD_SIGN_RSA_PUBLIC_KEY_MOD_SIZE: usize = 384; + +/// File header for signed payload. +/// +/// Please refer to doc/secure_boot.md for definition. +#[repr(C, align(4))] +#[derive(Debug, Pread, Pwrite)] +pub struct PayloadSignHeader { + pub type_guid: [u8; 16], + pub struct_version: u32, + pub length: u32, + pub payload_version: u64, + pub payload_svn: u64, + pub signing_algorithm: u32, + pub reserved: u32, +} + +impl PayloadSignHeader { + pub fn as_bytes(&self) -> &[u8] { + unsafe { + &*core::ptr::slice_from_raw_parts( + self as *const Self as *const u8, + core::mem::size_of::(), + ) + } + } +}