Skip to content

Commit be6a27d

Browse files
committed
feat(tdx): parse TDVF and generate UEFI HOB
Signed-off-by: Changyuan Lyu <changyuanl@google.com>
1 parent 7e0d035 commit be6a27d

File tree

5 files changed

+346
-10
lines changed

5 files changed

+346
-10
lines changed

alioth/src/board/board_x86_64/board_x86_64.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use std::collections::HashMap;
2020
use std::mem::{offset_of, size_of, size_of_val};
2121
use std::path::Path;
2222
use std::sync::Arc;
23-
use std::sync::atomic::AtomicU32;
23+
use std::sync::atomic::{AtomicU32, AtomicU64};
2424

2525
use parking_lot::Mutex;
2626
use snafu::ResultExt;
@@ -53,6 +53,7 @@ where
5353
{
5454
cpuids: HashMap<CpuidIn, CpuidResult>,
5555
sev_ap_eip: AtomicU32,
56+
tdx_hob: AtomicU64,
5657
pub(crate) io_apic: Arc<IoApic<V::MsiSender>>,
5758
}
5859

@@ -167,6 +168,7 @@ impl<V: Vm> ArchBoard<V> {
167168
Ok(Self {
168169
cpuids,
169170
sev_ap_eip: AtomicU32::new(0),
171+
tdx_hob: AtomicU64::new(0),
170172
io_apic: Arc::new(IoApic::new(vm.create_msi_sender()?)),
171173
})
172174
}
@@ -216,7 +218,7 @@ where
216218
match coco {
217219
Coco::AmdSev { policy } => self.setup_sev(fw, *policy),
218220
Coco::AmdSnp { .. } => self.setup_snp(fw),
219-
Coco::IntelTdx { attr } => todo!("Intel TDX {attr:?}"),
221+
Coco::IntelTdx { .. } => self.setup_tdx(fw),
220222
}
221223
}
222224

alioth/src/board/board_x86_64/tdx.rs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@
1313
// limitations under the License.
1414

1515
use std::sync::Arc;
16+
use std::sync::atomic::Ordering;
1617

18+
use crate::arch::layout::MEM_64_START;
1719
use crate::arch::tdx::TdAttr;
18-
use crate::board::{Board, Result};
20+
use crate::board::{Board, Result, error};
21+
use crate::firmware::ovmf::tdx::{TdvfSectionType, create_hob, parse_entries};
1922
use crate::hv::{Vm, VmMemory};
2023
use crate::mem::MarkPrivateMemory;
24+
use crate::mem::mapped::ArcMemPages;
2125

2226
impl<V> Board<V>
2327
where
@@ -29,4 +33,45 @@ where
2933
self.memory.register_change_callback(mark_private_memory)?;
3034
Ok(())
3135
}
36+
37+
pub(crate) fn create_hob(&self, dst: &mut [u8], mut accepted: Vec<(u64, u64)>) -> Result<u64> {
38+
let hob_phys = self.arch.tdx_hob.load(Ordering::Relaxed);
39+
let mut entries = self.memory.mem_region_entries();
40+
create_hob(dst, hob_phys, &mut entries, &mut accepted)?;
41+
Ok(hob_phys)
42+
}
43+
44+
pub(crate) fn setup_tdx(&self, fw: &mut ArcMemPages) -> Result<()> {
45+
let data = fw.as_slice();
46+
let entries = parse_entries(data)?;
47+
48+
let fw_gpa = MEM_64_START - data.len() as u64;
49+
self.memory
50+
.mark_private_memory(fw_gpa, data.len() as _, true)?;
51+
52+
let mut accepted = Vec::new();
53+
let mut hob_ram = None;
54+
for entry in entries {
55+
match entry.r#type {
56+
TdvfSectionType::TD_HOB => {
57+
let p = ArcMemPages::from_anonymous(entry.size as usize, None, None)?;
58+
hob_ram = Some(p);
59+
let tdx_hob = &self.arch.tdx_hob;
60+
tdx_hob.store(entry.address, Ordering::Relaxed);
61+
accepted.push((entry.address, entry.size));
62+
}
63+
TdvfSectionType::TEMP_MEM => {
64+
accepted.push((entry.address, entry.size));
65+
}
66+
_ => {}
67+
};
68+
}
69+
70+
let Some(hob_ram) = &mut hob_ram else {
71+
return error::MissingPayload.fail();
72+
};
73+
self.create_hob(hob_ram.as_slice_mut(), accepted)?;
74+
75+
todo!()
76+
}
3277
}

