Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 7 additions & 23 deletions crates/vm-core/src/arch/aarch64/vm_exit.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -52,24 +39,23 @@ pub enum HandleVmExitResult {
pub fn handle_vm_exit(
vcpu: &mut Vcpu,
exit_reason: VmExitReason,
vm_exit_handler: &dyn VmExit,
) -> Result<HandleVmExitResult, VcpuError> {
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!(),
Expand All @@ -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)
}
Expand Down
2 changes: 0 additions & 2 deletions crates/vm-core/src/arch/x86_64.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
pub mod layout;
pub mod vcpu;
pub mod vm_exit;

pub const BASE_ADDRESS: u64 = 0x0;
4 changes: 2 additions & 2 deletions crates/vm-core/src/device/pio/pio_as_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
}
}
4 changes: 2 additions & 2 deletions crates/vm-core/src/device/pio/pio_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub type PortRange = Range<u16>;
pub trait PioDevice: Device {
fn ports(&self) -> Vec<PortRange>;

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]);
}
1 change: 0 additions & 1 deletion crates/vm-core/src/device_manager.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
pub mod manager;
pub mod vm_exit;
80 changes: 2 additions & 78 deletions crates/vm-core/src/device_manager/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions crates/vm-core/src/vcpu.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod error;
pub mod vcpu;
pub mod vcpu_manager;
pub mod vm_exit;
12 changes: 3 additions & 9 deletions crates/vm-core/src/vcpu/error.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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),
}
8 changes: 2 additions & 6 deletions crates/vm-core/src/vcpu/vcpu.rs
Original file line number Diff line number Diff line change
@@ -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<dyn crate::virt::vcpu::Vcpu>,
pub device_vm_exit_handler: Arc<dyn DeviceVmExitHandler>,
#[cfg(target_arch = "aarch64")]
pub psci: Arc<dyn Psci>,
pub vm_exit_handler: Arc<dyn VmExit>,
}
31 changes: 18 additions & 13 deletions crates/vm-core/src/vcpu/vcpu_manager.rs
Original file line number Diff line number Diff line change
@@ -1,58 +1,56 @@
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;
#[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::virt::Vm;
use crate::vcpu::vm_exit::VmExit;
use crate::virt::vm::Vm;

pub struct VcpuManager {
vm_instance: Arc<dyn Vm>,
vcpus: Vec<Arc<Mutex<Vcpu>>>,
handlers: Vec<JoinHandle<Result<(), VcpuError>>>,
}

impl VcpuManager {
pub fn new(vm_instance: Arc<dyn Vm>) -> Self {
VcpuManager {
vm_instance,
vcpus: Default::default(),
handlers: Default::default(),
}
}

pub fn create_vcpu(
&mut self,
vcpu_id: usize,
device_vm_exit_handler: Arc<dyn DeviceVmExitHandler>,
#[cfg(target_arch = "aarch64")] psci: Arc<dyn Psci>,
vm_exit_handler: Arc<dyn VmExit>,
) -> 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)));

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()?;
Expand All @@ -62,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()?;

Expand All @@ -70,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)?;
Expand All @@ -82,6 +85,8 @@ impl VcpuManager {
}
});

self.handlers.push(handle);

Ok(())
}
}
Original file line number Diff line number Diff line change
@@ -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),

Expand All @@ -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>;
}
Loading
Loading