Skip to content

Commit b54dd6d

Browse files
committed
Move I/O buffers to scratch region
These are, for now, still set up at certain distinguished addresses (at the beginning of the region) that the host and the guest can both compute. In the future, hopefully all of this will be replaced with a more flexible set up based on the ring-buffer I/O design doc. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
1 parent 7fc2d80 commit b54dd6d

12 files changed

Lines changed: 168 additions & 147 deletions

File tree

src/hyperlight_common/src/arch/amd64/layout.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ pub const MAX_GPA: usize = 0x0000_000f_ffff_ffff;
3737
/// - A page for the smallest possible non-exception stack
3838
/// - (up to) 3 pages for mapping that
3939
/// - Two pages for the exception stack and metadata
40-
pub fn min_scratch_size() -> usize {
41-
12 * crate::vmem::PAGE_SIZE
40+
/// - A page-aligned amount of memory for I/O buffers (for now)
41+
pub fn min_scratch_size(input_data_size: usize, output_data_size: usize) -> usize {
42+
(input_data_size + output_data_size).next_multiple_of(crate::vmem::PAGE_SIZE)
43+
+ 12 * crate::vmem::PAGE_SIZE
4244
}

src/hyperlight_host/benches/benchmarks.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ fn guest_call_benchmark_large_param(c: &mut Criterion) {
385385

386386
let mut config = SandboxConfiguration::default();
387387
config.set_input_data_size(2 * SIZE + (1024 * 1024)); // 2 * SIZE + 1 MB, to allow 1MB for the rest of the serialized function call
388+
config.set_scratch_size(2 * SIZE + 2 * (1024 * 1024)); // 2 * SIZE + 2 MB, to allow 1MB for data outside of the I/O regions
388389
config.set_heap_size(SIZE as u64 * 15);
389390

390391
let sandbox = UninitializedSandbox::new(

src/hyperlight_host/src/error.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,11 @@ pub enum HyperlightError {
160160
#[error("Memory requested {0} exceeds maximum size allowed {1}")]
161161
MemoryRequestTooBig(usize, usize),
162162

163+
/// The memory request is too small to contain everything that is
164+
/// required
165+
#[error("Memory requested {0} is less than the minimum size allowed {1}")]
166+
MemoryRequestTooSmall(usize, usize),
167+
163168
/// Metric Not Found.
164169
#[error("Metric Not Found {0:?}.")]
165170
MetricNotFound(&'static str),
@@ -363,6 +368,7 @@ impl HyperlightError {
363368
| HyperlightError::MemoryAllocationFailed(_)
364369
| HyperlightError::MemoryProtectionFailed(_)
365370
| HyperlightError::MemoryRequestTooBig(_, _)
371+
| HyperlightError::MemoryRequestTooSmall(_, _)
366372
| HyperlightError::MetricNotFound(_)
367373
| HyperlightError::MmapFailed(_)
368374
| HyperlightError::MprotectFailed(_)

src/hyperlight_host/src/mem/layout.rs

Lines changed: 78 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,6 @@ limitations under the License.
2727
//! +-------------------------------------------+
2828
//! | Guest Heap |
2929
//! +-------------------------------------------+
30-
//! | Output Data |
31-
//! +-------------------------------------------+
32-
//! | Input Data |
33-
//! +-------------------------------------------+
3430
//! | PEB Struct | (HyperlightPEB size)
3531
//! +-------------------------------------------+
3632
//! | Guest Code |
@@ -46,17 +42,23 @@ limitations under the License.
4642
//! - `InitData` - some extra data that can be loaded onto the sandbox during
4743
//! initialization.
4844
//!
49-
//! - `HostDefinitions` - the length of this is the `HostFunctionDefinitionSize`
50-
//! field from `SandboxConfiguration`
51-
//!
52-
//! - `InputData` - this is a buffer that is used for input data to the host program.
53-
//! the length of this field is `InputDataSize` from `SandboxConfiguration`
54-
//!
55-
//! - `OutputData` - this is a buffer that is used for output data from host program.
56-
//! the length of this field is `OutputDataSize` from `SandboxConfiguration`
57-
//!
5845
//! - `GuestHeap` - this is a buffer that is used for heap data in the guest. the length
5946
//! of this field is returned by the `heap_size()` method of this struct
47+
//!
48+
//! There is also a scratch region at the top of physical memory,
49+
//! which is mostly laid out as a large undifferentiated blob of
50+
//! memory, although at present the snapshot process specially
51+
//! privileges the statically allocated input and output data regions:
52+
//!
53+
//! +-------------------------------------------+ (top of physical memory)
54+
//! | Exception Stack, Metadata |
55+
//! +-------------------------------------------+ (1 page below)
56+
//! | Scratch Memory |
57+
//! +-------------------------------------------+
58+
//! | Output Data |
59+
//! +-------------------------------------------+
60+
//! | Input Data |
61+
//! +-------------------------------------------+ (scratch size)
6062
6163
use std::fmt::Debug;
6264
use std::mem::{offset_of, size_of};
@@ -66,13 +68,15 @@ use tracing::{Span, instrument};
6668

6769
#[cfg(feature = "init-paging")]
6870
use super::memory_region::MemoryRegionType::PageTables;
69-
use super::memory_region::MemoryRegionType::{Code, Heap, InitData, InputData, OutputData, Peb};
71+
use super::memory_region::MemoryRegionType::{Code, Heap, InitData, Peb};
7072
use super::memory_region::{
7173
DEFAULT_GUEST_BLOB_MEM_FLAGS, MemoryRegion_, MemoryRegionFlags, MemoryRegionKind,
7274
MemoryRegionVecBuilder,
7375
};
7476
use super::shared_mem::{ExclusiveSharedMemory, SharedMemory};
75-
use crate::error::HyperlightError::{GuestOffsetIsInvalid, MemoryRequestTooBig};
77+
use crate::error::HyperlightError::{
78+
GuestOffsetIsInvalid, MemoryRequestTooBig, MemoryRequestTooSmall,
79+
};
7680
use crate::sandbox::SandboxConfiguration;
7781
use crate::{Result, new_error};
7882

@@ -92,10 +96,6 @@ pub(crate) struct SandboxMemoryLayout {
9296
peb_init_data_offset: usize,
9397
peb_heap_data_offset: usize,
9498

95-
// The following are the actual values
96-
// that are written to the PEB struct
97-
pub(super) input_data_buffer_offset: usize,
98-
pub(super) output_data_buffer_offset: usize,
9999
guest_heap_buffer_offset: usize,
100100
init_data_offset: usize,
101101
pt_offset: usize,
@@ -149,14 +149,6 @@ impl Debug for SandboxMemoryLayout {
149149
"Guest Heap Offset",
150150
&format_args!("{:#x}", self.peb_heap_data_offset),
151151
)
152-
.field(
153-
"Input Data Buffer Offset",
154-
&format_args!("{:#x}", self.input_data_buffer_offset),
155-
)
156-
.field(
157-
"Output Data Buffer Offset",
158-
&format_args!("{:#x}", self.output_data_buffer_offset),
159-
)
160152
.field(
161153
"Guest Heap Buffer Offset",
162154
&format_args!("{:#x}", self.guest_heap_buffer_offset),
@@ -181,9 +173,14 @@ impl Debug for SandboxMemoryLayout {
181173

182174
impl SandboxMemoryLayout {
183175
/// The maximum amount of memory a single sandbox will be allowed.
184-
/// The addressable virtual memory with current paging setup is virtual address 0x0 - 0x40000000 (excl.),
185-
/// However, the memory up to Self::BASE_ADDRESS is not used.
186-
const MAX_MEMORY_SIZE: usize = 0x40000000 - Self::BASE_ADDRESS;
176+
///
177+
/// Currently, both the scratch region and the snapshot region are
178+
/// bounded by this size. The current value is essentially
179+
/// arbitrary and chosen for historical reasons; the modern
180+
/// sandbox virtual memory layout can support much more, so this
181+
/// could be increased should use cases for larger sandboxes
182+
/// arise.
183+
const MAX_MEMORY_SIZE: usize = 0x4000_0000 - Self::BASE_ADDRESS;
187184

188185
/// The base address of the sandbox's memory.
189186
#[cfg(feature = "init-paging")]
@@ -192,7 +189,7 @@ impl SandboxMemoryLayout {
192189
pub(crate) const BASE_ADDRESS: usize = 0x0;
193190

194191
// the offset into a sandbox's input/output buffer where the stack starts
195-
const STACK_POINTER_SIZE_BYTES: u64 = 8;
192+
pub(crate) const STACK_POINTER_SIZE_BYTES: u64 = 8;
196193

197194
/// Create a new `SandboxMemoryLayout` with the given
198195
/// `SandboxConfiguration`, code size and stack/heap size.
@@ -229,14 +226,10 @@ impl SandboxMemoryLayout {
229226
// The following offsets are the actual values that relate to memory layout,
230227
// which are written to PEB struct
231228
let peb_address = Self::BASE_ADDRESS + peb_offset;
232-
// make sure input data buffer starts at 4K boundary
233-
let input_data_buffer_offset = (peb_heap_data_offset + size_of::<GuestMemoryRegion>())
234-
.next_multiple_of(PAGE_SIZE_USIZE);
235-
let output_data_buffer_offset = (input_data_buffer_offset + cfg.get_input_data_size())
236-
.next_multiple_of(PAGE_SIZE_USIZE);
237229
// make sure heap buffer starts at 4K boundary
238-
let guest_heap_buffer_offset = (output_data_buffer_offset + cfg.get_output_data_size())
230+
let guest_heap_buffer_offset = (peb_heap_data_offset + size_of::<GuestMemoryRegion>())
239231
.next_multiple_of(PAGE_SIZE_USIZE);
232+
240233
// make sure init data starts at 4K boundary
241234
let init_data_offset =
242235
(guest_heap_buffer_offset + heap_size).next_multiple_of(PAGE_SIZE_USIZE);
@@ -252,8 +245,6 @@ impl SandboxMemoryLayout {
252245
peb_heap_data_offset,
253246
sandbox_memory_config: cfg,
254247
code_size,
255-
input_data_buffer_offset,
256-
output_data_buffer_offset,
257248
guest_heap_buffer_offset,
258249
peb_address,
259250
guest_code_offset,
@@ -301,11 +292,18 @@ impl SandboxMemoryLayout {
301292
self.get_init_data_size_offset() + size_of::<u64>()
302293
}
303294

304-
/// Get the offset in guest memory to the start of output data.
295+
/// Get the guest virtual address of the start of output data.
305296
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
306-
#[cfg(test)]
307-
pub(crate) fn get_output_data_offset(&self) -> usize {
308-
self.output_data_buffer_offset
297+
pub(crate) fn get_output_data_buffer_gva(&self) -> u64 {
298+
hyperlight_common::layout::scratch_base_gva(self.scratch_size)
299+
+ self.sandbox_memory_config.get_input_data_size() as u64
300+
}
301+
302+
/// Get the offset into the host scratch buffer of the start of
303+
/// the output data.
304+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
305+
pub(crate) fn get_output_data_buffer_scratch_host_offset(&self) -> usize {
306+
self.sandbox_memory_config.get_input_data_size()
309307
}
310308

311309
/// Get the offset in guest memory to the input data size.
@@ -323,6 +321,29 @@ impl SandboxMemoryLayout {
323321
self.get_input_data_size_offset() + size_of::<u64>()
324322
}
325323

324+
/// Get the guest virtual address of the start of input data
325+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
326+
fn get_input_data_buffer_gva(&self) -> u64 {
327+
hyperlight_common::layout::scratch_base_gva(self.scratch_size)
328+
}
329+
330+
/// Get the offset into the host scratch buffer of the start of
331+
/// the input data
332+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
333+
pub(crate) fn get_input_data_buffer_scratch_host_offset(&self) -> usize {
334+
0
335+
}
336+
337+
/// Get the offset into the host scratch buffer of the start of
338+
/// the input data
339+
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
340+
pub(crate) fn get_first_free_scratch_gpa(&self) -> u64 {
341+
(hyperlight_common::layout::scratch_base_gpa(self.scratch_size) as usize
342+
+ self.sandbox_memory_config.get_input_data_size()
343+
+ self.sandbox_memory_config.get_output_data_size())
344+
.next_multiple_of(hyperlight_common::vmem::PAGE_SIZE) as u64
345+
}
346+
326347
/// Get the offset in guest memory to where the guest dispatch function
327348
/// pointer is written
328349
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
@@ -424,47 +445,12 @@ impl SandboxMemoryLayout {
424445
}
425446

426447
// PEB
427-
let input_data_offset = builder.push_page_aligned(
448+
let heap_offset = builder.push_page_aligned(
428449
size_of::<HyperlightPEB>(),
429450
MemoryRegionFlags::READ | MemoryRegionFlags::WRITE,
430451
Peb,
431452
);
432453

433-
let expected_input_data_offset = TryInto::<usize>::try_into(self.input_data_buffer_offset)?;
434-
435-
if input_data_offset != expected_input_data_offset {
436-
return Err(new_error!(
437-
"Input Data offset does not match expected Input Data offset expected: {}, actual: {}",
438-
expected_input_data_offset,
439-
input_data_offset
440-
));
441-
}
442-
443-
// guest input data
444-
let output_data_offset = builder.push_page_aligned(
445-
self.sandbox_memory_config.get_input_data_size(),
446-
MemoryRegionFlags::READ | MemoryRegionFlags::WRITE,
447-
InputData,
448-
);
449-
450-
let expected_output_data_offset =
451-
TryInto::<usize>::try_into(self.output_data_buffer_offset)?;
452-
453-
if output_data_offset != expected_output_data_offset {
454-
return Err(new_error!(
455-
"Output Data offset does not match expected Output Data offset expected: {}, actual: {}",
456-
expected_output_data_offset,
457-
output_data_offset
458-
));
459-
}
460-
461-
// guest output data
462-
let heap_offset = builder.push_page_aligned(
463-
self.sandbox_memory_config.get_output_data_size(),
464-
MemoryRegionFlags::READ | MemoryRegionFlags::WRITE,
465-
OutputData,
466-
);
467-
468454
let expected_heap_offset = TryInto::<usize>::try_into(self.guest_heap_buffer_offset)?;
469455

470456
if heap_offset != expected_heap_offset {
@@ -595,8 +581,10 @@ impl SandboxMemoryLayout {
595581
.get_input_data_size()
596582
.try_into()?,
597583
)?;
598-
let addr = get_address!(input_data_buffer_offset);
599-
shared_mem.write_u64(self.get_input_data_pointer_offset(), addr)?;
584+
shared_mem.write_u64(
585+
self.get_input_data_pointer_offset(),
586+
self.get_input_data_buffer_gva(),
587+
)?;
600588

601589
// Set up output buffer pointer
602590
shared_mem.write_u64(
@@ -605,8 +593,10 @@ impl SandboxMemoryLayout {
605593
.get_output_data_size()
606594
.try_into()?,
607595
)?;
608-
let addr = get_address!(output_data_buffer_offset);
609-
shared_mem.write_u64(self.get_output_data_pointer_offset(), addr)?;
596+
shared_mem.write_u64(
597+
self.get_output_data_pointer_offset(),
598+
self.get_output_data_buffer_gva(),
599+
)?;
610600

611601
// Set up init data pointer
612602
shared_mem.write_u64(
@@ -623,17 +613,10 @@ impl SandboxMemoryLayout {
623613

624614
// End of setting up the PEB
625615

626-
// Initialize the stack pointers of input data and output data
627-
// to point to the ninth (index 8) byte, which is the first free address
628-
// of the each respective stack. The first 8 bytes are the stack pointer itself.
629-
shared_mem.write_u64(
630-
self.input_data_buffer_offset,
631-
Self::STACK_POINTER_SIZE_BYTES,
632-
)?;
633-
shared_mem.write_u64(
634-
self.output_data_buffer_offset,
635-
Self::STACK_POINTER_SIZE_BYTES,
636-
)?;
616+
// The input and output data regions do not have their layout
617+
// initialised here, because they are in the scratch
618+
// region---they are instead set in
619+
// [`SandboxMemoryManager::update_scratch_bookkeeping`].
637620

638621
Ok(())
639622
}
@@ -647,17 +630,12 @@ mod tests {
647630

648631
// helper func for testing
649632
fn get_expected_memory_size(layout: &SandboxMemoryLayout) -> usize {
650-
let cfg = layout.sandbox_memory_config;
651633
let mut expected_size = 0;
652634
// in order of layout
653635
expected_size += layout.code_size;
654636

655637
expected_size += size_of::<HyperlightPEB>().next_multiple_of(PAGE_SIZE_USIZE);
656638

657-
expected_size += cfg.get_input_data_size().next_multiple_of(PAGE_SIZE_USIZE);
658-
659-
expected_size += cfg.get_output_data_size().next_multiple_of(PAGE_SIZE_USIZE);
660-
661639
expected_size += layout.heap_size.next_multiple_of(PAGE_SIZE_USIZE);
662640

663641
expected_size
@@ -676,6 +654,7 @@ mod tests {
676654
#[test]
677655
fn test_max_memory_sandbox() {
678656
let mut cfg = SandboxConfiguration::default();
657+
cfg.set_scratch_size(0x40004000);
679658
cfg.set_input_data_size(0x40000000);
680659
let layout = SandboxMemoryLayout::new(cfg, 4096, 4096, None);
681660
assert!(matches!(layout.unwrap_err(), MemoryRequestTooBig(..)));

src/hyperlight_host/src/mem/memory_region.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,6 @@ pub enum MemoryRegionType {
126126
InitData,
127127
/// The region contains the PEB
128128
Peb,
129-
/// The region contains the Host Function Definitions
130-
HostFunctionDefinitions,
131-
/// The region contains the Input Data
132-
InputData,
133-
/// The region contains the Output Data
134-
OutputData,
135129
/// The region contains the Heap
136130
Heap,
137131
/// The region contains the Guard Page

0 commit comments

Comments
 (0)