Skip to content

Commit e1cefb9

Browse files
committed
boot shim side changes
1 parent 479fbcc commit e1cefb9

File tree

11 files changed

+192
-43
lines changed

11 files changed

+192
-43
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4975,6 +4975,7 @@ dependencies = [
49754975
"memory_range",
49764976
"minimal_rt",
49774977
"minimal_rt_build",
4978+
"page_table",
49784979
"safe_intrinsics",
49794980
"sha2",
49804981
"sidecar_defs",

openhcl/openhcl_boot/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ thiserror.workspace = true
3131
zerocopy.workspace = true
3232

3333
[target.'cfg(target_arch = "x86_64")'.dependencies]
34+
page_table.workspace = true
3435
safe_intrinsics.workspace = true
3536
tdcall.workspace = true
3637
x86defs.workspace = true

openhcl/openhcl_boot/src/arch/x86_64/memory.rs

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,36 @@
55
66
use super::address_space::LocalMap;
77
use super::address_space::init_local_map;
8+
use crate::AddressSpaceManager;
89
use crate::ShimParams;
910
use crate::arch::TdxHypercallPage;
1011
use crate::arch::x86_64::address_space::tdx_share_large_page;
1112
use crate::host_params::PartitionInfo;
1213
use crate::host_params::shim_params::IsolationType;
1314
use crate::hypercall::hvcall;
15+
use crate::memory::AllocationPolicy;
16+
use crate::memory::AllocationType;
17+
use crate::off_stack;
18+
use arrayvec::ArrayVec;
19+
use loader_defs::shim::MemoryVtlType;
1420
use memory_range::MemoryRange;
21+
use page_table::x64::PAGE_TABLE_MAX_BYTES;
22+
use page_table::x64::PAGE_TABLE_MAX_COUNT;
23+
use page_table::x64::PageTable;
24+
use page_table::x64::PageTableBuilder;
1525
use sha2::Digest;
1626
use sha2::Sha384;
1727
use x86defs::X64_LARGE_PAGE_SIZE;
1828
use x86defs::tdx::TDX_SHARED_GPA_BOUNDARY_ADDRESS_BIT;
29+
use zerocopy::FromZeros;
1930

2031
/// On isolated systems, transitions all VTL2 RAM to be private and accepted, with the appropriate
2132
/// VTL permissions applied.
22-
pub fn setup_vtl2_memory(shim_params: &ShimParams, partition_info: &PartitionInfo) {
33+
pub fn setup_vtl2_memory(
34+
shim_params: &ShimParams,
35+
partition_info: &PartitionInfo,
36+
address_space: &mut AddressSpaceManager,
37+
) {
2338
// Only if the partition is VBS-isolated, accept memory and apply vtl 2 protections here.
2439
// Non-isolated partitions can undergo servicing, and additional information
2540
// would be needed to determine whether vtl 2 protections should be applied
@@ -125,6 +140,71 @@ pub fn setup_vtl2_memory(shim_params: &ShimParams, partition_info: &PartitionInf
125140
// hypercall IO pages. ram_buffer must not be used again beyond this point
126141
// TODO: find an approach that does not require re-using the ram_buffer
127142
if shim_params.isolation_type == IsolationType::Tdx {
143+
let page_table_region = address_space
144+
.allocate(
145+
None,
146+
PAGE_TABLE_MAX_BYTES as u64,
147+
AllocationType::TdxPageTables,
148+
AllocationPolicy::LowMemory,
149+
)
150+
.expect("allocation of space for TDX page tables must succeed");
151+
152+
const MAX_RANGE_COUNT: usize = 64;
153+
let mut ranges = off_stack!(
154+
ArrayVec::<(u64, u64), MAX_RANGE_COUNT>,
155+
ArrayVec::new_const()
156+
);
157+
158+
let vtl2_ram = address_space
159+
.vtl2_ranges()
160+
.filter_map(|(range, typ)| match typ {
161+
MemoryVtlType::VTL2_RAM => Some((range.start(), range.end())),
162+
_ => None,
163+
});
164+
165+
ranges.extend(vtl2_ram);
166+
167+
let mut page_table_work_buffer =
168+
off_stack!(ArrayVec<PageTable, PAGE_TABLE_MAX_COUNT>, ArrayVec::new_const());
169+
for _ in 0..PAGE_TABLE_MAX_COUNT {
170+
page_table_work_buffer.push(PageTable::new_zeroed());
171+
}
172+
let mut page_table = off_stack!(ArrayVec<u8, PAGE_TABLE_MAX_BYTES>, ArrayVec::new_const());
173+
for _ in 0..PAGE_TABLE_MAX_BYTES {
174+
page_table.push(0);
175+
}
176+
177+
let page_table_builder = PageTableBuilder::new(
178+
page_table_region.range.start(),
179+
page_table_work_buffer.as_mut_slice(),
180+
page_table.as_mut_slice(),
181+
)
182+
.expect("page table builder must return no error")
183+
.with_ranges(ranges.as_slice());
184+
185+
let page_tables = page_table_builder
186+
.build()
187+
.expect("page table construction must succeed");
188+
189+
address_space.truncate_range(
190+
page_table_region,
191+
page_tables.len() as u64,
192+
AllocationPolicy::LowMemory,
193+
);
194+
195+
//TODO safety comment
196+
unsafe {
197+
core::ptr::copy_nonoverlapping(
198+
page_tables.as_ptr(),
199+
page_table_region.range.start() as *mut u8,
200+
page_tables.len(),
201+
);
202+
}
203+
204+
crate::arch::tdx::tdx_prepare_ap_trampoline(
205+
page_table_region.range.start()
206+
);
207+
128208
let free_buffer = ram_buffer.as_mut_ptr() as u64;
129209
assert!(free_buffer.is_multiple_of(X64_LARGE_PAGE_SIZE));
130210
// SAFETY: The bottom 2MB region of the ram_buffer is unused by the shim

openhcl/openhcl_boot/src/arch/x86_64/tdx.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ pub fn get_tdx_tsc_reftime() -> Option<u64> {
182182
/// Update the TdxTrampolineContext, setting the necessary control registers for AP startup,
183183
/// and ensuring that LGDT will be skipped, so the GDT page does not need to be added to the
184184
/// e820 entries
185-
pub fn tdx_prepare_ap_trampoline() {
185+
pub fn tdx_prepare_ap_trampoline(cr3: u64) {
186186
let context_ptr: *mut TdxTrampolineContext = RESET_VECTOR_PAGE as *mut TdxTrampolineContext;
187187
// SAFETY: The TdxTrampolineContext is known to be stored at the architectural reset vector address
188188
let tdxcontext: &mut TdxTrampolineContext = unsafe { context_ptr.as_mut().unwrap() };
@@ -191,13 +191,11 @@ pub fn tdx_prepare_ap_trampoline() {
191191
tdxcontext.code_selector = 0;
192192
tdxcontext.task_selector = 0;
193193
tdxcontext.cr0 |= x86defs::X64_CR0_PG | x86defs::X64_CR0_PE | x86defs::X64_CR0_NE;
194+
tdxcontext.cr3 = cr3;
194195
tdxcontext.cr4 |= x86defs::X64_CR4_PAE | x86defs::X64_CR4_MCE;
195196
}
196197

197198
pub fn setup_vtl2_vp(partition_info: &PartitionInfo) {
198-
// Update the TDX Trampoline Context for AP Startup
199-
tdx_prepare_ap_trampoline();
200-
201199
for cpu in 1..partition_info.cpus.len() {
202200
hvcall()
203201
.tdx_enable_vp_vtl2(cpu as u32)

openhcl/openhcl_boot/src/host_params/dt/mod.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -501,15 +501,6 @@ impl PartitionInfo {
501501
));
502502
}
503503

504-
// Only specify pagetables as a reserved region on TDX, as they are used
505-
// for AP startup via the mailbox protocol. On other platforms, the
506-
// memory is free to be reclaimed.
507-
if params.isolation_type == IsolationType::Tdx {
508-
assert!(params.page_tables.is_some());
509-
address_space_builder = address_space_builder
510-
.with_page_tables(params.page_tables.expect("always present on tdx"));
511-
}
512-
513504
address_space_builder
514505
.init()
515506
.expect("failed to initialize address space manager");

openhcl/openhcl_boot/src/host_params/shim_params.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,6 @@ pub struct ShimParams {
101101
/// Memory used by the shim.
102102
pub used: MemoryRange,
103103
pub bounce_buffer: Option<MemoryRange>,
104-
/// Page tables region used by the shim.
105-
pub page_tables: Option<MemoryRange>,
106104
/// Log buffer region used by the shim.
107105
pub log_buffer: MemoryRange,
108106
/// Memory to be used for the heap.
@@ -133,8 +131,6 @@ impl ShimParams {
133131
used_end,
134132
bounce_buffer_start,
135133
bounce_buffer_size,
136-
page_tables_start,
137-
page_tables_size,
138134
log_buffer_start,
139135
log_buffer_size,
140136
heap_start_offset,
@@ -150,13 +146,6 @@ impl ShimParams {
150146
Some(MemoryRange::new(base..base + bounce_buffer_size))
151147
};
152148

153-
let page_tables = if page_tables_size == 0 {
154-
None
155-
} else {
156-
let base = shim_base_address.wrapping_add_signed(page_tables_start);
157-
Some(MemoryRange::new(base..base + page_tables_size))
158-
};
159-
160149
let log_buffer = {
161150
let base = shim_base_address.wrapping_add_signed(log_buffer_start);
162151
MemoryRange::new(base..base + log_buffer_size)
@@ -189,7 +178,6 @@ impl ShimParams {
189178
..shim_base_address.wrapping_add_signed(used_end),
190179
),
191180
bounce_buffer,
192-
page_tables,
193181
log_buffer,
194182
heap,
195183
}

openhcl/openhcl_boot/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ fn shim_main(shim_params_raw_offset: isize) -> ! {
630630

631631
validate_vp_hw_ids(partition_info);
632632

633-
setup_vtl2_memory(&p, partition_info);
633+
setup_vtl2_memory(&p, partition_info, address_space);
634634
setup_vtl2_vp(partition_info);
635635

636636
verify_imported_regions_hash(&p);

openhcl/openhcl_boot/src/memory.rs

Lines changed: 89 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,6 @@ impl<'a, I: Iterator<Item = MemoryRange>> AddressSpaceManagerBuilder<'a, I> {
170170
self
171171
}
172172

173-
/// Pagetables that are reported as type [`MemoryVtlType::VTL2_TDX_PAGE_TABLES`].
174-
pub fn with_page_tables(mut self, page_tables: MemoryRange) -> Self {
175-
self.page_tables = Some(page_tables);
176-
self
177-
}
178-
179173
/// Log buffer that is reported as type [`MemoryVtlType::VTL2_BOOTSHIM_LOG_BUFFER`].
180174
pub fn with_log_buffer(mut self, log_buffer: MemoryRange) -> Self {
181175
self.log_buffer = Some(log_buffer);
@@ -362,6 +356,91 @@ impl AddressSpaceManager {
362356
allocated
363357
}
364358

359+
/// Truncate a memory range, with allocation policy deciding whether
360+
/// free the low part or high part.
361+
pub fn truncate_range(
362+
&mut self,
363+
range: AllocatedRange,
364+
len: u64,
365+
allocation_policy: AllocationPolicy,
366+
) {
367+
//TODO babayet2 ASSERT 4k or align
368+
//get index of range to modify
369+
//let index = self.address_space.iter().position(range).exepct("allocated range must be present");
370+
371+
let index = self
372+
.address_space
373+
.iter()
374+
.position(|r| r.range.start() == range.range.start())
375+
.unwrap();
376+
377+
let (used, remainder) = match allocation_policy {
378+
AllocationPolicy::LowMemory => {
379+
// Allocate from the beginning (low addresses)
380+
range.range.split_at_offset(len)
381+
}
382+
AllocationPolicy::HighMemory => {
383+
// Allocate from the end (high addresses)
384+
let offset = range.range.len() - len;
385+
let (remainder, used) = range.range.split_at_offset(offset);
386+
(used, remainder)
387+
}
388+
};
389+
390+
let remainder = if !remainder.is_empty() {
391+
Some(AddressRange {
392+
range: remainder,
393+
vnode: range.vnode,
394+
usage: AddressUsage::Free,
395+
})
396+
} else {
397+
None
398+
};
399+
400+
if let Some(remainder) = remainder {
401+
let (free_range, free_index) = match allocation_policy {
402+
AllocationPolicy::LowMemory => {
403+
let next = self.address_space.get(index + 1);
404+
if next.is_some()
405+
&& next.unwrap().usage == AddressUsage::Free
406+
&& next.unwrap().range.start() == remainder.range.end()
407+
{
408+
(MemoryRange::new(remainder.range.start()..next.unwrap().range.end()), index + 1)
409+
} else {
410+
(remainder.range, index + 1)
411+
}
412+
}
413+
AllocationPolicy::HighMemory => {
414+
// When allocating from high memory, the remainder goes
415+
// before the allocated range
416+
let prev = self.address_space.get(index - 1);
417+
if prev.is_some()
418+
&& prev.unwrap().usage == AddressUsage::Free
419+
&& prev.unwrap().range.end() == remainder.range.start()
420+
{
421+
(MemoryRange::new(prev.unwrap().range.start()..remainder.range.end()), index - 1)
422+
} else {
423+
(remainder.range, index - 1)
424+
}
425+
}
426+
};
427+
428+
let usage = self.address_space[index].usage;
429+
430+
self.address_space[index] = AddressRange {
431+
range: used,
432+
vnode: range.vnode,
433+
usage,
434+
};
435+
436+
self.address_space[free_index] = AddressRange {
437+
range: free_range,
438+
vnode: range.vnode,
439+
usage: AddressUsage::Free,
440+
};
441+
}
442+
}
443+
365444
/// Allocate a new range of memory with the given type and policy. None is
366445
/// returned if the allocation was unable to be satisfied.
367446
///
@@ -423,6 +502,9 @@ impl AddressSpaceManager {
423502
AllocationType::SidecarNode => {
424503
AddressUsage::Reserved(ReservedMemoryType::SidecarNode)
425504
}
505+
AllocationType::TdxPageTables => {
506+
AddressUsage::Reserved(ReservedMemoryType::TdxPageTables)
507+
}
426508
},
427509
allocation_policy,
428510
)
@@ -463,6 +545,7 @@ impl AddressSpaceManager {
463545
pub enum AllocationType {
464546
GpaPool,
465547
SidecarNode,
548+
TdxPageTables,
466549
}
467550

468551
pub enum AllocationPolicy {

vm/loader/loader_defs/src/shim.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,6 @@ pub struct ShimParamsRaw {
5353
pub bounce_buffer_start: i64,
5454
/// The size of the bounce buffer range. This is 0 if unavailable.
5555
pub bounce_buffer_size: u64,
56-
/// The offset to the page_tables start address. This is 0 if unavailable.
57-
pub page_tables_start: i64,
58-
/// The size of the openhcl_boot page tables. This is 0 if unavailable.
59-
pub page_tables_size: u64,
6056
/// The offset to the persisted bootshim log buffer.
6157
pub log_buffer_start: i64,
6258
/// The size of the persisted bootshim log buffer.

0 commit comments

Comments
 (0)