refactor configure and launch of VM to be much simpler and nicer
This commit is contained in:
parent
c8153e4f51
commit
1a587bb6cc
@ -1,10 +1,8 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
extern crate libc;
|
#[macro_use] extern crate lazy_static;
|
||||||
extern crate byteorder;
|
|
||||||
extern crate termios;
|
|
||||||
|
|
||||||
|
|
||||||
|
#[macro_use] mod log;
|
||||||
mod vm;
|
mod vm;
|
||||||
mod memory;
|
mod memory;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -12,48 +10,14 @@ mod system;
|
|||||||
mod devices;
|
mod devices;
|
||||||
mod kvm;
|
mod kvm;
|
||||||
mod virtio;
|
mod virtio;
|
||||||
|
mod disk;
|
||||||
|
|
||||||
|
pub use log::{Logger,LogLevel};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::path::PathBuf;
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
vm::VmConfig::new(env::args())
|
||||||
let mut config = vm::VmConfig::new();
|
.ram_size_megs(1024)
|
||||||
config.ram_size_megs(1024);
|
.use_realmfs("/home/user/Shared/main-realmfs.img")
|
||||||
match find_kernel() {
|
.boot();
|
||||||
Some(path) => config.kernel_path(&path),
|
|
||||||
None => { println!("Could not find kernel"); return; }
|
|
||||||
}
|
|
||||||
match find_init() {
|
|
||||||
Some(path) => config.init_path(&path),
|
|
||||||
None => { println!("Could not find init"); return; }
|
|
||||||
}
|
|
||||||
match vm::Vm::open(config) {
|
|
||||||
Ok(vm) => {
|
|
||||||
vm.start().unwrap();
|
|
||||||
},
|
|
||||||
Err(e) => println!("error :( {}", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_init() -> Option<PathBuf> {
|
|
||||||
let mut cwd = env::current_dir().unwrap();
|
|
||||||
if cwd.join("rust/target/release/ph-init").exists() {
|
|
||||||
cwd.push("rust/target/release/ph-init");
|
|
||||||
return Some(cwd)
|
|
||||||
}
|
|
||||||
if cwd.join("rust/target/debug/ph-init").exists() {
|
|
||||||
cwd.push("rust/target/debug/ph-init");
|
|
||||||
return Some(cwd)
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_kernel() -> Option<PathBuf> {
|
|
||||||
let mut cwd = env::current_dir().unwrap();
|
|
||||||
if cwd.join("kernel/ph_linux").exists() {
|
|
||||||
cwd.push("kernel/ph_linux");
|
|
||||||
return Some(cwd)
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,10 @@ impl MemoryManager {
|
|||||||
&self.ram
|
&self.ram
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn kvm_mut(&mut self) -> &mut Kvm {
|
||||||
|
&mut self.kvm
|
||||||
|
}
|
||||||
|
|
||||||
pub fn kvm(&self) -> &Kvm {
|
pub fn kvm(&self) -> &Kvm {
|
||||||
&self.kvm
|
&self.kvm
|
||||||
}
|
}
|
||||||
|
185
rust/src/vm/config.rs
Normal file
185
rust/src/vm/config.rs
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
use std::path::{PathBuf, Path};
|
||||||
|
use crate::vm::{Vm, Result, ErrorKind};
|
||||||
|
use std::{env, process};
|
||||||
|
|
||||||
|
pub enum RootFS {
|
||||||
|
SelfRoot,
|
||||||
|
RealmFSImage(PathBuf),
|
||||||
|
RawImage(PathBuf),
|
||||||
|
RawOffset(PathBuf, usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VmConfig {
|
||||||
|
ram_size: usize,
|
||||||
|
ncpus: usize,
|
||||||
|
verbose: bool,
|
||||||
|
launch_systemd: bool,
|
||||||
|
kernel_path: Option<PathBuf>,
|
||||||
|
init_path: Option<PathBuf>,
|
||||||
|
init_cmd: Option<String>,
|
||||||
|
rootfs: RootFS,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
impl VmConfig {
|
||||||
|
pub fn new(args: env::Args) -> VmConfig {
|
||||||
|
let mut config = VmConfig {
|
||||||
|
ram_size: 256 * 1024 * 1024,
|
||||||
|
ncpus: 1,
|
||||||
|
verbose: false,
|
||||||
|
launch_systemd: false,
|
||||||
|
kernel_path: None,
|
||||||
|
init_path: None,
|
||||||
|
init_cmd: None,
|
||||||
|
rootfs: RootFS::SelfRoot,
|
||||||
|
};
|
||||||
|
config.parse_args(args);
|
||||||
|
config
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ram_size_megs(mut self, megs: usize) -> Self {
|
||||||
|
self.ram_size = megs * 1024 * 1024;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn num_cpus(mut self, ncpus: usize) -> Self {
|
||||||
|
self.ncpus = ncpus;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_cmdline(mut self, val: &str) -> Self {
|
||||||
|
self.init_cmd = Some(val.to_owned());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kernel_path<P: Into<PathBuf>>(mut self, path: P) -> Self {
|
||||||
|
self.kernel_path = Some(path.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_path<P: Into<PathBuf>>(mut self, path: P) -> Self {
|
||||||
|
self.init_path = Some(path.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn use_realmfs<P: Into<PathBuf>>(mut self, path: P) -> Self {
|
||||||
|
self.rootfs = RootFS::RealmFSImage(path.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn use_rawdisk<P: Into<PathBuf>>(mut self, path: P) -> Self {
|
||||||
|
self.rootfs = RootFS::RawImage(path.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn use_rawdisk_with_offset<P: Into<PathBuf>>(mut self, path: P, offset: usize) -> Self {
|
||||||
|
self.rootfs = RootFS::RawOffset(path.into(), offset);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn use_systemd(mut self) -> Self {
|
||||||
|
self.launch_systemd = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn boot(self) {
|
||||||
|
match Vm::open(self) {
|
||||||
|
Ok(vm) => if let Err(err) = vm.start() {
|
||||||
|
notify!("Error starting VM: {}", err);
|
||||||
|
}
|
||||||
|
Err(e) => notify!("Error creating VM: {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ram_size(&self) -> usize {
|
||||||
|
self.ram_size
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ncpus(&self) -> usize {
|
||||||
|
self.ncpus
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verbose(&self) -> bool {
|
||||||
|
self.verbose
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn launch_systemd(&self) -> bool {
|
||||||
|
self.launch_systemd
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_kernel_path(&self) -> Result<PathBuf> {
|
||||||
|
match self.kernel_path {
|
||||||
|
Some(ref path) if path.exists() => return Ok(path.to_path_buf()),
|
||||||
|
None => if let Some(path) = Self::search_kernel() {
|
||||||
|
return Ok(path)
|
||||||
|
}
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
Err(ErrorKind::KernelNotFound.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_init_path(&self) -> Result<PathBuf> {
|
||||||
|
match self.init_path {
|
||||||
|
Some(ref path) if path.exists() => return Ok(path.to_path_buf()),
|
||||||
|
None => if let Some(path) = Self::search_init() {
|
||||||
|
return Ok(path)
|
||||||
|
}
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
Err(ErrorKind::InitNotFound.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_init_cmdline(&self) -> Option<&str> {
|
||||||
|
self.init_cmd.as_ref().map(|s| s.as_str())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rootfs(&self) -> &RootFS {
|
||||||
|
&self.rootfs
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_init() -> Option<PathBuf> {
|
||||||
|
Self::search_binary("ph-init", &[
|
||||||
|
"rust/target/release", "rust/target/debug",
|
||||||
|
"target/debug", "target/release"
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_kernel() -> Option<PathBuf> {
|
||||||
|
Self::search_binary("ph_linux", &["kernel", "../kernel"])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_binary(name: &str, paths: &[&str]) -> Option<PathBuf> {
|
||||||
|
let cwd = match env::current_dir() {
|
||||||
|
Ok(cwd) => cwd,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
for p in paths {
|
||||||
|
let p = Path::new(p).join(name);
|
||||||
|
let current = if p.is_absolute() {
|
||||||
|
p
|
||||||
|
} else {
|
||||||
|
cwd.join(p)
|
||||||
|
};
|
||||||
|
if current.exists() {
|
||||||
|
return Some(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_args(&mut self, args: env::Args) {
|
||||||
|
for arg in args.skip(1) {
|
||||||
|
self.parse_one_arg(&arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_one_arg(&mut self, arg: &str) {
|
||||||
|
if arg == "-v" {
|
||||||
|
self.verbose = true;
|
||||||
|
} else {
|
||||||
|
eprintln!("Unrecognized command line argument: {}", arg);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
use std::result;
|
use std::{result, io};
|
||||||
use std::error;
|
use std::error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::str;
|
use std::str;
|
||||||
@ -10,6 +10,8 @@ pub type Result<T> = result::Result<T, Error>;
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ErrorKind {
|
pub enum ErrorKind {
|
||||||
|
KernelNotFound,
|
||||||
|
InitNotFound,
|
||||||
InvalidAddress(u64),
|
InvalidAddress(u64),
|
||||||
InvalidMappingOffset(usize),
|
InvalidMappingOffset(usize),
|
||||||
RegisterMemoryFailed,
|
RegisterMemoryFailed,
|
||||||
@ -22,12 +24,15 @@ pub enum ErrorKind {
|
|||||||
CreateVmFailed,
|
CreateVmFailed,
|
||||||
BadVersion,
|
BadVersion,
|
||||||
EventFdError,
|
EventFdError,
|
||||||
DiskImageOpen(disk::Error)
|
DiskImageOpen(disk::Error),
|
||||||
|
TerminalTermios(io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ErrorKind {
|
impl ErrorKind {
|
||||||
fn as_str(&self) -> &'static str {
|
fn as_str(&self) -> &'static str {
|
||||||
match *self {
|
match *self {
|
||||||
|
ErrorKind::KernelNotFound => "Could not find kernel image",
|
||||||
|
ErrorKind::InitNotFound => "Could not find init image",
|
||||||
ErrorKind::InvalidAddress(..) => "Invalid guest memory address",
|
ErrorKind::InvalidAddress(..) => "Invalid guest memory address",
|
||||||
ErrorKind::InvalidMappingOffset(..) => "Invalid memory mapping offset",
|
ErrorKind::InvalidMappingOffset(..) => "Invalid memory mapping offset",
|
||||||
ErrorKind::RegisterMemoryFailed => "Failed to register memory region",
|
ErrorKind::RegisterMemoryFailed => "Failed to register memory region",
|
||||||
@ -41,6 +46,7 @@ impl ErrorKind {
|
|||||||
ErrorKind::BadVersion => "unexpected kvm api version",
|
ErrorKind::BadVersion => "unexpected kvm api version",
|
||||||
ErrorKind::EventFdError => "eventfd error",
|
ErrorKind::EventFdError => "eventfd error",
|
||||||
ErrorKind::DiskImageOpen(_) => "failed to open disk image",
|
ErrorKind::DiskImageOpen(_) => "failed to open disk image",
|
||||||
|
ErrorKind::TerminalTermios(_) => "failed termios",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,6 +58,7 @@ impl fmt::Display for ErrorKind {
|
|||||||
ErrorKind::InvalidMappingOffset(offset) => write!(f, "{}: 0x{:x}", self.as_str(), offset),
|
ErrorKind::InvalidMappingOffset(offset) => write!(f, "{}: 0x{:x}", self.as_str(), offset),
|
||||||
ErrorKind::IoctlFailed(name) => write!(f, "Ioctl {} failed", name),
|
ErrorKind::IoctlFailed(name) => write!(f, "Ioctl {} failed", name),
|
||||||
ErrorKind::DiskImageOpen(ref e) => write!(f, "failed to open disk image: {}", e),
|
ErrorKind::DiskImageOpen(ref e) => write!(f, "failed to open disk image: {}", e),
|
||||||
|
ErrorKind::TerminalTermios(ref e) => write!(f, "error reading/restoring terminal state: {}", e),
|
||||||
_ => write!(f, "{}", self.as_str()),
|
_ => write!(f, "{}", self.as_str()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,7 @@ use crate::memory::{GuestRam,KERNEL_CMDLINE_ADDRESS};
|
|||||||
use super::Result;
|
use super::Result;
|
||||||
|
|
||||||
|
|
||||||
fn add_defaults(cmdline: &mut KernelCmdLine, rdonly_root: bool, verbose: bool) {
|
fn add_defaults(cmdline: &mut KernelCmdLine) {
|
||||||
let root_mount_type = if rdonly_root { "ro" } else { "rw" };
|
|
||||||
|
|
||||||
let output = if verbose {"earlyprintk=serial"} else {"quiet"};
|
|
||||||
|
|
||||||
cmdline
|
cmdline
|
||||||
.push("noapic")
|
.push("noapic")
|
||||||
.push("noacpi")
|
.push("noacpi")
|
||||||
@ -24,10 +20,6 @@ fn add_defaults(cmdline: &mut KernelCmdLine, rdonly_root: bool, verbose: bool) {
|
|||||||
.push_set_true("rcuupdate.rcu_normal_after_boot")
|
.push_set_true("rcuupdate.rcu_normal_after_boot")
|
||||||
.push_set_val("console", "hvc0")
|
.push_set_val("console", "hvc0")
|
||||||
|
|
||||||
.push(root_mount_type)
|
|
||||||
.push_set_val("rootfstype", "9p")
|
|
||||||
.push_set_val("rootflags", "trans=virtio,version=9p2000.L,cache=loose")
|
|
||||||
|
|
||||||
.push_set_true("i8042.direct")
|
.push_set_true("i8042.direct")
|
||||||
.push_set_true("i8042.dumbkbd")
|
.push_set_true("i8042.dumbkbd")
|
||||||
.push_set_true("i8042.nopnp")
|
.push_set_true("i8042.nopnp")
|
||||||
@ -37,11 +29,7 @@ fn add_defaults(cmdline: &mut KernelCmdLine, rdonly_root: bool, verbose: bool) {
|
|||||||
.push_set_val("iommu", "off")
|
.push_set_val("iommu", "off")
|
||||||
.push("cryptomgr.notests")
|
.push("cryptomgr.notests")
|
||||||
|
|
||||||
.push(output)
|
.push_set_val("8250.nr_uarts", "0");
|
||||||
|
|
||||||
.push_set_val("8250.nr_uarts", "0")
|
|
||||||
//.push_set_val("init", "/home/user/virt/init");
|
|
||||||
.push_set_val("init", "/phinit");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -55,13 +43,12 @@ impl KernelCmdLine {
|
|||||||
KernelCmdLine { address: KERNEL_CMDLINE_ADDRESS, buffer: OsString::new() }
|
KernelCmdLine { address: KERNEL_CMDLINE_ADDRESS, buffer: OsString::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_default(verbose: bool) -> KernelCmdLine {
|
pub fn new_default() -> KernelCmdLine {
|
||||||
let mut cmdline = KernelCmdLine::new();
|
let mut cmdline = KernelCmdLine::new();
|
||||||
add_defaults(&mut cmdline, true, verbose);
|
add_defaults(&mut cmdline);
|
||||||
cmdline
|
cmdline
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn push(&mut self, option: &str) -> &mut Self {
|
pub fn push(&mut self, option: &str) -> &mut Self {
|
||||||
if !self.buffer.is_empty() {
|
if !self.buffer.is_empty() {
|
||||||
self.buffer.push(" ");
|
self.buffer.push(" ");
|
||||||
@ -89,13 +76,8 @@ impl KernelCmdLine {
|
|||||||
pub fn write_to_memory(&self, memory: &GuestRam) -> Result<()> {
|
pub fn write_to_memory(&self, memory: &GuestRam) -> Result<()> {
|
||||||
let bs = self.buffer.as_bytes();
|
let bs = self.buffer.as_bytes();
|
||||||
let len = bs.len();
|
let len = bs.len();
|
||||||
//println!("Kernel CmdLine: {:?}", self.buffer);
|
|
||||||
//println!("writing {} command line bytes to 0x{:x}", len + 1, KERNEL_CMDLINE_ADDRESS);
|
|
||||||
memory.write_bytes(KERNEL_CMDLINE_ADDRESS, bs)?;
|
memory.write_bytes(KERNEL_CMDLINE_ADDRESS, bs)?;
|
||||||
memory.write_int(KERNEL_CMDLINE_ADDRESS + len as u64, 0u8)?;
|
memory.write_int(KERNEL_CMDLINE_ADDRESS + len as u64, 0u8)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,21 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::path::{PathBuf,Path};
|
|
||||||
use std::env;
|
|
||||||
|
|
||||||
use self::io::IoDispatcher;
|
use self::io::IoDispatcher;
|
||||||
|
|
||||||
use crate::virtio::VirtioBus;
|
use crate::virtio::VirtioBus;
|
||||||
use crate::devices;
|
use crate::devices;
|
||||||
|
use crate::disk;
|
||||||
|
|
||||||
use crate::memory::{GuestRam, KVM_KERNEL_LOAD_ADDRESS, MemoryManager, SystemAllocator, AddressRange};
|
use crate::memory::{GuestRam, KVM_KERNEL_LOAD_ADDRESS, MemoryManager, SystemAllocator, AddressRange};
|
||||||
use crate::kvm::*;
|
use crate::kvm::*;
|
||||||
|
|
||||||
|
|
||||||
mod run;
|
mod run;
|
||||||
pub mod io;
|
pub mod io;
|
||||||
mod setup;
|
mod setup;
|
||||||
mod error;
|
mod error;
|
||||||
mod kernel_cmdline;
|
mod kernel_cmdline;
|
||||||
|
mod config;
|
||||||
|
pub use config::VmConfig;
|
||||||
|
|
||||||
pub use self::error::{Result,Error,ErrorKind};
|
pub use self::error::{Result,Error,ErrorKind};
|
||||||
|
|
||||||
@ -24,48 +23,20 @@ pub use self::error::{Result,Error,ErrorKind};
|
|||||||
use self::run::KvmRunArea;
|
use self::run::KvmRunArea;
|
||||||
|
|
||||||
use self::kernel_cmdline::KernelCmdLine;
|
use self::kernel_cmdline::KernelCmdLine;
|
||||||
|
use std::sync::Arc;
|
||||||
pub struct VmConfig {
|
use std::sync::atomic::AtomicBool;
|
||||||
ram_size: usize,
|
use crate::disk::OpenType;
|
||||||
ncpus: usize,
|
use termios::Termios;
|
||||||
kernel_path: PathBuf,
|
use crate::vm::config::RootFS;
|
||||||
init_path: PathBuf,
|
use std::path::Path;
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
impl VmConfig {
|
|
||||||
pub fn new() -> VmConfig {
|
|
||||||
VmConfig {
|
|
||||||
ram_size: 256 * 1024 * 1024,
|
|
||||||
ncpus: 1,
|
|
||||||
kernel_path: PathBuf::new(),
|
|
||||||
init_path: PathBuf::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ram_size_megs(&mut self, megs: usize) {
|
|
||||||
self.ram_size = megs * 1024 * 1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn num_cpus(&mut self, ncpus: usize) {
|
|
||||||
self.ncpus = ncpus;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kernel_path(&mut self, path: &Path) {
|
|
||||||
self.kernel_path = path.to_path_buf();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init_path(&mut self, path: &Path) {
|
|
||||||
self.init_path = path.to_path_buf();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
pub struct Vm {
|
pub struct Vm {
|
||||||
kvm: Kvm,
|
_config: VmConfig,
|
||||||
memory: MemoryManager,
|
memory: MemoryManager,
|
||||||
io_dispatcher: Arc<IoDispatcher>,
|
io_dispatcher: Arc<IoDispatcher>,
|
||||||
_virtio: VirtioBus,
|
termios: Option<Termios>,
|
||||||
|
_virtio: Arc<VirtioBus>,
|
||||||
}
|
}
|
||||||
|
|
||||||
static REQUIRED_EXTENSIONS: &[u32] = &[
|
static REQUIRED_EXTENSIONS: &[u32] = &[
|
||||||
@ -89,55 +60,122 @@ fn get_base_dev_pfn(mem_size: u64) -> u64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Vm {
|
impl Vm {
|
||||||
pub fn open(config: VmConfig) -> Result<Vm> {
|
fn create_kvm() -> Result<Kvm> {
|
||||||
let mut kvm = Kvm::open(&REQUIRED_EXTENSIONS)?;
|
let kvm = Kvm::open(&REQUIRED_EXTENSIONS)?;
|
||||||
|
|
||||||
kvm.set_tss_addr(0xFFFbd000)?;
|
kvm.set_tss_addr(0xFFFbd000)?;
|
||||||
kvm.create_pit2()?;
|
kvm.create_pit2()?;
|
||||||
|
kvm.create_irqchip()?;
|
||||||
let ram = GuestRam::new(config.ram_size, &kvm)?;
|
Ok(kvm)
|
||||||
let dev_addr_start = get_base_dev_pfn(config.ram_size as u64) * 4096;
|
}
|
||||||
|
fn create_memory_manager(ram_size: usize) -> Result<MemoryManager> {
|
||||||
|
let kvm = Self::create_kvm()?;
|
||||||
|
let ram = GuestRam::new(ram_size, &kvm)?;
|
||||||
|
let dev_addr_start = get_base_dev_pfn(ram_size as u64) * 4096;
|
||||||
let dev_addr_size = u64::max_value() - dev_addr_start;
|
let dev_addr_size = u64::max_value() - dev_addr_start;
|
||||||
let allocator = SystemAllocator::new(AddressRange::new(dev_addr_start,dev_addr_size as usize));
|
let allocator = SystemAllocator::new(AddressRange::new(dev_addr_start,dev_addr_size as usize));
|
||||||
let memory = MemoryManager::new(kvm.clone(), ram, allocator);
|
Ok(MemoryManager::new(kvm, ram, allocator))
|
||||||
|
}
|
||||||
|
|
||||||
kvm.create_irqchip()?;
|
fn setup_virtio(config: &VmConfig, cmdline: &mut KernelCmdLine, virtio: &mut VirtioBus) -> Result<()> {
|
||||||
|
devices::VirtioSerial::create(virtio)?;
|
||||||
|
devices::VirtioRandom::create(virtio)?;
|
||||||
|
devices::VirtioWayland::create(virtio)?;
|
||||||
|
let init_path = config.get_init_path()?;
|
||||||
|
devices::VirtioP9::create(virtio, "home", "/home/user", &init_path)?;
|
||||||
|
|
||||||
let verbose = env::args().any(|arg| arg == "-v");
|
Self::setup_rootfs(config, cmdline, virtio, &init_path)
|
||||||
let cmdline = KernelCmdLine::new_default(verbose);
|
}
|
||||||
|
|
||||||
cmdline.write_to_memory(memory.guest_ram())?;
|
fn setup_rootfs(config: &VmConfig, cmdline: &mut KernelCmdLine, virtio: &mut VirtioBus, init_path: &Path) -> Result<()> {
|
||||||
let path = PathBuf::from(&config.kernel_path);
|
match config.rootfs() {
|
||||||
setup::kernel::load_pm_kernel(memory.guest_ram(), &path, cmdline.address(), cmdline.size())?;
|
RootFS::SelfRoot => {
|
||||||
|
devices::VirtioP9::create(virtio, "/dev/root", "/", &init_path)?;
|
||||||
|
notify!("9p root");
|
||||||
|
cmdline.push_set_val("root", "/dev/root");
|
||||||
|
cmdline.push("ro");
|
||||||
|
cmdline.push_set_val("rootfstype", "9p");
|
||||||
|
cmdline.push_set_val("rootflags", "trans=virtio,version=9p2000.L,cache=loose");
|
||||||
|
cmdline.push_set_val("init", "/phinit");
|
||||||
|
},
|
||||||
|
RootFS::RealmFSImage(ref path) => {
|
||||||
|
let disk = disk::RealmFSImage::open(path, false)
|
||||||
|
.map_err(ErrorKind::DiskImageOpen)?;
|
||||||
|
devices::VirtioBlock::create(virtio, disk)?;
|
||||||
|
cmdline.push_set_val("root", "/dev/vda");
|
||||||
|
cmdline.push("rw");
|
||||||
|
cmdline.push_set_val("init", "/usr/bin/ph-init");
|
||||||
|
},
|
||||||
|
RootFS::RawImage(ref path) => {
|
||||||
|
let disk = disk::RawDiskImage::open(path, OpenType::MemoryOverlay).map_err(ErrorKind::DiskImageOpen)?;
|
||||||
|
devices::VirtioBlock::create(virtio, disk)?;
|
||||||
|
cmdline.push_set_val("root", "/dev/vda");
|
||||||
|
cmdline.push("rw");
|
||||||
|
},
|
||||||
|
RootFS::RawOffset(path, offset) => {
|
||||||
|
let disk = disk::RawDiskImage::open_with_offset(path, OpenType::ReadWrite, *offset)
|
||||||
|
.map_err(ErrorKind::DiskImageOpen)?;
|
||||||
|
devices::VirtioBlock::create(virtio, disk)?;
|
||||||
|
cmdline.push_set_val("root", "/dev/vda");
|
||||||
|
cmdline.push("rw");
|
||||||
|
cmdline.push_set_val("init", "/usr/bin/ph-init");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open(config: VmConfig) -> Result<Vm> {
|
||||||
|
let kernel_path = config.get_kernel_path()?;
|
||||||
|
|
||||||
|
let mut memory = Self::create_memory_manager(config.ram_size())?;
|
||||||
|
|
||||||
|
let mut cmdline = KernelCmdLine::new_default();
|
||||||
|
|
||||||
|
setup::kernel::load_pm_kernel(memory.guest_ram(), &kernel_path, cmdline.address(), cmdline.size())?;
|
||||||
|
|
||||||
let io_dispatch = IoDispatcher::new();
|
let io_dispatch = IoDispatcher::new();
|
||||||
|
|
||||||
kvm.create_vcpus(config.ncpus)?;
|
memory.kvm_mut().create_vcpus(config.ncpus())?;
|
||||||
|
|
||||||
devices::rtc::Rtc::register(io_dispatch.clone());
|
devices::rtc::Rtc::register(io_dispatch.clone());
|
||||||
|
|
||||||
if verbose {
|
if config.verbose() {
|
||||||
devices::serial::SerialDevice::register(kvm.clone(),io_dispatch.clone(), 0);
|
cmdline.push("earlyprintk=serial");
|
||||||
|
devices::serial::SerialDevice::register(memory.kvm().clone(),io_dispatch.clone(), 0);
|
||||||
|
} else {
|
||||||
|
cmdline.push("quiet");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut virtio = VirtioBus::new(memory.clone(), io_dispatch.clone(), kvm.clone());
|
let saved= Termios::from_fd(0)
|
||||||
devices::VirtioSerial::create(&mut virtio)?;
|
.map_err(ErrorKind::TerminalTermios)?;
|
||||||
devices::VirtioRandom::create(&mut virtio)?;
|
let termios = Some(saved);
|
||||||
devices::VirtioP9::create(&mut virtio, "/dev/root", "/", &config.init_path)?;
|
|
||||||
|
|
||||||
setup::mptable::setup_mptable(&memory, config.ncpus, virtio.pci_irqs())?;
|
let mut virtio = VirtioBus::new(memory.clone(), io_dispatch.clone(), memory.kvm().clone());
|
||||||
|
Self::setup_virtio(&config, &mut cmdline, &mut virtio)?;
|
||||||
|
|
||||||
|
if config.launch_systemd() {
|
||||||
|
cmdline.push("phinit.run_systemd");
|
||||||
|
}
|
||||||
|
if let Some(init_cmd) = config.get_init_cmdline() {
|
||||||
|
cmdline.push_set_val("init", init_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdline.write_to_memory(memory.guest_ram())?;
|
||||||
|
|
||||||
|
setup::mptable::setup_mptable(memory.guest_ram(), config.ncpus(), virtio.pci_irqs())?;
|
||||||
|
|
||||||
Ok(Vm {
|
Ok(Vm {
|
||||||
kvm,
|
_config: config,
|
||||||
memory,
|
memory,
|
||||||
io_dispatcher: io_dispatch,
|
io_dispatcher: io_dispatch,
|
||||||
_virtio: virtio,
|
termios,
|
||||||
|
_virtio: Arc::new(virtio),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(&self) -> Result<()> {
|
pub fn start(&self) -> Result<()> {
|
||||||
|
let shutdown = Arc::new(AtomicBool::new(false));
|
||||||
let mut handles = Vec::new();
|
let mut handles = Vec::new();
|
||||||
for vcpu in self.kvm.get_vcpus() {
|
for vcpu in self.memory.kvm().get_vcpus() {
|
||||||
setup::cpu::setup_protected_mode(&vcpu, KVM_KERNEL_LOAD_ADDRESS + 0x200, self.memory.guest_ram())?;
|
setup::cpu::setup_protected_mode(&vcpu, KVM_KERNEL_LOAD_ADDRESS + 0x200, self.memory.guest_ram())?;
|
||||||
let mut run_area = KvmRunArea::new(vcpu, shutdown.clone(), self.io_dispatcher.clone())?;
|
let mut run_area = KvmRunArea::new(vcpu, shutdown.clone(), self.io_dispatcher.clone())?;
|
||||||
let h = thread::spawn(move || run_area.run());
|
let h = thread::spawn(move || run_area.run());
|
||||||
@ -147,6 +185,10 @@ impl Vm {
|
|||||||
for h in handles {
|
for h in handles {
|
||||||
h.join().expect("...");
|
h.join().expect("...");
|
||||||
}
|
}
|
||||||
|
if let Some(termios) = self.termios {
|
||||||
|
let _ = termios::tcsetattr(0, termios::TCSANOW, &termios)
|
||||||
|
.map_err(ErrorKind::TerminalTermios)?;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ use crate::kvm::KvmVcpu;
|
|||||||
use crate::memory::Mapping;
|
use crate::memory::Mapping;
|
||||||
use super::Result;
|
use super::Result;
|
||||||
use super::io::IoDispatcher;
|
use super::io::IoDispatcher;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
const KVM_EXIT_UNKNOWN:u32 = 0;
|
const KVM_EXIT_UNKNOWN:u32 = 0;
|
||||||
const KVM_EXIT_IO:u32 = 2;
|
const KVM_EXIT_IO:u32 = 2;
|
||||||
@ -17,6 +18,7 @@ pub struct KvmRunArea {
|
|||||||
vcpu: KvmVcpu,
|
vcpu: KvmVcpu,
|
||||||
io: Arc<IoDispatcher>,
|
io: Arc<IoDispatcher>,
|
||||||
mapping: Mapping,
|
mapping: Mapping,
|
||||||
|
shutdown: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IoExitData {
|
pub struct IoExitData {
|
||||||
@ -34,13 +36,14 @@ pub struct MmioExitData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl KvmRunArea {
|
impl KvmRunArea {
|
||||||
pub fn new(vcpu: KvmVcpu, io_dispatcher: Arc<IoDispatcher>) -> Result<KvmRunArea> {
|
pub fn new(vcpu: KvmVcpu, shutdown: Arc<AtomicBool>, io_dispatcher: Arc<IoDispatcher>) -> Result<KvmRunArea> {
|
||||||
let size = vcpu.get_vcpu_mmap_size()?;
|
let size = vcpu.get_vcpu_mmap_size()?;
|
||||||
let mapping = Mapping::new_from_fd(vcpu.raw_fd(), size)?;
|
let mapping = Mapping::new_from_fd(vcpu.raw_fd(), size)?;
|
||||||
Ok(KvmRunArea{
|
Ok(KvmRunArea{
|
||||||
vcpu,
|
vcpu,
|
||||||
io: io_dispatcher,
|
io: io_dispatcher,
|
||||||
mapping,
|
mapping,
|
||||||
|
shutdown,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,6 +100,9 @@ impl KvmRunArea {
|
|||||||
} else {
|
} else {
|
||||||
self.handle_exit();
|
self.handle_exit();
|
||||||
}
|
}
|
||||||
|
if self.shutdown.load(Ordering::Relaxed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,8 +112,8 @@ impl KvmRunArea {
|
|||||||
KVM_EXIT_IO => { self.handle_exit_io() },
|
KVM_EXIT_IO => { self.handle_exit_io() },
|
||||||
KVM_EXIT_MMIO => { self.handle_exit_mmio() },
|
KVM_EXIT_MMIO => { self.handle_exit_mmio() },
|
||||||
KVM_EXIT_INTR => { println!("intr")},
|
KVM_EXIT_INTR => { println!("intr")},
|
||||||
KVM_EXIT_SHUTDOWN => { println!("shut");
|
KVM_EXIT_SHUTDOWN => {
|
||||||
self.handle_problem();
|
self.handle_shutdown();
|
||||||
},
|
},
|
||||||
KVM_EXIT_SYSTEM_EVENT => { println!("event")},
|
KVM_EXIT_SYSTEM_EVENT => { println!("event")},
|
||||||
KVM_EXIT_INTERNAL_ERROR => {
|
KVM_EXIT_INTERNAL_ERROR => {
|
||||||
@ -120,7 +126,11 @@ impl KvmRunArea {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_problem(&mut self) {
|
fn handle_shutdown(&mut self) {
|
||||||
|
self.shutdown.store(true, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _handle_problem(&mut self) {
|
||||||
let regs = self.vcpu.get_regs().unwrap();
|
let regs = self.vcpu.get_regs().unwrap();
|
||||||
let sregs = self.vcpu.get_sregs().unwrap();
|
let sregs = self.vcpu.get_sregs().unwrap();
|
||||||
println!("REGS:\n{:?}", regs);
|
println!("REGS:\n{:?}", regs);
|
||||||
|
Loading…
Reference in New Issue
Block a user