From d2d2ba7c6602e73dc2e3dbd0aa4215e4c412a688 Mon Sep 17 00:00:00 2001 From: johannst Date: Wed, 2 Jun 2021 22:38:57 +0000 Subject: deploy: d2e2063cb2b5a82709e9c5188602a9fc0f7dadbd --- src/kvm_rs/fmt.rs.html | 265 ++++++++++++++++++++++++++++++ src/kvm_rs/kvm.rs.html | 111 +++++++++++++ src/kvm_rs/kvm_sys.rs.html | 401 +++++++++++++++++++++++++++++++++++++++++++++ src/kvm_rs/lib.rs.html | 337 +++++++++++++++++++++++++++++++++++++ src/kvm_rs/vcpu.rs.html | 279 +++++++++++++++++++++++++++++++ src/kvm_rs/vm.rs.html | 145 ++++++++++++++++ src/kvm_rs/x86_64.rs.html | 315 +++++++++++++++++++++++++++++++++++ 7 files changed, 1853 insertions(+) create mode 100644 src/kvm_rs/fmt.rs.html create mode 100644 src/kvm_rs/kvm.rs.html create mode 100644 src/kvm_rs/kvm_sys.rs.html create mode 100644 src/kvm_rs/lib.rs.html create mode 100644 src/kvm_rs/vcpu.rs.html create mode 100644 src/kvm_rs/vm.rs.html create mode 100644 src/kvm_rs/x86_64.rs.html (limited to 'src/kvm_rs') diff --git a/src/kvm_rs/fmt.rs.html b/src/kvm_rs/fmt.rs.html new file mode 100644 index 0000000..ec871ef --- /dev/null +++ b/src/kvm_rs/fmt.rs.html @@ -0,0 +1,265 @@ +fmt.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+
+use std::fmt;
+
+use crate::kvm_sys::{kvm_dtable, kvm_regs, kvm_segment, kvm_sregs};
+use crate::x86_64::*;
+
+impl fmt::Display for kvm_regs {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "rax: {:#018x} rbx: {:#018x} rcx: {:#018x} rdx: {:#018x}\n\
+             rsi: {:#018x} rdi: {:#018x}\n\
+             r8 : {:#018x} r9 : {:#018x} r10: {:#018x} r11: {:#018x}\n\
+             r12: {:#018x} r13: {:#018x} r14: {:#018x} r15: {:#018x}\n\
+             rsp: {:#018x} rbp: {:#018x}\n\
+             rip: {:#018x} rfl: {:#018x} O({}) D({}) I({}) S({}) Z({}) P({}) C({})",
+            self.rax,
+            self.rbx,
+            self.rcx,
+            self.rdx,
+            self.rsi,
+            self.rdi,
+            self.r8,
+            self.r9,
+            self.r10,
+            self.r11,
+            self.r12,
+            self.r13,
+            self.r14,
+            self.r15,
+            self.rsp,
+            self.rbp,
+            self.rip,
+            self.rflags,
+            rflags_of(self.rflags),
+            rflags_df(self.rflags),
+            rflags_if(self.rflags),
+            rflags_sf(self.rflags),
+            rflags_zf(self.rflags),
+            rflags_pf(self.rflags),
+            rflags_cf(self.rflags),
+        )
+    }
+}
+
+impl fmt::Display for kvm_segment {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if self.present == 0 {
+            write!(f, "{:#04x} P(0)", self.selector)
+        } else {
+            write!(
+                f,
+                "{:#06x} T({}) RPL({}) BASE({:#010x}) LIMIT({:#07x}) P(1) S({}) DPL({}) DB({}) L({}) TYPE({})",
+                self.selector,
+                if seg_selector_ti(self.selector) == 0 {
+                    "GDT"
+                } else {
+                    "LDT"
+                },
+                seg_selector_rpl(self.selector),
+                self.base,
+                self.limit,
+                self.s,
+                self.dpl,
+                self.db,
+                self.l,
+                match self.type_ {
+                    0 => "D:R---",
+                    1 => "D:R-A-",
+                    2 => "D:RW--",
+                    3 => "D:RWA-",
+                    4 => "D:R--E",
+                    5 => "D:R-AE",
+                    6 => "D:RW-E",
+                    7 => "D:RWAE",
+                    8 => "C:X---",
+                    9 => "C:X-A-",
+                    10 => "C:XR--",
+                    11 => "C:XRA-",
+                    12 => "C:X--C",
+                    13 => "C:X-AC",
+                    14 => "C:XR-C",
+                    15 => "C:XRAC",
+                    _ => unreachable!(),
+                }
+            )
+        }
+    }
+}
+
+impl fmt::Display for kvm_dtable {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "BASE({:#018x}) LIMIT({:#07x})", self.base, self.limit)
+    }
+}
+
+impl fmt::Display for kvm_sregs {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "cs  : {}\n\
+             ds  : {}\n\
+             es  : {}\n\
+             fs  : {}\n\
+             gs  : {}\n\
+             ss  : {}\n\
+             tr  : {}\n\
+             ldt : {}\n\
+             gdt : {}\n\
+             idt : {}\n\
+             cr0 : {:#018x} cr2: {:#018x} cr3: {:#018x} cr4: {:#018x}\n\
+             efer: {:#018x}",
+            self.cs,
+            self.ds,
+            self.es,
+            self.fs,
+            self.gs,
+            self.ss,
+            self.tr,
+            self.ldt,
+            self.gdt,
+            self.idt,
+            self.cr0,
+            self.cr2,
+            self.cr3,
+            self.cr4,
+            self.efer,
+        )
+    }
+}
+
+
+ \ No newline at end of file diff --git a/src/kvm_rs/kvm.rs.html b/src/kvm_rs/kvm.rs.html new file mode 100644 index 0000000..ccd6c37 --- /dev/null +++ b/src/kvm_rs/kvm.rs.html @@ -0,0 +1,111 @@ +kvm.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+
+//! KVM system ioctls.
+
+use std::fs;
+use std::io;
+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)
+        })
+        .map(|fd| unsafe { fs::File::from_raw_fd(fd) })?;
+
+        assert_eq!(
+            kvm_sys::KVM_API_VERSION,
+            ioctl(&kvm, kvm_sys::KVM_GET_API_VERSION, 0)?
+        );
+
+        Ok(Kvm { kvm })
+    }
+
+    fn get_vpcu_mmap_size(&self) -> io::Result<usize> {
+        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) })?;
+
+        let vcpu_mmap_size = self.get_vpcu_mmap_size()?;
+
+        Ok(Vm::new(vm, vcpu_mmap_size))
+    }
+}
+
+
+ \ No newline at end of file diff --git a/src/kvm_rs/kvm_sys.rs.html b/src/kvm_rs/kvm_sys.rs.html new file mode 100644 index 0000000..44136b6 --- /dev/null +++ b/src/kvm_rs/kvm_sys.rs.html @@ -0,0 +1,401 @@ +kvm_sys.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+
+//! 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)]
+
+// Generated by `build.rs`.
+include!(concat!(env!("OUT_DIR"), "/kvm_constants.rs"));
+
+#[repr(C)]
+#[derive(Default, Debug)]
+pub struct kvm_regs {
+    pub rax: u64,
+    pub rbx: u64,
+    pub rcx: u64,
+    pub rdx: u64,
+    pub rsi: u64,
+    pub rdi: u64,
+    pub rsp: u64,
+    pub rbp: u64,
+    pub r8: u64,
+    pub r9: u64,
+    pub r10: u64,
+    pub r11: u64,
+    pub r12: u64,
+    pub r13: u64,
+    pub r14: u64,
+    pub r15: u64,
+    pub rip: u64,
+    pub rflags: u64,
+}
+
+#[repr(C)]
+#[derive(Default, Debug)]
+pub struct kvm_segment {
+    pub base: u64,
+    pub limit: u32,
+    pub selector: u16,
+    pub type_: u8,
+    pub present: u8,
+    pub dpl: u8,
+    pub db: u8,
+    pub s: u8,
+    pub l: u8,
+    pub g: u8,
+    pub avl: u8,
+    unusable: u8,
+    _padding: u8,
+}
+
+#[repr(C)]
+#[derive(Default, Debug)]
+pub struct kvm_dtable {
+    pub base: u64,
+    pub limit: u16,
+    _padding: [u16; 3],
+}
+
+#[repr(C)]
+#[derive(Default, Debug)]
+pub struct kvm_sregs {
+    pub cs: kvm_segment,
+    pub ds: kvm_segment,
+    pub es: kvm_segment,
+    pub fs: kvm_segment,
+    pub gs: kvm_segment,
+    pub ss: kvm_segment,
+    pub tr: kvm_segment,
+    pub ldt: kvm_segment,
+    pub gdt: kvm_dtable,
+    pub idt: kvm_dtable,
+    pub cr0: u64,
+    pub cr2: u64,
+    pub cr3: u64,
+    pub cr4: u64,
+    pub cr8: u64,
+    pub efer: u64,
+    pub apic_base: u64,
+    pub interrupt_bitmap: [u64; 4],
+}
+
+#[repr(C)]
+#[derive(Default, Debug)]
+pub(crate) struct kvm_userspace_memory_region {
+    pub slot: u32,
+    pub flags: u32,
+    pub guest_phys_addr: u64,
+    pub memory_size: u64,
+    pub userspace_addr: u64,
+}
+
+#[repr(C)]
+pub(crate) struct kvm_run {
+    request_interrupt_window: u8,
+    immediate_exit: u8,
+    padding1: [u8; 6],
+    pub exit_reason: u32,
+    ready_for_interrupt_injection: u8,
+    if_flag: u8,
+    flags: u16,
+    cr8: u64,
+    apic_base: u64,
+    pub inner: kvm_run_union,
+    kvm_valid_regs: u64,
+    kvm_dirty_regs: u64,
+    s: kvm_run_union_s,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone, Debug)]
+pub(crate) struct kvm_run_io {
+    pub direction: u8,
+    pub size: u8,
+    pub port: u16,
+    pub count: u32,
+    pub data_offset: u64,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone, Debug)]
+pub(crate) struct kvm_run_mmio {
+    pub phys_addr: u64,
+    pub data: [u8; 8],
+    pub len: u32,
+    pub is_write: u8,
+}
+
+// Only add the union fields used here.
+#[repr(C)]
+pub(crate) union kvm_run_union {
+    pub io: kvm_run_io,
+    pub mmio: kvm_run_mmio,
+    padding: [u8; 256],
+}
+
+// Only add the union fields used here.
+#[repr(C)]
+union kvm_run_union_s {
+    padding: [u8; 2048],
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::mem;
+
+    #[test]
+    fn check_kvm_regs() {
+        assert_eq!(mem::size_of::<kvm_regs>(), TEST_KVM_REGS_SIZE);
+        assert_eq!(mem::align_of::<kvm_regs>(), TEST_KVM_REGS_ALIGN);
+    }
+
+    #[test]
+    fn check_kvm_segment() {
+        assert_eq!(mem::size_of::<kvm_segment>(), TEST_KVM_SEGMENT_SIZE);
+        assert_eq!(mem::align_of::<kvm_segment>(), TEST_KVM_SEGMENT_ALIGN);
+    }
+
+    #[test]
+    fn check_kvm_dtable() {
+        assert_eq!(mem::size_of::<kvm_dtable>(), TEST_KVM_DTABLE_SIZE);
+        assert_eq!(mem::align_of::<kvm_dtable>(), TEST_KVM_DTABLE_ALIGN);
+    }
+
+    #[test]
+    fn check_kvm_sregs() {
+        assert_eq!(mem::size_of::<kvm_sregs>(), TEST_KVM_SREGS_SIZE);
+        assert_eq!(mem::align_of::<kvm_sregs>(), TEST_KVM_SREGS_ALIGN);
+        assert_eq!(
+            mem::size_of_val(&kvm_sregs::default().interrupt_bitmap),
+            TEST_KVM_SREGS_INTERRTUP_BITMAP_SIZE
+        );
+    }
+
+    #[test]
+    fn check_kvm_userspace_memory_region() {
+        assert_eq!(
+            mem::size_of::<kvm_userspace_memory_region>(),
+            TEST_KVM_USERSPACE_MEMORY_REGION_SIZE
+        );
+        assert_eq!(
+            mem::align_of::<kvm_userspace_memory_region>(),
+            TEST_KVM_USERSPACE_MEMORY_REGION_ALIGN
+        );
+    }
+
+    #[test]
+    fn check_kvm_run() {
+        assert_eq!(mem::size_of::<kvm_run>(), TEST_KVM_RUN_SIZE);
+        assert_eq!(mem::align_of::<kvm_run>(), TEST_KVM_RUN_ALIGN);
+        assert_eq!(mem::size_of::<kvm_run_io>(), TEST_KVM_RUN_IO_SIZE);
+        assert_eq!(mem::size_of::<kvm_run_mmio>(), TEST_KVM_RUN_MMIO_SIZE);
+        assert_eq!(mem::size_of::<kvm_run_union_s>(), TEST_KVM_RUN_UNION_S_SIZE);
+    }
+}
+
+
+ \ No newline at end of file diff --git a/src/kvm_rs/lib.rs.html b/src/kvm_rs/lib.rs.html new file mode 100644 index 0000000..8d74487 --- /dev/null +++ b/src/kvm_rs/lib.rs.html @@ -0,0 +1,337 @@ +lib.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+
+use std::convert::{AsMut, AsRef};
+use std::io;
+use std::ops;
+use std::os::unix::io::AsRawFd;
+
+mod fmt;
+pub mod kvm;
+pub mod kvm_sys;
+pub mod vcpu;
+pub mod vm;
+pub mod x86_64;
+
+/// Strong type representing physical addresses.
+pub struct PhysAddr(pub u64);
+
+/// Helper to turn libc return values into an [io::Result](std::io::Result). Returns
+/// [`Error::last_os_error`](std::io::Error::last_os_error) if `ret < 0`.
+fn libcret(ret: libc::c_int) -> io::Result<libc::c_int> {
+    if ret < 0 {
+        Err(io::Error::last_os_error())
+    } else {
+        Ok(ret)
+    }
+}
+
+/// Wrapper of `libc::ioctl` for KVM ioctls with one argument and returning an
+/// [`io::Result`](std::io::Result).
+fn ioctl<F: AsRawFd>(fd: &F, cmd: u64, arg: u64) -> io::Result<libc::c_int> {
+    libcret(unsafe { libc::ioctl(fd.as_raw_fd(), cmd, arg) })
+}
+
+/// Wrapper to safely allocate memory for guest VMs.
+///
+/// The underlying memory is freed automatically once the `UserMem` instance is dropped.
+///
+/// Memory can be mapped into a guest VM with
+/// [`Vm::set_user_memory_region`](crate::vm::Vm::set_user_memory_region).
+pub struct UserMem {
+    ptr: *mut u8,
+    len: usize,
+}
+
+impl UserMem {
+    /// Allocate a zero-initialized memory region of `len` bytes.
+    pub fn new(len: usize) -> io::Result<UserMem> {
+        let ptr = unsafe {
+            libc::mmap(
+                std::ptr::null_mut(),
+                len,
+                libc::PROT_READ | libc::PROT_WRITE,
+                libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
+                -1,
+                0,
+            )
+        };
+
+        if ptr == libc::MAP_FAILED {
+            Err(io::Error::last_os_error())
+        } else {
+            Ok(UserMem {
+                ptr: ptr.cast(),
+                len,
+            })
+        }
+    }
+
+    /// Allocate a zero-initialized memory region of `len` bytes and initialize the first bytes
+    /// with `init_from`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `init_from` is larger than the memory size `len`.
+    pub fn with_init(len: usize, init_from: &[u8]) -> io::Result<UserMem> {
+        assert!(len >= init_from.len());
+
+        let mut m = UserMem::new(len)?;
+        m.load(PhysAddr(0), init_from);
+        Ok(m)
+    }
+
+    /// Load the bytes stored in `data` into memory at physical address `addr`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `addr + data.len` is larger than the memory size `len`.
+    pub fn load(&mut self, addr: PhysAddr, data: &[u8]) {
+        assert!(self.len >= addr.0 as usize + data.len());
+
+        let addr = addr.0 as usize;
+        self.as_mut()[addr..addr + data.len()].copy_from_slice(data);
+    }
+}
+
+impl ops::Drop for UserMem {
+    /// Free underlying memory.
+    fn drop(&mut self) {
+        unsafe { libc::munmap(self.ptr.cast(), self.len) };
+    }
+}
+
+impl AsRef<[u8]> for UserMem {
+    fn as_ref(&self) -> &[u8] {
+        unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
+    }
+}
+
+impl AsMut<[u8]> for UserMem {
+    fn as_mut(&mut self) -> &mut [u8] {
+        unsafe { std::slice::from_raw_parts_mut(self.ptr, self.len) }
+    }
+}
+
+/// Internal wrapper to automatically `mmap` and `munmap` the the [`struct kvm_run`][kvm_run]
+/// for a given VPCU.
+///
+/// [kvm_run]: https://www.kernel.org/doc/html/latest/virt/kvm/api.html#the-kvm-run-structure
+struct KvmRun {
+    ptr: *mut kvm_sys::kvm_run,
+    len: usize,
+}
+
+impl KvmRun {
+    /// Mmap the `struct kvm_run` for a given `VCPU` referenced by the argument file descriptor
+    /// `vcpu`.
+    fn new<F: AsRawFd>(vcpu: &F, len: usize) -> io::Result<KvmRun> {
+        let ptr = unsafe {
+            libc::mmap(
+                std::ptr::null_mut(),
+                len,
+                libc::PROT_READ | libc::PROT_WRITE,
+                libc::MAP_SHARED,
+                vcpu.as_raw_fd(),
+                0,
+            )
+        };
+
+        if ptr == libc::MAP_FAILED {
+            Err(io::Error::last_os_error())
+        } else {
+            Ok(KvmRun {
+                ptr: ptr.cast(),
+                len,
+            })
+        }
+    }
+}
+
+impl ops::Drop for KvmRun {
+    /// Munmap the mmaped `struct kvm_run`.
+    fn drop(&mut self) {
+        unsafe { libc::munmap(self.ptr.cast(), self.len) };
+    }
+}
+
+impl AsRef<kvm_sys::kvm_run> for KvmRun {
+    fn as_ref(&self) -> &kvm_sys::kvm_run {
+        unsafe { & *(self.ptr as *const kvm_sys::kvm_run) }
+    }
+}
+
+impl AsMut<kvm_sys::kvm_run> for KvmRun {
+    fn as_mut(&mut self) -> &mut kvm_sys::kvm_run {
+        unsafe { &mut *(self.ptr as *mut kvm_sys::kvm_run) }
+    }
+}
+
+
+ \ No newline at end of file diff --git a/src/kvm_rs/vcpu.rs.html b/src/kvm_rs/vcpu.rs.html new file mode 100644 index 0000000..df4a7bc --- /dev/null +++ b/src/kvm_rs/vcpu.rs.html @@ -0,0 +1,279 @@ +vcpu.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+
+//! 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]),
+    IoOut(u16, &'cpu [u8]),
+    MmioRead(u64, &'cpu mut [u8]),
+    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,
+}
+
+impl Vcpu {
+    pub(crate) fn new(vcpu: fs::File, kvm_run: KvmRun) -> 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(
+            &self.vcpu,
+            kvm_sys::KVM_GET_REGS,
+            &mut regs as *mut _ as u64,
+        )?;
+        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, &regs 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(
+            &self.vcpu,
+            kvm_sys::KVM_GET_SREGS,
+            &mut sregs as *mut _ as u64,
+        )?;
+        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,
+            kvm_sys::KVM_SET_SREGS,
+            &sregs as *const _ as u64,
+        )
+        .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)?;
+
+        let kvm_run = self.kvm_run.as_mut();
+
+        match kvm_run.exit_reason as u64 {
+            kvm_sys::KVM_EXIT_HLT => Ok(KvmExit::Halt),
+            kvm_sys::KVM_EXIT_IO => {
+                // Safe to use union `io` field, as Kernel instructed us to.
+                let io = unsafe { kvm_run.inner.io };
+
+                let kvm_run_ptr = kvm_run as *mut kvm_sys::kvm_run as *mut u8;
+
+                // Create IO buffer located at `kvm_run + io.offset`.
+                let data = unsafe {
+                    std::slice::from_raw_parts_mut(
+                        kvm_run_ptr.offset(io.data_offset as isize),
+                        io.count /* num blocks */ as usize * io.size /* bytes per block */ as usize,
+                    )
+                };
+
+                match io.direction as u64 {
+                    kvm_sys::KVM_EXIT_IO_IN => Ok(KvmExit::IoIn(io.port, data)),
+                    kvm_sys::KVM_EXIT_IO_OUT => Ok(KvmExit::IoOut(io.port, data)),
+                    _ => unreachable!(),
+                }
+            }
+            kvm_sys::KVM_EXIT_MMIO => {
+                // Safe to use union `mmio` filed, as Kernel instructed us to.
+                let mmio = unsafe { &mut kvm_run.inner.mmio };
+                let len = mmio.len as usize;
+
+                match mmio.is_write {
+                    0 => Ok(KvmExit::MmioRead(mmio.phys_addr, &mut mmio.data[..len])),
+                    1 => Ok(KvmExit::MmioWrite(mmio.phys_addr, &mmio.data[..len])),
+                    _ => unreachable!(),
+                }
+            }
+            r @ _ => {
+                todo!("KVM_EXIT_... (exit_reason={}) not implemented!", r)
+            }
+        }
+    }
+}
+
+
+ \ No newline at end of file diff --git a/src/kvm_rs/vm.rs.html b/src/kvm_rs/vm.rs.html new file mode 100644 index 0000000..94f2c10 --- /dev/null +++ b/src/kvm_rs/vm.rs.html @@ -0,0 +1,145 @@ +vm.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+
+//! VM system ioctls.
+
+use std::fs;
+use std::io;
+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,
+}
+
+impl Vm {
+    pub(crate) fn new(vm: fs::File, vcpu_mmap_size: usize) -> 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`.
+        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;
+        kvm_mem.guest_phys_addr = phys_addr.0;
+
+        ioctl(
+            &self.vm,
+            kvm_sys::KVM_SET_USER_MEMORY_REGION,
+            &kvm_mem as *const _ as u64,
+        )
+        .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) })?;
+
+        let kvm_run = KvmRun::new(&vcpu, self.vcpu_mmap_size)?;
+
+        Ok(Vcpu::new(vcpu, kvm_run))
+    }
+}
+
+
+ \ No newline at end of file diff --git a/src/kvm_rs/x86_64.rs.html b/src/kvm_rs/x86_64.rs.html new file mode 100644 index 0000000..5671eba --- /dev/null +++ b/src/kvm_rs/x86_64.rs.html @@ -0,0 +1,315 @@ +x86_64.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+
+//! `x86_64` flags and bitfields.
+
+/* Rflags Register */
+
+/// Carry flag.
+pub const RFLAGS_CF: u64 = 1 << 0;
+/// Parity flag.
+pub const RFLAGS_PF: u64 = 1 << 2;
+/// Adjust flag.
+pub const RFLAGS_AF: u64 = 1 << 4;
+/// Zero flag.
+pub const RFLAGS_ZF: u64 = 1 << 6;
+/// Sign flag.
+pub const RFLAGS_SF: u64 = 1 << 7;
+/// Sign flag.
+pub const RFLAGS_IF: u64 = 1 << 9;
+/// Direction flag.
+pub const RFLAGS_DF: u64 = 1 << 10;
+/// Overflow flag.
+pub const RFLAGS_OF: u64 = 1 << 11;
+/// I/O privilege level.
+pub const RFLAGS_IOPL: u64 = 0b11 << 12;
+/// Alignment check.
+pub const RFLAGS_AC: u64 = 1 << 18;
+
+pub const fn rflags_cf(r: u64) -> u64   { (r & RFLAGS_CF)   >> 0 }
+pub const fn rflags_pf(r: u64) -> u64   { (r & RFLAGS_PF)   >> 2 }
+pub const fn rflags_af(r: u64) -> u64   { (r & RFLAGS_AF)   >> 4 }
+pub const fn rflags_zf(r: u64) -> u64   { (r & RFLAGS_ZF)   >> 6 }
+pub const fn rflags_sf(r: u64) -> u64   { (r & RFLAGS_SF)   >> 7 }
+pub const fn rflags_if(r: u64) -> u64   { (r & RFLAGS_IF)   >> 9 }
+pub const fn rflags_df(r: u64) -> u64   { (r & RFLAGS_DF)   >> 10 }
+pub const fn rflags_of(r: u64) -> u64   { (r & RFLAGS_OF)   >> 11 }
+pub const fn rflags_iopl(r: u64) -> u64 { (r & RFLAGS_IOPL) >> 12 }
+pub const fn rflags_ac(r: u64) -> u64   { (r & RFLAGS_AC)   >> 18 }
+
+/* Segment Selector */
+
+/// Requested privilege level.
+///
+/// Privilege level of the segment selector, where `0` is the most privileged mode and `3` the
+/// least.
+pub const SEG_SELECTOR_RPL : u16 = 0b11 << 0;
+/// Table indicator.
+///
+/// | TI | Table |
+/// |----|-------|
+/// | 0  | GDT   |
+/// | 1  | LDT   |
+pub const SEG_SELECTOR_TI : u16 = 1 << 2;
+/// Table index.
+///
+/// Index into the `GDT` or `LDT` table to select the segment descriptor. `GDT.base + 8 * index`
+/// gives the address of the segment descriptor (times `8` because every segment descriptor is `8
+/// byte`).
+pub const SEG_SELECTOR_INDEX : u16 = 0x1fff << 3;
+
+pub const fn seg_selector_rpl(s : u16) -> u16   { (s & SEG_SELECTOR_RPL)   >> 0 }
+pub const fn seg_selector_ti(s : u16) -> u16    { (s & SEG_SELECTOR_TI)    >> 2 }
+pub const fn seg_selector_index(s : u16) -> u16 { (s & SEG_SELECTOR_INDEX) >> 3 }
+
+/* Control Register CR0 (operation mode & state of the processor) */
+
+/// Protection Enable.
+///
+/// Enables `protected mode` when set and `real-address mode` when cleared. This enables
+/// `segment-level protection` not paging.
+pub const CR0_PE: u64 = 1 << 0;
+/// Monitor Coprocessor.
+pub const CR0_MP: u64 = 1 << 1;
+/// Emulation.
+///
+/// When set indicates the process does not have a FPU. FPU instructions will generate an exception
+/// that software can emulate the instruction.
+pub const CR0_EM: u64 = 1 << 2;
+/// Task Switched.
+pub const CR0_TS: u64 = 1 << 3;
+/// Extension Type.
+pub const CR0_ET: u64 = 1 << 4;
+/// Numeric Error.
+pub const CR0_NE: u64 = 1 << 5;
+/// Write Protect.
+///
+/// When set supervisor-level procedures can't write to read-only pages.
+pub const CR0_WP: u64 = 1 << 16;
+/// Alignment Mask.
+///
+/// Enables alignment check for `CPL=3`, check is only done if the [AC
+/// bit](crate::x86_64::RFLAGS_AC) of the `rflags` register ist set.
+pub const CR0_AM: u64 = 1 << 18;
+/// Not Write-Torugh.
+pub const CR0_NW: u64 = 1 << 29;
+/// Cachine disable.
+pub const CR0_CD: u64 = 1 << 30;
+/// Paging.
+///
+/// Enables paging when set, requires [CR0_PE](crate::x86_64::CR0_PE) to be set as well.
+pub const CR0_PG: u64 = 1 << 31;
+
+/* Control Register CR3 (paging information)
+ *
+ * Holds the physical base address of the first paging structure. The 12 lower bytes of the base
+ * address are assumed to be 0 and hence the first paging structure must be aligned to a 4K
+ * boundary.
+ */
+
+/// Mask for physical base address of paging structure.
+pub const CR3_PAGE_BASE_MASK: u64 = 0xffff_ffff_ffff_0000;
+
+/// Page-level Write-Through.
+pub const CR3_PWT: u64 = 1 << 3;
+/// Page-level Cache Disable.
+pub const CR3_PCD: u64 = 1 << 4;
+
+/* Control Register CR4 (flags for arch extenstions processor capabilities) */
+
+/// Physical Address Extenstion.
+///
+/// When set enables paging to produce physicall addresses with more than 32 bits. Required before
+/// entering `long mode`.
+pub const CR4_PAE: u64 = 1 << 5;
+/// 57-bit Linear Addresses.
+///
+/// When set in `long mode` enables `5-level` paging to translate `57-bit` linear addresses. When
+/// cleared use `4-level` paging to translate `48-bit` linear addresses.
+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.
+///
+/// When set enables long mode operations.
+pub const EFER_LME: u64 = 1 << 8;
+/// Long Mode Active (readonly).
+///
+/// When set indicates long mode is active.
+pub const EFER_LMA: u64 = 1 << 10;
+
+/* Paging */
+
+/// Page entry present.
+pub const PAGE_ENTRY_PRESENT : u64 = 1 << 0;
+/// Page region read/write.
+///
+/// If set, region reference by paging entry is writeable.
+pub const PAGE_RENTRY_RW : u64 = 1 << 1;
+
+
+ \ No newline at end of file -- cgit v1.2.3