From acfd551aa48286d61566e0577e61f1261cfbbfc8 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 2 Apr 2026 14:07:21 +0800 Subject: [PATCH 1/3] refine: Refine code --- crates/vm-core/src/arch/x86_64.rs | 2 -- crates/vm-core/src/vcpu/vcpu_manager.rs | 2 +- crates/vm-core/src/virt.rs | 22 ++---------------- crates/vm-core/src/virt/hvp.rs | 2 +- .../vm-core/src/virt/kvm/vcpu/arch/aarch64.rs | 2 +- .../vm-core/src/virt/kvm/vcpu/arch/x86_64.rs | 2 +- crates/vm-core/src/virt/vm.rs | 23 +++++++++++++++++++ crates/vm-machine/src/vm.rs | 2 +- crates/vm-machine/src/vmm.rs | 4 ++-- 9 files changed, 32 insertions(+), 29 deletions(-) create mode 100644 crates/vm-core/src/virt/vm.rs diff --git a/crates/vm-core/src/arch/x86_64.rs b/crates/vm-core/src/arch/x86_64.rs index c8f709d..cdd4493 100644 --- a/crates/vm-core/src/arch/x86_64.rs +++ b/crates/vm-core/src/arch/x86_64.rs @@ -1,5 +1,3 @@ pub mod layout; pub mod vcpu; pub mod vm_exit; - -pub const BASE_ADDRESS: u64 = 0x0; diff --git a/crates/vm-core/src/vcpu/vcpu_manager.rs b/crates/vm-core/src/vcpu/vcpu_manager.rs index 5313222..7430ae9 100644 --- a/crates/vm-core/src/vcpu/vcpu_manager.rs +++ b/crates/vm-core/src/vcpu/vcpu_manager.rs @@ -10,7 +10,7 @@ use crate::device_manager::vm_exit::DeviceVmExitHandler; use crate::error::Error as VmError; use crate::vcpu::error::VcpuError; use crate::vcpu::vcpu::Vcpu; -use crate::virt::Vm; +use crate::virt::vm::Vm; pub struct VcpuManager { vm_instance: Arc, diff --git a/crates/vm-core/src/virt.rs b/crates/vm-core/src/virt.rs index b1b0b10..2599ef2 100644 --- a/crates/vm-core/src/virt.rs +++ b/crates/vm-core/src/virt.rs @@ -1,8 +1,7 @@ use std::sync::Arc; -use crate::arch::irq::InterruptController; use crate::error::Error; -use crate::virt::vcpu::Vcpu; +use crate::virt::vm::Vm; #[cfg(feature = "kvm")] pub mod kvm; @@ -11,24 +10,7 @@ pub mod kvm; pub mod hvp; pub mod vcpu; - -pub enum SetUserMemoryRegionFlags { - ReadWriteExec, -} - -pub trait Vm: Send + Sync { - fn create_vcpu(&self, vcpu_id: usize) -> Result, Error>; - - fn create_irq_chip(&self) -> Result, Error>; - - fn set_user_memory_region( - &self, - userspace_addr: u64, - guest_phys_addr: u64, - memory_size: usize, - flags: SetUserMemoryRegionFlags, - ) -> Result<(), Error>; -} +pub mod vm; pub trait Virt { fn create_vm(&self) -> Result, Error>; diff --git a/crates/vm-core/src/virt/hvp.rs b/crates/vm-core/src/virt/hvp.rs index 1549ecb..6cb6b52 100644 --- a/crates/vm-core/src/virt/hvp.rs +++ b/crates/vm-core/src/virt/hvp.rs @@ -23,12 +23,12 @@ use crate::arch::aarch64::layout::RAM_BASE; use crate::arch::irq::InterruptController; use crate::error::Error; use crate::error::Result; -use crate::virt::SetUserMemoryRegionFlags; use crate::virt::Virt; use crate::virt::Vm; use crate::virt::hvp::irq_chip::HvpGicV3; use crate::virt::hvp::vcpu::HvpVcpu; use crate::virt::vcpu::Vcpu; +use crate::virt::vm::SetUserMemoryRegionFlags; pub(crate) mod vcpu; diff --git a/crates/vm-core/src/virt/kvm/vcpu/arch/aarch64.rs b/crates/vm-core/src/virt/kvm/vcpu/arch/aarch64.rs index ac10919..a19523e 100644 --- a/crates/vm-core/src/virt/kvm/vcpu/arch/aarch64.rs +++ b/crates/vm-core/src/virt/kvm/vcpu/arch/aarch64.rs @@ -5,8 +5,8 @@ use crate::arch::aarch64::vcpu::reg::CoreRegister; use crate::arch::aarch64::vcpu::reg::SysRegister; use crate::arch::aarch64::vm_exit::VmExitReason; use crate::vcpu::error::VcpuError; -use crate::virt::Vcpu; use crate::virt::kvm::vcpu::KvmVcpu; +use crate::virt::vcpu::Vcpu; mod encode; diff --git a/crates/vm-core/src/virt/kvm/vcpu/arch/x86_64.rs b/crates/vm-core/src/virt/kvm/vcpu/arch/x86_64.rs index 468fed5..eeaf589 100644 --- a/crates/vm-core/src/virt/kvm/vcpu/arch/x86_64.rs +++ b/crates/vm-core/src/virt/kvm/vcpu/arch/x86_64.rs @@ -4,8 +4,8 @@ use kvm_ioctls::Kvm; use crate::arch::x86_64::vcpu::X86_64Vcpu; use crate::arch::x86_64::vm_exit::VmExitReason; use crate::vcpu::error::VcpuError; -use crate::virt::Vcpu; use crate::virt::kvm::vcpu::KvmVcpu; +use crate::virt::vcpu::Vcpu; impl KvmVcpu { pub fn set_cpuid2(&self, cpuid: &CpuId) -> Result<(), VcpuError> { diff --git a/crates/vm-core/src/virt/vm.rs b/crates/vm-core/src/virt/vm.rs new file mode 100644 index 0000000..07e0cb2 --- /dev/null +++ b/crates/vm-core/src/virt/vm.rs @@ -0,0 +1,23 @@ +use std::sync::Arc; + +use crate::arch::irq::InterruptController; +use crate::error::Error; +use crate::virt::vcpu::Vcpu; + +pub enum SetUserMemoryRegionFlags { + ReadWriteExec, +} + +pub trait Vm: Send + Sync { + fn create_vcpu(&self, vcpu_id: usize) -> Result, Error>; + + fn create_irq_chip(&self) -> Result, Error>; + + fn set_user_memory_region( + &self, + userspace_addr: u64, + guest_phys_addr: u64, + memory_size: usize, + flags: SetUserMemoryRegionFlags, + ) -> Result<(), Error>; +} diff --git a/crates/vm-machine/src/vm.rs b/crates/vm-machine/src/vm.rs index 3edcc0d..1ee6516 100644 --- a/crates/vm-machine/src/vm.rs +++ b/crates/vm-machine/src/vm.rs @@ -18,7 +18,7 @@ use crate::vm::config::VmConfig; pub mod config; pub struct Vm { - pub(crate) vm_instance: Arc, + pub(crate) _vm_instance: Arc, pub(crate) vcpu_manager: Arc>, pub(crate) memory_address_space: Arc, pub(crate) irq_chip: Arc, diff --git a/crates/vm-machine/src/vmm.rs b/crates/vm-machine/src/vmm.rs index 5c6b1c9..48c8c53 100644 --- a/crates/vm-machine/src/vmm.rs +++ b/crates/vm-machine/src/vmm.rs @@ -21,8 +21,8 @@ use vm_core::device::mmio::layout::MmioLayout; use vm_core::device_manager::manager::DeviceManager; use vm_core::monitor::MonitorServerBuilder; use vm_core::vcpu::vcpu_manager::VcpuManager; -use vm_core::virt::SetUserMemoryRegionFlags; use vm_core::virt::Virt; +use vm_core::virt::vm::SetUserMemoryRegionFlags; use vm_device::device::Device; use vm_mm::allocator::Allocator; use vm_mm::allocator::std_allocator::StdAllocator; @@ -109,7 +109,7 @@ impl Vmm { } let vm = Vm { - vm_instance, + _vm_instance: vm_instance, vcpu_manager, memory_address_space, irq_chip, From 4eaefa98f3277765e70c7d7ee2e59168cab76560 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 2 Apr 2026 14:29:01 +0800 Subject: [PATCH 2/3] refine: Refine VcpuMananger --- crates/vm-core/src/vcpu/vcpu_manager.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/vm-core/src/vcpu/vcpu_manager.rs b/crates/vm-core/src/vcpu/vcpu_manager.rs index 7430ae9..031657f 100644 --- a/crates/vm-core/src/vcpu/vcpu_manager.rs +++ b/crates/vm-core/src/vcpu/vcpu_manager.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use std::sync::Mutex; use std::thread; +use std::thread::JoinHandle; #[cfg(target_arch = "aarch64")] use crate::arch::aarch64::firmware::psci::Psci; @@ -15,6 +16,7 @@ use crate::virt::vm::Vm; pub struct VcpuManager { vm_instance: Arc, vcpus: Vec>>, + handlers: Vec>>, } impl VcpuManager { @@ -22,6 +24,7 @@ impl VcpuManager { VcpuManager { vm_instance, vcpus: Default::default(), + handlers: Default::default(), } } @@ -45,14 +48,14 @@ impl VcpuManager { Ok(()) } - pub fn start_vcpu(&self, vcpu_id: usize, start_pc: u64, x0: u64) -> Result<(), VcpuError> { + pub fn start_vcpu(&mut self, vcpu_id: usize, start_pc: u64, x0: u64) -> Result<(), VcpuError> { let vcpu = self .vcpus .get(vcpu_id) .ok_or(VcpuError::VcpuNotCreated(vcpu_id))? .clone(); - thread::spawn(move || -> Result<(), VcpuError> { + let handle = thread::spawn(move || -> Result<(), VcpuError> { let mut vcpu = vcpu.lock().unwrap(); vcpu.vcpu_instance.post_init_within_thread()?; @@ -82,6 +85,8 @@ impl VcpuManager { } }); + self.handlers.push(handle); + Ok(()) } } From c1824aae0b9404587535788a26ff371b7fae6f46 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 2 Apr 2026 14:56:53 +0800 Subject: [PATCH 3/3] refine: Refine VmExit --- crates/vm-core/src/arch/aarch64/vm_exit.rs | 30 ++--- .../vm-core/src/device/pio/pio_as_manager.rs | 4 +- crates/vm-core/src/device/pio/pio_device.rs | 4 +- crates/vm-core/src/device_manager.rs | 1 - crates/vm-core/src/device_manager/manager.rs | 80 +------------- crates/vm-core/src/vcpu.rs | 1 + crates/vm-core/src/vcpu/error.rs | 12 +- crates/vm-core/src/vcpu/vcpu.rs | 8 +- crates/vm-core/src/vcpu/vcpu_manager.rs | 20 ++-- .../src/{device_manager => vcpu}/vm_exit.rs | 25 ++++- crates/vm-device/src/device/cmos.rs | 4 +- crates/vm-device/src/device/coprocessor.rs | 4 +- crates/vm-device/src/device/dummy.rs | 4 +- crates/vm-device/src/device/i8042/mod.rs | 4 +- crates/vm-device/src/device/pic.rs | 4 +- crates/vm-device/src/device/post_debug.rs | 4 +- crates/vm-device/src/device/uart8250.rs | 103 ++++++++++-------- crates/vm-device/src/device/vga.rs | 4 +- crates/vm-machine/src/vm.rs | 2 + crates/vm-machine/src/vm/vm_exit_handler.rs | 103 ++++++++++++++++++ crates/vm-machine/src/vmm.rs | 19 ++-- crates/vm-pci/src/root_complex/pio.rs | 46 ++++---- 22 files changed, 262 insertions(+), 224 deletions(-) rename crates/vm-core/src/{device_manager => vcpu}/vm_exit.rs (55%) create mode 100644 crates/vm-machine/src/vm/vm_exit_handler.rs diff --git a/crates/vm-core/src/arch/aarch64/vm_exit.rs b/crates/vm-core/src/arch/aarch64/vm_exit.rs index 2a7c100..2ed49f0 100644 --- a/crates/vm-core/src/arch/aarch64/vm_exit.rs +++ b/crates/vm-core/src/arch/aarch64/vm_exit.rs @@ -1,23 +1,10 @@ use tracing::trace; -use crate::arch::aarch64::firmware::psci::error::PsciError; use crate::arch::aarch64::vcpu::reg::CoreRegister; use crate::arch::aarch64::vcpu::reg::SysRegister; -use crate::device_manager::vm_exit::DeviceError; use crate::vcpu::error::VcpuError; use crate::vcpu::vcpu::Vcpu; - -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("Failed to handle mmio, err: {0}")] - DeviceError(#[from] DeviceError), - - #[error("Failed to rw vcpu, err: {0}")] - VcpuError(String), - - #[error("Failed to handle smc, err: {0}")] - PsciError(#[from] PsciError), -} +use crate::vcpu::vm_exit::VmExit; #[derive(Debug)] pub enum VmExitReason { @@ -52,24 +39,23 @@ pub enum HandleVmExitResult { pub fn handle_vm_exit( vcpu: &mut Vcpu, exit_reason: VmExitReason, + vm_exit_handler: &dyn VmExit, ) -> Result { - let device_vm_exit_handler = vcpu.device_vm_exit_handler.clone(); - trace!(?exit_reason); match exit_reason { VmExitReason::Unknown => Ok(HandleVmExitResult::Continue), VmExitReason::Wf => Ok(HandleVmExitResult::NextInstruction), - VmExitReason::MMRead { gpa, srt, len } if device_vm_exit_handler.in_mmio_region(gpa) => { + VmExitReason::MMRead { gpa, srt, len } if vm_exit_handler.in_mmio_region(gpa) => { let mut buf = [0; 8]; - device_vm_exit_handler.mmio_read(gpa, len, &mut buf[0..len])?; + vm_exit_handler.mmio_read(gpa, len, &mut buf[0..len])?; vcpu.vcpu_instance .set_core_reg(srt, u64::from_le_bytes(buf))?; Ok(HandleVmExitResult::NextInstruction) } VmExitReason::MMRead { .. } => todo!(), - VmExitReason::MMWrite { gpa, buf, len } if device_vm_exit_handler.in_mmio_region(gpa) => { - device_vm_exit_handler.mmio_write(gpa, len, &buf)?; + VmExitReason::MMWrite { gpa, buf, len } if vm_exit_handler.in_mmio_region(gpa) => { + vm_exit_handler.mmio_write(gpa, len, &buf)?; Ok(HandleVmExitResult::NextInstruction) } VmExitReason::MMWrite { .. } => todo!(), @@ -83,10 +69,8 @@ pub fn handle_vm_exit( Ok(HandleVmExitResult::NextInstruction) } VmExitReason::Smc => { - let psci = vcpu.psci.clone(); - // We only support psci for smc now - psci.call(vcpu.vcpu_instance.as_mut())?; + vm_exit_handler.call_smc(vcpu.vcpu_instance.as_mut())?; Ok(HandleVmExitResult::NextInstruction) } diff --git a/crates/vm-core/src/device/pio/pio_as_manager.rs b/crates/vm-core/src/device/pio/pio_as_manager.rs index fe0970b..08af9d8 100644 --- a/crates/vm-core/src/device/pio/pio_as_manager.rs +++ b/crates/vm-core/src/device/pio/pio_as_manager.rs @@ -30,9 +30,9 @@ impl PioAddressSpaceManager { Ok(()) } - pub fn get_device_by_port(&mut self, port: u16) -> Option<&mut dyn PioDevice> { + pub fn get_device_by_port(&self, port: u16) -> Option<&dyn PioDevice> { let (_, &idx) = self.address_space.try_get_value_by_key(port)?; - Some(self.device[idx].as_mut()) + Some(self.device[idx].as_ref()) } } diff --git a/crates/vm-core/src/device/pio/pio_device.rs b/crates/vm-core/src/device/pio/pio_device.rs index 6469ee1..5f592f2 100644 --- a/crates/vm-core/src/device/pio/pio_device.rs +++ b/crates/vm-core/src/device/pio/pio_device.rs @@ -6,7 +6,7 @@ pub type PortRange = Range; pub trait PioDevice: Device { fn ports(&self) -> Vec; - fn io_in(&mut self, port: u16, data: &mut [u8]); + fn io_in(&self, port: u16, data: &mut [u8]); - fn io_out(&mut self, port: u16, data: &[u8]); + fn io_out(&self, port: u16, data: &[u8]); } diff --git a/crates/vm-core/src/device_manager.rs b/crates/vm-core/src/device_manager.rs index 0204d70..ff8de9e 100644 --- a/crates/vm-core/src/device_manager.rs +++ b/crates/vm-core/src/device_manager.rs @@ -1,2 +1 @@ pub mod manager; -pub mod vm_exit; diff --git a/crates/vm-core/src/device_manager/manager.rs b/crates/vm-core/src/device_manager/manager.rs index 3582856..e66ffbb 100644 --- a/crates/vm-core/src/device_manager/manager.rs +++ b/crates/vm-core/src/device_manager/manager.rs @@ -5,87 +5,11 @@ use crate::device::mmio::mmio_as_manager::MmioAddressSpaceManager; use crate::device::mmio::mmio_device::MmioDevice; use crate::device::pio::pio_as_manager::PioAddressSpaceManager; use crate::device::pio::pio_device::PioDevice; -use crate::device_manager::vm_exit::DeviceError; -use crate::device_manager::vm_exit::DeviceVmExitHandler; use crate::utils::address_space::AddressSpaceError; pub struct DeviceManager { - pio_manager: PioAddressSpaceManager, - mmio_manager: MmioAddressSpaceManager, -} - -impl DeviceVmExitHandler for DeviceManager { - fn io_in(&mut self, port: u16, data: &mut [u8]) -> Result<(), DeviceError> { - let device = self - .pio_manager - .get_device_by_port(port) - .ok_or(DeviceError::NoDeviceForPort(port))?; - - device.io_in(port, data); - - Ok(()) - } - - fn io_out(&mut self, port: u16, data: &[u8]) -> Result<(), DeviceError> { - let device = self - .pio_manager - .get_device_by_port(port) - .ok_or(DeviceError::NoDeviceForPort(port))?; - - device.io_out(port, data); - - Ok(()) - } - - fn mmio_read(&self, addr: u64, len: usize, data: &mut [u8]) -> Result<(), DeviceError> { - let (range, handler) = self - .mmio_manager - .get_handler_by_addr(addr) - .ok_or(DeviceError::NoDeviceForAddr(addr))?; - - let err = || DeviceError::MmioOutOfMemory { - mmio_start: range.start, - mmio_len: range.len, - addr, - }; - - if addr.checked_add(len as u64).ok_or_else(err)? - > range.start.checked_add(range.len as u64).ok_or_else(err)? - { - return Err(err()); - } - - handler.mmio_read(addr - range.start, len, data); - - Ok(()) - } - - fn mmio_write(&self, addr: u64, len: usize, data: &[u8]) -> Result<(), DeviceError> { - let (range, handler) = self - .mmio_manager - .get_handler_by_addr(addr) - .ok_or(DeviceError::NoDeviceForAddr(addr))?; - - let err = || DeviceError::MmioOutOfMemory { - mmio_start: range.start, - mmio_len: range.len, - addr, - }; - - if addr.checked_add(len as u64).ok_or_else(err)? - > range.start.checked_add(range.len as u64).ok_or_else(err)? - { - return Err(err()); - } - - handler.mmio_write(addr - range.start, len, data); - - Ok(()) - } - - fn in_mmio_region(&self, addr: u64) -> bool { - self.mmio_manager.mmio_layout().in_mmio_region(addr) - } + pub pio_manager: PioAddressSpaceManager, + pub mmio_manager: MmioAddressSpaceManager, } impl DeviceManager { diff --git a/crates/vm-core/src/vcpu.rs b/crates/vm-core/src/vcpu.rs index 8544dd0..cc7bc72 100644 --- a/crates/vm-core/src/vcpu.rs +++ b/crates/vm-core/src/vcpu.rs @@ -1,3 +1,4 @@ pub mod error; pub mod vcpu; pub mod vcpu_manager; +pub mod vm_exit; diff --git a/crates/vm-core/src/vcpu/error.rs b/crates/vm-core/src/vcpu/error.rs index 5dc4edf..3c4017a 100644 --- a/crates/vm-core/src/vcpu/error.rs +++ b/crates/vm-core/src/vcpu/error.rs @@ -1,6 +1,4 @@ -#[cfg(target_arch = "aarch64")] -use crate::arch::aarch64::firmware::psci::error::PsciError; -use crate::device_manager::vm_exit::DeviceError; +use crate::vcpu::vm_exit::VmExitHandlerError; #[derive(Debug, thiserror::Error)] pub enum VcpuError { @@ -15,13 +13,9 @@ pub enum VcpuError { #[error("{0}")] KvmError(#[from] kvm_ioctls::Error), - #[cfg(target_arch = "aarch64")] #[error("{0}")] - PsciError(#[from] PsciError), - - #[error("{0}")] - DeviceError(#[from] DeviceError), + GuestError(String), #[error("{0}")] - GuestError(String), + VmExitHandlerErr(#[from] VmExitHandlerError), } diff --git a/crates/vm-core/src/vcpu/vcpu.rs b/crates/vm-core/src/vcpu/vcpu.rs index 3904960..1567826 100644 --- a/crates/vm-core/src/vcpu/vcpu.rs +++ b/crates/vm-core/src/vcpu/vcpu.rs @@ -1,12 +1,8 @@ use std::sync::Arc; -#[cfg(target_arch = "aarch64")] -use crate::arch::aarch64::firmware::psci::Psci; -use crate::device_manager::vm_exit::DeviceVmExitHandler; +use crate::vcpu::vm_exit::VmExit; pub struct Vcpu { pub vcpu_instance: Box, - pub device_vm_exit_handler: Arc, - #[cfg(target_arch = "aarch64")] - pub psci: Arc, + pub vm_exit_handler: Arc, } diff --git a/crates/vm-core/src/vcpu/vcpu_manager.rs b/crates/vm-core/src/vcpu/vcpu_manager.rs index 031657f..94a7681 100644 --- a/crates/vm-core/src/vcpu/vcpu_manager.rs +++ b/crates/vm-core/src/vcpu/vcpu_manager.rs @@ -3,14 +3,12 @@ use std::sync::Mutex; use std::thread; use std::thread::JoinHandle; -#[cfg(target_arch = "aarch64")] -use crate::arch::aarch64::firmware::psci::Psci; #[cfg(target_arch = "aarch64")] use crate::arch::aarch64::vcpu::setup_cpu; -use crate::device_manager::vm_exit::DeviceVmExitHandler; use crate::error::Error as VmError; use crate::vcpu::error::VcpuError; use crate::vcpu::vcpu::Vcpu; +use crate::vcpu::vm_exit::VmExit; use crate::virt::vm::Vm; pub struct VcpuManager { @@ -31,16 +29,13 @@ impl VcpuManager { pub fn create_vcpu( &mut self, vcpu_id: usize, - device_vm_exit_handler: Arc, - #[cfg(target_arch = "aarch64")] psci: Arc, + vm_exit_handler: Arc, ) -> Result<(), VmError> { let vcpu_instance = self.vm_instance.create_vcpu(vcpu_id)?; let vcpu = Vcpu { vcpu_instance, - device_vm_exit_handler, - #[cfg(target_arch = "aarch64")] - psci, + vm_exit_handler, }; self.vcpus.push(Arc::new(Mutex::new(vcpu))); @@ -65,6 +60,8 @@ impl VcpuManager { setup_cpu(x0, start_pc, vcpu_id, &mut *vcpu.vcpu_instance)?; } + let vm_exit_handler = vcpu.vm_exit_handler.clone(); + loop { let vm_exit_reason = vcpu.vcpu_instance.run()?; @@ -73,8 +70,11 @@ impl VcpuManager { use crate::arch::aarch64::vcpu::reg::CoreRegister; use crate::arch::aarch64::vm_exit::HandleVmExitResult; - match crate::arch::aarch64::vm_exit::handle_vm_exit(&mut *vcpu, vm_exit_reason)? - { + match crate::arch::aarch64::vm_exit::handle_vm_exit( + &mut *vcpu, + vm_exit_reason, + vm_exit_handler.as_ref(), + )? { HandleVmExitResult::Continue => (), HandleVmExitResult::NextInstruction => { let pc = vcpu.vcpu_instance.get_core_reg(CoreRegister::PC)?; diff --git a/crates/vm-core/src/device_manager/vm_exit.rs b/crates/vm-core/src/vcpu/vm_exit.rs similarity index 55% rename from crates/vm-core/src/device_manager/vm_exit.rs rename to crates/vm-core/src/vcpu/vm_exit.rs index a07b09a..582681a 100644 --- a/crates/vm-core/src/device_manager/vm_exit.rs +++ b/crates/vm-core/src/vcpu/vm_exit.rs @@ -1,5 +1,7 @@ +use crate::virt::vcpu::Vcpu; + #[derive(Debug, thiserror::Error)] -pub enum DeviceError { +pub enum VmExitHandlerError { #[error("no device found for port 0x{0:#x}")] NoDeviceForPort(u16), @@ -14,12 +16,23 @@ pub enum DeviceError { mmio_len: usize, addr: u64, }, + + #[cfg(target_arch = "aarch64")] + #[error("{0}")] + SmcError(#[from] crate::arch::aarch64::firmware::psci::error::PsciError), } -pub trait DeviceVmExitHandler: Send + Sync { - fn io_in(&mut self, port: u16, data: &mut [u8]) -> Result<(), DeviceError>; - fn io_out(&mut self, port: u16, data: &[u8]) -> Result<(), DeviceError>; - fn mmio_read(&self, addr: u64, len: usize, data: &mut [u8]) -> Result<(), DeviceError>; - fn mmio_write(&self, addr: u64, len: usize, data: &[u8]) -> Result<(), DeviceError>; +pub trait VmExit: Send + Sync { + fn io_in(&mut self, port: u16, data: &mut [u8]) -> Result<(), VmExitHandlerError>; + + fn io_out(&mut self, port: u16, data: &[u8]) -> Result<(), VmExitHandlerError>; + + fn mmio_read(&self, addr: u64, len: usize, data: &mut [u8]) -> Result<(), VmExitHandlerError>; + + fn mmio_write(&self, addr: u64, len: usize, data: &[u8]) -> Result<(), VmExitHandlerError>; + fn in_mmio_region(&self, addr: u64) -> bool; + + #[cfg(target_arch = "aarch64")] + fn call_smc(&self, vcpu: &mut dyn Vcpu) -> Result<(), VmExitHandlerError>; } diff --git a/crates/vm-device/src/device/cmos.rs b/crates/vm-device/src/device/cmos.rs index 0598667..d0425f6 100644 --- a/crates/vm-device/src/device/cmos.rs +++ b/crates/vm-device/src/device/cmos.rs @@ -25,11 +25,11 @@ impl PioDevice for Cmos { ] } - fn io_in(&mut self, _port: u16, _data: &mut [u8]) { + fn io_in(&self, _port: u16, _data: &mut [u8]) { // TODO } - fn io_out(&mut self, _port: u16, _data: &[u8]) { + fn io_out(&self, _port: u16, _data: &[u8]) { // TODO } } diff --git a/crates/vm-device/src/device/coprocessor.rs b/crates/vm-device/src/device/coprocessor.rs index b3c1f2f..575fad2 100644 --- a/crates/vm-device/src/device/coprocessor.rs +++ b/crates/vm-device/src/device/coprocessor.rs @@ -25,11 +25,11 @@ impl PioDevice for Coprocessor { ] } - fn io_in(&mut self, _port: u16, _data: &mut [u8]) { + fn io_in(&self, _port: u16, _data: &mut [u8]) { todo!() } - fn io_out(&mut self, port: u16, _data: &[u8]) { + fn io_out(&self, port: u16, _data: &[u8]) { match port { 0xf0 => { // ignore diff --git a/crates/vm-device/src/device/dummy.rs b/crates/vm-device/src/device/dummy.rs index 0c96c90..a7fe10b 100644 --- a/crates/vm-device/src/device/dummy.rs +++ b/crates/vm-device/src/device/dummy.rs @@ -33,7 +33,7 @@ impl PioDevice for Dummy { ] } - fn io_in(&mut self, _port: u16, _data: &mut [u8]) {} + fn io_in(&self, _port: u16, _data: &mut [u8]) {} - fn io_out(&mut self, _port: u16, _data: &[u8]) {} + fn io_out(&self, _port: u16, _data: &[u8]) {} } diff --git a/crates/vm-device/src/device/i8042/mod.rs b/crates/vm-device/src/device/i8042/mod.rs index ec15ffa..cbfad7d 100644 --- a/crates/vm-device/src/device/i8042/mod.rs +++ b/crates/vm-device/src/device/i8042/mod.rs @@ -223,11 +223,11 @@ impl PioDevice for I8042 { ] } - fn io_in(&mut self, port: u16, data: &mut [u8]) { + fn io_in(&self, port: u16, data: &mut [u8]) { self.0.lock().unwrap().io_in(port, data); } - fn io_out(&mut self, port: u16, data: &[u8]) { + fn io_out(&self, port: u16, data: &[u8]) { self.0.lock().unwrap().io_out(port, data); } } diff --git a/crates/vm-device/src/device/pic.rs b/crates/vm-device/src/device/pic.rs index 3c99bc5..7f954fe 100644 --- a/crates/vm-device/src/device/pic.rs +++ b/crates/vm-device/src/device/pic.rs @@ -25,7 +25,7 @@ impl PioDevice for Pic { ] } - fn io_in(&mut self, port: u16, _data: &mut [u8]) { + fn io_in(&self, port: u16, _data: &mut [u8]) { match port { 0xa1 => (), 0x21 => (), @@ -33,7 +33,7 @@ impl PioDevice for Pic { } } - fn io_out(&mut self, port: u16, _data: &[u8]) { + fn io_out(&self, port: u16, _data: &[u8]) { match port { 0xa1 => { // ignore diff --git a/crates/vm-device/src/device/post_debug.rs b/crates/vm-device/src/device/post_debug.rs index d5fdfe4..9a3b85e 100644 --- a/crates/vm-device/src/device/post_debug.rs +++ b/crates/vm-device/src/device/post_debug.rs @@ -21,11 +21,11 @@ impl PioDevice for PostDebug { }] } - fn io_in(&mut self, _port: u16, _data: &mut [u8]) { + fn io_in(&self, _port: u16, _data: &mut [u8]) { todo!() } - fn io_out(&mut self, port: u16, _data: &[u8]) { + fn io_out(&self, port: u16, _data: &[u8]) { if port == PORT {} } } diff --git a/crates/vm-device/src/device/uart8250.rs b/crates/vm-device/src/device/uart8250.rs index eef8670..1d18476 100644 --- a/crates/vm-device/src/device/uart8250.rs +++ b/crates/vm-device/src/device/uart8250.rs @@ -1,6 +1,7 @@ use std::io::Write; use std::io::{self}; use std::sync::Arc; +use std::sync::Mutex; use vm_core::arch::irq::InterruptController; use vm_core::device::Device; @@ -163,7 +164,7 @@ mod msr { } } -pub struct Uart8250 { +struct Uart8250Internal { port_base: Option, txr: u8, @@ -181,27 +182,7 @@ pub struct Uart8250 { irq_state: bool, } -impl Uart8250 { - pub fn new(port_base: Option, irq_controller: Arc) -> Self { - Uart8250 { - port_base, - txr: Default::default(), - rbr: Default::default(), - dll: Default::default(), - dlh: Default::default(), - ier: Default::default(), - iir: Default::default(), - lcr: Default::default(), - mcr: Default::default(), - lsr: Default::default(), - msr: Default::default(), - irq_controller, - irq_state: false, - } - } -} - -impl Uart8250 { +impl Uart8250Internal { // Transmitter holding register fn out_thr(&mut self, data: &[u8]) { assert_eq!(data.len(), 1); @@ -349,6 +330,30 @@ impl Uart8250 { } } +pub struct Uart8250(Mutex>); + +impl Uart8250 { + pub fn new(port_base: Option, irq_controller: Arc) -> Self { + let internal = Uart8250Internal { + port_base, + txr: Default::default(), + rbr: Default::default(), + dll: Default::default(), + dlh: Default::default(), + ier: Default::default(), + iir: Default::default(), + lcr: Default::default(), + mcr: Default::default(), + lsr: Default::default(), + msr: Default::default(), + irq_controller, + irq_state: false, + }; + + Uart8250(Mutex::new(internal)) + } +} + impl Device for Uart8250 { fn name(&self) -> String { "uart8250".to_string() @@ -357,7 +362,9 @@ impl Device for Uart8250 { impl PioDevice for Uart8250 { fn ports(&self) -> Vec { - let base = *self.port_base.as_ref().unwrap(); + let internal = self.0.lock().unwrap(); + + let base = *internal.port_base.as_ref().unwrap(); vec![ PortRange { @@ -395,44 +402,48 @@ impl PioDevice for Uart8250 { ] } - fn io_in(&mut self, port: u16, data: &mut [u8]) { - let base = self.port_base.as_ref().unwrap(); + fn io_in(&self, port: u16, data: &mut [u8]) { + let mut internal = self.0.lock().unwrap(); + + let base = internal.port_base.as_ref().unwrap(); match port - base { - RBR if !self.lcr.is_dlab_set() => self.in_rbr(data), - DLL if self.lcr.is_dlab_set() => self.in_dll(data), - IER if !self.lcr.is_dlab_set() => self.in_ier(data), - DLH if self.lcr.is_dlab_set() => self.in_dlh(data), - IIR => self.in_iir(data), - LCR => self.in_lcr(data), - MCR => self.in_mcr(data), - LSR => self.in_lsr(data), - MSR => self.in_msr(data), - SR => self.in_sr(data), + RBR if !internal.lcr.is_dlab_set() => internal.in_rbr(data), + DLL if internal.lcr.is_dlab_set() => internal.in_dll(data), + IER if !internal.lcr.is_dlab_set() => internal.in_ier(data), + DLH if internal.lcr.is_dlab_set() => internal.in_dlh(data), + IIR => internal.in_iir(data), + LCR => internal.in_lcr(data), + MCR => internal.in_mcr(data), + LSR => internal.in_lsr(data), + MSR => internal.in_msr(data), + SR => internal.in_sr(data), _ => unreachable!(), } - self.update_irq(); + internal.update_irq(); } - fn io_out(&mut self, port: u16, data: &[u8]) { - let base = self.port_base.as_ref().unwrap(); + fn io_out(&self, port: u16, data: &[u8]) { + let mut internal = self.0.lock().unwrap(); + + let base = internal.port_base.as_ref().unwrap(); match port - base { - THR if !self.lcr.is_dlab_set() => self.out_thr(data), - DLL if self.lcr.is_dlab_set() => self.out_dll(data), - IER if !self.lcr.is_dlab_set() => self.out_ier(data), - DLH if self.lcr.is_dlab_set() => self.out_dlh(data), - // FCR => self.out_fcr(data), + THR if !internal.lcr.is_dlab_set() => internal.out_thr(data), + DLL if internal.lcr.is_dlab_set() => internal.out_dll(data), + IER if !internal.lcr.is_dlab_set() => internal.out_ier(data), + DLH if internal.lcr.is_dlab_set() => internal.out_dlh(data), + // FCR => internal.out_fcr(data), FCR => (), // no fifo, - LCR => self.out_lcr(data), - MCR => self.out_mcr(data), + LCR => internal.out_lcr(data), + MCR => internal.out_mcr(data), LSR => (), // Ignore MSR => (), // Ignore SR => (), // 8250 does not have sr _ => unreachable!(), } - self.update_irq(); + internal.update_irq(); } } diff --git a/crates/vm-device/src/device/vga.rs b/crates/vm-device/src/device/vga.rs index e080b41..8ee8004 100644 --- a/crates/vm-device/src/device/vga.rs +++ b/crates/vm-device/src/device/vga.rs @@ -25,11 +25,11 @@ impl PioDevice for Vga { ] } - fn io_in(&mut self, _port: u16, _data: &mut [u8]) { + fn io_in(&self, _port: u16, _data: &mut [u8]) { todo!() } - fn io_out(&mut self, port: u16, _data: &[u8]) { + fn io_out(&self, port: u16, _data: &[u8]) { match port { 0x3d4 => { // Ignore diff --git a/crates/vm-machine/src/vm.rs b/crates/vm-machine/src/vm.rs index 1ee6516..8c16d9c 100644 --- a/crates/vm-machine/src/vm.rs +++ b/crates/vm-machine/src/vm.rs @@ -17,6 +17,8 @@ use crate::vm::config::VmConfig; pub mod config; +pub(crate) mod vm_exit_handler; + pub struct Vm { pub(crate) _vm_instance: Arc, pub(crate) vcpu_manager: Arc>, diff --git a/crates/vm-machine/src/vm/vm_exit_handler.rs b/crates/vm-machine/src/vm/vm_exit_handler.rs new file mode 100644 index 0000000..53431ba --- /dev/null +++ b/crates/vm-machine/src/vm/vm_exit_handler.rs @@ -0,0 +1,103 @@ +use std::sync::Arc; + +#[cfg(target_arch = "aarch64")] +use vm_core::arch::aarch64::firmware::psci::Psci; +#[cfg(target_arch = "aarch64")] +use vm_core::arch::aarch64::firmware::psci::psci_0_2::Psci02; +use vm_core::device_manager::manager::DeviceManager; +use vm_core::vcpu::vm_exit::VmExit; +use vm_core::vcpu::vm_exit::VmExitHandlerError; + +pub struct VmExitHandler { + pub device_manager: Arc, + #[cfg(target_arch = "aarch64")] + pub psci: Psci02, +} + +impl VmExit for VmExitHandler { + fn io_in(&mut self, port: u16, data: &mut [u8]) -> Result<(), VmExitHandlerError> { + let device = self + .device_manager + .pio_manager + .get_device_by_port(port) + .ok_or(VmExitHandlerError::NoDeviceForPort(port))?; + + device.io_in(port, data); + + Ok(()) + } + + fn io_out(&mut self, port: u16, data: &[u8]) -> Result<(), VmExitHandlerError> { + let device = self + .device_manager + .pio_manager + .get_device_by_port(port) + .ok_or(VmExitHandlerError::NoDeviceForPort(port))?; + + device.io_out(port, data); + + Ok(()) + } + + fn mmio_read(&self, addr: u64, len: usize, data: &mut [u8]) -> Result<(), VmExitHandlerError> { + let (range, handler) = self + .device_manager + .mmio_manager + .get_handler_by_addr(addr) + .ok_or(VmExitHandlerError::NoDeviceForAddr(addr))?; + + let err = || VmExitHandlerError::MmioOutOfMemory { + mmio_start: range.start, + mmio_len: range.len, + addr, + }; + + if addr.checked_add(len as u64).ok_or_else(err)? + > range.start.checked_add(range.len as u64).ok_or_else(err)? + { + return Err(err()); + } + + handler.mmio_read(addr - range.start, len, data); + + Ok(()) + } + + fn mmio_write(&self, addr: u64, len: usize, data: &[u8]) -> Result<(), VmExitHandlerError> { + let (range, handler) = self + .device_manager + .mmio_manager + .get_handler_by_addr(addr) + .ok_or(VmExitHandlerError::NoDeviceForAddr(addr))?; + + let err = || VmExitHandlerError::MmioOutOfMemory { + mmio_start: range.start, + mmio_len: range.len, + addr, + }; + + if addr.checked_add(len as u64).ok_or_else(err)? + > range.start.checked_add(range.len as u64).ok_or_else(err)? + { + return Err(err()); + } + + handler.mmio_write(addr - range.start, len, data); + + Ok(()) + } + + fn in_mmio_region(&self, addr: u64) -> bool { + self.device_manager + .mmio_manager + .mmio_layout() + .in_mmio_region(addr) + } + + #[cfg(target_arch = "aarch64")] + fn call_smc(&self, vcpu: &mut dyn vm_core::virt::vcpu::Vcpu) -> Result<(), VmExitHandlerError> { + self.psci.call(vcpu)?; + + Ok(()) + } +} diff --git a/crates/vm-machine/src/vmm.rs b/crates/vm-machine/src/vmm.rs index 48c8c53..a0ca8f7 100644 --- a/crates/vm-machine/src/vmm.rs +++ b/crates/vm-machine/src/vmm.rs @@ -35,6 +35,7 @@ use crate::error::Error; use crate::error::Result; use crate::vm::Vm; use crate::vm::config::VmConfig; +use crate::vm::vm_exit_handler::VmExitHandler; const PAGE_SIZE: usize = 4 << 10; @@ -95,17 +96,21 @@ impl Vmm { let vcpu_manager = Arc::new(Mutex::new(VcpuManager::new(vm_instance.clone()))); #[cfg(target_arch = "aarch64")] - let psci = Arc::new(Psci02 { + let psci = Psci02 { vcpu_manager: vcpu_manager.clone(), + }; + + let vm_exit_handler = Arc::new(VmExitHandler { + device_manager: device_manager.clone(), + #[cfg(target_arch = "aarch64")] + psci, }); for vcpu_id in 0..vm_config.vcpus { - vcpu_manager.lock().unwrap().create_vcpu( - vcpu_id, - device_manager.clone(), - #[cfg(target_arch = "aarch64")] - psci.clone(), - )?; + vcpu_manager + .lock() + .unwrap() + .create_vcpu(vcpu_id, vm_exit_handler.clone())?; } let vm = Vm { diff --git a/crates/vm-pci/src/root_complex/pio.rs b/crates/vm-pci/src/root_complex/pio.rs index ff02014..c3d8f2b 100644 --- a/crates/vm-pci/src/root_complex/pio.rs +++ b/crates/vm-pci/src/root_complex/pio.rs @@ -1,3 +1,5 @@ +use std::sync::Mutex; + use vm_core::device::Device; use vm_core::device::pio::pio_device::PioDevice; use vm_core::device::pio::pio_device::PortRange; @@ -12,54 +14,58 @@ const CONFIG_DATA: u16 = 0xcfc; #[derive(Default)] pub struct PciRootComplexPio { - config_address: ConfigAddress, - internal: PciRootComplex, + config_address: Mutex, + internal: Mutex, } impl PciRootComplexPio { - fn handle_out_config_address(&mut self, offset: u8, data: &[u8]) { - self.config_address.write(offset, data); + fn handle_out_config_address(&self, offset: u8, data: &[u8]) { + self.config_address.lock().unwrap().write(offset, data); } fn handle_in_config_address(&self, offset: u8, data: &mut [u8]) { - self.config_address.read(offset, data); + self.config_address.lock().unwrap().read(offset, data); } - fn handle_out_config_data(&mut self, offset: u8, data: &[u8]) { + fn handle_out_config_data(&self, offset: u8, data: &[u8]) { + let config_address = self.config_address.lock().unwrap(); + assert_eq!(data.len(), 4); - if !self.config_address.enable() { + if !config_address.enable() { return; } - let register = self.config_address.register(); + let register = config_address.register(); // let offset = self.config_address.offset(); let start = register * 4 + offset; - self.internal.handle_ecam_write( - self.config_address.bus(), - self.config_address.device(), - self.config_address.function(), + self.internal.lock().unwrap().handle_ecam_write( + config_address.bus(), + config_address.device(), + config_address.function(), start as u16, data, ); } fn handle_in_config_data(&self, offset: u8, data: &mut [u8]) { - if !self.config_address.enable() { + let config_address = self.config_address.lock().unwrap(); + + if !config_address.enable() { data.fill(0xff); return; } - let register = self.config_address.register(); + let register = config_address.register(); // let offset = self.config_address.offset(); // ignore offset? let start = register * 4 + offset; - self.internal.handle_ecam_read( - self.config_address.bus(), - self.config_address.device(), - self.config_address.function(), + self.internal.lock().unwrap().handle_ecam_read( + config_address.bus(), + config_address.device(), + config_address.function(), start as u16, data, ); @@ -86,7 +92,7 @@ impl PioDevice for PciRootComplexPio { ] } - fn io_in(&mut self, port: u16, data: &mut [u8]) { + fn io_in(&self, port: u16, data: &mut [u8]) { if (CONFIG_ADDRESS..CONFIG_ADDRESS + 4).contains(&port) { let offset = port - CONFIG_ADDRESS; self.handle_in_config_address(offset as u8, data); @@ -98,7 +104,7 @@ impl PioDevice for PciRootComplexPio { } } - fn io_out(&mut self, port: u16, data: &[u8]) { + fn io_out(&self, port: u16, data: &[u8]) { if (CONFIG_ADDRESS..CONFIG_ADDRESS + 4).contains(&port) { let offset = port - CONFIG_ADDRESS; self.handle_out_config_address(offset as u8, data);