Removes hard-coded RAM size (#1038)
Some checks are pending
Development Build / Build (push) Waiting to run
Development Build / Update PRs (push) Waiting to run

This commit is contained in:
Putta Khunchalee 2024-10-16 02:18:22 +07:00 committed by GitHub
parent 52698d73de
commit 2372243b41
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 86 additions and 63 deletions

View File

@ -9,29 +9,6 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
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;
}
extern "C" int kvm_run(int vcpu) extern "C" int kvm_run(int vcpu)
{ {
return ioctl(vcpu, KVM_RUN, 0); return ioctl(vcpu, KVM_RUN, 0);

View File

@ -92,7 +92,11 @@ impl<T> Debugger<T> {
if matches!(s.deref(), DataState::None) { if matches!(s.deref(), DataState::None) {
*s = DataState::DebuggerOwned(v); *s = DataState::DebuggerOwned(v);
return ResponseHandle(&self.0);
return ResponseHandle {
data: &self.0,
taken: false,
};
} }
// Once the debugger has been requested the data it will wait for the data and a signal from // Once the debugger has been requested the data it will wait for the data and a signal from
@ -121,27 +125,47 @@ impl<T> Debugger<T> {
// wake them up. Condvar::notify_one do nothing if there are no any thread waiting on it. // wake them up. Condvar::notify_one do nothing if there are no any thread waiting on it.
self.0.signal.notify_one(); self.0.signal.notify_one();
ResponseHandle(&self.0) ResponseHandle {
data: &self.0,
taken: false,
}
} }
} }
/// Provides method to get a response from the debugger. /// Provides method to get a response from the debugger.
pub struct ResponseHandle<'a, T>(&'a Data<T>); pub struct ResponseHandle<'a, T> {
data: &'a Data<T>,
taken: bool,
}
impl<'a, T> ResponseHandle<'a, T> { impl<'a, T> ResponseHandle<'a, T> {
pub fn into_response(self) -> T { pub fn into_response(mut self) -> T {
let mut s = self.0.state.lock().unwrap(); let mut s = self.data.state.lock().unwrap();
let v = match std::mem::take(s.deref_mut()) { let v = match std::mem::take(s.deref_mut()) {
DataState::DebuggeeOwned(v) => v, DataState::DebuggeeOwned(v) => v,
_ => panic!("the debugger did not release the data"), _ => panic!("the debugger did not release the data"),
}; };
self.taken = true;
v
}
}
impl<'a, T> Drop for ResponseHandle<'a, T> {
fn drop(&mut self) {
if !self.taken {
let mut s = self.data.state.lock().unwrap();
if !matches!(std::mem::take(s.deref_mut()), DataState::DebuggeeOwned(_)) {
panic!("the debugger did not release the data");
}
}
// It is possible for this method to get called after the debugger has reacquired the lock // It is possible for this method to get called after the debugger has reacquired the lock
// so we need to wake them up. Condvar::notify_one do nothing if there are no any thread // so we need to wake them up. Condvar::notify_one do nothing if there are no any thread
// waiting on it. // waiting on it.
self.0.signal.notify_one(); self.data.signal.notify_one();
v
} }
} }

View File

@ -1,10 +1,11 @@
use std::ffi::{c_int, c_ulong, c_void}; use std::ffi::{c_int, c_ulong};
pub const KVM_GET_API_VERSION: c_ulong = _IO(KVMIO, 0x00); pub const KVM_GET_API_VERSION: c_ulong = _IO(KVMIO, 0x00);
pub const KVM_CREATE_VM: c_ulong = _IO(KVMIO, 0x01); pub const KVM_CREATE_VM: c_ulong = _IO(KVMIO, 0x01);
pub const KVM_CHECK_EXTENSION: c_ulong = _IO(KVMIO, 0x03); pub const KVM_CHECK_EXTENSION: c_ulong = _IO(KVMIO, 0x03);
pub const KVM_GET_VCPU_MMAP_SIZE: c_ulong = _IO(KVMIO, 0x04); pub const KVM_GET_VCPU_MMAP_SIZE: c_ulong = _IO(KVMIO, 0x04);
pub const KVM_CREATE_VCPU: c_ulong = _IO(KVMIO, 0x41); pub const KVM_CREATE_VCPU: c_ulong = _IO(KVMIO, 0x41);
pub const KVM_SET_USER_MEMORY_REGION: c_ulong = _IOW::<KvmUserspaceMemoryRegion>(KVMIO, 0x46);
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
pub const KVM_GET_ONE_REG: c_ulong = _IOW::<KvmOneReg<()>>(KVMIO, 0xab); pub const KVM_GET_ONE_REG: c_ulong = _IOW::<KvmOneReg<()>>(KVMIO, 0xab);
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
@ -78,6 +79,15 @@ const fn _IOC(dir: c_ulong, ty: c_ulong, nr: c_ulong, size: c_ulong) -> c_ulong
| (size << _IOC_SIZESHIFT) | (size << _IOC_SIZESHIFT)
} }
#[repr(C)]
pub struct KvmUserspaceMemoryRegion {
pub slot: u32,
pub flags: u32,
pub guest_phys_addr: u64,
pub memory_size: u64,
pub userspace_addr: u64,
}
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
#[repr(C)] #[repr(C)]
pub struct KvmOneReg<'a, T> { pub struct KvmOneReg<'a, T> {
@ -93,12 +103,5 @@ pub struct KvmVcpuInit {
} }
extern "C" { extern "C" {
pub fn kvm_set_user_memory_region(
vm: c_int,
slot: u32,
addr: u64,
len: u64,
mem: *mut c_void,
) -> c_int;
pub fn kvm_run(vcpu: c_int) -> c_int; pub fn kvm_run(vcpu: c_int) -> c_int;
} }

