Skip to content

Commit 18bc6b9

Browse files
dianpopaandreeaflorescu
authored andcommitted
aarch64: update main doc
The main doc example for running some machine code in a microVM is adapted to also support aarch64 architecture. Signed-off-by: Diana Popa <[email protected]>
1 parent a1f6425 commit 18bc6b9

File tree

1 file changed

+67
-36
lines changed

1 file changed

+67
-36
lines changed

src/lib.rs

Lines changed: 67 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@
2424
//! # Example - Running a VM on x86_64
2525
//!
2626
//! In this example we are creating a Virtual Machine (VM) with one vCPU.
27-
//! On the vCPU we are running x86_64 specific code. This example is based on
27+
//! On the vCPU we are running machine specific code. This example is based on
2828
//! the [LWN article](https://lwn.net/Articles/658511/) on using the KVM API.
29+
//! The aarch64 example was modfied accordingly.
2930
//!
3031
//! To get code running on the vCPU we are going through the following steps:
3132
//!
@@ -37,7 +38,7 @@
3738
//! are adding only one memory region and write the code in one memory page.
3839
//! 4. Create a vCPU using the VM object. The vCPU is used for running
3940
//! [vCPU specific ioctls](struct.VcpuFd.html).
40-
//! 5. Setup x86 specific general purpose registers and special registers. For
41+
//! 5. Setup architectural specific general purpose registers and special registers. For
4142
//! details about how and why these registers are set, please check the
4243
//! [LWN article](https://lwn.net/Articles/658511/) on which this example is
4344
//! built.
@@ -52,7 +53,6 @@
5253
//! use kvm_ioctls::{Kvm, VmFd, VcpuFd};
5354
//! use kvm_ioctls::VcpuExit;
5455
//!
55-
//! #[cfg(target_arch = "x86_64")]
5656
//! fn main(){
5757
//! use std::io::Write;
5858
//! use std::slice;
@@ -61,15 +61,41 @@
6161
//! use kvm_bindings::KVM_MEM_LOG_DIRTY_PAGES;
6262
//! use kvm_bindings::kvm_userspace_memory_region;
6363
//!
64+
//! let mem_size = 0x4000;
65+
//! let guest_addr = 0x1000;
66+
//! let asm_code: &[u8];
67+
//!
68+
//! // Setting up architectural dependent values.
69+
//! #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
70+
//! {
71+
//! asm_code = &[
72+
//! 0xba, 0xf8, 0x03, /* mov $0x3f8, %dx */
73+
//! 0x00, 0xd8, /* add %bl, %al */
74+
//! 0x04, b'0', /* add $'0', %al */
75+
//! 0xee, /* out %al, %dx */
76+
//! 0xec, /* in %dx, %al */
77+
//! 0xc6, 0x06, 0x00, 0x80, 0x00, /* movl $0, (0x8000); This generates a MMIO Write.*/
78+
//! 0x8a, 0x16, 0x00, 0x80, /* movl (0x8000), %dl; This generates a MMIO Read.*/
79+
//! 0xf4, /* hlt */
80+
//! ];
81+
//! }
82+
//! #[cfg(target_arch = "aarch64")]
83+
//! {
84+
//! asm_code = &[
85+
//! 0x01, 0x00, 0x00, 0x10, /* adr x1, <this address> */
86+
//! 0x22, 0x10, 0x00, 0xb9, /* str w2, [x1, #16]; write to this page */
87+
//! 0x02, 0x00, 0x00, 0xb9, /* str w2, [x0]; This generates a MMIO Write.*/
88+
//! 0x00, 0x00, 0x00, 0x14, /* b <this address>; shouldn't get here, but if so loop forever */
89+
//! ];
90+
//! }
91+
//!
6492
//! // 1. Instantiate KVM.
6593
//! let kvm = Kvm::new().unwrap();
6694
//!
6795
//! // 2. Create a VM.
6896
//! let vm = kvm.create_vm().unwrap();
6997
//!
7098
//! // 3. Initialize Guest Memory.
71-
//! let mem_size = 0x4000;
72-
//! let guest_addr: u64 = 0x1000;
7399
//! let load_addr: *mut u8 = unsafe {
74100
//! libc::mmap(
75101
//! null_mut(),
@@ -93,39 +119,44 @@
93119
//! };
94120
//! unsafe { vm.set_user_memory_region(mem_region).unwrap() };
95121
//!
96-
//!
97-
//! let x86_code = [
98-
//! 0xba, 0xf8, 0x03, /* mov $0x3f8, %dx */
99-
//! 0x00, 0xd8, /* add %bl, %al */
100-
//! 0x04, b'0', /* add $'0', %al */
101-
//! 0xee, /* out %al, %dx */
102-
//! 0xec, /* in %dx, %al */
103-
//! 0xc6, 0x06, 0x00, 0x80, 0x00, /* movl $0, (0x8000); This generates a MMIO Write.*/
104-
//! 0x8a, 0x16, 0x00, 0x80, /* movl (0x8000), %dl; This generates a MMIO Read.*/
105-
//! 0xf4, /* hlt */
106-
//! ];
107-
//!
108122
//! // Write the code in the guest memory. This will generate a dirty page.
109123
//! unsafe {
110124
//! let mut slice = slice::from_raw_parts_mut(load_addr, mem_size);
111-
//! slice.write(&x86_code).unwrap();
125+
//! slice.write(&asm_code).unwrap();
112126
//! }
113127
//!
114128
//! // 4. Create one vCPU.
115129
//! let vcpu_fd = vm.create_vcpu(0).unwrap();
116130
//!
117131
//! // 5. Initialize general purpose and special registers.
118-
//! let mut vcpu_sregs = vcpu_fd.get_sregs().unwrap();
119-
//! vcpu_sregs.cs.base = 0;
120-
//! vcpu_sregs.cs.selector = 0;
121-
//! vcpu_fd.set_sregs(&vcpu_sregs).unwrap();
122-
//!
123-
//! let mut vcpu_regs = vcpu_fd.get_regs().unwrap();
124-
//! vcpu_regs.rip = guest_addr;
125-
//! vcpu_regs.rax = 2;
126-
//! vcpu_regs.rbx = 3;
127-
//! vcpu_regs.rflags = 2;
128-
//! vcpu_fd.set_regs(&vcpu_regs).unwrap();
132+
//! #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
133+
//! {
134+
//! // x86_64 specific registry setup.
135+
//! let mut vcpu_sregs = vcpu_fd.get_sregs().unwrap();
136+
//! vcpu_sregs.cs.base = 0;
137+
//! vcpu_sregs.cs.selector = 0;
138+
//! vcpu_fd.set_sregs(&vcpu_sregs).unwrap();
139+
//!
140+
//! let mut vcpu_regs = vcpu_fd.get_regs().unwrap();
141+
//! vcpu_regs.rip = guest_addr;
142+
//! vcpu_regs.rax = 2;
143+
//! vcpu_regs.rbx = 3;
144+
//! vcpu_regs.rflags = 2;
145+
//! vcpu_fd.set_regs(&vcpu_regs).unwrap();
146+
//! }
147+
//!
148+
//! #[cfg(target_arch = "aarch64")]
149+
//! {
150+
//! // aarch64 specific registry setup.
151+
//! let mut kvi = kvm_bindings::kvm_vcpu_init::default();
152+
//! vm.get_preferred_target(&mut kvi).unwrap();
153+
//! vcpu_fd.vcpu_init(&kvi).unwrap();
154+
//!
155+
//! let core_reg_base: u64 = 0x6030_0000_0010_0000;
156+
//! let mmio_addr: u64 = guest_addr + mem_size as u64;
157+
//! vcpu_fd.set_one_reg(core_reg_base + 2 * 32, guest_addr); // set PC
158+
//! vcpu_fd.set_one_reg(core_reg_base + 2 * 0, mmio_addr); // set X0
159+
//! }
129160
//!
130161
//! // 6. Run code on the vCPU.
131162
//! loop {
@@ -155,26 +186,26 @@
155186
//! "Received an MMIO Write Request to the address {:#x}.",
156187
//! addr,
157188
//! );
158-
//! }
159-
//! VcpuExit::Hlt => {
160189
//! // The code snippet dirties 1 page when it is loaded in memory
161190
//! let dirty_pages_bitmap = vm.get_dirty_log(slot, mem_size).unwrap();
162191
//! let dirty_pages = dirty_pages_bitmap
163192
//! .into_iter()
164193
//! .map(|page| page.count_ones())
165194
//! .fold(0, |dirty_page_count, i| dirty_page_count + i);
166195
//! assert_eq!(dirty_pages, 1);
196+
//! // Since on aarch64 there is not halt instruction,
197+
//! // we break immediately after the last known instruction
198+
//! // of the asm code example so that we avoid an infinite loop.
199+
//! #[cfg(target_arch = "aarch64")]
200+
//! break;
201+
//! }
202+
//! VcpuExit::Hlt => {
167203
//! break;
168204
//! }
169205
//! r => panic!("Unexpected exit reason: {:?}", r),
170206
//! }
171207
//! }
172208
//! }
173-
//!
174-
//! #[cfg(not(target_arch = "x86_64"))]
175-
//! fn main() {
176-
//! println!("This code example only works on x86_64.");
177-
//! }
178209
//! ```
179210
180211
extern crate kvm_bindings;

0 commit comments

Comments
 (0)