mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-22 13:45:20 +00:00
cloud-hypervisor: Initial kernel booting implementation
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
parent
b56b4ca834
commit
539367b58c
33
Cargo.lock
generated
33
Cargo.lock
generated
@ -3,6 +3,22 @@ name = "ansi_term"
|
|||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arch"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"arch_gen 0.1.0",
|
||||||
|
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"kvm-bindings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"kvm-ioctls 0.1.0 (git+https://github.com/rust-vmm/kvm-ioctls)",
|
||||||
|
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"vm-memory 0.1.0 (git+https://github.com/rust-vmm/vm-memory)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arch_gen"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.11"
|
version = "0.2.11"
|
||||||
@ -18,6 +34,11 @@ name = "bitflags"
|
|||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "2.27.1"
|
version = "2.27.1"
|
||||||
@ -59,6 +80,14 @@ name = "libc"
|
|||||||
version = "0.2.48"
|
version = "0.2.48"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-loader"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/sameo/linux-loader#f0905480bd9f9aae8b88c63ca5dd6f3469483b65"
|
||||||
|
dependencies = [
|
||||||
|
"vm-memory 0.1.0 (git+https://github.com/rust-vmm/vm-memory)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.1.51"
|
version = "0.1.51"
|
||||||
@ -117,8 +146,10 @@ dependencies = [
|
|||||||
name = "vmm"
|
name = "vmm"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"arch 0.1.0",
|
||||||
"kvm-bindings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"kvm-bindings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"kvm-ioctls 0.1.0 (git+https://github.com/rust-vmm/kvm-ioctls)",
|
"kvm-ioctls 0.1.0 (git+https://github.com/rust-vmm/kvm-ioctls)",
|
||||||
|
"linux-loader 0.1.0 (git+https://github.com/sameo/linux-loader)",
|
||||||
"vm-memory 0.1.0 (git+https://github.com/rust-vmm/vm-memory)",
|
"vm-memory 0.1.0 (git+https://github.com/rust-vmm/vm-memory)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -145,10 +176,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
|
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
|
||||||
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||||
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
||||||
|
"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
|
||||||
"checksum clap 2.27.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1b8c532887f1a292d17de05ae858a8fe50a301e196f9ef0ddb7ccd0d1d00f180"
|
"checksum clap 2.27.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1b8c532887f1a292d17de05ae858a8fe50a301e196f9ef0ddb7ccd0d1d00f180"
|
||||||
"checksum kvm-bindings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c223e8703d2eb76d990c5f58e29c85b0f6f50e24b823babde927948e7c71fc03"
|
"checksum kvm-bindings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c223e8703d2eb76d990c5f58e29c85b0f6f50e24b823babde927948e7c71fc03"
|
||||||
"checksum kvm-ioctls 0.1.0 (git+https://github.com/rust-vmm/kvm-ioctls)" = "<none>"
|
"checksum kvm-ioctls 0.1.0 (git+https://github.com/rust-vmm/kvm-ioctls)" = "<none>"
|
||||||
"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
|
"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
|
||||||
|
"checksum linux-loader 0.1.0 (git+https://github.com/sameo/linux-loader)" = "<none>"
|
||||||
"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85"
|
"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85"
|
||||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||||
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
|
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
|
||||||
|
@ -32,5 +32,5 @@ fn main() {
|
|||||||
|
|
||||||
println!("Booting {:?}...", kernel_path.as_path());
|
println!("Booting {:?}...", kernel_path.as_path());
|
||||||
|
|
||||||
vmm::test_vm()
|
vmm::boot_kernel(kernel_path.as_path()).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,10 @@ authors = ["The Cloud Hypervisor Authors"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
arch = { path = "../arch" }
|
||||||
kvm-bindings = "0.1"
|
kvm-bindings = "0.1"
|
||||||
kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls" }
|
kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls" }
|
||||||
|
linux-loader = { git = "https://github.com/sameo/linux-loader" }
|
||||||
|
|
||||||
[dependencies.vm-memory]
|
[dependencies.vm-memory]
|
||||||
git = "https://github.com/rust-vmm/vm-memory"
|
git = "https://github.com/rust-vmm/vm-memory"
|
||||||
|
120
vmm/src/lib.rs
120
vmm/src/lib.rs
@ -4,110 +4,30 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
extern crate kvm_ioctls;
|
extern crate kvm_ioctls;
|
||||||
extern crate vm_memory;
|
|
||||||
|
|
||||||
use kvm_bindings::kvm_userspace_memory_region;
|
|
||||||
use kvm_ioctls::*;
|
use kvm_ioctls::*;
|
||||||
use std::str;
|
use std::path::Path;
|
||||||
use vm_memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap, GuestMemoryRegion};
|
pub mod vm;
|
||||||
|
|
||||||
pub fn test_vm() {
|
use self::vm::{Result, Vm};
|
||||||
// This example based on https://lwn.net/Articles/658511/
|
|
||||||
let code = [
|
|
||||||
0xba, 0xf8, 0x03, /* mov $0x3f8, %dx */
|
|
||||||
0x00, 0xd8, /* add %bl, %al */
|
|
||||||
0x04, b'0', /* add $'0', %al */
|
|
||||||
0xee, /* out %al, (%dx) */
|
|
||||||
0xb0, b'\n', /* mov $'\n', %al */
|
|
||||||
0xee, /* out %al, (%dx) */
|
|
||||||
0xf4, /* hlt */
|
|
||||||
];
|
|
||||||
|
|
||||||
let mem_size = 0x1000;
|
struct Vmm {
|
||||||
let load_addr = GuestAddress(0x1000);
|
kvm: Kvm,
|
||||||
let mem = GuestMemoryMmap::new(&[(load_addr, mem_size)]).unwrap();
|
}
|
||||||
|
|
||||||
let kvm = Kvm::new().expect("new KVM instance creation failed");
|
impl Vmm {
|
||||||
let vm_fd = kvm.create_vm().expect("new VM fd creation failed");
|
fn new() -> Result<Self> {
|
||||||
|
let kvm = Kvm::new().expect("new KVM instance creation failed");
|
||||||
mem.with_regions(|index, region| {
|
Ok(Vmm { kvm })
|
||||||
let mem_region = kvm_userspace_memory_region {
|
|
||||||
slot: index as u32,
|
|
||||||
guest_phys_addr: region.start_addr().raw_value(),
|
|
||||||
memory_size: region.len() as u64,
|
|
||||||
userspace_addr: region.as_ptr() as u64,
|
|
||||||
flags: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Safe because the guest regions are guaranteed not to overlap.
|
|
||||||
vm_fd.set_user_memory_region(mem_region)
|
|
||||||
})
|
|
||||||
.expect("Cannot configure guest memory");
|
|
||||||
|
|
||||||
mem.write_slice(&code, load_addr)
|
|
||||||
.expect("Writing code to memory failed");
|
|
||||||
|
|
||||||
let vcpu_fd = vm_fd.create_vcpu(0).expect("new VcpuFd failed");
|
|
||||||
|
|
||||||
let mut vcpu_sregs = vcpu_fd.get_sregs().expect("get sregs failed");
|
|
||||||
vcpu_sregs.cs.base = 0;
|
|
||||||
vcpu_sregs.cs.selector = 0;
|
|
||||||
vcpu_fd.set_sregs(&vcpu_sregs).expect("set sregs failed");
|
|
||||||
|
|
||||||
let mut vcpu_regs = vcpu_fd.get_regs().expect("get regs failed");
|
|
||||||
vcpu_regs.rip = 0x1000;
|
|
||||||
vcpu_regs.rax = 2;
|
|
||||||
vcpu_regs.rbx = 3;
|
|
||||||
vcpu_regs.rflags = 2;
|
|
||||||
vcpu_fd.set_regs(&vcpu_regs).expect("set regs failed");
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match vcpu_fd.run().expect("run failed") {
|
|
||||||
VcpuExit::IoIn(addr, data) => {
|
|
||||||
println!(
|
|
||||||
"IO in -- addr: {:#x} data [{:?}]",
|
|
||||||
addr,
|
|
||||||
str::from_utf8(&data).unwrap()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
VcpuExit::IoOut(addr, data) => {
|
|
||||||
println!(
|
|
||||||
"IO out -- addr: {:#x} data [{:?}]",
|
|
||||||
addr,
|
|
||||||
str::from_utf8(&data).unwrap()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
VcpuExit::MmioRead(_addr, _data) => {}
|
|
||||||
VcpuExit::MmioWrite(_addr, _data) => {}
|
|
||||||
VcpuExit::Unknown => {}
|
|
||||||
VcpuExit::Exception => {}
|
|
||||||
VcpuExit::Hypercall => {}
|
|
||||||
VcpuExit::Debug => {}
|
|
||||||
VcpuExit::Hlt => {
|
|
||||||
println!("HLT");
|
|
||||||
}
|
|
||||||
VcpuExit::IrqWindowOpen => {}
|
|
||||||
VcpuExit::Shutdown => {}
|
|
||||||
VcpuExit::FailEntry => {}
|
|
||||||
VcpuExit::Intr => {}
|
|
||||||
VcpuExit::SetTpr => {}
|
|
||||||
VcpuExit::TprAccess => {}
|
|
||||||
VcpuExit::S390Sieic => {}
|
|
||||||
VcpuExit::S390Reset => {}
|
|
||||||
VcpuExit::Dcr => {}
|
|
||||||
VcpuExit::Nmi => {}
|
|
||||||
VcpuExit::InternalError => {}
|
|
||||||
VcpuExit::Osi => {}
|
|
||||||
VcpuExit::PaprHcall => {}
|
|
||||||
VcpuExit::S390Ucontrol => {}
|
|
||||||
VcpuExit::Watchdog => {}
|
|
||||||
VcpuExit::S390Tsch => {}
|
|
||||||
VcpuExit::Epr => {}
|
|
||||||
VcpuExit::SystemEvent => {}
|
|
||||||
VcpuExit::S390Stsi => {}
|
|
||||||
VcpuExit::IoapicEoi => {}
|
|
||||||
VcpuExit::Hyperv => {}
|
|
||||||
}
|
|
||||||
// r => panic!("unexpected exit reason: {:?}", r),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn boot_kernel(kernel: &Path) -> Result<()> {
|
||||||
|
let vmm = Vmm::new()?;
|
||||||
|
let mut vm = Vm::new(&vmm.kvm, kernel)?;
|
||||||
|
|
||||||
|
vm.load_kernel()?;
|
||||||
|
vm.start()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
271
vmm/src/vm.rs
Normal file
271
vmm/src/vm.rs
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
// Copyright © 2019 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
extern crate arch;
|
||||||
|
extern crate kvm_ioctls;
|
||||||
|
extern crate linux_loader;
|
||||||
|
extern crate vm_memory;
|
||||||
|
|
||||||
|
use kvm_bindings::kvm_userspace_memory_region;
|
||||||
|
use kvm_ioctls::*;
|
||||||
|
use linux_loader::cmdline;
|
||||||
|
use linux_loader::loader::KernelLoader;
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::{io, result, str, thread};
|
||||||
|
use vm_memory::{
|
||||||
|
Address, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap, GuestMemoryRegion, GuestUsize,
|
||||||
|
MmapError,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DEFAULT_CMDLINE: &str =
|
||||||
|
"console=ttyS0,115200n8 init=/init tsc=reliable no_timer_check cryptomgr.notests";
|
||||||
|
const CMDLINE_OFFSET: GuestAddress = GuestAddress(0x20000);
|
||||||
|
|
||||||
|
/// Errors associated with the wrappers over KVM ioctls.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Cannot open the VM file descriptor.
|
||||||
|
VmFd(io::Error),
|
||||||
|
|
||||||
|
/// Cannot create the KVM instance
|
||||||
|
VmCreate(io::Error),
|
||||||
|
|
||||||
|
/// Cannot set the VM up
|
||||||
|
VmSetup(io::Error),
|
||||||
|
|
||||||
|
/// Cannot open the kernel image
|
||||||
|
KernelFile(io::Error),
|
||||||
|
|
||||||
|
/// Mmap backed guest memory error
|
||||||
|
GuestMemory(MmapError),
|
||||||
|
|
||||||
|
/// Cannot load the kernel in memory
|
||||||
|
KernelLoad(linux_loader::loader::Error),
|
||||||
|
|
||||||
|
/// Cannot load the command line in memory
|
||||||
|
CmdLine,
|
||||||
|
}
|
||||||
|
pub type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
|
struct VmConfig<'a> {
|
||||||
|
kernel_path: &'a Path,
|
||||||
|
cmdline: Option<cmdline::Cmdline>,
|
||||||
|
cmdline_addr: GuestAddress,
|
||||||
|
|
||||||
|
memory_size: GuestUsize,
|
||||||
|
vcpu_count: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Default for VmConfig<'a> {
|
||||||
|
fn default() -> Self {
|
||||||
|
let line = String::from(DEFAULT_CMDLINE);
|
||||||
|
let mut cmdline = cmdline::Cmdline::new(line.capacity());
|
||||||
|
cmdline.insert_str(line);
|
||||||
|
|
||||||
|
VmConfig {
|
||||||
|
kernel_path: Path::new(""),
|
||||||
|
cmdline: Some(cmdline),
|
||||||
|
cmdline_addr: CMDLINE_OFFSET,
|
||||||
|
memory_size: 512,
|
||||||
|
vcpu_count: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Vm<'a> {
|
||||||
|
fd: VmFd,
|
||||||
|
kernel: File,
|
||||||
|
memory: GuestMemoryMmap,
|
||||||
|
vcpus: Option<Vec<thread::JoinHandle<()>>>,
|
||||||
|
config: VmConfig<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Vm<'a> {
|
||||||
|
pub fn new(kvm: &Kvm, kernel_path: &'a Path) -> Result<Self> {
|
||||||
|
let vm_config = VmConfig {
|
||||||
|
kernel_path,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let kernel = File::open(kernel_path).map_err(Error::KernelFile)?;
|
||||||
|
let fd = kvm.create_vm().map_err(Error::VmCreate)?;
|
||||||
|
|
||||||
|
// Init guest memory
|
||||||
|
let arch_mem_regions = arch::arch_memory_regions(vm_config.memory_size << 20);
|
||||||
|
let guest_memory = GuestMemoryMmap::new(&arch_mem_regions).map_err(Error::GuestMemory)?;
|
||||||
|
|
||||||
|
guest_memory
|
||||||
|
.with_regions(|index, region| {
|
||||||
|
let mem_region = kvm_userspace_memory_region {
|
||||||
|
slot: index as u32,
|
||||||
|
guest_phys_addr: region.start_addr().raw_value(),
|
||||||
|
memory_size: region.len() as u64,
|
||||||
|
userspace_addr: region.as_ptr() as u64,
|
||||||
|
flags: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Size {:?} guest addr 0x{:x} host addr 0x{:x}",
|
||||||
|
mem_region.memory_size, mem_region.guest_phys_addr, mem_region.userspace_addr
|
||||||
|
);
|
||||||
|
|
||||||
|
// Safe because the guest regions are guaranteed not to overlap.
|
||||||
|
fd.set_user_memory_region(mem_region)
|
||||||
|
})
|
||||||
|
.map_err(|_| Error::GuestMemory(MmapError::NoMemoryRegion))?;
|
||||||
|
|
||||||
|
// Set TSS
|
||||||
|
fd.set_tss_address(arch::x86_64::layout::KVM_TSS_ADDRESS.raw_value() as usize)
|
||||||
|
.map_err(Error::VmSetup)?;
|
||||||
|
|
||||||
|
Ok(Vm {
|
||||||
|
fd,
|
||||||
|
kernel,
|
||||||
|
memory: guest_memory,
|
||||||
|
vcpus: None,
|
||||||
|
config: vm_config,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_kernel(&mut self) -> Result<GuestAddress> {
|
||||||
|
let cmdline = self.config.cmdline.clone().ok_or(Error::CmdLine)?;
|
||||||
|
|
||||||
|
let cmdline_cstring = CString::new(cmdline).map_err(|_| Error::CmdLine)?;
|
||||||
|
|
||||||
|
let entry_addr = linux_loader::loader::Elf::load(
|
||||||
|
&self.memory,
|
||||||
|
None,
|
||||||
|
&mut self.kernel,
|
||||||
|
Some(arch::HIMEM_START),
|
||||||
|
)
|
||||||
|
.map_err(Error::KernelLoad)?;
|
||||||
|
|
||||||
|
linux_loader::loader::load_cmdline(
|
||||||
|
&self.memory,
|
||||||
|
self.config.cmdline_addr,
|
||||||
|
&cmdline_cstring,
|
||||||
|
)
|
||||||
|
.map_err(|_| Error::CmdLine)?;
|
||||||
|
|
||||||
|
let vcpu_count = self.config.vcpu_count;
|
||||||
|
|
||||||
|
arch::configure_system(
|
||||||
|
&self.memory,
|
||||||
|
self.config.cmdline_addr,
|
||||||
|
cmdline_cstring.to_bytes().len() + 1,
|
||||||
|
vcpu_count,
|
||||||
|
)
|
||||||
|
.map_err(|_| Error::CmdLine)?;
|
||||||
|
|
||||||
|
Ok(entry_addr.kernel_load)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start(&mut self) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn test_vm() {
|
||||||
|
// This example based on https://lwn.net/Articles/658511/
|
||||||
|
let code = [
|
||||||
|
0xba, 0xf8, 0x03, /* mov $0x3f8, %dx */
|
||||||
|
0x00, 0xd8, /* add %bl, %al */
|
||||||
|
0x04, b'0', /* add $'0', %al */
|
||||||
|
0xee, /* out %al, (%dx) */
|
||||||
|
0xb0, b'\n', /* mov $'\n', %al */
|
||||||
|
0xee, /* out %al, (%dx) */
|
||||||
|
0xf4, /* hlt */
|
||||||
|
];
|
||||||
|
|
||||||
|
let mem_size = 0x1000;
|
||||||
|
let load_addr = GuestAddress(0x1000);
|
||||||
|
let mem = GuestMemoryMmap::new(&[(load_addr, mem_size)]).unwrap();
|
||||||
|
|
||||||
|
let kvm = Kvm::new().expect("new KVM instance creation failed");
|
||||||
|
let vm_fd = kvm.create_vm().expect("new VM fd creation failed");
|
||||||
|
|
||||||
|
mem.with_regions(|index, region| {
|
||||||
|
let mem_region = kvm_userspace_memory_region {
|
||||||
|
slot: index as u32,
|
||||||
|
guest_phys_addr: region.start_addr().raw_value(),
|
||||||
|
memory_size: region.len() as u64,
|
||||||
|
userspace_addr: region.as_ptr() as u64,
|
||||||
|
flags: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Safe because the guest regions are guaranteed not to overlap.
|
||||||
|
vm_fd.set_user_memory_region(mem_region)
|
||||||
|
})
|
||||||
|
.expect("Cannot configure guest memory");
|
||||||
|
mem.write_slice(&code, load_addr)
|
||||||
|
.expect("Writing code to memory failed");
|
||||||
|
|
||||||
|
let vcpu_fd = vm_fd.create_vcpu(0).expect("new VcpuFd failed");
|
||||||
|
|
||||||
|
let mut vcpu_sregs = vcpu_fd.get_sregs().expect("get sregs failed");
|
||||||
|
vcpu_sregs.cs.base = 0;
|
||||||
|
vcpu_sregs.cs.selector = 0;
|
||||||
|
vcpu_fd.set_sregs(&vcpu_sregs).expect("set sregs failed");
|
||||||
|
|
||||||
|
let mut vcpu_regs = vcpu_fd.get_regs().expect("get regs failed");
|
||||||
|
vcpu_regs.rip = 0x1000;
|
||||||
|
vcpu_regs.rax = 2;
|
||||||
|
vcpu_regs.rbx = 3;
|
||||||
|
vcpu_regs.rflags = 2;
|
||||||
|
vcpu_fd.set_regs(&vcpu_regs).expect("set regs failed");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match vcpu_fd.run().expect("run failed") {
|
||||||
|
VcpuExit::IoIn(addr, data) => {
|
||||||
|
println!(
|
||||||
|
"IO in -- addr: {:#x} data [{:?}]",
|
||||||
|
addr,
|
||||||
|
str::from_utf8(&data).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
VcpuExit::IoOut(addr, data) => {
|
||||||
|
println!(
|
||||||
|
"IO out -- addr: {:#x} data [{:?}]",
|
||||||
|
addr,
|
||||||
|
str::from_utf8(&data).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
VcpuExit::MmioRead(_addr, _data) => {}
|
||||||
|
VcpuExit::MmioWrite(_addr, _data) => {}
|
||||||
|
VcpuExit::Unknown => {}
|
||||||
|
VcpuExit::Exception => {}
|
||||||
|
VcpuExit::Hypercall => {}
|
||||||
|
VcpuExit::Debug => {}
|
||||||
|
VcpuExit::Hlt => {
|
||||||
|
println!("HLT");
|
||||||
|
}
|
||||||
|
VcpuExit::IrqWindowOpen => {}
|
||||||
|
VcpuExit::Shutdown => {}
|
||||||
|
VcpuExit::FailEntry => {}
|
||||||
|
VcpuExit::Intr => {}
|
||||||
|
VcpuExit::SetTpr => {}
|
||||||
|
VcpuExit::TprAccess => {}
|
||||||
|
VcpuExit::S390Sieic => {}
|
||||||
|
VcpuExit::S390Reset => {}
|
||||||
|
VcpuExit::Dcr => {}
|
||||||
|
VcpuExit::Nmi => {}
|
||||||
|
VcpuExit::InternalError => {}
|
||||||
|
VcpuExit::Osi => {}
|
||||||
|
VcpuExit::PaprHcall => {}
|
||||||
|
VcpuExit::S390Ucontrol => {}
|
||||||
|
VcpuExit::Watchdog => {}
|
||||||
|
VcpuExit::S390Tsch => {}
|
||||||
|
VcpuExit::Epr => {}
|
||||||
|
VcpuExit::SystemEvent => {}
|
||||||
|
VcpuExit::S390Stsi => {}
|
||||||
|
VcpuExit::IoapicEoi => {}
|
||||||
|
VcpuExit::Hyperv => {}
|
||||||
|
}
|
||||||
|
// r => panic!("unexpected exit reason: {:?}", r),
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user