5454use std:: fmt:: Debug ;
5555use std:: mem:: size_of;
5656
57- use hyperlight_common:: layout:: TransportArena ;
57+ use hyperlight_common:: layout:: { QueueDims , TransportArena } ;
5858use hyperlight_common:: mem:: HyperlightPEB ;
5959use hyperlight_common:: vmem:: PAGE_SIZE ;
6060use tracing:: { Span , instrument} ;
@@ -255,18 +255,16 @@ pub(crate) struct SandboxMemoryLayout {
255255 init_data_permissions : Option < MemoryRegionFlags > ,
256256 /// The size of the scratch region in physical memory.
257257 scratch_size : usize ,
258- /// Number of descriptors in the G2H virtqueue .
259- g2h_queue_size : usize ,
260- /// Number of descriptors in the H2G virtqueue .
261- h2g_queue_size : usize ,
258+ /// G2H ring and buffer pool dimensions .
259+ g2h_dims : QueueDims ,
260+ /// H2G ring and buffer pool dimensions .
261+ h2g_dims : QueueDims ,
262262 /// Capacity of each G2H upper-tier buffer.
263263 g2h_buffer_size : usize ,
264264 /// Capacity of each H2G buffer.
265265 h2g_buffer_size : usize ,
266- /// Number of pages in the G2H buffer pool.
267- g2h_pool_pages : usize ,
268- /// Number of pages in the H2G buffer pool.
269- h2g_pool_pages : usize ,
266+ /// Fixed ring and pool placement within scratch.
267+ transport_arena : TransportArena ,
270268 /// Size of the primary guest memory region at `BASE_ADDRESS`
271269 /// (code, PEB, heap, init data). For a snapshot-backed layout
272270 /// this is also the guest-visible prefix of the host snapshot
@@ -301,12 +299,12 @@ impl Debug for SandboxMemoryLayout {
301299 & format_args ! ( "{:#x}" , self . output_data_size) ,
302300 )
303301 . field ( "Scratch Size" , & format_args ! ( "{:#x}" , self . scratch_size) )
304- . field ( "G2H Queue Size" , & self . g2h_queue_size )
305- . field ( "H2G Queue Size" , & self . h2g_queue_size )
302+ . field ( "G2H Queue Size" , & self . get_g2h_queue_size ( ) )
303+ . field ( "H2G Queue Size" , & self . get_h2g_queue_size ( ) )
306304 . field ( "G2H Buffer Size" , & self . g2h_buffer_size )
307305 . field ( "H2G Buffer Size" , & self . h2g_buffer_size )
308- . field ( "G2H Pool Pages" , & self . g2h_pool_pages )
309- . field ( "H2G Pool Pages" , & self . h2g_pool_pages )
306+ . field ( "G2H Pool Pages" , & self . get_g2h_pool_pages ( ) )
307+ . field ( "H2G Pool Pages" , & self . get_h2g_pool_pages ( ) )
310308 . field ( "Snapshot Size" , & format_args ! ( "{:#x}" , self . snapshot_size) )
311309 . field ( "PT Size" , & format_args ! ( "{:#x}" , self . pt_size. unwrap_or( 0 ) ) )
312310 . field (
@@ -380,6 +378,15 @@ impl SandboxMemoryLayout {
380378 return Err ( MemoryRequestTooSmall ( scratch_size, min_scratch_size) ) ;
381379 }
382380
381+ let g2h_dims = QueueDims :: new ( g2h_queue_size, g2h_pool_pages)
382+ . ok_or_else ( || new_error ! ( "invalid G2H queue dimensions" ) ) ?;
383+ let h2g_dims = QueueDims :: new ( h2g_queue_size, h2g_pool_pages)
384+ . ok_or_else ( || new_error ! ( "invalid H2G queue dimensions" ) ) ?;
385+ let arena_base_gpa = hyperlight_common:: layout:: scratch_base_gpa ( scratch_size)
386+ + ( input_data_size + output_data_size) . next_multiple_of ( PAGE_SIZE ) as u64 ;
387+ let transport_arena = TransportArena :: new ( arena_base_gpa, g2h_dims, h2g_dims)
388+ . ok_or_else ( || new_error ! ( "invalid virtqueue arena dimensions" ) ) ?;
389+
383390 let mut ret = Self {
384391 input_data_size,
385392 output_data_size,
@@ -389,12 +396,11 @@ impl SandboxMemoryLayout {
389396 init_data_permissions,
390397 pt_size : None ,
391398 scratch_size,
392- g2h_queue_size ,
393- h2g_queue_size ,
399+ g2h_dims ,
400+ h2g_dims ,
394401 g2h_buffer_size,
395402 h2g_buffer_size,
396- g2h_pool_pages,
397- h2g_pool_pages,
403+ transport_arena,
398404 snapshot_size : 0 ,
399405 } ;
400406 ret. set_snapshot_size ( ret. get_memory_size ( ) ?) ;
@@ -431,12 +437,12 @@ impl SandboxMemoryLayout {
431437
432438 #[ allow( dead_code) ]
433439 pub ( crate ) fn get_g2h_queue_size ( & self ) -> usize {
434- self . g2h_queue_size
440+ usize :: from ( self . g2h_dims . size ( ) . get ( ) )
435441 }
436442
437443 #[ allow( dead_code) ]
438444 pub ( crate ) fn get_h2g_queue_size ( & self ) -> usize {
439- self . h2g_queue_size
445+ usize :: from ( self . h2g_dims . size ( ) . get ( ) )
440446 }
441447
442448 #[ allow( dead_code) ]
@@ -451,22 +457,20 @@ impl SandboxMemoryLayout {
451457
452458 #[ allow( dead_code) ]
453459 pub ( crate ) fn get_g2h_pool_pages ( & self ) -> usize {
454- self . g2h_pool_pages
460+ self . g2h_dims . pool_pages ( ) . get ( )
455461 }
456462
457463 #[ allow( dead_code) ]
458464 pub ( crate ) fn get_h2g_pool_pages ( & self ) -> usize {
459- self . h2g_pool_pages
465+ self . h2g_dims . pool_pages ( ) . get ( )
460466 }
461467
462- pub ( crate ) fn get_g2h_queue_dims ( & self ) -> hyperlight_common:: layout:: QueueDims {
463- hyperlight_common:: layout:: QueueDims :: new ( self . g2h_queue_size , self . g2h_pool_pages )
464- . expect ( "validated G2H queue dimensions" )
468+ pub ( crate ) fn get_g2h_queue_dims ( & self ) -> QueueDims {
469+ self . g2h_dims
465470 }
466471
467- pub ( crate ) fn get_h2g_queue_dims ( & self ) -> hyperlight_common:: layout:: QueueDims {
468- hyperlight_common:: layout:: QueueDims :: new ( self . h2g_queue_size , self . h2g_pool_pages )
469- . expect ( "validated H2G queue dimensions" )
472+ pub ( crate ) fn get_h2g_queue_dims ( & self ) -> QueueDims {
473+ self . h2g_dims
470474 }
471475
472476 /// Guest-visible prefix size of the snapshot blob.
@@ -494,10 +498,10 @@ impl SandboxMemoryLayout {
494498 let min_fixed_scratch = hyperlight_common:: layout:: min_scratch_size (
495499 self . input_data_size ,
496500 self . output_data_size ,
497- self . g2h_queue_size ,
498- self . h2g_queue_size ,
499- self . g2h_pool_pages ,
500- self . h2g_pool_pages ,
501+ self . get_g2h_queue_size ( ) ,
502+ self . get_h2g_queue_size ( ) ,
503+ self . get_g2h_pool_pages ( ) ,
504+ self . get_h2g_pool_pages ( ) ,
501505 ) ;
502506 let min_scratch = min_fixed_scratch. saturating_add ( size) ;
503507 if self . scratch_size < min_scratch {
@@ -760,36 +764,23 @@ impl SandboxMemoryLayout {
760764 /// Offset from the beginning of the scratch region to the location
761765 /// where page tables are eagerly copied on restore.
762766 pub ( crate ) fn get_pt_base_scratch_offset ( & self ) -> usize {
763- self . get_virtq_base_scratch_offset ( ) + self . get_transport_arena ( ) . size ( )
767+ ( self . get_pt_base_gpa ( ) - hyperlight_common:: layout:: scratch_base_gpa ( self . scratch_size ) )
768+ as usize
764769 }
765770
766771 /// Base GPA to which the page tables are eagerly copied on restore.
767772 pub ( crate ) fn get_pt_base_gpa ( & self ) -> u64 {
768- hyperlight_common:: layout:: scratch_base_gpa ( self . scratch_size )
769- + self . get_pt_base_scratch_offset ( ) as u64
773+ self . transport_arena . end_addr ( )
770774 }
771775
772776 /// First GPA available to the guest scratch allocator.
773777 pub ( crate ) fn get_first_free_scratch_gpa ( & self ) -> u64 {
774778 self . get_pt_base_gpa ( ) + self . pt_size . unwrap_or ( 0 ) as u64
775779 }
776780
777- fn get_virtq_base_scratch_offset ( & self ) -> usize {
778- ( self . input_data_size + self . output_data_size )
779- . next_multiple_of ( hyperlight_common:: vmem:: PAGE_SIZE )
780- }
781-
782781 /// Exact transport placement in the fixed scratch prefix.
783782 pub ( crate ) fn get_transport_arena ( & self ) -> TransportArena {
784- let base_gpa = hyperlight_common:: layout:: scratch_base_gpa ( self . scratch_size )
785- + self . get_virtq_base_scratch_offset ( ) as u64 ;
786-
787- TransportArena :: new (
788- base_gpa,
789- self . get_g2h_queue_dims ( ) ,
790- self . get_h2g_queue_dims ( ) ,
791- )
792- . expect ( "validated virtqueue arena dimensions" )
783+ self . transport_arena
793784 }
794785
795786 /// Total size of guest memory in `self`'s memory layout.
@@ -847,6 +838,27 @@ mod tests {
847838 ) ;
848839 }
849840
841+ #[ test]
842+ fn transport_arena_after_unaligned_io_buffers ( ) {
843+ let mut cfg = SandboxConfiguration :: default ( ) ;
844+ cfg. set_input_data_size ( 0x4001 ) ;
845+ cfg. set_output_data_size ( 0x2001 ) ;
846+ let mut layout = SandboxMemoryLayout :: new ( cfg, 4096 , 0 , None ) . unwrap ( ) ;
847+ let arena = layout. get_transport_arena ( ) ;
848+ let scratch_base = hyperlight_common:: layout:: scratch_base_gpa ( layout. get_scratch_size ( ) ) ;
849+
850+ assert_eq ! ( arena. base_addr( ) , scratch_base + 0x7000 ) ;
851+ assert_eq ! ( layout. get_pt_base_gpa( ) , arena. end_addr( ) ) ;
852+
853+ layout. set_pt_size ( PAGE_SIZE ) . unwrap ( ) ;
854+
855+ assert_eq ! ( layout. get_transport_arena( ) , arena) ;
856+ assert_eq ! (
857+ layout. get_first_free_scratch_gpa( ) ,
858+ arena. end_addr( ) + PAGE_SIZE as u64
859+ ) ;
860+ }
861+
850862 #[ test]
851863 fn transport_memory_is_part_of_minimum_scratch_size ( ) {
852864 let mut cfg = SandboxConfiguration :: default ( ) ;
0 commit comments