diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/kvm.rs | 13 | ||||
-rw-r--r-- | src/kvm_sys.rs | 4 | ||||
-rw-r--r-- | src/vcpu.rs | 36 | ||||
-rw-r--r-- | src/vm.rs | 26 | ||||
-rw-r--r-- | src/x86_64.rs | 8 |
5 files changed, 86 insertions, 1 deletions
@@ -1,3 +1,5 @@ +//! KVM system ioctls. + use std::fs; use std::io; use std::os::unix::io::FromRawFd; @@ -5,11 +7,18 @@ use std::os::unix::io::FromRawFd; use crate::{libcret, ioctl, kvm_sys}; use crate::vm::Vm; +/// Wrapper for `/dev/kvm` ioctls. +/// +/// Representation of the file descriptor obtained by opening `/dev/kvm`. +/// This wrapper provides access to the `system ioctls` as described in [KVM API][kvm]. +/// +/// [kvm]: https://www.kernel.org/doc/html/latest/virt/kvm/api.html#general-description pub struct Kvm { kvm: fs::File, } impl Kvm { + /// Open the `/dev/kvm` device. pub fn new() -> io::Result<Kvm> { let kvm = libcret(unsafe { libc::open("/dev/kvm\0".as_ptr().cast(), libc::O_RDWR | libc::O_CLOEXEC) @@ -28,6 +37,10 @@ impl Kvm { ioctl(&self.kvm, kvm_sys::KVM_GET_VCPU_MMAP_SIZE, 0).map(|size| size as usize) } + /// Create a new virtual machine with the [`KVM_CREATE_VM`][kvm-create-vm] ioctl. + /// Returns a wrapper [`vm::Vm`][crate::vm::Vm] representing the VM. + /// + /// [kvm-create-vm]: https://www.kernel.org/doc/html/latest/virt/kvm/api.html#kvm-create-vm pub fn create_vm(&self) -> io::Result<Vm> { let vm = ioctl(&self.kvm, kvm_sys::KVM_CREATE_VM, 0 /* machine id */) .map(|fd| unsafe { fs::File::from_raw_fd(fd) })?; diff --git a/src/kvm_sys.rs b/src/kvm_sys.rs index 2ce8ba5..d21da47 100644 --- a/src/kvm_sys.rs +++ b/src/kvm_sys.rs @@ -1,3 +1,7 @@ +//! Definitions of the system header [`<linux/kvm.h>`][kvm-h]. +//! +//! [kvm-h]: https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/kvm.h + #![allow(non_snake_case)] #![allow(non_camel_case_types)] #![allow(dead_code)] diff --git a/src/vcpu.rs b/src/vcpu.rs index 7d5b8bb..239c663 100644 --- a/src/vcpu.rs +++ b/src/vcpu.rs @@ -1,8 +1,17 @@ +//! VCPU system ioctls. + use std::fs; use std::io; use crate::{ioctl, kvm_sys, KvmRun}; +/// Exit reasons for the [`Vcpu::kvm_run`][crate::vcpu::Vcpu::kvm_run] function. +/// +/// Details for the different exit reasons can be found in the [`kvm_run` +/// structure][kvm-run-struct] description. +/// +/// [kvm-run]: https://www.kernel.org/doc/html/latest/virt/kvm/api.html#kvm-run +/// [kvm-run-struct]: https://www.kernel.org/doc/html/latest/virt/kvm/api.html#the-kvm-run-structure pub enum KvmExit<'cpu> { Halt, IoIn(u16, &'cpu mut [u8]), @@ -11,6 +20,13 @@ pub enum KvmExit<'cpu> { MmioWrite(u64, &'cpu [u8]), } +/// Wrapper for VCPU ioctls. +/// +/// Representation of the file descriptor obtained by the [`KVM_CREATE_VCPU`][kvm-create-vcpu] ioctl. +/// This wrapper provides access to the `VCPU ioctls` as described in [KVM API][kvm]. +/// +/// [kvm]: https://www.kernel.org/doc/html/latest/virt/kvm/api.html#general-description +/// [kvm-create-vcpu]: https://www.kernel.org/doc/html/latest/virt/kvm/api.html#kvm-create-vcpu pub struct Vcpu { vcpu: fs::File, kvm_run: KvmRun, @@ -21,6 +37,10 @@ impl Vcpu { Vcpu { vcpu, kvm_run } } + /// Get the general purpose registers with the [`KVM_GET_REGS`][kvm-get-regs] ioctl in form of + /// [`kvm_regs`](crate::kvm_sys::kvm_regs). + /// + /// [kvm-get-regs]: https://www.kernel.org/doc/html/latest/virt/kvm/api.html#kvm-get-regs pub fn get_regs(&self) -> io::Result<kvm_sys::kvm_regs> { let mut regs = kvm_sys::kvm_regs::default(); ioctl( @@ -31,10 +51,18 @@ impl Vcpu { Ok(regs) } + /// Set the general purpose registers with the [`KVM_SET_REGS`][kvm-set-regs] ioctl in form of + /// [`kvm_regs`](crate::kvm_sys::kvm_regs). + /// + /// [kvm-set-regs]: https://www.kernel.org/doc/html/latest/virt/kvm/api.html#kvm-set-regs pub fn set_regs(&self, regs: kvm_sys::kvm_regs) -> io::Result<()> { ioctl(&self.vcpu, kvm_sys::KVM_SET_REGS, ®s as *const _ as u64).map(|_| ()) } + /// Get the special registers with the [`KVM_GET_SREGS`][kvm-get-sregs] ioctl in form of + /// [`kvm_sregs`](crate::kvm_sys::kvm_sregs). + /// + /// [kvm-get-sregs]: https://www.kernel.org/doc/html/latest/virt/kvm/api.html#kvm-get-sregs pub fn get_sregs(&self) -> io::Result<kvm_sys::kvm_sregs> { let mut sregs = kvm_sys::kvm_sregs::default(); ioctl( @@ -45,6 +73,10 @@ impl Vcpu { Ok(sregs) } + /// Set the special registers with the [`KVM_SET_SREGS`][kvm-set-sregs] ioctl in form of + /// [`kvm_sregs`](crate::kvm_sys::kvm_sregs). + /// + /// [kvm-set-sregs]: https://www.kernel.org/doc/html/latest/virt/kvm/api.html#kvm-set-sregs pub fn set_sregs(&self, sregs: kvm_sys::kvm_sregs) -> io::Result<()> { ioctl( &self.vcpu, @@ -54,6 +86,10 @@ impl Vcpu { .map(|_| ()) } + /// Run the guest VCPU with the [`KVM_RUN`][kvm-run] ioctl until it exits with one of the exit + /// reasons described in [`KvmExit`](crate::vcpu::KvmExit). + /// + /// [kvm-run]: https://www.kernel.org/doc/html/latest/virt/kvm/api.html#kvm-run pub fn run(&mut self) -> io::Result<KvmExit<'_>> { ioctl(&self.vcpu, kvm_sys::KVM_RUN, 0)?; @@ -1,3 +1,5 @@ +//! VM system ioctls. + use std::fs; use std::io; use std::os::unix::io::FromRawFd; @@ -5,6 +7,13 @@ use std::os::unix::io::FromRawFd; use crate::vcpu::Vcpu; use crate::{ioctl, kvm_sys, KvmRun, PhysAddr, UserMem}; +/// Wrapper for VM ioctls. +/// +/// Representation of the file descriptor obtained by the [`KVM_CREATE_VM`][kvm-create-vm] ioctl. +/// This wrapper provides access to the `VM ioctls` as described in [KVM API][kvm]. +/// +/// [kvm]: https://www.kernel.org/doc/html/latest/virt/kvm/api.html#general-description +/// [kvm-create-vm]: https://www.kernel.org/doc/html/latest/virt/kvm/api.html#kvm-create-vm pub struct Vm { vm: fs::File, vcpu_mmap_size: usize, @@ -15,12 +24,23 @@ impl Vm { Vm { vm, vcpu_mmap_size } } + /// Map memory from userspace into the VM as `guest physical` memory starting at address + /// `phys_addr`. + /// The underlying operation is the [`KVM_SET_USER_MEMORY_REGION`][kmv-set-user-memory-region] + /// ioctl. + /// + /// # Safety + /// + /// The `mem: &UserMem` argument passed to this function must at least live as long the `Vcpu` + /// instance. + /// + /// [kvm-set-user-memory-region]: https://www.kernel.org/doc/html/latest/virt/kvm/api.html#kvm-set-user-memory-region pub unsafe fn set_user_memory_region( &self, phys_addr: PhysAddr, mem: &UserMem, ) -> io::Result<()> { - // Create guest physical memory mapping for `slot : 0` at guest `phys addr : 0`. + // Create guest physical memory mapping for `slot : 0` at guest `phys_addr`. let mut kvm_mem = kvm_sys::kvm_userspace_memory_region::default(); kvm_mem.userspace_addr = mem.ptr as u64; kvm_mem.memory_size = mem.len as u64; @@ -34,6 +54,10 @@ impl Vm { .map(|_| ()) } + /// Create a new virtual cpu with the [`KVM_CREATE_VCPU`][kvm-create-vcpu] ioctl. + /// Returns a wrapper [`vcpu::Vcpu`][crate::vcpu::Vcpu] representing the VCPU. + /// + /// [kvm-create-vcpu]: https://www.kernel.org/doc/html/latest/virt/kvm/api.html#kvm-create-vcpu pub fn create_vpcu(&self, id: u64) -> io::Result<Vcpu> { let vcpu = ioctl(&self.vm, kvm_sys::KVM_CREATE_VCPU, id) .map(|fd| unsafe { fs::File::from_raw_fd(fd) })?; diff --git a/src/x86_64.rs b/src/x86_64.rs index 978bd84..c16a6ad 100644 --- a/src/x86_64.rs +++ b/src/x86_64.rs @@ -1,3 +1,5 @@ +//! `x86_64` flags and bitfields. + /* Rflags Register */ /// Carry flag. @@ -125,6 +127,12 @@ pub const CR4_LA57: u64 = 1 << 5; /* Extended Feature Enable Register (EFER) */ +/// Extended Feature Enable Register MSR number. +/// +/// MSR number used with the [`rdmsr`][msr] and [`wrmsr`][msr] instructions to read/write the +/// `EFER` model specific register. +/// +/// [msr]: https://johannst.github.io/notes/arch/x86_64.html#model-specific-register-msr pub const MSR_EFER: u64 = 0xc000_0080; /// Long Mode Enable. |