From 49b012ce8b1d7fad2399861fdfa6bf6b9deb3733 Mon Sep 17 00:00:00 2001 From: "Panagiotis \"Ivory\" Vasilopoulos" Date: Thu, 19 Sep 2024 00:19:16 +0200 Subject: [PATCH] feat(vm): change UhyveVm struct parameters As I was moving some functionality away from new(...) so as to progress with my work on ASLR and some future work, I found it necessary to use certain parameters later. A particular example from UhyveVm's current structure would be params.thp and params.ksm, which pose one of the obstacles preventing us from initializing the memory later (e.g. in load_kernel or init_guest_mem, after loading the kernel and being able to establish a guest address), even though separate variables for those don't make much sense. This change will mostly be useful for future work, but aims to establish a consistent convention now. --- src/linux/x86_64/kvm_cpu.rs | 8 +++--- src/macos/aarch64/vcpu.rs | 8 +++--- src/macos/x86_64/vcpu.rs | 9 ++++--- src/vm.rs | 51 +++++++++++++++++++++---------------- 4 files changed, 44 insertions(+), 32 deletions(-) diff --git a/src/linux/x86_64/kvm_cpu.rs b/src/linux/x86_64/kvm_cpu.rs index 8ef03734..553201fa 100644 --- a/src/linux/x86_64/kvm_cpu.rs +++ b/src/linux/x86_64/kvm_cpu.rs @@ -402,12 +402,14 @@ impl VirtualCPU for KvmCpu { hypercall::address_to_hypercall(&self.parent_vm.mem, port, data_addr) } { match hypercall { - Hypercall::Cmdsize(syssize) => syssize - .update(self.parent_vm.kernel_path(), self.parent_vm.args()), + Hypercall::Cmdsize(syssize) => syssize.update( + self.parent_vm.kernel_path(), + &self.parent_vm.params.kernel_args, + ), Hypercall::Cmdval(syscmdval) => { hypercall::copy_argv( self.parent_vm.kernel_path().as_os_str(), - self.parent_vm.args(), + &self.parent_vm.params.kernel_args, syscmdval, &self.parent_vm.mem, ); diff --git a/src/macos/aarch64/vcpu.rs b/src/macos/aarch64/vcpu.rs index 35d86869..5f72ef7c 100644 --- a/src/macos/aarch64/vcpu.rs +++ b/src/macos/aarch64/vcpu.rs @@ -174,12 +174,14 @@ impl VirtualCPU for XhyveCpu { Hypercall::Exit(sysexit) => { return Ok(VcpuStopReason::Exit(sysexit.arg)); } - Hypercall::Cmdsize(syssize) => syssize - .update(self.parent_vm.kernel_path(), self.parent_vm.args()), + Hypercall::Cmdsize(syssize) => syssize.update( + self.parent_vm.kernel_path(), + &self.parent_vm.params.kernel_args, + ), Hypercall::Cmdval(syscmdval) => { copy_argv( self.parent_vm.kernel_path().as_os_str(), - self.parent_vm.args(), + &self.parent_vm.params.kernel_args, syscmdval, &self.parent_vm.mem, ); diff --git a/src/macos/x86_64/vcpu.rs b/src/macos/x86_64/vcpu.rs index b3799ba3..07033eb4 100644 --- a/src/macos/x86_64/vcpu.rs +++ b/src/macos/x86_64/vcpu.rs @@ -720,13 +720,14 @@ impl VirtualCPU for XhyveCpu { hypercall::address_to_hypercall(&self.parent_vm.mem, port, data_addr) } { match hypercall { - Hypercall::Cmdsize(syssize) => { - syssize.update(self.parent_vm.kernel_path(), self.parent_vm.args()) - } + Hypercall::Cmdsize(syssize) => syssize.update( + self.parent_vm.kernel_path(), + &self.parent_vm.params.kernel_args, + ), Hypercall::Cmdval(syscmdval) => { copy_argv( self.parent_vm.kernel_path().as_os_str(), - self.parent_vm.args(), + &self.parent_vm.params.kernel_args, syscmdval, &self.parent_vm.mem, ); diff --git a/src/vm.rs b/src/vm.rs index a789b89f..f8fc0b13 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,5 +1,4 @@ use std::{ - ffi::OsString, fmt, fs, io, marker::PhantomData, num::NonZeroU32, @@ -105,11 +104,11 @@ pub struct UhyveVm { entry_point: u64, stack_address: u64, pub mem: Arc, + pub params: Params, + memory_size: usize, num_cpus: u32, path: PathBuf, - args: Vec, boot_info: *const RawBootInfo, - verbose: bool, pub virtio_device: Arc>, #[allow(dead_code)] // gdb is not supported on macos pub(super) gdb_port: Option, @@ -117,7 +116,12 @@ pub struct UhyveVm { } impl UhyveVm { pub fn new(kernel_path: PathBuf, params: Params) -> HypervisorResult> { + // We expose the params struct, but use some extra variables for the + // gdb_port (because of pub(super)) and memory_size (later, num_cpus) + // which require a get() to reduce overhead, and, most importantly, + // increase flexibility. let memory_size = params.memory_size.get(); + let gdb_port = params.gdb_port; #[cfg(target_os = "linux")] let mem = MmapMemory::new(0, memory_size, arch::RAM_START, params.thp, params.ksm); @@ -133,14 +137,14 @@ impl UhyveVm { #[cfg(target_os = "linux")] initialize_kvm(&mem, params.pit)?; - let cpu_count = params.cpu_count.get(); + let num_cpus = params.cpu_count.get(); assert!( - params.gdb_port.is_none() || cfg!(target_os = "linux"), + gdb_port.is_none() || cfg!(target_os = "linux"), "gdb is only supported on linux (yet)" ); assert!( - params.gdb_port.is_none() || cpu_count == 1, + gdb_port.is_none() || num_cpus == 1, "gdbstub is only supported with one CPU" ); @@ -149,13 +153,13 @@ impl UhyveVm { entry_point: 0, stack_address: 0, mem: mem.into(), - num_cpus: cpu_count, + params, + memory_size, + num_cpus, path: kernel_path, - args: params.kernel_args, boot_info: ptr::null(), - verbose: params.verbose, virtio_device, - gdb_port: params.gdb_port, + gdb_port, _vcpu_type: PhantomData, }; @@ -164,10 +168,6 @@ impl UhyveVm { Ok(vm) } - fn verbose(&self) -> bool { - self.verbose - } - /// Returns the section offsets relative to their base addresses pub fn get_offset(&self) -> u64 { self.offset @@ -181,7 +181,17 @@ impl UhyveVm { self.stack_address } - /// Returns the number of cores for the vm. + // Returns the struct containing all parameters. + pub fn params(&self) -> &Params { + &self.params + } + + // Returns the total memory size made available. + pub fn memory_size(&self) -> usize { + self.memory_size + } + + // Returns number of cores for the VM. pub fn num_cpus(&self) -> u32 { self.num_cpus } @@ -190,10 +200,6 @@ impl UhyveVm { &self.path } - pub fn args(&self) -> &Vec { - &self.args - } - /// Initialize the page tables for the guest fn init_guest_mem(&mut self) { debug!("Initialize guest memory"); @@ -232,7 +238,7 @@ impl UhyveVm { hardware_info: HardwareInfo { phys_addr_range: self.mem.guest_address.as_u64() ..self.mem.guest_address.as_u64() + self.mem.memory_size as u64, - serial_port_base: self.verbose().then(|| { + serial_port_base: self.params.verbose.then(|| { SerialPortBase::new((uhyve_interface::HypercallAddress::Uart as u16).into()) .unwrap() }), @@ -241,7 +247,7 @@ impl UhyveVm { load_info, platform_info: PlatformInfo::Uhyve { has_pci: cfg!(target_os = "linux"), - num_cpus: u64::from(self.num_cpus()).try_into().unwrap(), + num_cpus: u64::from(self.num_cpus).try_into().unwrap(), cpu_freq: NonZeroU32::new(detect_cpu_freq() * 1000), boot_time: SystemTime::now().into(), }, @@ -269,10 +275,11 @@ impl fmt::Debug for UhyveVm { .field("entry_point", &self.entry_point) .field("stack_address", &self.stack_address) .field("mem", &self.mem) + .field("params", &self.params) + .field("memory_size", &self.memory_size) .field("num_cpus", &self.num_cpus) .field("path", &self.path) .field("boot_info", &self.boot_info) - .field("verbose", &self.verbose) .field("virtio_device", &self.virtio_device) .finish() }