1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-21 23:56:18 +04:00

hypervisor: import RVM

This commit is contained in:
Yuekai Jia 2020-09-20 23:30:28 +08:00
parent 87e4039dd8
commit 180e855ace
9 changed files with 709 additions and 62 deletions

165
kernel/Cargo.lock generated
View File

@ -26,9 +26,9 @@ dependencies = [
[[package]]
name = "aho-corasick"
version = "0.7.10"
version = "0.7.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86"
dependencies = [
"memchr",
]
@ -48,16 +48,16 @@ name = "apic"
version = "0.1.0"
source = "git+https://github.com/rcore-os/apic-rs?rev=fb86bd7#fb86bd7c798608a18cbb48755637d97d4266eb89"
dependencies = [
"bit_field 0.10.0",
"bit_field 0.10.1",
"bitflags",
"x86",
]
[[package]]
name = "autocfg"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bare-metal"
@ -78,6 +78,21 @@ dependencies = [
"volatile",
]
[[package]]
name = "bit-set"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0dc55f2d8a1a85650ac47858bb001b4c0dd73d79e3c455a842925e68d29cd3"
[[package]]
name = "bit_field"
version = "0.9.0"
@ -86,9 +101,9 @@ checksum = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56"
[[package]]
name = "bit_field"
version = "0.10.0"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a165d606cf084741d4ac3a28fb6e9b1eb0bd31f6cd999098cfddb0b2ab381dc0"
checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4"
[[package]]
name = "bitflags"
@ -96,6 +111,14 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "bitmap-allocator"
version = "0.1.0"
source = "git+https://github.com/rcore-os/bitmap-allocator#03bd9909d0dc85e99f5559b97a163ab81073df83"
dependencies = [
"bit_field 0.9.0",
]
[[package]]
name = "bitmap-allocator"
version = "0.1.0"
@ -141,9 +164,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.54"
version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311"
checksum = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c"
[[package]]
name = "cfg-if"
@ -170,9 +193,9 @@ source = "git+https://github.com/rcore-os/device_tree-rs?rev=eee2c23#eee2c23d50a
[[package]]
name = "either"
version = "1.5.3"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "embedded-graphics"
@ -206,9 +229,9 @@ dependencies = [
[[package]]
name = "filetime"
version = "0.2.10"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "affc17579b132fc2461adf7c575cc6e8b134ebca52c51f5411388965227dc695"
checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e"
dependencies = [
"cfg-if",
"libc",
@ -239,15 +262,15 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.71"
version = "0.2.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"
[[package]]
name = "log"
version = "0.4.8"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
dependencies = [
"cfg-if",
]
@ -269,7 +292,7 @@ name = "mips"
version = "0.3.0"
source = "git+https://github.com/Harry-Chen/rust-mips?rev=3b828a2#3b828a2afed97f2769a66cf9cd8239a285804dc0"
dependencies = [
"bit_field 0.10.0",
"bit_field 0.10.1",
"bitflags",
]
@ -303,9 +326,9 @@ dependencies = [
[[package]]
name = "num-derive"
version = "0.3.0"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c8b15b261814f992e33760b1fca9fe8b693d8a65299f20c9901688636cfb746"
checksum = "6f09b9841adb6b5e1f89ef7087ea636e0fd94b2851f887c1e3eb5d5f8228fab3"
dependencies = [
"proc-macro2",
"quote",
@ -354,10 +377,16 @@ dependencies = [
]
[[package]]
name = "paste"
version = "0.1.16"
name = "numeric-enum-macro"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d508492eeb1e5c38ee696371bf7b9fc33c83d46a7d451606b96458fbbbdc2dec"
checksum = "300e4bdb6b46b592948e700ea1ef24a4296491f6a0ee722b258040abd15a3714"
[[package]]
name = "paste"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880"
dependencies = [
"paste-impl",
"proc-macro-hack",
@ -365,21 +394,18 @@ dependencies = [
[[package]]
name = "paste-impl"
version = "0.1.16"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84f328a6a63192b333fce5fbb4be79db6758a4d518dfac6d54412f1492f72d32"
checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6"
dependencies = [
"proc-macro-hack",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pc-keyboard"
version = "0.5.0"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c48392db76c4e9a69e0b3be356c5f97ebb7b14413c5e4fd0af4755dbf86e2fce"
checksum = "5c6f2d937e3b8d63449b01401e2bae4041bc9dd1129c2e3e0d239407cf6635ac"
[[package]]
name = "pci"
@ -391,15 +417,15 @@ dependencies = [
[[package]]
name = "proc-macro-hack"
version = "0.5.16"
version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4"
checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598"
[[package]]
name = "proc-macro2"
version = "1.0.18"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa"
checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c"
dependencies = [
"unicode-xid",
]
@ -450,9 +476,9 @@ dependencies = [
"aml",
"apic",
"bcm2837",
"bit_field 0.10.0",
"bit_field 0.10.1",
"bitflags",
"bitmap-allocator",
"bitmap-allocator 0.1.0 (git+https://github.com/rcore-os/bitmap-allocator?rev=03bd9909)",
"bitvec",
"buddy_system_allocator",
"compression",
@ -480,6 +506,7 @@ dependencies = [
"rcore-memory",
"riscv",
"rlibc",
"rvm",
"smoltcp",
"spin",
"trapframe",
@ -563,9 +590,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.1.56"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "regex"
@ -600,7 +627,7 @@ version = "0.5.6"
source = "git+https://github.com/rcore-os/riscv?rev=38f3786#38f3786966ba15cc76977375162e3f3622a30f4b"
dependencies = [
"bare-metal",
"bit_field 0.10.0",
"bit_field 0.10.1",
"bitflags",
"log",
"riscv-target",
@ -633,15 +660,43 @@ dependencies = [
[[package]]
name = "rustversion"
version = "1.0.2"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3bba175698996010c4f6dce5e7f173b6eb781fce25d2cfc45e27091ce0b79f6"
checksum = "b9bdc5e856e51e685846fb6c13a1f5e5432946c2c90501bdc76a1319f19e29da"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "rvm"
version = "1.0.1"
source = "git+https://github.com/rcore-os/RVM?rev=939eb0a#939eb0aafd100e9944e4f2fe90eebfa8149d2b85"
dependencies = [
"bit-set",
"bit_field 0.10.1",
"bitflags",
"bitmap-allocator 0.1.0 (git+https://github.com/rcore-os/bitmap-allocator)",
"lazy_static",
"log",
"numeric-enum-macro",
"raw-cpuid",
"rvm_macros",
"spin",
"x86",
"x86_64",
]
[[package]]
name = "rvm_macros"
version = "0.1.0"
source = "git+https://github.com/rcore-os/RVM?rev=939eb0a#939eb0aafd100e9944e4f2fe90eebfa8149d2b85"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "semver"
version = "0.9.0"
@ -682,9 +737,9 @@ checksum = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
[[package]]
name = "syn"
version = "1.0.31"
version = "1.0.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6"
checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b"
dependencies = [
"proc-macro2",
"quote",
@ -737,7 +792,7 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85061f4e43545a613c0da6b87725bf23f8da8613cf2473719c4f71a270c4ce8a"
dependencies = [
"bit_field 0.10.0",
"bit_field 0.10.1",
]
[[package]]
@ -754,9 +809,9 @@ dependencies = [
[[package]]
name = "uefi-macros"
version = "0.3.2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a69fa8dd920e84d783769c44560484ade81f6c765cde2e1cc46c754ddf95947"
checksum = "3dcca10ca861f34a320d178f3fdb29ffbf05087fc2c70d2a99860e3329bee1a8"
dependencies = [
"proc-macro2",
"quote",
@ -765,9 +820,9 @@ dependencies = [
[[package]]
name = "unicode-xid"
version = "0.2.0"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "usize_conversions"
@ -799,9 +854,9 @@ dependencies = [
[[package]]
name = "volatile"
version = "0.2.6"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6af0edf5b4faacc31fc51159244d78d65ec580f021afcef7bd53c04aeabc7f29"
checksum = "f6b06ad3ed06fef1713569d547cdbdb439eafed76341820fb0e0344f29a41945"
[[package]]
name = "vte"
@ -814,9 +869,9 @@ dependencies = [
[[package]]
name = "winapi"
version = "0.3.8"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
@ -846,16 +901,16 @@ version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2786ac694ed572ab5d2bbcd9e188805dba26b3501973dd69718914fb3d4a5a69"
dependencies = [
"bit_field 0.10.0",
"bit_field 0.10.1",
"bitflags",
"raw-cpuid",
]
[[package]]
name = "x86_64"
version = "0.11.0"
version = "0.11.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "365de37eb7c6da582cbb510dd0f3f1235d24ff6309a8a96e8a9909cc9bfd608f"
checksum = "aa580d2cf2a6a8c55f6283d6d06271b1ccab4d93cb3741edab290d5408d848c4"
dependencies = [
"bit_field 0.9.0",
"bitflags",

View File

@ -36,6 +36,8 @@ link_user = []
run_cmdline = []
# Add performance profiling
profile = []
# Rcore Virtual machine
hypervisor = ["rvm"]
[profile.dev]
# MUST >= 2 : Enable RVO to avoid stack overflow
@ -74,6 +76,7 @@ virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "df
volatile = "0.2"
woke = "0.0.2"
xmas-elf = "0.7"
rvm = { git = "https://github.com/rcore-os/RVM", rev = "939eb0a", optional = true }
[target.'cfg(target_arch = "x86_64")'.dependencies]
apic = { git = "https://github.com/rcore-os/apic-rs", rev = "fb86bd7" }
@ -93,4 +96,4 @@ bcm2837 = { git = "https://github.com/rcore-os/bcm2837", version = "2.5.1", opti
[target.'cfg(target_arch = "mips")'.dependencies]
mips = { git = "https://github.com/Harry-Chen/rust-mips", rev = "3b828a2" }
paste = "0.1"
paste = "0.1"

View File

@ -26,6 +26,8 @@
# PCI_PASSTHRU = 0000:00:00.1 [ x86_64 only] Passthrough the specified PCI device
# INIT = /bin/ls [riscv64 only] Run specified program instead of user shell
# EXTRA_NIC = on | off [ x86_64 only] Add an additional e1000 nic
# ACCEL = on | off [ x86_64 only] Enable/disable kvm/hvf acceleration
# HYPERVISOR = on | off [ x86_64 only] Enable/disable the RVM hypervisor, and set ACCEL to on
# FEATURES = profile | ... Add additional features
ARCH ?= riscv64
@ -36,6 +38,8 @@ SMP ?= 4
PCI_PASSTHRU ?=
INIT ?=
EXTRA_NIC ?= off
ACCEL ?= off
HYPERVISOR ?= off
qemu := qemu-system-$(ARCH)
target := $(ARCH)
@ -93,10 +97,6 @@ qemu_net_opts += \
qemu_ui_opts += \
-vga std
endif
ifeq ($(shell uname), Darwin)
qemu_opts += \
-machine accel=hvf
endif
ifeq ($(EXTRA_NIC), on)
qemu_net_opts += \
-netdev type=tap,id=net1,script=no,downscript=no \
@ -171,6 +171,19 @@ qemu_opts += $(qemu_net_opts)
qemu := sudo $(qemu)
endif
ifeq ($(HYPERVISOR), on)
FEATURES += hypervisor
ACCEL = on
endif
ifeq ($(ACCEL), on)
ifeq ($(shell uname), Darwin)
qemu_opts += -accel hvf
else
qemu_opts += -accel kvm -cpu host
endif
endif
### build args ###
ifeq ($(GRAPHIC), off)
FEATURES += nographic

View File

@ -83,6 +83,9 @@ lazy_static! {
devfs.add("fb0", Arc::new(Fbdev::default())).expect("failed to mknod /dev/fb0");
devfs.add("shm", Arc::new(ShmINode::default())).expect("failed to mkdir shm");
#[cfg(feature = "hypervisor")]
devfs.add("rvm", Arc::new(crate::rvm::RvmINode::new())).expect("failed to mknod /dev/rvm");
// mount DevFS at /dev
let dev = root.find(true, "dev").unwrap_or_else(|_| {
root.create("dev", FileType::Dir, 0o666).expect("failed to mkdir /dev")

View File

@ -21,8 +21,6 @@
#![allow(unused_mut)]
#![allow(unused_variables)]
#![allow(unused_imports)]
#![allow(unreachable_patterns)]
#![allow(unused_assignments)]
#![no_std]
// just keep it ...
@ -54,6 +52,8 @@ pub mod lkm;
pub mod memory;
pub mod net;
pub mod process;
#[cfg(feature = "hypervisor")]
pub mod rvm;
pub mod shell;
pub mod signal;
pub mod sync;

367
kernel/src/rvm/inode.rs Normal file
View File

@ -0,0 +1,367 @@
//! Implement INode for Rcore Virtual Machine
use alloc::collections::BTreeMap;
use core::any::Any;
use core::convert::{TryFrom, TryInto};
use core::mem::size_of;
use spin::RwLock;
use rcore_fs::vfs::*;
use rvm::{RvmError, RvmExitPacket, RvmResult, TrapKind, VcpuIo, VcpuReadWriteKind, VcpuState};
use super::into_fs_error;
use super::structs::{Guest, Vcpu};
use crate::syscall::{UserInOutPtr, UserInPtr, UserOutPtr};
const MAX_GUEST_NUM: usize = 64;
const MAX_VCPU_NUM: usize = 64;
const RVM_IO: u32 = 0xAE00;
const RVM_GUEST_CREATE: u32 = RVM_IO + 0x01;
const RVM_GUEST_ADD_MEMORY_REGION: u32 = RVM_IO + 0x02;
const RVM_GUEST_SET_TRAP: u32 = RVM_IO + 0x03;
const RVM_VCPU_CREATE: u32 = RVM_IO + 0x11;
const RVM_VCPU_RESUME: u32 = RVM_IO + 0x12;
const RVM_VCPU_READ_STATE: u32 = RVM_IO + 0x13;
const RVM_VCPU_WRITE_STATE: u32 = RVM_IO + 0x14;
const RVM_VCPU_INTERRUPT: u32 = RVM_IO + 0x15;
pub struct RvmINode {
guests: RwLock<BTreeMap<usize, Guest>>,
vcpus: RwLock<BTreeMap<usize, Vcpu>>,
}
#[repr(C)]
#[derive(Debug)]
struct RvmVcpuCreateArgs {
vmid: u16,
entry: u64,
}
#[repr(C)]
#[derive(Debug)]
struct RvmGuestAddMemoryRegionArgs {
vmid: u16,
guest_start_paddr: u64,
memory_size: u64,
}
#[repr(C)]
#[derive(Debug)]
struct RvmGuestSetTrapArgs {
vmid: u16,
kind: u32,
addr: u64,
size: u64,
key: u64,
}
#[repr(C)]
#[derive(Debug)]
struct RvmVcpuResumeArgs {
vcpu_id: u16,
packet: RvmExitPacket,
}
#[repr(C)]
#[derive(Debug)]
struct RvmVcpuStateArgs {
vcpu_id: u16,
kind: u32,
user_buf_ptr: u64,
buf_size: u64,
}
#[repr(C)]
#[derive(Debug)]
struct RvmVcpuInterruptArgs {
vcpu_id: u16,
vector: u32,
}
impl INode for RvmINode {
fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize> {
Err(FsError::NotSupported)
}
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
Err(FsError::NotSupported)
}
fn poll(&self) -> Result<PollStatus> {
Ok(PollStatus {
read: false,
write: false,
error: false,
})
}
fn metadata(&self) -> Result<Metadata> {
Ok(Metadata {
dev: 0,
inode: 0,
size: 0,
blk_size: 0,
blocks: 0,
atime: Timespec { sec: 0, nsec: 0 },
mtime: Timespec { sec: 0, nsec: 0 },
ctime: Timespec { sec: 0, nsec: 0 },
type_: FileType::CharDevice,
mode: 0o660,
nlinks: 1,
uid: 0,
gid: 0,
rdev: make_rdev(10, 232), // misc major, kvm minor
})
}
fn io_control(&self, cmd: u32, data: usize) -> Result<usize> {
match cmd {
RVM_GUEST_CREATE => {
info!("[RVM] ioctl RVM_GUEST_CREATE");
self.guest_create().map_err(into_fs_error)
}
RVM_GUEST_ADD_MEMORY_REGION => {
let args = UserInPtr::<RvmGuestAddMemoryRegionArgs>::from(data)
.read()
.or(Err(FsError::InvalidParam))?;
info!("[RVM] ioctl RVM_GUEST_ADD_MEMORY_REGION {:x?}", args);
self.guest_add_memory_region(
args.vmid as usize,
args.guest_start_paddr as usize,
args.memory_size as usize,
)
.map_err(into_fs_error)
}
RVM_GUEST_SET_TRAP => {
let args = UserInPtr::<RvmGuestSetTrapArgs>::from(data)
.read()
.or(Err(FsError::InvalidParam))?;
info!("[RVM] ioctl RVM_GUEST_SET_TRAP {:x?}", args);
self.guest_set_trap(
args.vmid as usize,
args.kind.try_into().map_err(into_fs_error)?,
args.addr as usize,
args.size as usize,
args.key,
)
.map_err(into_fs_error)?;
Ok(0)
}
RVM_VCPU_CREATE => {
let args = UserInPtr::<RvmVcpuCreateArgs>::from(data)
.read()
.or(Err(FsError::InvalidParam))?;
info!("[RVM] ioctl RVM_VCPU_CREATE {:x?}", args);
self.vcpu_create(args.vmid as usize, args.entry)
.map_err(into_fs_error)
}
RVM_VCPU_RESUME => {
let mut ptr = UserInOutPtr::<RvmVcpuResumeArgs>::from(data);
let mut args = ptr.read().or(Err(FsError::InvalidParam))?;
info!("[RVM] ioctl RVM_VCPU_RESUME {:#x}", args.vcpu_id);
args.packet = self
.vcpu_resume(args.vcpu_id as usize)
.map_err(into_fs_error)?;
ptr.write(args).or(Err(FsError::DeviceError))?;
Ok(0)
}
RVM_VCPU_READ_STATE => {
let args = UserInPtr::<RvmVcpuStateArgs>::from(data)
.read()
.or(Err(FsError::InvalidParam))?;
info!("[RVM] ioctl RVM_VCPU_READ_STATE {:#x?}", args);
self.vcpu_read_state(
args.vcpu_id as usize,
args.kind,
args.user_buf_ptr as usize,
args.buf_size as usize,
)
.map_err(into_fs_error)?;
Ok(0)
}
RVM_VCPU_WRITE_STATE => {
let args = UserInPtr::<RvmVcpuStateArgs>::from(data)
.read()
.or(Err(FsError::InvalidParam))?;
info!("[RVM] ioctl RVM_VCPU_WRITE_STATE {:#x?}", args);
self.vcpu_write_state(
args.vcpu_id as usize,
args.kind,
args.user_buf_ptr as usize,
args.buf_size as usize,
)
.map_err(into_fs_error)?;
Ok(0)
}
RVM_VCPU_INTERRUPT => {
let args = UserInPtr::<RvmVcpuInterruptArgs>::from(data)
.read()
.or(Err(FsError::InvalidParam))?;
info!("[RVM] ioctl RVM_VCPU_INTERRUPT {:#x?}", args);
self.vcpu_interrupt(args.vcpu_id as usize, args.vector)
.map_err(into_fs_error)?;
Ok(0)
}
_ => {
warn!("[RVM] invalid ioctl number {:#x}", cmd);
Err(FsError::InvalidParam)
}
}
}
fn mmap(&self, area: MMapArea) -> Result<()> {
info!("[RVM] mmap {:x?}", area);
Err(FsError::NotSupported)
}
fn as_any_ref(&self) -> &dyn Any {
self
}
}
impl RvmINode {
pub fn new() -> Self {
Self {
guests: RwLock::new(BTreeMap::new()),
vcpus: RwLock::new(BTreeMap::new()),
}
}
fn get_free_vmid(&self) -> usize {
(1..).find(|i| !self.guests.read().contains_key(i)).unwrap()
}
fn add_guest(&self, guest: Guest, vmid_option: Option<usize>) -> usize {
let vmid = vmid_option.unwrap_or_else(|| self.get_free_vmid());
self.guests.write().insert(vmid, guest);
vmid
}
fn get_free_vcpu_id(&self) -> usize {
(1..).find(|i| !self.vcpus.read().contains_key(i)).unwrap()
}
fn add_vcpu(&self, vcpu: Vcpu, vcpu_id_option: Option<usize>) -> usize {
let vcpu_id = vcpu_id_option.unwrap_or_else(|| self.get_free_vcpu_id());
self.vcpus.write().insert(vcpu_id, vcpu);
vcpu_id
}
fn guest_create(&self) -> RvmResult<usize> {
if rvm::check_hypervisor_feature() {
let vmid = self.get_free_vmid();
if vmid >= MAX_GUEST_NUM {
warn!("[RVM] too many guests ({})", MAX_GUEST_NUM);
return Err(RvmError::NoMemory);
}
self.add_guest(Guest::new()?, Some(vmid));
Ok(vmid)
} else {
warn!("[RVM] no hardware support");
Err(RvmError::NotSupported)
}
}
fn guest_add_memory_region(&self, vmid: usize, gpaddr: usize, size: usize) -> RvmResult<usize> {
if let Some(guest) = self.guests.read().get(&vmid) {
Ok(guest.add_memory_region(gpaddr, size)?)
} else {
Err(RvmError::InvalidParam)
}
}
fn guest_set_trap(
&self,
vmid: usize,
kind: TrapKind,
addr: usize,
size: usize,
key: u64,
) -> RvmResult<()> {
if let Some(guest) = self.guests.read().get(&vmid) {
guest.inner.set_trap(kind, addr, size, None, key)
} else {
Err(RvmError::InvalidParam)
}
}
fn vcpu_create(&self, vmid: usize, entry: u64) -> RvmResult<usize> {
if let Some(guest) = self.guests.read().get(&vmid) {
let vcpu_id = self.get_free_vcpu_id();
if vcpu_id >= MAX_VCPU_NUM {
warn!("[RVM] too many vcpus ({})", MAX_VCPU_NUM);
return Err(RvmError::NoMemory);
}
let vcpu = Vcpu::new(entry, guest.inner.clone())?;
self.add_vcpu(vcpu, Some(vcpu_id));
Ok(vcpu_id)
} else {
Err(RvmError::InvalidParam)
}
}
fn vcpu_resume(&self, vcpu_id: usize) -> RvmResult<RvmExitPacket> {
if let Some(vcpu) = self.vcpus.write().get_mut(&vcpu_id) {
Ok(vcpu.inner.lock().resume()?)
} else {
Err(RvmError::InvalidParam)
}
}
fn vcpu_read_state(
&self,
vcpu_id: usize,
kind: u32,
user_buf_ptr: usize,
buf_size: usize,
) -> RvmResult<()> {
if kind != VcpuReadWriteKind::VcpuState as u32 || buf_size != size_of::<VcpuState>() {
return Err(RvmError::InvalidParam);
}
if let Some(vcpu) = self.vcpus.read().get(&vcpu_id) {
let mut ptr = UserOutPtr::<VcpuState>::from(user_buf_ptr);
let state = vcpu.inner.lock().read_state()?;
ptr.write(state).or(Err(RvmError::InvalidParam))?;
Ok(())
} else {
Err(RvmError::InvalidParam)
}
}
fn vcpu_write_state(
&self,
vcpu_id: usize,
kind: u32,
user_buf_ptr: usize,
buf_size: usize,
) -> RvmResult<()> {
if let Some(vcpu) = self.vcpus.write().get_mut(&vcpu_id) {
match VcpuReadWriteKind::try_from(kind) {
Ok(VcpuReadWriteKind::VcpuState) => {
if buf_size != size_of::<VcpuState>() {
return Err(RvmError::InvalidParam);
}
let ptr = UserInPtr::<VcpuState>::from(user_buf_ptr);
let state = ptr.read().or(Err(RvmError::InvalidParam))?;
vcpu.inner.lock().write_state(&state)
}
Ok(VcpuReadWriteKind::VcpuIo) => {
if buf_size != size_of::<VcpuIo>() {
return Err(RvmError::InvalidParam);
}
let ptr = UserInPtr::<VcpuIo>::from(user_buf_ptr);
let state = ptr.read().or(Err(RvmError::InvalidParam))?;
vcpu.inner.lock().write_io_state(&state)
}
Err(_) => return Err(RvmError::InvalidParam),
}
} else {
Err(RvmError::InvalidParam)
}
}
fn vcpu_interrupt(&self, vcpu_id: usize, vector: u32) -> RvmResult<()> {
if let Some(vcpu) = self.vcpus.write().get_mut(&vcpu_id) {
vcpu.inner.lock().virtual_interrupt(vector)
} else {
Err(RvmError::InvalidParam)
}
}
// TODO: remove guest & vcpu
}

97
kernel/src/rvm/memory.rs Normal file
View File

@ -0,0 +1,97 @@
//! Used for delay mapping host's virtual memory to guest's physical memory
use alloc::{boxed::Box, sync::Arc};
use rvm::RvmPageTable;
use rvm::{DefaultGuestPhysMemorySet, GuestMemoryAttr, GuestPhysAddr, HostVirtAddr};
use rcore_memory::memory_set::handler::{FrameAllocator, MemoryHandler};
use rcore_memory::memory_set::MemoryAttr;
use rcore_memory::paging::PageTable;
#[derive(Debug, Clone)]
pub struct RvmPageTableHandlerDelay<T: FrameAllocator> {
guest_start_paddr: GuestPhysAddr,
host_start_vaddr: HostVirtAddr,
gpm: Arc<DefaultGuestPhysMemorySet>,
allocator: T,
}
impl<T: FrameAllocator> RvmPageTableHandlerDelay<T> {
pub fn new(
guest_start_paddr: GuestPhysAddr,
host_start_vaddr: HostVirtAddr,
gpm: Arc<DefaultGuestPhysMemorySet>,
allocator: T,
) -> Self {
Self {
guest_start_paddr,
host_start_vaddr,
gpm,
allocator,
}
}
}
impl<T: FrameAllocator> MemoryHandler for RvmPageTableHandlerDelay<T> {
fn box_clone(&self) -> Box<dyn MemoryHandler> {
Box::new(self.clone())
}
fn map(&self, pt: &mut dyn PageTable, addr: HostVirtAddr, attr: &MemoryAttr) {
let entry = pt.map(addr, 0);
entry.set_present(false);
attr.apply(entry);
}
fn unmap(&self, pt: &mut dyn PageTable, addr: HostVirtAddr) {
let entry = pt.get_entry(addr).expect("failed to get entry");
// PageTable::unmap requires page to be present
entry.set_present(true);
pt.unmap(addr);
}
fn clone_map(
&self,
pt: &mut dyn PageTable,
src_pt: &mut dyn PageTable,
addr: HostVirtAddr,
attr: &MemoryAttr,
) {
let entry = src_pt.get_entry(addr).expect("failed to get entry");
if entry.present() {
// eager map and copy data
let data = src_pt.get_page_slice_mut(addr);
let target = self.allocator.alloc().expect("failed to alloc frame");
let entry = pt.map(addr, target);
attr.apply(entry);
pt.get_page_slice_mut(addr).copy_from_slice(data);
} else {
// delay map
self.map(pt, addr, attr);
}
}
fn handle_page_fault(&self, pt: &mut dyn PageTable, addr: HostVirtAddr) -> bool {
let entry = pt.get_entry(addr).expect("failed to get entry");
if entry.present() {
// not a delay case
return false;
}
let guest_paddr = addr - self.host_start_vaddr + self.guest_start_paddr;
let mut rvm_pt = self.gpm.rvm_page_table.lock();
let mut target = rvm_pt.query(guest_paddr).unwrap_or(0);
if target == 0 {
target = self.allocator.alloc().expect("failed to alloc frame");
}
rvm_pt
.map(guest_paddr, target, GuestMemoryAttr::default())
.expect("failed to create GPA -> HPA mapping");
entry.set_target(target);
entry.set_present(true);
entry.update();
true
}
}

55
kernel/src/rvm/mod.rs Normal file
View File

@ -0,0 +1,55 @@
//! Implement hypervisor using rvm crate
#![deny(non_upper_case_globals)]
#![deny(dead_code)]
#![deny(unused_mut)]
#![deny(unused_variables)]
#![deny(unused_imports)]
use rcore_fs::vfs::FsError;
use rvm::RvmError;
mod inode;
mod memory;
mod structs;
pub use inode::RvmINode;
fn into_fs_error(e: RvmError) -> FsError {
match e {
RvmError::Internal => FsError::DeviceError,
RvmError::NotSupported => FsError::NotSupported,
RvmError::NoMemory => FsError::NoDeviceSpace,
RvmError::InvalidParam => FsError::InvalidParam,
RvmError::OutOfRange => FsError::InvalidParam,
RvmError::BadState => FsError::DeviceError,
RvmError::NotFound => FsError::InvalidParam,
}
}
mod rvm_extern_fn {
use crate::memory::{alloc_frame, dealloc_frame, phys_to_virt};
#[rvm::extern_fn(alloc_frame)]
fn rvm_alloc_frame() -> Option<usize> {
alloc_frame()
}
#[rvm::extern_fn(dealloc_frame)]
fn rvm_dealloc_frame(paddr: usize) {
dealloc_frame(paddr)
}
#[rvm::extern_fn(phys_to_virt)]
fn rvm_phys_to_virt(paddr: usize) -> usize {
phys_to_virt(paddr)
}
#[cfg(target_arch = "x86_64")]
#[rvm::extern_fn(x86_all_traps_handler_addr)]
unsafe fn rvm_x86_all_traps_handler_addr() -> usize {
extern "C" {
fn __alltraps();
}
__alltraps as usize
}
}

54
kernel/src/rvm/structs.rs Normal file
View File

@ -0,0 +1,54 @@
//! Wrappers of rvm::Guest and rvm::Vcpu
use alloc::sync::Arc;
use spin::Mutex;
use rcore_memory::{memory_set::MemoryAttr, PAGE_SIZE};
use rvm::{DefaultGuestPhysMemorySet, GuestPhysAddr, HostVirtAddr, RvmResult};
use rvm::{Guest as GuestInner, Vcpu as VcpuInner};
use super::memory::RvmPageTableHandlerDelay;
use crate::memory::GlobalFrameAlloc;
pub(super) struct Guest {
gpm: Arc<DefaultGuestPhysMemorySet>,
pub(super) inner: Arc<GuestInner>,
}
pub(super) struct Vcpu {
pub(super) inner: Mutex<VcpuInner>,
}
impl Guest {
pub fn new() -> RvmResult<Self> {
let gpm = DefaultGuestPhysMemorySet::new();
Ok(Self {
inner: GuestInner::new(gpm.clone())?,
gpm,
})
}
pub fn add_memory_region(&self, gpaddr: GuestPhysAddr, size: usize) -> RvmResult<HostVirtAddr> {
self.inner.add_memory_region(gpaddr, size, None)?;
let thread = crate::process::current_thread().unwrap();
let hvaddr = thread.vm.lock().find_free_area(PAGE_SIZE, size);
let handler =
RvmPageTableHandlerDelay::new(gpaddr, hvaddr, self.gpm.clone(), GlobalFrameAlloc);
thread.vm.lock().push(
hvaddr,
hvaddr + size,
MemoryAttr::default().user().writable(),
handler,
"rvm_guest_physical",
);
Ok(hvaddr)
}
}
impl Vcpu {
pub fn new(entry: u64, guest: Arc<GuestInner>) -> RvmResult<Self> {
Ok(Self {
inner: Mutex::new(VcpuInner::new(entry, guest)?),
})
}
}