Skip to content

Commit 86e6b16

Browse files
committed
Add Apple Silicon example
Signed-off-by: Maksym Pavlenko <pavlenko.maksym@gmail.com>
1 parent 1fe56a5 commit 86e6b16

5 files changed

Lines changed: 111 additions & 17 deletions

File tree

hv/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ readme = "../README.md"
1010

1111
[dependencies]
1212
bitflags = "1.2"
13-
1413
hv-sys = { path = "../hv-sys", version = "0.1.0" }
1514

15+
[dev-dependencies]
16+
libc = "0.2"
17+
1618
[features]
1719
hv_10_15 = []
1820
default = ["hv_10_15"]

hv/examples/as.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// Apple Silicon example.
2+
// Adapted from https://github.com/zhuowei/FakeHVF/blob/main/simplevm.c
3+
4+
use std::ptr;
5+
6+
use hv::arm64::{Reg, VcpuExt};
7+
8+
static CODE: &[u8] = &[
9+
// Compute ((2 + 2) - 1)
10+
0x40, 0x00, 0x80, 0xD2, // mov x0, #2
11+
0x00, 0x08, 0x00, 0x91, // add x0, x0, #2
12+
0x00, 0x04, 0x00, 0xD1, // sub x0, x0, #1
13+
// Write it to memory pointed by x1
14+
0x20, 0x00, 0x00, 0xF9, // str x0, [x1]
15+
// Reboot the computer with PSCI/SMCCC
16+
// 0x84000009 is PSCI SYSTEM_RESET using SMC32 calling convention
17+
0x20, 0x01, 0x80, 0xd2, // mov x0, 0x0009
18+
0x00, 0x80, 0xb0, 0xf2, // movk x0, 0x8400, lsl #16
19+
0x02, 0x00, 0x00, 0xD4, // hvc #0
20+
// Infinite loop
21+
0x00, 0x00, 0x00, 0x14,
22+
];
23+
24+
const MEM_SIZE: usize = 0x100000;
25+
const GUEST_ADDR: usize = 0x69420000;
26+
27+
const RESULT_OFFSET: usize = 0x100;
28+
const GUEST_RESULT_ADDR: usize = GUEST_ADDR + RESULT_OFFSET;
29+
30+
fn main() -> Result<(), hv::Error> {
31+
let load_addr = unsafe {
32+
libc::mmap(
33+
ptr::null_mut(),
34+
MEM_SIZE,
35+
libc::PROT_READ | libc::PROT_WRITE,
36+
libc::MAP_ANONYMOUS | libc::MAP_PRIVATE | libc::MAP_NORESERVE,
37+
-1,
38+
0,
39+
) as *mut u8
40+
};
41+
42+
if load_addr == libc::MAP_FAILED as _ {
43+
panic!("libc::mmap returned MAP_FAILED");
44+
}
45+
46+
unsafe {
47+
ptr::copy_nonoverlapping(CODE.as_ptr(), load_addr, CODE.len());
48+
}
49+
50+
// Init VM
51+
hv::Vm::create_vm(ptr::null_mut()).expect("Failed to create VM");
52+
53+
// Initialize guest memory
54+
hv::Vm::map(
55+
load_addr,
56+
GUEST_ADDR as _,
57+
MEM_SIZE as _,
58+
hv::Memory::READ | hv::Memory::WRITE | hv::Memory::EXEC,
59+
)
60+
.expect("Failed to map guest memory");
61+
62+
// Create VCPU
63+
let cpu = hv::Vm::create_cpu().expect("Failed to create CPU");
64+
65+
// Register regs
66+
cpu.set_reg(Reg::PC, GUEST_ADDR as _)
67+
.expect("Failed to set PC reg");
68+
69+
cpu.set_reg(Reg::X1, GUEST_RESULT_ADDR as _)
70+
.expect("Failed to set X1");
71+
72+
loop {
73+
cpu.run().expect("Failed to run CPU");
74+
75+
let info = cpu.exit_info();
76+
println!("{:?}", info);
77+
78+
break;
79+
}
80+
81+
let result_addr = unsafe { load_addr.add(RESULT_OFFSET) } as *const u64;
82+
let result = unsafe { *result_addr };
83+
84+
println!("Result: {}", result);
85+
assert_eq!(result, 3);
86+
87+
drop(cpu);
88+
89+
hv::Vm::destroy()?;
90+
91+
Ok(())
92+
}

hv/src/arm64/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::{call, sys, Error, Vcpu};
66

77
mod regs;
88
pub use regs::*;
9+
use std::process::exit;
910

1011
/// Injected interrupt type.
1112
#[repr(u32)]

hv/src/lib.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! `hv` is a high level safe Rust crate to access Hypervisor Framework.
22
33
use std::error;
4-
use std::ffi::c_void;
54
use std::fmt;
65

76
/// Low level access to generated bindings.
@@ -20,11 +19,20 @@ pub mod x86;
2019
pub type Size = u64;
2120

2221
/// Type of a user virtual address.
23-
pub type Addr = *const c_void;
22+
pub type Addr = *const u8;
2423

2524
/// Type of a guest physical address.
2625
pub type GPAddr = u64;
2726

27+
bitflags::bitflags! {
28+
/// Guest physical memory region permissions.
29+
pub struct Memory: u32 {
30+
const READ = sys::HV_MEMORY_READ;
31+
const WRITE = sys::HV_MEMORY_WRITE;
32+
const EXEC = sys::HV_MEMORY_EXEC;
33+
}
34+
}
35+
2836
/// Helper macro to call unsafe Hypervisor functions and map returned error codes to [Error] type.
2937
#[macro_export]
3038
macro_rules! call {

hv/src/vm.rs

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,20 @@
11
use std::ffi::c_void;
22

3-
use crate::{call, sys, Addr, Error, GPAddr, Size, Vcpu};
4-
5-
bitflags::bitflags! {
6-
/// Guest physical memory region permissions.
7-
pub struct Memory: u32 {
8-
const READ = sys::HV_MEMORY_READ;
9-
const WRITE = sys::HV_MEMORY_WRITE;
10-
const EXEC = sys::HV_MEMORY_EXEC;
11-
}
12-
}
3+
use crate::{call, sys, Addr, Error, GPAddr, Memory, Size, Vcpu};
134

145
/// Vm is an entry point to Hypervisor Framework.
156
#[derive(Debug)]
167
pub struct Vm;
178

189
#[cfg(target_arch = "x86_64")]
19-
pub type VmOptions = crate::x86::VmOptions;
10+
pub type Options = crate::x86::VmOptions;
2011

2112
#[cfg(target_arch = "aarch64")]
22-
pub type VmOptions = sys::hv_vm_config_t;
13+
pub type Options = sys::hv_vm_config_t;
2314

2415
impl Vm {
2516
/// Creates a VM instance for the current process.
26-
pub fn create_vm(options: VmOptions) -> Result<(), Error> {
17+
pub fn create_vm(options: Options) -> Result<(), Error> {
2718
#[cfg(target_arch = "x86_64")]
2819
let options = options.bits();
2920

@@ -54,7 +45,7 @@ impl Vm {
5445
uva as *mut c_void,
5546
gpa,
5647
size,
57-
flags.bits().into()
48+
flags.bits() as _
5849
))
5950
}
6051

0 commit comments

Comments
 (0)