View File

@ -1,8 +1,9 @@
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
use self::cpu::KvmCpu; use self::cpu::KvmCpu;
use self::ffi::{ use self::ffi::{
kvm_set_user_memory_region, KVM_API_VERSION, KVM_CAP_MAX_VCPUS, KVM_CHECK_EXTENSION, KvmUserspaceMemoryRegion, KVM_API_VERSION, KVM_CAP_MAX_VCPUS, KVM_CHECK_EXTENSION,
KVM_CREATE_VCPU, KVM_CREATE_VM, KVM_GET_API_VERSION, KVM_GET_VCPU_MMAP_SIZE, KVM_CREATE_VCPU, KVM_CREATE_VM, KVM_GET_API_VERSION, KVM_GET_VCPU_MMAP_SIZE,
KVM_SET_USER_MEMORY_REGION,
}; };
use super::{CpuFeats, Hypervisor}; use super::{CpuFeats, Hypervisor};
use crate::vmm::ram::Ram; use crate::vmm::ram::Ram;
@ -81,13 +82,16 @@ pub fn new(cpu: usize, ram: Ram) -> Result<Kvm, VmmError> {
}; };
// Set RAM. // Set RAM.
let slot = 0; let mr = KvmUserspaceMemoryRegion {
let len = ram.len().try_into().unwrap(); slot: 0,
let mem = ram.host_addr().cast_mut().cast(); flags: 0,
guest_phys_addr: 0,
memory_size: ram.len().get().try_into().unwrap(),
userspace_addr: (ram.host_addr() as usize).try_into().unwrap(),
};
match unsafe { kvm_set_user_memory_region(vm.as_raw_fd(), slot, 0, len, mem) } { if unsafe { ioctl(vm.as_raw_fd(), KVM_SET_USER_MEMORY_REGION, &mr) } < 0 {
0 => {} return Err(VmmError::MapRamFailed(Error::last_os_error()));
v => return Err(VmmError::MapRamFailed(Error::from_raw_os_error(v))),
} }
// AArch64 require all CPU to be created before calling KVM_ARM_VCPU_INIT. // AArch64 require all CPU to be created before calling KVM_ARM_VCPU_INIT.

View File