alioth/src/firmware/firmware.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ pub enum Error {
4040
MissingTdvfVersion { got: u32 },
4141
#[snafu(display("Invalid firmware data layout"))]
4242
InvalidLayout,
43+
#[snafu(display("Uncovered TDVF section"))]
44+
UncoveredTdvfSection,
45+
#[snafu(display("Failed to write HOB"))]
46+
WriteHob { error: std::io::Error },
4347
}
4448

4549
type Result<T, E = Error> = std::result::Result<T, E>;

alioth/src/firmware/ovmf/ovmf_x86_64/tdx.rs

Lines changed: 147 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,20 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
15+
use std::cmp::min;
16+
use std::io::Write;
1617

17-
use crate::firmware::ovmf::x86_64::GUID_SIZE;
18-
use crate::{bitflags, consts};
18+
use snafu::ResultExt;
19+
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
1920

20-
use crate::firmware::ovmf::x86_64::parse_data;
21+
use crate::firmware::ovmf::x86_64::{GUID_SIZE, parse_data};
22+
use crate::firmware::uefi::{
23+
HOB_HANDOFF_TABLE_VERSION, HobGenericHeader, HobHandoffInfoTable, HobResourceDesc,
24+
HobResourceType, HobType, ResourceAttr,
25+
};
2126
use crate::firmware::{Result, error};
27+
use crate::mem::{MemRegionEntry, MemRegionType};
28+
use crate::{bitflags, consts};
2229

