Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Makes RAM belong to hypervisor #976

Merged
merged 1 commit into from
Sep 9, 2024
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
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