Maps VM memory (#759)

This commit is contained in:
Putta Khunchalee 2024-03-24 16:31:52 +07:00 committed by GitHub
parent f180e556b9
commit 6bca86fdf6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 120 additions and 10 deletions

View File

@ -1,9 +1,13 @@
fn main() {
match std::env::var("CARGO_CFG_TARGET_OS").unwrap().as_str() {
"linux" | "android" => cc::Build::new()
.cpp(true)
.file("src/linux/kvm.cpp")
.compile("hvkvm"),
"linux" | "android" => {
println!("cargo::rerun-if-changed=src/linux/kvm.cpp");
cc::Build::new()
.cpp(true)
.file("src/linux/kvm.cpp")
.compile("obhv");
}
"macos" => println!("cargo:rustc-link-lib=framework=Hypervisor"),
_ => {}
}

View File

@ -1,5 +1,5 @@
use crate::NewError;
use std::ffi::c_int;
use std::ffi::{c_int, c_void};
use std::ptr::null_mut;
/// RAII struct for `hv_vm_create` and `hv_vm_destroy`.
@ -21,6 +21,13 @@ impl Vm {
v => Err(v),
}
}
pub fn vm_map(&self, host: *mut c_void, guest: u64, len: usize) -> Result<(), c_int> {
match unsafe { hv_vm_map(host, guest, len, 1 | 2 | 4) } {
0 => Ok(()),
v => Err(v),
}
}
}
impl Drop for Vm {
@ -37,4 +44,5 @@ extern "C" {
fn hv_vm_create(config: *mut ()) -> c_int;
fn hv_vm_destroy() -> c_int;
fn hv_capability(capability: u64, value: *mut u64) -> c_int;
fn hv_vm_map(uva: *mut c_void, gpa: u64, size: usize, flags: u64) -> c_int;
}

View File

@ -84,6 +84,15 @@ impl Hypervisor {
// Create a new VM.
let vm = self::linux::create_vm(kvm.as_fd()).map_err(NewError::CreateVmFailed)?;
self::linux::set_user_memory_region(
vm.as_fd(),
0,
addr.try_into().unwrap(),
len.try_into().unwrap(),
ram.cast(),
)
.map_err(NewError::MapMemoryFailed)?;
Ok(Self { vm, kvm, active })
}
@ -95,9 +104,18 @@ impl Hypervisor {
addr: usize,
len: usize,
) -> Result<Self, NewError> {
// Setup a partition.
let mut whp = self::win32::Partition::new(cpu)?;
whp.setup()?;
whp.setup().map_err(NewError::SetupPartitionFailed)?;
// Map memory.
whp.map_gpa(
ram.cast(),
addr.try_into().unwrap(),
len.try_into().unwrap(),
)
.map_err(NewError::MapMemoryFailed)?;
Ok(Self { whp, active })
}
@ -118,6 +136,10 @@ impl Hypervisor {
return Err(NewError::InvalidCpuCount);
}
// Map memory.
vm.vm_map(ram.cast(), addr.try_into().unwrap(), len)
.map_err(NewError::MapMemoryFailed)?;
Ok(Self { vm, active })
}
@ -197,6 +219,10 @@ pub enum NewError {
#[error("couldn't create a VM")]
CreateVmFailed(#[source] std::io::Error),
#[cfg(any(target_os = "linux", target_os = "android"))]
#[error("couldn't map a VM memory")]
MapMemoryFailed(#[source] std::io::Error),
#[cfg(target_os = "windows")]
#[error("couldn't create WHP partition object ({0:#x})")]
CreatePartitionFailed(windows_sys::core::HRESULT),
@ -209,6 +235,10 @@ pub enum NewError {
#[error("couldn't setup WHP partition ({0:#x})")]
SetupPartitionFailed(windows_sys::core::HRESULT),
#[cfg(target_os = "windows")]
#[error("couldn't map memory to WHP partition ({0:#x})")]
MapMemoryFailed(windows_sys::core::HRESULT),
#[cfg(target_os = "macos")]
#[error("couldn't create a VM ({0:#x})")]
CreateVmFailed(std::ffi::c_int),
@ -216,6 +246,10 @@ pub enum NewError {
#[cfg(target_os = "macos")]
#[error("couldn't get maximum number of CPU for a VM")]
GetMaxCpuFailed(std::ffi::c_int),
#[cfg(target_os = "macos")]
#[error("couldn't map memory to the VM")]
MapMemoryFailed(std::ffi::c_int),
}
static ACTIVE: AtomicBool = AtomicBool::new(false);

View File

@ -5,6 +5,8 @@
#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
extern "C" int kvm_check_version(int kvm, bool *compat)
{
@ -41,3 +43,26 @@ extern "C" int kvm_create_vm(int kvm, int *fd)
*fd = vm;
return 0;
}
extern "C" int kvm_set_user_memory_region(
int vm,
uint32_t slot,
uint64_t addr,
uint64_t len,
void *mem)
{
kvm_userspace_memory_region mr;
memset(&mr, 0, sizeof(mr));
mr.slot = slot;
mr.guest_phys_addr = addr;
mr.memory_size = len;
mr.userspace_addr = reinterpret_cast<uint64_t>(mem);
if (ioctl(vm, KVM_SET_USER_MEMORY_REGION, &mr) < 0) {
return errno;
}
return 0;
}

View File

@ -1,6 +1,6 @@
use crate::NewError;
use libc::{open, O_RDWR};
use std::ffi::c_int;
use std::ffi::{c_int, c_void};
use std::io::Error;
use std::os::fd::{AsRawFd, BorrowedFd, FromRawFd, OwnedFd};
@ -46,8 +46,28 @@ pub fn create_vm(kvm: BorrowedFd) -> Result<OwnedFd, Error> {
}
}
pub fn set_user_memory_region(
vm: BorrowedFd,
slot: u32,
addr: u64,
len: u64,
mem: *mut c_void,
) -> Result<(), Error> {
match unsafe { kvm_set_user_memory_region(vm.as_raw_fd(), slot, addr, len, mem) } {
0 => Ok(()),
v => Err(Error::from_raw_os_error(v)),
}
}
extern "C" {
fn kvm_check_version(kvm: c_int, compat: *mut bool) -> c_int;
fn kvm_max_vcpus(kvm: c_int, max: *mut usize) -> c_int;
fn kvm_create_vm(kvm: c_int, fd: *mut c_int) -> c_int;
fn kvm_set_user_memory_region(
vm: c_int,
slot: u32,
addr: u64,
len: u64,
mem: *mut c_void,
) -> c_int;
}

View File

@ -4,7 +4,8 @@ use std::mem::size_of;
use std::num::NonZeroUsize;
use windows_sys::core::HRESULT;
use windows_sys::Win32::System::Hypervisor::{
WHvCreatePartition, WHvDeletePartition, WHvPartitionPropertyCodeProcessorCount,
WHvCreatePartition, WHvDeletePartition, WHvMapGpaRange, WHvMapGpaRangeFlagExecute,
WHvMapGpaRangeFlagRead, WHvMapGpaRangeFlagWrite, WHvPartitionPropertyCodeProcessorCount,
WHvSetPartitionProperty, WHvSetupPartition, WHV_PARTITION_HANDLE, WHV_PARTITION_PROPERTY,
WHV_PARTITION_PROPERTY_CODE,
};
@ -58,11 +59,29 @@ impl Partition {
)
}
pub fn setup(&mut self) -> Result<(), NewError> {
pub fn setup(&mut self) -> Result<(), HRESULT> {
let status = unsafe { WHvSetupPartition(self.0) };
if status < 0 {
Err(NewError::SetupPartitionFailed(status))
Err(status)
} else {
Ok(())
}
}
pub fn map_gpa(&self, host: *const c_void, guest: u64, len: u64) -> Result<(), HRESULT> {
let status = unsafe {
WHvMapGpaRange(
self.0,
host,
guest,
len,
WHvMapGpaRangeFlagRead | WHvMapGpaRangeFlagWrite | WHvMapGpaRangeFlagExecute,
)
};
if status < 0 {
Err(status)
} else {
Ok(())
}