diff --git a/Cargo.lock b/Cargo.lock index 1fa17f282..728a352da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -362,6 +362,7 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" name = "hvf" version = "0.1.0" dependencies = [ + "crossbeam-channel", "env_logger", "log", ] @@ -466,8 +467,10 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" name = "libkrun" version = "1.7.2" dependencies = [ + "crossbeam-channel", "devices", "env_logger", + "hvf", "libc", "log", "once_cell", diff --git a/Makefile b/Makefile index 5d2a74347..2bb9a95c8 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ ifeq ($(NET),1) endif ifeq ($(EFI),1) VARIANT = -efi - FEATURE_FLAGS := --features efi + FEATURE_FLAGS := --features efi,gpu BUILD_INIT = 0 endif @@ -86,6 +86,9 @@ ifeq ($(OS),Linux) patchelf --set-soname $(KRUN_SONAME_$(OS)) --output $(LIBRARY_RELEASE_$(OS)) target/release/$(KRUN_BASE_$(OS)) else ifeq ($(EFI),1) +ifeq ($(OS),Darwin) + install_name_tool -id libkrun-efi.dylib target/release/libkrun.dylib +endif mv target/release/libkrun.dylib target/release/$(KRUN_BASE_$(OS)) endif cp target/release/$(KRUN_BASE_$(OS)) $(LIBRARY_RELEASE_$(OS)) diff --git a/src/arch/src/aarch64/macos/gic.rs b/src/arch/src/aarch64/macos/gic.rs index f8284de60..6195f22e1 100644 --- a/src/arch/src/aarch64/macos/gic.rs +++ b/src/arch/src/aarch64/macos/gic.rs @@ -11,7 +11,7 @@ pub enum Error {} type Result = result::Result; /// Trait for GIC devices. -pub trait GICDevice { +pub trait GICDevice: Send { /// Returns an array with GIC device properties fn device_properties(&self) -> &[u64]; diff --git a/src/devices/src/virtio/device.rs b/src/devices/src/virtio/device.rs index 70b2ce26e..242ba83ae 100644 --- a/src/devices/src/virtio/device.rs +++ b/src/devices/src/virtio/device.rs @@ -125,12 +125,12 @@ pub trait VirtioDevice: AsAny + Send { } } -pub trait VmmExitObserver { +pub trait VmmExitObserver: Send { /// Callback to finish processing or cleanup the device resources fn on_vmm_exit(&mut self) {} } -impl VmmExitObserver for F { +impl VmmExitObserver for F { fn on_vmm_exit(&mut self) { self() } diff --git a/src/devices/src/virtio/gpu/device.rs b/src/devices/src/virtio/gpu/device.rs index 6235acf0b..64929777c 100644 --- a/src/devices/src/virtio/gpu/device.rs +++ b/src/devices/src/virtio/gpu/device.rs @@ -17,6 +17,8 @@ use super::defs::uapi::virtio_gpu_config; use super::worker::Worker; use crate::legacy::Gic; use crate::Error as DeviceError; +#[cfg(target_os = "macos")] +use hvf::MemoryMapping; // Control queue. pub(crate) const CTL_INDEX: usize = 0; @@ -26,6 +28,7 @@ pub(crate) const CUR_INDEX: usize = 1; // Supported features. pub(crate) const AVAIL_FEATURES: u64 = 1u64 << uapi::VIRTIO_F_VERSION_1 | 1u64 << uapi::VIRTIO_GPU_F_VIRGL + | 1u64 << uapi::VIRTIO_GPU_F_RESOURCE_UUID | 1u64 << uapi::VIRTIO_GPU_F_RESOURCE_BLOB | 1u64 << uapi::VIRTIO_GPU_F_CONTEXT_INIT; @@ -45,10 +48,16 @@ pub struct Gpu { irq_line: Option, pub(crate) sender: Option>, virgl_flags: u32, + #[cfg(target_os = "macos")] + map_sender: Sender, } impl Gpu { - pub(crate) fn with_queues(queues: Vec, virgl_flags: u32) -> super::Result { + pub(crate) fn with_queues( + queues: Vec, + virgl_flags: u32, + #[cfg(target_os = "macos")] map_sender: Sender, + ) -> super::Result { let mut queue_events = Vec::new(); for _ in 0..queues.len() { queue_events @@ -74,15 +83,25 @@ impl Gpu { irq_line: None, sender: None, virgl_flags, + #[cfg(target_os = "macos")] + map_sender, }) } - pub fn new(virgl_flags: u32) -> super::Result { + pub fn new( + virgl_flags: u32, + #[cfg(target_os = "macos")] map_sender: Sender, + ) -> super::Result { let queues: Vec = defs::QUEUE_SIZES .iter() .map(|&max_size| VirtQueue::new(max_size)) .collect(); - Self::with_queues(queues, virgl_flags) + Self::with_queues( + queues, + virgl_flags, + #[cfg(target_os = "macos")] + map_sender, + ) } pub fn id(&self) -> &str { @@ -268,6 +287,8 @@ impl VirtioDevice for Gpu { self.irq_line, shm_region, self.virgl_flags, + #[cfg(target_os = "macos")] + self.map_sender.clone(), ); worker.run(); diff --git a/src/devices/src/virtio/gpu/virtio_gpu.rs b/src/devices/src/virtio/gpu/virtio_gpu.rs index 3682cde49..50750e7ff 100644 --- a/src/devices/src/virtio/gpu/virtio_gpu.rs +++ b/src/devices/src/virtio/gpu/virtio_gpu.rs @@ -1,16 +1,27 @@ use std::collections::BTreeMap; use std::env; +#[cfg(target_os = "linux")] use std::os::fd::AsRawFd; use std::path::PathBuf; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; +#[cfg(target_os = "macos")] +use crossbeam_channel::{unbounded, Sender}; +#[cfg(target_os = "macos")] +use hvf::MemoryMapping; use libc::c_void; +#[cfg(target_os = "macos")] +use rutabaga_gfx::RUTABAGA_MEM_HANDLE_TYPE_APPLE; use rutabaga_gfx::{ ResourceCreate3D, ResourceCreateBlob, Rutabaga, RutabagaBuilder, RutabagaChannel, RutabagaFence, RutabagaFenceHandler, RutabagaIovec, Transfer3D, RUTABAGA_CHANNEL_TYPE_WAYLAND, + RUTABAGA_MAP_CACHE_MASK, +}; +#[cfg(target_os = "linux")] +use rutabaga_gfx::{ RUTABAGA_MAP_ACCESS_MASK, RUTABAGA_MAP_ACCESS_READ, RUTABAGA_MAP_ACCESS_RW, - RUTABAGA_MAP_ACCESS_WRITE, RUTABAGA_MAP_CACHE_MASK, RUTABAGA_MEM_HANDLE_TYPE_OPAQUE_FD, + RUTABAGA_MAP_ACCESS_WRITE, RUTABAGA_MEM_HANDLE_TYPE_OPAQUE_FD, }; use utils::eventfd::EventFd; use vm_memory::{GuestAddress, GuestMemory, GuestMemoryMmap, VolatileSlice}; @@ -21,6 +32,7 @@ use super::protocol::{ GpuResponse, GpuResponsePlaneInfo, VirtioGpuResult, VIRTIO_GPU_BLOB_FLAG_CREATE_GUEST_HANDLE, VIRTIO_GPU_BLOB_MEM_HOST3D, }; + use super::{GpuError, Result}; use crate::legacy::Gic; use crate::virtio::gpu::protocol::VIRTIO_GPU_FLAG_INFO_RING_IDX; @@ -89,6 +101,8 @@ pub struct VirtioGpu { rutabaga: Rutabaga, resources: BTreeMap, fence_state: Arc>, + #[cfg(target_os = "macos")] + map_sender: Sender, } impl VirtioGpu { @@ -149,6 +163,7 @@ impl VirtioGpu { }) } + #[allow(clippy::too_many_arguments)] pub fn new( mem: GuestMemoryMmap, queue_ctl: Arc>, @@ -157,6 +172,7 @@ impl VirtioGpu { intc: Option>>, irq_line: Option, virgl_flags: u32, + #[cfg(target_os = "macos")] map_sender: Sender, ) -> Self { let xdg_runtime_dir = match env::var("XDG_RUNTIME_DIR") { Ok(dir) => dir, @@ -199,6 +215,8 @@ impl VirtioGpu { rutabaga, resources: Default::default(), fence_state, + #[cfg(target_os = "macos")] + map_sender, } } @@ -469,6 +487,7 @@ impl VirtioGpu { /// rutabaga as ExternalMapping. /// When sandboxing is enabled, external_blob is set and opaque fds must be mapped in the /// hypervisor process by Vulkano using metadata provided by Rutabaga::vulkan_info(). + #[cfg(target_os = "linux")] pub fn resource_map_blob( &mut self, resource_id: u32, @@ -525,8 +544,62 @@ impl VirtioGpu { map_info: map_info & RUTABAGA_MAP_CACHE_MASK, }) } + #[cfg(target_os = "macos")] + pub fn resource_map_blob( + &mut self, + resource_id: u32, + shm_region: &VirtioShmRegion, + offset: u64, + ) -> VirtioGpuResult { + let resource = self + .resources + .get_mut(&resource_id) + .ok_or(ErrInvalidResourceId)?; + + let map_info = self.rutabaga.map_info(resource_id).map_err(|_| ErrUnspec)?; + let map_ptr = self.rutabaga.map_ptr(resource_id).map_err(|_| ErrUnspec)?; + + if let Ok(export) = self.rutabaga.export_blob(resource_id) { + if export.handle_type == RUTABAGA_MEM_HANDLE_TYPE_APPLE { + if offset + resource.size > shm_region.size as u64 { + error!("mapping DOES NOT FIT"); + return Err(ErrUnspec); + } + + let guest_addr = shm_region.guest_addr + offset; + debug!( + "mapping: map_ptr={:x}, guest_addr={:x}, size={}", + map_ptr, guest_addr, resource.size + ); + + let (reply_sender, reply_receiver) = unbounded(); + self.map_sender + .send(MemoryMapping::AddMapping( + reply_sender, + map_ptr, + guest_addr, + resource.size, + )) + .unwrap(); + if !reply_receiver.recv().unwrap() { + return Err(ErrUnspec); + } + } else { + return Err(ErrUnspec); + } + } else { + return Err(ErrUnspec); + } + + resource.shmem_offset = Some(offset); + // Access flags not a part of the virtio-gpu spec. + Ok(OkMapInfo { + map_info: map_info & RUTABAGA_MAP_CACHE_MASK, + }) + } /// Uses the hypervisor to unmap the blob resource. + #[cfg(target_os = "linux")] pub fn resource_unmap_blob( &mut self, resource_id: u32, @@ -557,6 +630,42 @@ impl VirtioGpu { resource.shmem_offset = None; + Ok(OkNoData) + } + #[cfg(target_os = "macos")] + pub fn resource_unmap_blob( + &mut self, + resource_id: u32, + shm_region: &VirtioShmRegion, + ) -> VirtioGpuResult { + let resource = self + .resources + .get_mut(&resource_id) + .ok_or(ErrInvalidResourceId)?; + + debug!("resource_unmap_blob"); + let shmem_offset = resource.shmem_offset.ok_or(ErrUnspec)?; + + let guest_addr = shm_region.guest_addr + shmem_offset; + debug!( + "unmapping: guest_addr={:x}, size={}", + guest_addr, resource.size + ); + + let (reply_sender, reply_receiver) = unbounded(); + self.map_sender + .send(MemoryMapping::RemoveMapping( + reply_sender, + guest_addr, + resource.size, + )) + .unwrap(); + if !reply_receiver.recv().unwrap() { + return Err(ErrUnspec); + } + + resource.shmem_offset = None; + Ok(OkNoData) } } diff --git a/src/devices/src/virtio/gpu/worker.rs b/src/devices/src/virtio/gpu/worker.rs index c657aa74f..c530bae5b 100644 --- a/src/devices/src/virtio/gpu/worker.rs +++ b/src/devices/src/virtio/gpu/worker.rs @@ -4,6 +4,10 @@ use std::sync::{Arc, Mutex}; use std::{result, thread}; use crossbeam_channel::Receiver; +#[cfg(target_os = "macos")] +use crossbeam_channel::Sender; +#[cfg(target_os = "macos")] +use hvf::MemoryMapping; use rutabaga_gfx::{ ResourceCreate3D, ResourceCreateBlob, RutabagaFence, Transfer3D, RUTABAGA_PIPE_BIND_RENDER_TARGET, RUTABAGA_PIPE_TEXTURE_2D, @@ -32,6 +36,8 @@ pub struct Worker { irq_line: Option, shm_region: VirtioShmRegion, virgl_flags: u32, + #[cfg(target_os = "macos")] + map_sender: Sender, } impl Worker { @@ -46,6 +52,7 @@ impl Worker { irq_line: Option, shm_region: VirtioShmRegion, virgl_flags: u32, + #[cfg(target_os = "macos")] map_sender: Sender, ) -> Self { Self { receiver, @@ -57,6 +64,8 @@ impl Worker { irq_line, shm_region, virgl_flags, + #[cfg(target_os = "macos")] + map_sender, } } @@ -73,6 +82,8 @@ impl Worker { self.intc.clone(), self.irq_line, self.virgl_flags, + #[cfg(target_os = "macos")] + self.map_sender.clone(), ); loop { diff --git a/src/hvf/Cargo.toml b/src/hvf/Cargo.toml index b729e10f7..4f43b5c7c 100644 --- a/src/hvf/Cargo.toml +++ b/src/hvf/Cargo.toml @@ -5,5 +5,6 @@ authors = ["Sergio Lopez "] edition = "2021" [dependencies] +crossbeam-channel = "0.5" log = "0.4.0" -env_logger = "0.9.0" \ No newline at end of file +env_logger = "0.9.0" diff --git a/src/hvf/src/lib.rs b/src/hvf/src/lib.rs index 2d6f765a2..a66b32d17 100644 --- a/src/hvf/src/lib.rs +++ b/src/hvf/src/lib.rs @@ -14,6 +14,7 @@ use std::convert::TryInto; use std::fmt::{Display, Formatter}; use std::time::Duration; +use crossbeam_channel::Sender; use log::debug; extern "C" { @@ -84,6 +85,7 @@ arm64_sys_reg!(SYSREG_ICC_SRE_EL1, 3, 0, 5, 12, 12); #[derive(Clone, Debug)] pub enum Error { MemoryMap, + MemoryUnmap, VcpuCreate, VcpuInitialRegisters, VcpuReadRegister, @@ -103,6 +105,7 @@ impl Display for Error { match self { MemoryMap => write!(f, "Error registering memory region in HVF"), + MemoryUnmap => write!(f, "Error unregistering memory region in HVF"), VcpuCreate => write!(f, "Error creating HVF vCPU instance"), VcpuInitialRegisters => write!(f, "Error setting up initial HVF vCPU registers"), VcpuReadRegister => write!(f, "Error reading HVF vCPU register"), @@ -118,6 +121,12 @@ impl Display for Error { } } +/// Messages for requesting memory maps/unmaps. +pub enum MemoryMapping { + AddMapping(Sender, u64, u64, u64), + RemoveMapping(Sender, u64, u64), +} + pub enum InterruptType { Irq, Fiq, @@ -195,6 +204,15 @@ impl HvfVm { Ok(()) } } + + pub fn unmap_memory(&self, guest_start_addr: u64, size: u64) -> Result<(), Error> { + let ret = unsafe { hv_vm_unmap(guest_start_addr, size) }; + if ret != HV_SUCCESS { + Err(Error::MemoryUnmap) + } else { + Ok(()) + } + } } #[derive(Debug)] diff --git a/src/libkrun/Cargo.toml b/src/libkrun/Cargo.toml index 67cb5bdae..83dea9c10 100644 --- a/src/libkrun/Cargo.toml +++ b/src/libkrun/Cargo.toml @@ -14,6 +14,7 @@ efi = [ "blk", "net" ] gpu = [] [dependencies] +crossbeam-channel = "0.5" env_logger = "0.9.0" libc = ">=0.2.39" log = "0.4.0" @@ -24,6 +25,9 @@ polly = { path = "../polly" } utils = { path = "../utils" } vmm = { path = "../vmm" } +[target.'cfg(target_os = "macos")'.dependencies] +hvf = { path = "../hvf" } + [lib] name = "krun" crate-type = ["cdylib"] diff --git a/src/libkrun/src/lib.rs b/src/libkrun/src/lib.rs index bf17791ad..bb8715838 100644 --- a/src/libkrun/src/lib.rs +++ b/src/libkrun/src/lib.rs @@ -18,11 +18,15 @@ use std::slice; use std::sync::atomic::{AtomicI32, Ordering}; use std::sync::Mutex; +#[cfg(target_os = "macos")] +use crossbeam_channel::unbounded; #[cfg(feature = "net")] use devices::virtio::net::device::VirtioNetBackend; #[cfg(feature = "blk")] use devices::virtio::CacheType; use env_logger::Env; +#[cfg(target_os = "macos")] +use hvf::MemoryMapping; #[cfg(not(feature = "efi"))] use libc::size_t; use libc::{c_char, c_int}; @@ -1041,14 +1045,40 @@ pub extern "C" fn krun_start_enter(ctx_id: u32) -> i32 { ctx_cfg.vmr.set_gpu_virgl_flags(virgl_flags); } - let _vmm = - match vmm::builder::build_microvm(&ctx_cfg.vmr, &mut event_manager, ctx_cfg.shutdown_efd) { - Ok(vmm) => vmm, - Err(e) => { - error!("Building the microVM failed: {:?}", e); - return -libc::EINVAL; - } - }; + #[cfg(target_os = "macos")] + let (sender, receiver) = unbounded(); + + let _vmm = match vmm::builder::build_microvm( + &ctx_cfg.vmr, + &mut event_manager, + ctx_cfg.shutdown_efd, + #[cfg(target_os = "macos")] + sender, + ) { + Ok(vmm) => vmm, + Err(e) => { + error!("Building the microVM failed: {:?}", e); + return -libc::EINVAL; + } + }; + + #[cfg(target_os = "macos")] + let mapper_vmm = _vmm.clone(); + + #[cfg(target_os = "macos")] + std::thread::spawn(move || loop { + match receiver.recv() { + Err(e) => error!("Error in receiver: {:?}", e), + Ok(m) => match m { + MemoryMapping::AddMapping(s, h, g, l) => { + mapper_vmm.lock().unwrap().add_mapping(s, h, g, l) + } + MemoryMapping::RemoveMapping(s, g, l) => { + mapper_vmm.lock().unwrap().remove_mapping(s, g, l) + } + }, + } + }); loop { match event_manager.run() { diff --git a/src/rutabaga_gfx/src/cross_domain/mod.rs b/src/rutabaga_gfx/src/cross_domain/mod.rs index aee2fa66b..341a2069d 100644 --- a/src/rutabaga_gfx/src/cross_domain/mod.rs +++ b/src/rutabaga_gfx/src/cross_domain/mod.rs @@ -710,6 +710,8 @@ impl RutabagaContext for CrossDomainContext { blob_mem: resource_create_blob.blob_mem, blob_flags: resource_create_blob.blob_flags, map_info: Some(reqs.map_info | RUTABAGA_MAP_ACCESS_RW), + #[cfg(target_os = "macos")] + map_ptr: None, info_2d: None, info_3d: Some(info_3d), vulkan_info: reqs.vulkan_info, @@ -744,6 +746,8 @@ impl RutabagaContext for CrossDomainContext { blob_mem: resource_create_blob.blob_mem, blob_flags: resource_create_blob.blob_flags, map_info: Some(RUTABAGA_MAP_CACHE_CACHED | RUTABAGA_MAP_ACCESS_READ), + #[cfg(target_os = "macos")] + map_ptr: None, info_2d: None, info_3d: None, vulkan_info: None, @@ -937,6 +941,8 @@ impl RutabagaComponent for CrossDomain { blob_mem: resource_create_blob.blob_mem, blob_flags: resource_create_blob.blob_flags, map_info: None, + #[cfg(target_os = "macos")] + map_ptr: None, info_2d: None, info_3d: None, vulkan_info: None, diff --git a/src/rutabaga_gfx/src/generated/virgl_renderer_bindings.rs b/src/rutabaga_gfx/src/generated/virgl_renderer_bindings.rs index c00887f73..d709f1cda 100644 --- a/src/rutabaga_gfx/src/generated/virgl_renderer_bindings.rs +++ b/src/rutabaga_gfx/src/generated/virgl_renderer_bindings.rs @@ -41,6 +41,7 @@ pub const VIRGL_RENDERER_MAP_CACHE_WC: u32 = 3; pub const VIRGL_RENDERER_BLOB_FD_TYPE_DMABUF: u32 = 1; pub const VIRGL_RENDERER_BLOB_FD_TYPE_OPAQUE: u32 = 2; pub const VIRGL_RENDERER_BLOB_FD_TYPE_SHM: u32 = 3; +pub const VIRGL_RENDERER_BLOB_FD_TYPE_APPLE: u32 = 4; pub const VIRGL_RENDERER_FENCE_FLAG_MERGEABLE: u32 = 1; pub type __int32_t = ::std::os::raw::c_int; pub type __uint32_t = ::std::os::raw::c_uint; @@ -386,6 +387,13 @@ extern "C" { map_info: *mut u32, ) -> ::std::os::raw::c_int; } +#[cfg(target_os = "macos")] +extern "C" { + pub fn virgl_renderer_resource_get_map_ptr( + res_handle: u32, + map_ptr: *mut u64, + ) -> ::std::os::raw::c_int; +} extern "C" { pub fn virgl_renderer_resource_export_blob( res_id: u32, diff --git a/src/rutabaga_gfx/src/rutabaga_2d.rs b/src/rutabaga_gfx/src/rutabaga_2d.rs index 0877ff104..417e67952 100644 --- a/src/rutabaga_gfx/src/rutabaga_2d.rs +++ b/src/rutabaga_gfx/src/rutabaga_2d.rs @@ -179,6 +179,8 @@ impl RutabagaComponent for Rutabaga2D { blob_mem: 0, blob_flags: 0, map_info: None, + #[cfg(target_os = "macos")] + map_ptr: None, info_2d: Some(info_2d), info_3d: None, vulkan_info: None, diff --git a/src/rutabaga_gfx/src/rutabaga_core.rs b/src/rutabaga_gfx/src/rutabaga_core.rs index 5767cfbde..09c446a90 100644 --- a/src/rutabaga_gfx/src/rutabaga_core.rs +++ b/src/rutabaga_gfx/src/rutabaga_core.rs @@ -43,6 +43,8 @@ pub struct RutabagaResource { pub blob_mem: u32, pub blob_flags: u32, pub map_info: Option, + #[cfg(target_os = "macos")] + pub map_ptr: Option, pub info_2d: Option, pub info_3d: Option, pub vulkan_info: Option, @@ -107,6 +109,8 @@ pub trait RutabagaComponent { blob_mem: 0, blob_flags: 0, map_info: None, + #[cfg(target_os = "macos")] + map_ptr: None, info_2d: None, info_3d: None, vulkan_info: None, @@ -440,6 +444,8 @@ impl Rutabaga { blob_mem: 0, blob_flags: 0, map_info: None, + #[cfg(target_os = "macos")] + map_ptr: None, info_2d: Some(Rutabaga2DInfo { width: s.width, height: s.height, @@ -824,6 +830,19 @@ impl Rutabaga { .ok_or(RutabagaError::SpecViolation("no map info available")) } + /// Returns the `map_ptr` of the blob resource. + #[cfg(target_os = "macos")] + pub fn map_ptr(&self, resource_id: u32) -> RutabagaResult { + let resource = self + .resources + .get(&resource_id) + .ok_or(RutabagaError::InvalidResourceId)?; + + resource + .map_ptr + .ok_or(RutabagaError::SpecViolation("no map ptr available")) + } + /// Returns the `vulkan_info` of the blob resource, which consists of the physical device /// index and memory index associated with the resource. pub fn vulkan_info(&self, resource_id: u32) -> RutabagaResult { diff --git a/src/rutabaga_gfx/src/rutabaga_utils.rs b/src/rutabaga_gfx/src/rutabaga_utils.rs index 401c91ba3..6d7da2697 100644 --- a/src/rutabaga_gfx/src/rutabaga_utils.rs +++ b/src/rutabaga_gfx/src/rutabaga_utils.rs @@ -624,6 +624,7 @@ pub const RUTABAGA_MEM_HANDLE_TYPE_DMABUF: u32 = 0x0002; pub const RUTABAGA_MEM_HANDLE_TYPE_OPAQUE_WIN32: u32 = 0x0003; pub const RUTABAGA_MEM_HANDLE_TYPE_SHM: u32 = 0x0004; pub const RUTABAGA_MEM_HANDLE_TYPE_ZIRCON: u32 = 0x0005; +pub const RUTABAGA_MEM_HANDLE_TYPE_APPLE: u32 = 0x0006; pub const RUTABAGA_FENCE_HANDLE_TYPE_OPAQUE_FD: u32 = 0x0006; pub const RUTABAGA_FENCE_HANDLE_TYPE_SYNC_FD: u32 = 0x0007; diff --git a/src/rutabaga_gfx/src/virgl_renderer.rs b/src/rutabaga_gfx/src/virgl_renderer.rs index 56b0f913a..ed996e1f4 100644 --- a/src/rutabaga_gfx/src/virgl_renderer.rs +++ b/src/rutabaga_gfx/src/virgl_renderer.rs @@ -356,6 +356,15 @@ impl VirglRenderer { Err(RutabagaError::Unsupported) } + #[cfg(target_os = "macos")] + fn map_ptr(&self, resource_id: u32) -> RutabagaResult { + let mut map_ptr = 0; + let ret = unsafe { virgl_renderer_resource_get_map_ptr(resource_id, &mut map_ptr) }; + ret_to_res(ret)?; + + Ok(map_ptr) + } + fn query(&self, resource_id: u32) -> RutabagaResult { let query = export_query(resource_id)?; if query.out_num_fds == 0 { @@ -391,6 +400,7 @@ impl VirglRenderer { VIRGL_RENDERER_BLOB_FD_TYPE_DMABUF => RUTABAGA_MEM_HANDLE_TYPE_DMABUF, VIRGL_RENDERER_BLOB_FD_TYPE_SHM => RUTABAGA_MEM_HANDLE_TYPE_SHM, VIRGL_RENDERER_BLOB_FD_TYPE_OPAQUE => RUTABAGA_MEM_HANDLE_TYPE_OPAQUE_FD, + VIRGL_RENDERER_BLOB_FD_TYPE_APPLE => RUTABAGA_MEM_HANDLE_TYPE_APPLE, _ => { return Err(RutabagaError::Unsupported); } @@ -497,6 +507,8 @@ impl RutabagaComponent for VirglRenderer { blob_mem: 0, blob_flags: 0, map_info: None, + #[cfg(target_os = "macos")] + map_ptr: None, info_2d: None, info_3d: self.query(resource_id).ok(), vulkan_info: None, @@ -667,6 +679,8 @@ impl RutabagaComponent for VirglRenderer { blob_mem: resource_create_blob.blob_mem, blob_flags: resource_create_blob.blob_flags, map_info: self.map_info(resource_id).ok(), + #[cfg(target_os = "macos")] + map_ptr: self.map_ptr(resource_id).ok(), info_2d: None, info_3d: self.query(resource_id).ok(), vulkan_info: None, diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs index f8bb2ef87..39635fe5b 100644 --- a/src/vmm/src/builder.rs +++ b/src/vmm/src/builder.rs @@ -4,7 +4,7 @@ //! Enables pre-boot setup, instantiation and booting of a Firecracker VMM. #[cfg(target_os = "macos")] -use crossbeam_channel::unbounded; +use crossbeam_channel::{unbounded, Sender}; use std::fmt::{Display, Formatter}; use std::io; #[cfg(target_os = "linux")] @@ -23,6 +23,8 @@ use devices::virtio::Net; #[cfg(not(feature = "tee"))] use devices::virtio::VirtioShmRegion; use devices::virtio::{port_io, MmioTransport, PortDescription, Vsock}; +#[cfg(target_os = "macos")] +use hvf::MemoryMapping; #[cfg(feature = "tee")] use kbs_types::Tee; @@ -291,6 +293,7 @@ pub fn build_microvm( vm_resources: &super::resources::VmResources, event_manager: &mut EventManager, _shutdown_efd: Option, + #[cfg(target_os = "macos")] _map_sender: Sender, ) -> std::result::Result>, StartMicrovmError> { // Timestamp for measuring microVM boot duration. let request_ts = TimestampUs::default(); @@ -571,6 +574,8 @@ pub fn build_microvm( _shm_region, intc.clone(), virgl_flags, + #[cfg(target_os = "macos")] + _map_sender, )?; } #[cfg(not(feature = "tee"))] @@ -1353,10 +1358,18 @@ fn attach_gpu_device( shm_region: Option, intc: Option>>, virgl_flags: u32, + #[cfg(target_os = "macos")] map_sender: Sender, ) -> std::result::Result<(), StartMicrovmError> { use self::StartMicrovmError::*; - let gpu = Arc::new(Mutex::new(devices::virtio::Gpu::new(virgl_flags).unwrap())); + let gpu = Arc::new(Mutex::new( + devices::virtio::Gpu::new( + virgl_flags, + #[cfg(target_os = "macos")] + map_sender, + ) + .unwrap(), + )); event_manager .add_subscriber(gpu.clone()) diff --git a/src/vmm/src/lib.rs b/src/vmm/src/lib.rs index dcf7d43fb..d59af4b95 100644 --- a/src/vmm/src/lib.rs +++ b/src/vmm/src/lib.rs @@ -32,6 +32,8 @@ use crate::linux::vstate; mod macos; mod terminal; +#[cfg(target_os = "macos")] +pub use hvf::MemoryMapping; #[cfg(target_os = "macos")] use macos::vstate; @@ -49,9 +51,12 @@ use crate::terminal::term_set_canonical_mode; #[cfg(target_os = "linux")] use crate::vstate::VcpuEvent; use crate::vstate::{Vcpu, VcpuHandle, VcpuResponse, Vm}; + use arch::ArchMemoryInfo; use arch::DeviceType; use arch::InitrdConfig; +#[cfg(target_os = "macos")] +use crossbeam_channel::Sender; use devices::virtio::VmmExitObserver; use devices::BusDevice; use kernel::cmdline::Cmdline as KernelCmdline; @@ -365,6 +370,23 @@ impl Vmm { pub fn kvm_vm(&self) -> &Vm { &self.vm } + + #[cfg(target_os = "macos")] + pub fn add_mapping( + &self, + reply_sender: Sender, + host_addr: u64, + guest_addr: u64, + len: u64, + ) { + self.vm + .add_mapping(reply_sender, host_addr, guest_addr, len); + } + + #[cfg(target_os = "macos")] + pub fn remove_mapping(&self, reply_sender: Sender, guest_addr: u64, len: u64) { + self.vm.remove_mapping(reply_sender, guest_addr, len); + } } impl Subscriber for Vmm { diff --git a/src/vmm/src/macos/vstate.rs b/src/vmm/src/macos/vstate.rs index 9776eb2c8..25e61ca95 100644 --- a/src/vmm/src/macos/vstate.rs +++ b/src/vmm/src/macos/vstate.rs @@ -151,6 +151,36 @@ impl Vm { pub fn get_irqchip(&self) -> &Box { self.irqchip_handle.as_ref().unwrap() } + + pub fn add_mapping( + &self, + reply_sender: Sender, + host_addr: u64, + guest_addr: u64, + len: u64, + ) { + debug!("add_mapping: host_addr={host_addr:x}, guest_addr={guest_addr:x}, len={len}"); + if let Err(e) = self.hvf_vm.unmap_memory(guest_addr, len) { + error!("Error removing memory map: {:?}", e); + } + + if let Err(e) = self.hvf_vm.map_memory(host_addr, guest_addr, len) { + error!("Error adding memory map: {:?}", e); + reply_sender.send(false).unwrap(); + } else { + reply_sender.send(true).unwrap(); + } + } + + pub fn remove_mapping(&self, reply_sender: Sender, guest_addr: u64, len: u64) { + debug!("remove_mapping: guest_addr={guest_addr:x}, len={len}"); + if let Err(e) = self.hvf_vm.unmap_memory(guest_addr, len) { + error!("Error removing memory map: {:?}", e); + reply_sender.send(false).unwrap(); + } else { + reply_sender.send(true).unwrap(); + } + } } /// Encapsulates configuration parameters for the guest vCPUS.