7
7
8
8
use kvm_bindings:: * ;
9
9
use std:: fs:: File ;
10
- #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
11
10
use std:: os:: raw:: c_void;
12
11
use std:: os:: raw:: { c_int, c_ulong} ;
13
12
use std:: os:: unix:: io:: { AsRawFd , FromRawFd , RawFd } ;
@@ -697,7 +696,7 @@ impl VmFd {
697
696
/// # use kvm_bindings::{kvm_userspace_memory_region, KVM_MEM_LOG_DIRTY_PAGES};
698
697
/// # let kvm = Kvm::new().unwrap();
699
698
/// # let vm = kvm.create_vm().unwrap();
700
- /// // This examples is based on https://lwn.net/Articles/658511/.
699
+ /// // This example is based on https://lwn.net/Articles/658511/.
701
700
/// let mem_size = 0x4000;
702
701
/// let guest_addr: u64 = 0x1000;
703
702
/// let load_addr: *mut u8 = unsafe {
@@ -721,36 +720,62 @@ impl VmFd {
721
720
/// };
722
721
/// unsafe { vm.set_user_memory_region(mem_region).unwrap() };
723
722
///
724
- /// // Dummy x86 code that just calls halt.
725
- /// let x86_code = [
726
- /// 0xf4, /* hlt */
723
+ /// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
724
+ /// // ASM code that just forces a MMIO Write.
725
+ /// let asm_code = [
726
+ /// 0xc6, 0x06, 0x00, 0x80, 0x00,
727
+ /// ];
728
+ /// #[cfg(target_arch = "aarch64")]
729
+ /// let asm_code = [
730
+ /// 0x01, 0x00, 0x00, 0x10, /* adr x1, <this address> */
731
+ /// 0x22, 0x10, 0x00, 0xb9, /* str w2, [x1, #16]; write to this page */
732
+ /// 0x02, 0x00, 0x00, 0xb9, /* str w2, [x0]; force MMIO exit */
733
+ /// 0x00, 0x00, 0x00, 0x14, /* b <this address>; shouldn't get here, but if so loop forever */
727
734
/// ];
728
735
///
729
736
/// // Write the code in the guest memory. This will generate a dirty page.
730
737
/// unsafe {
731
738
/// let mut slice = slice::from_raw_parts_mut(load_addr, mem_size);
732
- /// slice.write(&x86_code ).unwrap();
739
+ /// slice.write(&asm_code ).unwrap();
733
740
/// }
734
741
///
735
742
/// let vcpu_fd = vm.create_vcpu(0).unwrap();
736
743
///
737
- /// let mut vcpu_sregs = vcpu_fd.get_sregs().unwrap();
738
- /// vcpu_sregs.cs.base = 0;
739
- /// vcpu_sregs.cs.selector = 0;
740
- /// vcpu_fd.set_sregs(&vcpu_sregs).unwrap();
744
+ /// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
745
+ /// {
746
+ /// // x86_64 specific registry setup.
747
+ /// let mut vcpu_sregs = vcpu_fd.get_sregs().unwrap();
748
+ /// vcpu_sregs.cs.base = 0;
749
+ /// vcpu_sregs.cs.selector = 0;
750
+ /// vcpu_fd.set_sregs(&vcpu_sregs).unwrap();
751
+ ///
752
+ /// let mut vcpu_regs = vcpu_fd.get_regs().unwrap();
753
+ /// // Set the Instruction Pointer to the guest address where we loaded the code.
754
+ /// vcpu_regs.rip = guest_addr;
755
+ /// vcpu_regs.rax = 2;
756
+ /// vcpu_regs.rbx = 3;
757
+ /// vcpu_regs.rflags = 2;
758
+ /// vcpu_fd.set_regs(&vcpu_regs).unwrap();
759
+ /// }
741
760
///
742
- /// let mut vcpu_regs = vcpu_fd.get_regs().unwrap();
743
- /// // Set the Instruction Pointer to the guest address where we loaded the code.
744
- /// vcpu_regs.rip = guest_addr;
745
- /// vcpu_regs.rax = 2;
746
- /// vcpu_regs.rbx = 3;
747
- /// vcpu_regs.rflags = 2;
748
- /// vcpu_fd.set_regs(&vcpu_regs).unwrap();
761
+ /// #[cfg(target_arch = "aarch64")]
762
+ /// {
763
+ /// // aarch64 specific registry setup.
764
+ /// let mut kvi = kvm_bindings::kvm_vcpu_init::default();
765
+ /// vm.get_preferred_target(&mut kvi).unwrap();
766
+ /// vcpu_fd.vcpu_init(&kvi).unwrap();
767
+ ///
768
+ /// let core_reg_base: u64 = 0x6030_0000_0010_0000;
769
+ /// let mmio_addr: u64 = guest_addr + mem_size as u64;
770
+ /// vcpu_fd.set_one_reg(core_reg_base + 2 * 32, guest_addr); // set PC
771
+ /// vcpu_fd.set_one_reg(core_reg_base + 2 * 0, mmio_addr); // set X0
772
+ /// }
749
773
///
750
774
/// loop {
751
775
/// match vcpu_fd.run().expect("run failed") {
752
- /// VcpuExit::Hlt => {
753
- /// // The code snippet dirties 1 page when loading the code in memory.
776
+ /// VcpuExit::MmioWrite(addr, data) => {
777
+ /// // On x86_64, the code snippet dirties 1 page when loading the code in memory
778
+ /// // while on aarch64 the dirty bit comes from writing to guest_addr (current PC).
754
779
/// let dirty_pages_bitmap = vm.get_dirty_log(0, mem_size).unwrap();
755
780
/// let dirty_pages = dirty_pages_bitmap
756
781
/// .into_iter()
@@ -764,7 +789,6 @@ impl VmFd {
764
789
/// }
765
790
/// ```
766
791
///
767
- #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
768
792
pub fn get_dirty_log ( & self , slot : u32 , memory_size : usize ) -> Result < Vec < u64 > > {
769
793
// Compute the length of the bitmap needed for all dirty pages in one memory slot.
770
794
// One memory page is 4KiB (4096 bits) and `KVM_GET_DIRTY_LOG` returns one dirty bit for
0 commit comments