@ -46,7 +46,7 @@ pub fn new(_: usize, ram: Ram) -> Result<Hvf, VmmError> {
// Set RAM. // Set RAM.
let host = hv.ram.host_addr().cast_mut().cast(); let host = hv.ram.host_addr().cast_mut().cast();
let len = hv.ram.len().try_into().unwrap(); let len = hv.ram.len().get().try_into().unwrap();
let ret = unsafe { let ret = unsafe {
hv_vm_map( hv_vm_map(
host, host,

View File

@ -19,8 +19,12 @@ pub fn new(cpu: usize, ram: Ram) -> Result<Whp, VmmError> {
part.setup().map_err(VmmError::SetupPartitionFailed)?; part.setup().map_err(VmmError::SetupPartitionFailed)?;
// Map memory. // Map memory.
part.map_gpa(ram.host_addr().cast(), 0, ram.len().try_into().unwrap()) part.map_gpa(
.map_err(VmmError::MapRamFailed)?; ram.host_addr().cast(),
0,
ram.len().get().try_into().unwrap(),
)
.map_err(VmmError::MapRamFailed)?;
Ok(Whp { Ok(Whp {
part, part,

View File

@ -329,7 +329,7 @@ pub unsafe extern "C" fn vmm_start(
}; };
// Setup RAM. // Setup RAM.
let ram = match Ram::new(block_size) { let ram = match Ram::new(NonZero::new(1024 * 1024 * 1024 * 8).unwrap(), block_size) {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
*err = RustError::with_source("couldn't create a RAM", e).into_c(); *err = RustError::with_source("couldn't create a RAM", e).into_c();
@ -337,6 +337,10 @@ pub unsafe extern "C" fn vmm_start(
} }
}; };
// Setup virtual devices.
let event = VmmEventHandler { fp: event, cx };
let devices = Arc::new(setup_devices(ram.len().get(), block_size, event));
// Setup hypervisor. // Setup hypervisor.
let mut hv = match self::hv::new(8, ram) { let mut hv = match self::hv::new(8, ram) {
Ok(v) => v, Ok(v) => v,
@ -401,8 +405,6 @@ pub unsafe extern "C" fn vmm_start(
} }
// Allocate arguments. // Allocate arguments.
let event = VmmEventHandler { fp: event, cx };
let devices = Arc::new(setup_devices(Ram::SIZE, block_size, event));
let env = BootEnv::Vm(Vm { let env = BootEnv::Vm(Vm {
vmm: devices.vmm().addr(), vmm: devices.vmm().addr(),
console: devices.console().addr(), console: devices.console().addr(),

View File

@ -16,15 +16,14 @@ mod builder;
/// RAM always started at address 0. /// RAM always started at address 0.
pub struct Ram { pub struct Ram {
mem: *mut u8, mem: *mut u8,
len: NonZero<usize>,
block_size: NonZero<usize>, block_size: NonZero<usize>,
} }
impl Ram { impl Ram {
pub(crate) const SIZE: usize = 1024 * 1024 * 1024 * 8; // 8GB
/// # Safety /// # Safety
/// `block_size` must be greater or equal host page size. /// `block_size` must be greater or equal host page size.
pub unsafe fn new(block_size: NonZero<usize>) -> Result<Self, Error> { pub unsafe fn new(len: NonZero<usize>, block_size: NonZero<usize>) -> Result<Self, Error> {
use std::io::Error; use std::io::Error;
// Reserve memory range. // Reserve memory range.
@ -35,7 +34,7 @@ impl Ram {
let mem = mmap( let mem = mmap(
null_mut(), null_mut(),
Self::SIZE, len.get(),
PROT_NONE, PROT_NONE,
MAP_PRIVATE | MAP_ANON, MAP_PRIVATE | MAP_ANON,
-1, -1,
@ -54,7 +53,7 @@ impl Ram {
use std::ptr::null; use std::ptr::null;
use windows_sys::Win32::System::Memory::{VirtualAlloc, MEM_RESERVE, PAGE_NOACCESS}; use windows_sys::Win32::System::Memory::{VirtualAlloc, MEM_RESERVE, PAGE_NOACCESS};
let mem = VirtualAlloc(null(), Self::SIZE, MEM_RESERVE, PAGE_NOACCESS); let mem = VirtualAlloc(null(), len.get(), MEM_RESERVE, PAGE_NOACCESS);
if mem.is_null() { if mem.is_null() {
return Err(Error::last_os_error()); return Err(Error::last_os_error());
@ -63,15 +62,19 @@ impl Ram {
mem.cast() mem.cast()
}; };
Ok(Self { mem, block_size }) Ok(Self {
mem,
len,
block_size,
})
} }
pub fn host_addr(&self) -> *const u8 { pub fn host_addr(&self) -> *const u8 {
self.mem self.mem
} }
pub fn len(&self) -> usize { pub fn len(&self) -> NonZero<usize> {
Self::SIZE self.len
} }
pub fn builder(&mut self) -> RamBuilder { pub fn builder(&mut self) -> RamBuilder {
@ -88,7 +91,10 @@ impl Ram {
assert_eq!(addr % self.block_size, 0); assert_eq!(addr % self.block_size, 0);
assert_eq!(len.get() % self.block_size, 0); assert_eq!(len.get() % self.block_size, 0);
if !addr.checked_add(len.get()).is_some_and(|v| v <= Self::SIZE) { if !addr
.checked_add(len.get())
.is_some_and(|v| v <= self.len.get())
{
return Err(RamError::InvalidAddr); return Err(RamError::InvalidAddr);
} }
@ -106,7 +112,10 @@ impl Ram {
assert_eq!(addr % self.block_size, 0); assert_eq!(addr % self.block_size, 0);
assert_eq!(len.get() % self.block_size, 0); assert_eq!(len.get() % self.block_size, 0);
if !addr.checked_add(len.get()).is_some_and(|v| v <= Self::SIZE) { if !addr
.checked_add(len.get())
.is_some_and(|v| v <= self.len.get())
{
return Err(RamError::InvalidAddr); return Err(RamError::InvalidAddr);
} }
@ -174,7 +183,7 @@ impl Drop for Ram {
fn drop(&mut self) { fn drop(&mut self) {
use libc::munmap; use libc::munmap;
if unsafe { munmap(self.mem.cast(), Self::SIZE) } < 0 { if unsafe { munmap(self.mem.cast(), self.len.get()) } < 0 {
panic!( panic!(
"failed to unmap RAM at {:p}: {}", "failed to unmap RAM at {:p}: {}",
self.mem, self.mem,