@@ -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
6163use std:: fmt:: Debug ;
6264use std:: mem:: { offset_of, size_of} ;
@@ -66,13 +68,15 @@ use tracing::{Span, instrument};
6668
6769#[ cfg( feature = "init-paging" ) ]
6870use 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 } ;
7072use super :: memory_region:: {
7173 DEFAULT_GUEST_BLOB_MEM_FLAGS , MemoryRegion_ , MemoryRegionFlags , MemoryRegionKind ,
7274 MemoryRegionVecBuilder ,
7375} ;
7476use super :: shared_mem:: { ExclusiveSharedMemory , SharedMemory } ;
75- use crate :: error:: HyperlightError :: { GuestOffsetIsInvalid , MemoryRequestTooBig } ;
77+ use crate :: error:: HyperlightError :: {
78+ GuestOffsetIsInvalid , MemoryRequestTooBig , MemoryRequestTooSmall ,
79+ } ;
7680use crate :: sandbox:: SandboxConfiguration ;
7781use 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
182174impl 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 ( ..) ) ) ;
0 commit comments