Skip to content

Commit

Permalink
Makes RAM belong to hypervisor (#976)
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon authored Sep 9, 2024
1 parent 1e68099 commit 376f8ce
Show file tree
Hide file tree
Showing 13 changed files with 260 additions and 284 deletions.
36 changes: 0 additions & 36 deletions src/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,42 +170,6 @@ struct Vmm *vmm_run(const char *kernel,

struct RustError *vmm_draw(struct Vmm *vmm);

#if defined(__linux__)
extern int kvm_check_version(int kvm, bool *compat);
#endif

#if defined(__linux__)
extern int kvm_max_vcpus(int kvm, size_t *max);
#endif

#if defined(__linux__)
extern int kvm_create_vm(int kvm, int *fd);
#endif

#if defined(__linux__)
extern int kvm_get_vcpu_mmap_size(int kvm);
#endif

#if defined(__linux__)
extern int kvm_set_user_memory_region(int vm,
uint32_t slot,
uint64_t addr,
uint64_t len,
void *mem);
#endif

#if defined(__linux__)
extern int kvm_create_vcpu(int vm, uint32_t id, int *fd);
#endif

#if defined(__linux__)
extern int kvm_run(int vcpu);
#endif

#if defined(__linux__)
extern int kvm_translate(int vcpu, kvm_translation *arg);
#endif

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
2 changes: 1 addition & 1 deletion src/core/src/vmm/aarch64.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use super::hv::{Cpu, CpuFeats, CpuStates, Pstate};
use super::hw::RamMap;
use super::ram::RamMap;
use super::MainCpuError;

pub fn setup_main_cpu(
Expand Down
139 changes: 72 additions & 67 deletions src/core/src/vmm/hv/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use self::ffi::{
kvm_set_user_memory_region,
};
use super::{CpuFeats, Hypervisor};
use crate::vmm::hw::Ram;
use crate::vmm::ram::Ram;
use crate::vmm::VmmError;
use libc::{mmap, open, MAP_FAILED, MAP_PRIVATE, O_RDWR, PROT_READ, PROT_WRITE};
use std::os::fd::{AsRawFd, FromRawFd, OwnedFd};
Expand All @@ -20,87 +20,84 @@ mod ffi;
mod regs;
mod run;

/// Implementation of [`Hypervisor`] using KVM.
///
/// Fields in this struct need to drop in a correct order (e.g. vm must be dropped before ram).
pub struct Kvm {
vcpu_mmap_size: usize,
vm: OwnedFd,
#[allow(dead_code)] // ram are needed by vm.
ram: Arc<Ram>,
#[allow(dead_code)] // kvm are needed by vm.
kvm: OwnedFd,
}

impl Kvm {
pub fn new(cpu: usize, ram: Arc<Ram>) -> Result<Self, VmmError> {
use std::io::Error;
pub fn new(cpu: usize, ram: Ram) -> Result<impl Hypervisor, VmmError> {
use std::io::Error;

// Open KVM device.
let kvm = unsafe { open(b"/dev/kvm\0".as_ptr().cast(), O_RDWR) };
// Open KVM device.
let kvm = unsafe { open(b"/dev/kvm\0".as_ptr().cast(), O_RDWR) };

if kvm < 0 {
return Err(VmmError::OpenKvmFailed(Error::last_os_error()));
}
if kvm < 0 {
return Err(VmmError::OpenKvmFailed(Error::last_os_error()));
}

// Check KVM version.
let kvm = unsafe { OwnedFd::from_raw_fd(kvm) };
let mut compat = false;
// Check KVM version.
let kvm = unsafe { OwnedFd::from_raw_fd(kvm) };
let mut compat = false;

match unsafe { kvm_check_version(kvm.as_raw_fd(), &mut compat) } {
0 if !compat => {
return Err(VmmError::KvmVersionMismatched);
}
0 => {}
v => return Err(VmmError::GetKvmVersionFailed(Error::from_raw_os_error(v))),
match unsafe { kvm_check_version(kvm.as_raw_fd(), &mut compat) } {
0 if !compat => {
return Err(VmmError::KvmVersionMismatched);
}
0 => {}
v => return Err(VmmError::GetKvmVersionFailed(Error::from_raw_os_error(v))),
}

// Check max CPU.
let mut max = 0;
// Check max CPU.
let mut max = 0;

match unsafe { kvm_max_vcpus(kvm.as_raw_fd(), &mut max) } {
0 => {}
v => {
return Err(VmmError::GetMaxCpuFailed(Error::from_raw_os_error(v)));
}
match unsafe { kvm_max_vcpus(kvm.as_raw_fd(), &mut max) } {
0 => {}
v => {
return Err(VmmError::GetMaxCpuFailed(Error::from_raw_os_error(v)));
}
}

if max < cpu {
return Err(VmmError::MaxCpuTooLow);
}
if max < cpu {
return Err(VmmError::MaxCpuTooLow);
}

// Get size of CPU context.
let vcpu_mmap_size = match unsafe { kvm_get_vcpu_mmap_size(kvm.as_raw_fd()) } {
size @ 0.. => size as usize,
_ => return Err(VmmError::GetMmapSizeFailed(Error::last_os_error())),
};
// Get size of CPU context.
let vcpu_mmap_size = match unsafe { kvm_get_vcpu_mmap_size(kvm.as_raw_fd()) } {
size @ 0.. => size as usize,
_ => return Err(VmmError::GetMmapSizeFailed(Error::last_os_error())),
};

// Create a VM.
let mut vm = -1;
// Create a VM.
let mut vm = -1;

match unsafe { kvm_create_vm(kvm.as_raw_fd(), &mut vm) } {
0 => {}
v => return Err(VmmError::CreateVmFailed(Error::from_raw_os_error(v))),
}

// Set RAM.
let vm = unsafe { OwnedFd::from_raw_fd(vm) };
let slot = 0;
let len = ram.len().try_into().unwrap();
let mem = ram.host_addr().cast_mut().cast();
match unsafe { kvm_create_vm(kvm.as_raw_fd(), &mut vm) } {
0 => {}
v => return Err(VmmError::CreateVmFailed(Error::from_raw_os_error(v))),
}

match unsafe { kvm_set_user_memory_region(vm.as_raw_fd(), slot, 0, len, mem) } {
0 => {}
v => return Err(VmmError::MapRamFailed(Error::from_raw_os_error(v))),
}
// Set RAM.
let vm = unsafe { OwnedFd::from_raw_fd(vm) };
let slot = 0;
let len = ram.len().try_into().unwrap();
let mem = ram.host_addr().cast_mut().cast();

Ok(Self {
vcpu_mmap_size,
vm,
ram,
kvm,
})
match unsafe { kvm_set_user_memory_region(vm.as_raw_fd(), slot, 0, len, mem) } {
0 => {}
v => return Err(VmmError::MapRamFailed(Error::from_raw_os_error(v))),
}

Ok(Kvm {
vcpu_mmap_size,
vm,
ram,
kvm,
})
}

/// Implementation of [`Hypervisor`] using KVM.
///
/// Fields in this struct need to drop in a correct order (e.g. vm must be dropped before ram).
struct Kvm {
vcpu_mmap_size: usize,
vm: OwnedFd,
ram: Ram,
#[allow(dead_code)] // kvm are needed by vm.
kvm: OwnedFd,
}

impl Hypervisor for Kvm {
Expand All @@ -111,6 +108,14 @@ impl Hypervisor for Kvm {
Ok(CpuFeats {})
}

fn ram(&self) -> &Ram {
&self.ram
}

fn ram_mut(&mut self) -> &mut Ram {
&mut self.ram
}

fn create_cpu(&self, id: usize) -> Result<Self::Cpu<'_>, Self::CpuErr> {
use std::io::Error;

Expand Down
39 changes: 22 additions & 17 deletions src/core/src/vmm/hv/macos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
use self::cpu::HfCpu;
use self::vm::Vm;
use super::{CpuFeats, Hypervisor};
use crate::vmm::hw::Ram;
use crate::vmm::ram::Ram;
use crate::vmm::VmmError;
use hv_sys::hv_vcpu_create;
use std::ffi::c_int;
use std::num::NonZero;
use std::sync::Arc;
use thiserror::Error;

#[cfg_attr(target_arch = "aarch64", path = "aarch64.rs")]
Expand All @@ -16,25 +15,23 @@ mod arch;
mod cpu;
mod vm;

pub fn new(_: usize, ram: Ram) -> Result<impl Hypervisor, VmmError> {
// Create a VM.
let vm = Vm::new().map_err(VmmError::CreateVmFailed)?;

// Map memory.
vm.vm_map(ram.host_addr().cast_mut().cast(), 0, ram.len())
.map_err(VmmError::MapRamFailed)?;

Ok(Hf { vm, ram })
}

/// Implementation of [`Hypervisor`] using Hypervisor Framework.
///
/// Fields in this struct need to drop in a correct order.
pub struct Hf {
struct Hf {
vm: Vm,
ram: Arc<Ram>,
}

impl Hf {
pub fn new(_: usize, ram: Arc<Ram>) -> Result<Self, VmmError> {
// Create a VM.
let vm = Vm::new().map_err(VmmError::CreateVmFailed)?;

// Map memory.
vm.vm_map(ram.host_addr().cast_mut().cast(), 0, ram.len())
.map_err(VmmError::MapRamFailed)?;

Ok(Self { vm, ram })
}
ram: Ram,
}

impl Hypervisor for Hf {
Expand Down Expand Up @@ -120,6 +117,14 @@ impl Hypervisor for Hf {
Ok(CpuFeats {})
}

fn ram(&self) -> &Ram {
&self.ram
}

fn ram_mut(&mut self) -> &mut Ram {
&mut self.ram
}

fn create_cpu(&self, _: usize) -> Result<Self::Cpu<'_>, Self::CpuErr> {
let mut instance = 0;

Expand Down
32 changes: 8 additions & 24 deletions src/core/src/vmm/hv/mod.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,17 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use super::hw::Ram;
use super::VmmError;
use super::ram::Ram;
use std::error::Error;
use std::sync::Arc;

pub use self::arch::*;
pub use self::os::new;

#[cfg_attr(target_arch = "aarch64", path = "aarch64.rs")]
#[cfg_attr(target_arch = "x86_64", path = "x86_64.rs")]
mod arch;
#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "macos")]
mod macos;
#[cfg(target_os = "windows")]
mod windows;

#[cfg(target_os = "linux")]
pub fn new(cpu: usize, ram: Arc<Ram>) -> Result<impl Hypervisor, VmmError> {
self::linux::Kvm::new(cpu, ram)
}

#[cfg(target_os = "windows")]
pub fn new(cpu: usize, ram: Arc<Ram>) -> Result<impl Hypervisor, VmmError> {
self::windows::Whp::new(cpu, ram)
}

#[cfg(target_os = "macos")]
pub fn new(cpu: usize, ram: Arc<Ram>) -> Result<impl Hypervisor, VmmError> {
self::macos::Hf::new(cpu, ram)
}
#[cfg_attr(target_os = "linux", path = "linux/mod.rs")]
#[cfg_attr(target_os = "macos", path = "macos/mod.rs")]
#[cfg_attr(target_os = "windows", path = "windows/mod.rs")]
mod os;

/// Underlying hypervisor (e.g. KVM on Linux).
pub trait Hypervisor: Send + Sync {
Expand All @@ -39,6 +21,8 @@ pub trait Hypervisor: Send + Sync {
type CpuErr: Error + Send + 'static;

fn cpu_features(&mut self) -> Result<CpuFeats, Self::CpuErr>;
fn ram(&self) -> &Ram;
fn ram_mut(&mut self) -> &mut Ram;

/// This method must be called by a thread that is going to drive the returned CPU.
fn create_cpu(&self, id: usize) -> Result<Self::Cpu<'_>, Self::CpuErr>;
Expand Down
Loading

0 comments on commit 376f8ce

Please sign in to comment.