Skip to content

Commit

Permalink
Port kvm io example to use assembled function
Browse files Browse the repository at this point in the history
  • Loading branch information
Ericson2314 committed Jul 15, 2016
1 parent b18825b commit 0a52a0d
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ performance-counter = ["phf", "phf_codegen", "csv", "serde_json"]
name = "no_std_build"
harness = false

[[test]]
name = "kvm"
path = "tests/kvm/bin.rs"

[build-dependencies]
phf_codegen = { version = "0.7.7", optional = true }
csv = { version = "0.14.3", optional = true }
Expand All @@ -37,3 +41,7 @@ serde_json = { version = "0.6.0", optional = true }
bitflags = "0.7"
raw-cpuid = "2.*"
phf = { version = "0.7.7", optional = true, features = ["core"] }

[dev-dependencies]
kvm = "0.2"
memmap = "0.2.1"
5 changes: 5 additions & 0 deletions test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh

rm target/debug/kvm-1204d1237e8c62b6
export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER="$(dirname $0)/tests/kvm/linker.sh"
cargo test --test kvm -- "$@"
112 changes: 112 additions & 0 deletions tests/kvm/bin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#![feature(linkage, naked_functions, asm)]
// In this example we will construct a single CPU x86 VM which will execute
// "inb 0x01" at ring 0 with paging disabled

extern crate kvm;
extern crate memmap;

use kvm::{Capability, Exit, IoDirection, System, Vcpu, VirtualMachine};
use memmap::{Mmap, Protection};

//#[allow(improper_ctypes)]
extern {
static kvmtest_begin_loc: u8;
static kvmtest_end_loc: u8;
}

#[naked]
//#[allow(dead_code)]
#[link_section = ".kvmtest"]
#[linkage = "external" ]
unsafe extern "C" fn use_the_port() {
asm!("inb $0, %al" :: "i"(0x01) :: "volatile");
}

#[test]
fn io_example() {
// Allocate 2MB for the guest memory
let mut anon_mmap = Mmap::anonymous(2 * (1 << 20), Protection::ReadWrite)
.unwrap();
let slice = unsafe { anon_mmap.as_mut_slice() };

let slice2: &mut [u8] = {
let kvmtest_begin: *mut u8 = &kvmtest_begin_loc as *const _ as _;
let kvmtest_end: *mut u8 = &kvmtest_end_loc as *const _ as _;
unsafe {
::std::slice::from_raw_parts_mut(
kvmtest_begin,
(kvmtest_end as usize) - (kvmtest_begin as usize))
}
};

slice[0x100000..][..slice2.len()].copy_from_slice(slice2);

println!("fn: {:x}", use_the_port as usize); // make sure is used

println!("slice: {:?}", slice2.as_ptr());
println!("len: {:x}", slice2.len());
println!("{:x}", slice[0]);
println!("{:x}", slice[1]);
println!("{:?}", &slice[..10]);

// Initialize the KVM system
let sys = System::initialize().unwrap();

// Create a Virtual Machine
let mut vm = VirtualMachine::create(&sys).unwrap();

// Ensure that the VM supports memory backing with user memory
assert!(vm.check_capability(Capability::UserMemory) > 0);
// Set the 2 MB range to start at physical address 0
vm.set_user_memory_region(0, slice, 0).unwrap();

// Create a new VCPU
let mut vcpu = Vcpu::create(&mut vm).unwrap();

// Set supported CPUID (KVM fails without doing this)
let mut cpuid = sys.get_supported_cpuid().unwrap();
vcpu.set_cpuid2(&mut cpuid).unwrap();

// Setup the special registers
let mut sregs = vcpu.get_sregs().unwrap();

// Set the code segment to have base 0, limit 4GB (flat segmentation)
sregs.cs.base = 0x0;
sregs.cs.limit = 0xffffffff;
sregs.cs.selector = 0x8;
sregs.cs._type = 0xb;
sregs.cs.present = 1;
sregs.cs.dpl = 0;
sregs.cs.db = 0;
sregs.cs.s = 1;
sregs.cs.l = 0;
sregs.cs.g = 1;
sregs.cs.avl = 0;

// We don't need to populate the GDT if we have our segments setup
// cr0 - protected mode on, paging disabled
sregs.cr0 = 0x50033;

// Set the special registers
vcpu.set_sregs(&sregs).unwrap();

let mut regs = vcpu.get_regs().unwrap();
// set the instruction pointer to 1 MB
regs.rip = 0x100000;
regs.rflags = 0x2;
vcpu.set_regs(&regs).unwrap();

// Actually run the VCPU
let run = unsafe { vcpu.run() }.unwrap();

// Ensure that the exit reason we get back indicates that the I/O
// instruction was executed
assert!(run.exit_reason == Exit::Io);
let io = unsafe { *run.io() };
assert!(io.direction == IoDirection::In);
assert!(io.size == 1);
assert!(io.port == 0x1);
unsafe {
println!("{:#?}", *run.io());
}
}
16 changes: 16 additions & 0 deletions tests/kvm/link.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*PHDRS
{
test PT_LOAD FLAGS(0x7); /* rwx 0b111 *//*
}*/

SECTIONS
{
.kvmtest :
{
kvmtest_begin_loc = .;
*(.kvmtest*)
kvmtest_end_loc = .;
} /* :test */
}

INSERT AFTER .rodata; /* do not override default script */
5 changes: 5 additions & 0 deletions tests/kvm/linker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh
set -x

${CC:=cc}
$CC -T $(dirname $0)/link.ld "$@"

0 comments on commit 0a52a0d

Please sign in to comment.