Skip to content

Commit 1d3c868

Browse files
committed
td-shim: support loading payload for each vCPU
When feature `multi-payload` is enabled, td-shim will load a payload binary for each vCPU, and it will also evenly divide the largest contiguous available memory among each vCPU, generating the e820 table and HOB for them. Signed-off-by: Jiaqi Gao <[email protected]>
1 parent 1ad3ca4 commit 1d3c868

File tree

8 files changed

+193
-42
lines changed

8 files changed

+193
-42
lines changed

td-shim/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ tdx = ["tdx-tdcall", "td-exception/tdx", "td-logger/tdx", "x86"]
5151
lazy-accept = ["tdx"]
5252
ring-hash = ["cc-measurement/ring"]
5353
sha2-hash = ["cc-measurement/sha2"]
54+
multi-payload = []
5455
main = [
5556
"log",
5657
"td-loader",

td-shim/src/bin/td-shim/e820.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use td_shim::e820::{E820Entry, E820Type};
88
// Linux BootParam supports 128 e820 entries, so...
99
const MAX_E820_ENTRY: usize = 128;
1010

11-
#[derive(Debug)]
11+
#[derive(Debug, Clone, Copy)]
1212
pub struct E820Table {
1313
entries: [E820Entry; MAX_E820_ENTRY],
1414
num_entries: usize,

td-shim/src/bin/td-shim/ipl.rs

+32-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
//
33
// SPDX-License-Identifier: BSD-2-Clause-Patent
44

5+
use core::convert::TryFrom;
6+
57
use td_layout::memslice;
68
use td_loader::elf;
79
use td_loader::elf64::ProgramHeader;
@@ -11,9 +13,23 @@ use crate::memory::Memory;
1113

1214
const SIZE_4KB: u64 = 0x00001000u64;
1315

16+
#[repr(u8)]
17+
#[derive(Debug, Copy, Clone)]
1418
pub enum ExecutablePayloadType {
15-
Elf,
16-
PeCoff,
19+
Elf = 0,
20+
PeCoff = 1,
21+
}
22+
23+
impl TryFrom<u8> for ExecutablePayloadType {
24+
type Error = ();
25+
26+
fn try_from(value: u8) -> Result<Self, Self::Error> {
27+
match value {
28+
0 => Ok(ExecutablePayloadType::Elf),
29+
1 => Ok(ExecutablePayloadType::PeCoff),
30+
_ => Err(()),
31+
}
32+
}
1733
}
1834

1935
pub struct PayloadRelocationInfo {
@@ -79,6 +95,20 @@ pub fn find_and_report_entry_point(
7995
}
8096
}
8197

98+
pub fn jump_to_payload_entry(entry: u64, image_type: u8, hob_addr: u64, payload_addr: u64) {
99+
let image_type = ExecutablePayloadType::try_from(image_type).expect("Unknown image type");
100+
match image_type {
101+
ExecutablePayloadType::Elf => {
102+
let entry = unsafe { core::mem::transmute::<u64, extern "sysv64" fn(u64, u64)>(entry) };
103+
entry(hob_addr, payload_addr);
104+
}
105+
ExecutablePayloadType::PeCoff => {
106+
let entry = unsafe { core::mem::transmute::<u64, extern "win64" fn(u64, u64)>(entry) };
107+
entry(hob_addr, payload_addr);
108+
}
109+
};
110+
}
111+
82112
#[cfg(test)]
83113
mod tests {
84114
use super::*;

td-shim/src/bin/td-shim/main.rs

+22-26
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,20 @@
77
#![cfg_attr(not(test), no_main)]
88
#![allow(unused_imports)]
99

10+
#[macro_use]
1011
extern crate alloc;
1112
use alloc::boxed::Box;
1213
use alloc::vec::Vec;
1314
use asm::{empty_exception_handler, empty_exception_handler_size};
1415
use core::ffi::c_void;
1516
use core::mem::size_of;
1617
use core::panic::PanicInfo;
18+
use e820::E820Table;
1719
use memory::Memory;
20+
use td::ap_set_payload;
1821
use td_exception::idt::{load_idtr, DescriptorTablePointer, Idt, IdtEntry};
22+
use td_layout::runtime::exec::PAYLOAD_SIZE;
23+
use td_shim::e820::E820Type;
1924
use td_shim::event_log::CCEL_CC_TYPE_TDX;
2025
use x86_64::instructions::hlt;
2126
use x86_64::registers::segmentation::{Segment, CS};
@@ -28,7 +33,7 @@ use zerocopy::{AsBytes, ByteSlice, FromBytes};
2833
use cc_measurement::{log::CcEventLogWriter, EV_EFI_HANDOFF_TABLES2, EV_PLATFORM_CONFIG_FLAGS};
2934
use td_layout::build_time::{self, *};
3035
use td_layout::memslice::{self, SliceType};
31-
use td_layout::RuntimeMemoryLayout;
36+
use td_layout::{mailbox, RuntimeMemoryLayout};
3237
use td_shim::event_log::{log_hob_list, log_payload_binary, log_payload_parameter};
3338
use td_shim::{
3439
speculation_barrier, PayloadInfo, TdPayloadInfoHobType, TD_ACPI_TABLE_HOB_GUID,
@@ -151,6 +156,7 @@ pub extern "win64" fn _start(
151156
&mut mem,
152157
&mut td_event_log,
153158
&dynamic_info.acpi_tables,
159+
num_vcpus,
154160
);
155161

156162
panic!("payload entry() should not return here, deadloop!!!");
@@ -207,6 +213,7 @@ fn boot_builtin_payload(
207213
mem: &mut memory::Memory,
208214
event_log: &mut CcEventLogWriter,
209215
acpi_tables: &Vec<&[u8]>,
216+
num_vcpus: u32,
210217
) {
211218
// Get and parse image file from the payload firmware volume.
212219
let fv_buffer = memslice::get_mem_slice(memslice::SliceType::ShimPayload);
@@ -230,6 +237,10 @@ fn boot_builtin_payload(
230237
// Create an EV_SEPARATOR event to mark the end of the td-shim events
231238
event_log.create_seperator();
232239

240+
if cfg!(feature = "multi-payload") {
241+
mp::launch_payload_per_cpu(mem, payload_bin, acpi_tables, num_vcpus);
242+
}
243+
233244
let payload = mem.get_dynamic_mem_slice_mut(memslice::SliceType::Payload);
234245
let relocation_info = ipl::find_and_report_entry_point(mem, payload_bin, payload)
235246
.expect("Entry point not found!");
@@ -241,8 +252,11 @@ fn boot_builtin_payload(
241252
payload_hob_region.size as u64,
242253
);
243254

255+
let payload_hob = mem.get_dynamic_mem_slice_mut(SliceType::Acpi);
256+
let e820 = mem.create_e820();
244257
// Prepare the HOB list to run the image
245-
payload_hob::build_payload_hob(acpi_tables, &mem).expect("Fail to create payload HOB");
258+
payload_hob::build_payload_hob(payload_hob, acpi_tables, &e820)
259+
.expect("Fail to create payload HOB");
246260

247261
// Finally let's switch stack and jump to the image entry point...
248262
log::info!(
@@ -258,30 +272,12 @@ fn boot_builtin_payload(
258272
// Relocate Mailbox along side with the AP function
259273
td::relocate_mailbox(mailbox);
260274

261-
match relocation_info.image_type {
262-
ExecutablePayloadType::Elf => {
263-
let entry = unsafe {
264-
core::mem::transmute::<u64, extern "sysv64" fn(u64, u64)>(
265-
relocation_info.entry_point,
266-
)
267-
};
268-
entry(
269-
payload_hob_region.base_address as u64,
270-
payload.as_ptr() as u64,
271-
);
272-
}
273-
ExecutablePayloadType::PeCoff => {
274-
let entry = unsafe {
275-
core::mem::transmute::<u64, extern "win64" fn(u64, u64)>(
276-
relocation_info.entry_point,
277-
)
278-
};
279-
entry(
280-
payload_hob_region.base_address as u64,
281-
payload.as_ptr() as u64,
282-
);
283-
}
284-
};
275+
ipl::jump_to_payload_entry(
276+
relocation_info.entry_point,
277+
relocation_info.image_type as u8,
278+
payload_hob_region.base_address as u64,
279+
payload.as_ptr() as u64,
280+
);
285281
}
286282

287283
// Reuse mailbox for the IDT used before payload setup its own one.

td-shim/src/bin/td-shim/mp.rs

+84
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,22 @@
22
//
33
// SPDX-License-Identifier: BSD-2-Clause-Patent
44

5+
use alloc::vec::Vec;
56
use core::convert::TryInto;
67
use core::mem::size_of;
8+
use td_layout::runtime::exec::{ACPI_SIZE, PAYLOAD_SIZE};
9+
use td_shim::e820::E820Type;
710
use zerocopy::{AsBytes, FromBytes, FromZeroes};
811

912
use td_shim_interface::acpi::{self, GenericSdtHeader};
1013

14+
use crate::{
15+
e820::E820Table,
16+
ipl::{self, jump_to_payload_entry, ExecutablePayloadType},
17+
memory::Memory,
18+
payload_hob, td,
19+
};
20+
1121
// 255 vCPUs needs 2278 bytes, refer to create_madt().
1222
const MADT_MAX_SIZE: usize = 0xc00;
1323
const NUM_8259_IRQS: usize = 16;
@@ -144,6 +154,80 @@ pub fn create_madt_default(cpu_num: u32, mailbox_base: u64) -> Option<Madt> {
144154
Some(madt)
145155
}
146156

157+
pub fn launch_payload_per_cpu(
158+
mem: &mut Memory,
159+
payload_bin: &[u8],
160+
acpi_tables: &Vec<&[u8]>,
161+
num_vcpus: u32,
162+
) {
163+
const TEMP_STACK_SIZE: u64 = 0x4000;
164+
165+
let e820 = mem.create_e820();
166+
167+
// Get the largest usable memory index in e820 table
168+
let (max_addr, max_usable) = e820
169+
.as_slice()
170+
.iter()
171+
.enumerate()
172+
.filter(|&(_, e)| e.r#type == E820Type::Memory as u32)
173+
.max_by_key(|&(_, e)| e.size)
174+
.map(|(_, e)| (e.addr, e.size))
175+
.expect("No usable memory found!");
176+
177+
let size_per_cpu = max_usable / num_vcpus as u64;
178+
let mut bsp_relocation_info = None;
179+
let mut bsp_hob_addr = 0;
180+
let mut bsp_payload_addr = 0;
181+
for cpu_idx in 0..num_vcpus {
182+
let start = cpu_idx as u64 * size_per_cpu + max_addr;
183+
let temp_stack = start;
184+
let payload_addr = temp_stack + TEMP_STACK_SIZE;
185+
let hob_addr = payload_addr + PAYLOAD_SIZE as u64;
186+
187+
let mut table = E820Table::new();
188+
table.add_range(E820Type::Memory, start, size_per_cpu);
189+
table.convert_range(E820Type::Reserved, temp_stack, TEMP_STACK_SIZE);
190+
table.convert_range(E820Type::Reserved, payload_addr, PAYLOAD_SIZE as u64);
191+
table.convert_range(E820Type::Acpi, hob_addr, ACPI_SIZE as u64);
192+
let payload =
193+
unsafe { core::slice::from_raw_parts_mut(payload_addr as *mut u8, PAYLOAD_SIZE) };
194+
let hob = unsafe { core::slice::from_raw_parts_mut(hob_addr as *mut u8, ACPI_SIZE) };
195+
196+
let relocation_info = ipl::find_and_report_entry_point(mem, payload_bin, payload)
197+
.expect("Entry point not found!");
198+
// Prepare the HOB list to run the image
199+
payload_hob::build_payload_hob(hob, acpi_tables, &table)
200+
.expect("Fail to create payload HOB");
201+
202+
// Skip the BSP
203+
if cpu_idx != 0 {
204+
td::ap_set_payload(
205+
cpu_idx,
206+
temp_stack + TEMP_STACK_SIZE,
207+
relocation_info.entry_point,
208+
relocation_info.image_type as u8,
209+
hob_addr,
210+
payload_addr,
211+
);
212+
}
213+
// Save the relocation info for BSP paylaod
214+
if cpu_idx == 0 {
215+
bsp_relocation_info = Some(relocation_info);
216+
bsp_hob_addr = hob_addr;
217+
bsp_payload_addr = payload_addr;
218+
}
219+
}
220+
221+
// For BSP
222+
let bsp_relocation_info = bsp_relocation_info.expect("Payload entry point not found for BSP!");
223+
jump_to_payload_entry(
224+
bsp_relocation_info.entry_point,
225+
bsp_relocation_info.image_type as u8,
226+
bsp_hob_addr,
227+
bsp_payload_addr,
228+
);
229+
}
230+
147231
#[cfg(test)]
148232
mod tests {
149233
use super::*;

td-shim/src/bin/td-shim/payload_hob.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ pub enum PayloadHobError {
2323
OutOfResource,
2424
}
2525

26-
pub struct PayloadHob {
27-
memory: &'static mut [u8],
26+
pub struct PayloadHob<'a> {
27+
memory: &'a mut [u8],
2828
end: usize,
2929
}
3030

31-
impl PayloadHob {
32-
pub fn new(memory: &'static mut [u8]) -> Option<Self> {
31+
impl<'a> PayloadHob<'a> {
32+
pub fn new(memory: &'a mut [u8]) -> Option<Self> {
3333
if memory.len() < size_of::<pi::hob::HandoffInfoTable>() {
3434
return None;
3535
}
@@ -168,10 +168,13 @@ impl PayloadHob {
168168
}
169169
}
170170

171-
pub fn build_payload_hob(acpi_tables: &Vec<&[u8]>, memory: &Memory) -> Option<PayloadHob> {
171+
pub fn build_payload_hob<'a>(
172+
hob: &'a mut [u8],
173+
acpi_tables: &Vec<&[u8]>,
174+
e820: &E820Table,
175+
) -> Option<PayloadHob<'a>> {
172176
// Reuse the ACPI memory to build the payload HOB.
173-
let mut payload_hob =
174-
PayloadHob::new(memory.get_dynamic_mem_slice_mut(memslice::SliceType::Acpi))?;
177+
let mut payload_hob = PayloadHob::new(hob)?;
175178

176179
payload_hob.add_cpu(memory::cpu_get_memory_space_size(), 16);
177180
payload_hob.add_fv(TD_SHIM_PAYLOAD_BASE as u64, TD_SHIM_PAYLOAD_SIZE as u64);
@@ -182,9 +185,6 @@ pub fn build_payload_hob(acpi_tables: &Vec<&[u8]>, memory: &Memory) -> Option<Pa
182185
.ok()?;
183186
}
184187

185-
let mut e820 = memory.create_e820();
186-
187-
log::info!("e820 table: {:x?}\n", e820.as_slice());
188188
payload_hob
189189
.add_guided_data(&TD_E820_TABLE_HOB_GUID, e820.as_bytes())
190190
.ok()?;

td-shim/src/bin/td-shim/td/tdx.rs

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use cc_measurement::log::CcEventLogError;
66
use td_exception::idt::DescriptorTablePointer;
77
use tdx_tdcall::tdx;
88

9+
pub use super::tdx_mailbox::ap_set_payload;
10+
911
extern "win64" {
1012
fn asm_read_msr64(index: u32) -> u64;
1113
fn asm_write_msr64(index: u32, value: u64) -> u64;

0 commit comments

Comments
 (0)