2330
pub const GUID_TDX_METADATA_OFFSET: [u8; GUID_SIZE] = [
2431
0x35, 0x65, 0x7a, 0xe4, 0x4a, 0x98, 0x98, 0x47, 0x86, 0x5e, 0x46, 0x85, 0xa7, 0xbf, 0x8e, 0xc2,
@@ -57,9 +64,9 @@ bitflags! {
5764
#[derive(Debug, Clone, Default, KnownLayout, Immutable, FromBytes, IntoBytes)]
5865
pub struct TdvfSectionEntry {
5966
pub data_offset: u32,
60-
pub raw_data_size: u32,
61-
pub memory_address: u64,
62-
pub memory_data_size: u64,
67+
pub data_size: u32,
68+
pub address: u64,
69+
pub size: u64,
6370
pub r#type: TdvfSectionType,
6471
pub attributes: TdvfSectionAttr,
6572
}
@@ -98,3 +105,136 @@ pub fn parse_entries(data: &[u8]) -> Result<&[TdvfSectionEntry]> {
98105
};
99106
Ok(entries)
100107
}
108+
109+
fn create_hob_mem_resources(
110+
entries: &[(u64, MemRegionEntry)],
111+
accepted: &[(u64, u64)],
112+
mut op: impl FnMut(HobResourceDesc) -> Result<()>,
113+
) -> Result<()> {
114+
let tmpl = HobResourceDesc {
115+
hdr: HobGenericHeader {
116+
r#type: HobType::RESOURCE_DESCRIPTOR,
117+
length: size_of::<HobResourceDesc>() as u16,
118+
reserved: 0,
119+
},
120+
owner: [0; 16],
121+
attr: ResourceAttr::PRESENT | ResourceAttr::INIT | ResourceAttr::TESTED,
122+
..Default::default()
123+
};
124+
let mut iter_e = entries.iter();
125+
let mut iter_a = accepted.iter();
126+
let mut section = iter_a.next().copied();
127+
let mut entry = iter_e.next().copied();
128+
loop {
129+
match (&mut entry, &mut section) {
130+
(None, None) => break,
131+
(None, Some((start, size))) => {
132+
log::error!(
133+
"Section [{start:x}, {:x}) is not covered by system memory",
134+
*start + *size
135+
);
136+
return error::UncoveredTdvfSection.fail();
137+
}
138+
(Some((_, e)), _) if e.type_ != MemRegionType::Ram => {
139+
entry = iter_e.next().copied();
140+
continue;
141+
}
142+
(Some((s, e)), None) => {
143+
op(HobResourceDesc {
144+
r#type: HobResourceType::MEMORY_UNACCEPTED,
145+
address: *s,
146+
len: e.size,
147+
..tmpl.clone()
148+
})?;
149+
entry = iter_e.next().copied();
150+
}
151+
(Some((s, e)), Some((start, size))) => {
152+
if let Some(len) = min(*s, *start + *size).checked_sub(*start)
153+
&& len > 0
154+
{
155+
*size = len;
156+
entry = None;
157+
// Jump to branch (Some, None)
158+
continue;
159+
}
160+
if let Some(len) = min(*s + e.size, *start).checked_sub(*s)
161+
&& len > 0
162+
{
163+
op(HobResourceDesc {
164+
r#type: HobResourceType::MEMORY_UNACCEPTED,
165+
address: *s,
166+
len,
167+
..tmpl.clone()
168+
})?;
169+
*s += len;
170+
e.size -= len;
171+
}
172+
if let Some(len) = min(*s + e.size, *start + *size).checked_sub(*start)
173+
&& len > 0
174+
{
175+
op(HobResourceDesc {
176+
r#type: HobResourceType::SYSTEM_MEMORY,
177+
address: *start,
178+
len,
179+
..tmpl.clone()
180+
})?;
181+
*start += len;
182+
*size -= len;
183+
*s += len;
184+
e.size -= len
185+
};
186+
if *size == 0 {
187+
section = iter_a.next().copied();
188+
};
189+
if e.size == 0 {
190+
entry = iter_e.next().copied();
191+
}
192+
}
193+
}
194+
}
195+
Ok(())
196+
}
197+
198+
pub fn create_hob(
199+
buffer: &mut [u8],
200+
hob_phys: u64,
201+
entries: &mut [(u64, MemRegionEntry)],
202+
accepted: &mut [(u64, u64)],
203+
) -> Result<()> {
204+
entries.sort_by_key(|(s, _)| *s);
205+
accepted.sort();
206+
207+
let Ok((table, mut dst)) = HobHandoffInfoTable::mut_from_prefix(buffer) else {
208+
return error::InvalidLayout.fail();
209+
};
210+
211+
let mut desc_size = 0;
212+
create_hob_mem_resources(entries, accepted, |d| {
213+
desc_size += size_of_val(&d);
214+
dst.write_all(d.as_bytes()).context(error::WriteHob)
215+
})?;
216+
217+
let end = HobGenericHeader {
218+
r#type: HobType::END_OF_HOB_LIST,
219+
length: size_of::<HobGenericHeader>() as u16,
220+
reserved: 0,
221+
};
222+
dst.write_all(end.as_bytes()).context(error::WriteHob)?;
223+
224+
*table = HobHandoffInfoTable {
225+
hdr: HobGenericHeader {
226+
r#type: HobType::HANDOFF,
227+
length: size_of::<HobHandoffInfoTable>() as u16,
228+
reserved: 0,
229+
},
230+
version: HOB_HANDOFF_TABLE_VERSION,
231+
end_of_hob_list: hob_phys + (size_of_val(table) + desc_size + size_of_val(&end)) as u64,
232+
..Default::default()
233+
};
234+
235+
Ok(())
236+
}
237+
238+
#[cfg(test)]
239+
#[path = "tdx_test.rs"]
240+
mod tests;

0 commit comments

Comments
 (0)