@@ -93,6 +93,8 @@ use vm_memory::mmap::MmapRegion;
9393#[ cfg( not( any( feature = "tee" , feature = "aws-nitro" ) ) ) ]
9494use vm_memory:: Address ;
9595use vm_memory:: Bytes ;
96+ #[ cfg( feature = "vhost-user" ) ]
97+ use vm_memory:: FileOffset ;
9698#[ cfg( not( feature = "aws-nitro" ) ) ]
9799use vm_memory:: GuestMemory ;
98100#[ cfg( all( target_arch = "x86_64" , not( feature = "tee" ) ) ) ]
@@ -1331,9 +1333,81 @@ fn load_payload(
13311333 return Err ( StartMicrovmError :: MissingKernelConfig ) ;
13321334 } ;
13331335
1334- let kernel_region = unsafe {
1335- MmapRegion :: build_raw ( kernel_host_addr as * mut u8 , kernel_size, 0 , 0 )
1336- . map_err ( StartMicrovmError :: InvalidKernelBundle ) ?
1336+ #[ cfg( feature = "vhost-user" ) ]
1337+ let use_vhost_user = _vm_resources. vhost_user_rng_socket . is_some ( ) ;
1338+ #[ cfg( not( feature = "vhost-user" ) ) ]
1339+ let use_vhost_user = false ;
1340+
1341+ let kernel_region = if use_vhost_user {
1342+ #[ cfg( feature = "vhost-user" ) ]
1343+ {
1344+ debug ! (
1345+ "Creating file-backed kernel region for vhost-user (size=0x{:x})" ,
1346+ kernel_size
1347+ ) ;
1348+ // SAFETY: memfd_create is called with a valid null-terminated C string and valid flags.
1349+ // File descriptor ownership is transferred to File::from_raw_fd below.
1350+ let memfd = unsafe {
1351+ let fd = libc:: memfd_create (
1352+ b"kernel\0 " . as_ptr ( ) as * const libc:: c_char ,
1353+ libc:: MFD_CLOEXEC ,
1354+ ) ;
1355+ if fd < 0 {
1356+ error ! (
1357+ "Failed to create memfd for kernel: {:?}" ,
1358+ io:: Error :: last_os_error( )
1359+ ) ;
1360+ return Err ( io:: Error :: last_os_error ( ) ) . map_err ( |e| {
1361+ StartMicrovmError :: GuestMemoryMmap ( vm_memory:: Error :: MmapRegion (
1362+ vm_memory:: mmap:: MmapRegionError :: Mmap ( e) ,
1363+ ) )
1364+ } ) ?;
1365+ }
1366+ if libc:: ftruncate ( fd, kernel_size as i64 ) < 0 {
1367+ error ! (
1368+ "Failed to ftruncate kernel memfd: {:?}" ,
1369+ io:: Error :: last_os_error( )
1370+ ) ;
1371+ libc:: close ( fd) ;
1372+ return Err ( io:: Error :: last_os_error ( ) ) . map_err ( |e| {
1373+ StartMicrovmError :: GuestMemoryMmap ( vm_memory:: Error :: MmapRegion (
1374+ vm_memory:: mmap:: MmapRegionError :: Mmap ( e) ,
1375+ ) )
1376+ } ) ?;
1377+ }
1378+ debug ! ( "Created kernel memfd with fd={}" , fd) ;
1379+ File :: from_raw_fd ( fd)
1380+ } ;
1381+
1382+ let file_offset = FileOffset :: new ( memfd, 0 ) ;
1383+ let region = MmapRegion :: from_file ( file_offset, kernel_size)
1384+ . map_err ( StartMicrovmError :: InvalidKernelBundle ) ?;
1385+
1386+ // SAFETY: kernel_host_addr points to valid kernel data of size kernel_size,
1387+ // provided by the kernel bundle loader.
1388+ let kernel_data = unsafe {
1389+ std:: slice:: from_raw_parts ( kernel_host_addr as * const u8 , kernel_size)
1390+ } ;
1391+ // SAFETY: Both source (kernel_data) and destination (region) are valid for
1392+ // kernel_size bytes. Regions don't overlap as dest is newly allocated memfd-backed
1393+ // memory and source is from kernel bundle.
1394+ unsafe {
1395+ let dest = region. as_ptr ( ) as * mut u8 ;
1396+ std:: ptr:: copy_nonoverlapping ( kernel_data. as_ptr ( ) , dest, kernel_size) ;
1397+ }
1398+ debug ! ( "Copied kernel data to file-backed region" ) ;
1399+
1400+ region
1401+ }
1402+ #[ cfg( not( feature = "vhost-user" ) ) ]
1403+ unreachable ! ( )
1404+ } else {
1405+ // SAFETY: kernel_host_addr points to valid kernel data of size kernel_size.
1406+ // The memory region is managed by the kernel bundle and remains valid.
1407+ unsafe {
1408+ MmapRegion :: build_raw ( kernel_host_addr as * mut u8 , kernel_size, 0 , 0 )
1409+ . map_err ( StartMicrovmError :: InvalidKernelBundle ) ?
1410+ }
13371411 } ;
13381412
13391413 Ok ( (
@@ -1498,10 +1572,76 @@ pub fn create_guest_memory(
14981572 . map_err ( StartMicrovmError :: ShmCreate ) ?;
14991573 }
15001574
1575+ // For vhost-user devices, we need file-backed memory so the backend can mmap it
1576+ #[ cfg( feature = "vhost-user" ) ]
1577+ let use_vhost_user = vm_resources. vhost_user_rng_socket . is_some ( ) ;
1578+ #[ cfg( not( feature = "vhost-user" ) ) ]
1579+ let use_vhost_user = false ;
1580+
1581+ // Add SHM regions before creating guest memory
15011582 arch_mem_regions. extend ( shm_manager. regions ( ) ) ;
15021583
1503- let guest_mem = GuestMemoryMmap :: from_ranges ( & arch_mem_regions)
1504- . map_err ( StartMicrovmError :: GuestMemoryMmap ) ?;
1584+ let guest_mem = if use_vhost_user {
1585+ #[ cfg( feature = "vhost-user" ) ]
1586+ {
1587+ debug ! (
1588+ "Creating file-backed memory for vhost-user (regions: {})" ,
1589+ arch_mem_regions. len( )
1590+ ) ;
1591+ // Create file-backed memory regions using memfd
1592+ let regions_with_files: Vec < _ > = arch_mem_regions
1593+ . iter ( )
1594+ . map ( |( addr, size) | {
1595+ debug ! (
1596+ " Creating memfd for region: addr=0x{:x}, size=0x{:x}" ,
1597+ addr. 0 , size
1598+ ) ;
1599+ // SAFETY: memfd_create is called with a valid null-terminated C string and valid flags.
1600+ // File descriptor ownership is transferred to File::from_raw_fd below.
1601+ let memfd = unsafe {
1602+ let fd = libc:: memfd_create (
1603+ b"guest_mem\0 " . as_ptr ( ) as * const libc:: c_char ,
1604+ libc:: MFD_CLOEXEC ,
1605+ ) ;
1606+ if fd < 0 {
1607+ error ! ( "Failed to create memfd: {:?}" , io:: Error :: last_os_error( ) ) ;
1608+ return Err ( io:: Error :: last_os_error ( ) ) ;
1609+ }
1610+ if libc:: ftruncate ( fd, * size as i64 ) < 0 {
1611+ error ! (
1612+ "Failed to ftruncate memfd: {:?}" ,
1613+ io:: Error :: last_os_error( )
1614+ ) ;
1615+ libc:: close ( fd) ;
1616+ return Err ( io:: Error :: last_os_error ( ) ) ;
1617+ }
1618+ debug ! ( " Created memfd with fd={}" , fd) ;
1619+ File :: from_raw_fd ( fd)
1620+ } ;
1621+
1622+ let file_offset = FileOffset :: new ( memfd, 0 ) ;
1623+ Ok ( ( * addr, * size, Some ( file_offset) ) )
1624+ } )
1625+ . collect :: < Result < Vec < _ > , io:: Error > > ( )
1626+ . map_err ( |e| {
1627+ StartMicrovmError :: GuestMemoryMmap ( vm_memory:: Error :: MmapRegion (
1628+ vm_memory:: mmap:: MmapRegionError :: Mmap ( e) ,
1629+ ) )
1630+ } ) ?;
1631+
1632+ debug ! (
1633+ "Created {} file-backed memory regions" ,
1634+ regions_with_files. len( )
1635+ ) ;
1636+ GuestMemoryMmap :: from_ranges_with_files ( & regions_with_files)
1637+ . map_err ( StartMicrovmError :: GuestMemoryMmap ) ?
1638+ }
1639+ #[ cfg( not( feature = "vhost-user" ) ) ]
1640+ unreachable ! ( )
1641+ } else {
1642+ GuestMemoryMmap :: from_ranges ( & arch_mem_regions)
1643+ . map_err ( StartMicrovmError :: GuestMemoryMmap ) ?
1644+ } ;
15051645
15061646 let ( guest_mem, entry_addr, initrd_config, cmdline) =
15071647 load_payload ( vm_resources, guest_mem, & arch_mem_info, payload) ?;
0 commit comments