mirror of
https://github.com/obhq/obliteration.git
synced 2024-11-27 05:00:24 +00:00
Maps VM memory (#759)
This commit is contained in:
parent
f180e556b9
commit
6bca86fdf6
@ -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"),
|
||||
_ => {}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user