diff options
author | Suleiman Souhlal <suleiman@google.com> | 2020-04-21 14:11:47 +0900 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-05-08 03:25:38 +0000 |
commit | 7dc915dd2af19ed4dbafb6b1b6e86733af5a922d (patch) | |
tree | d1820536e6f433eaf155b259c9d831b9360df807 | |
parent | a1c0e3c680c44ae4a949744b27f3cf0f7ea77939 (diff) | |
download | crosvm-7dc915dd2af19ed4dbafb6b1b6e86733af5a922d.tar crosvm-7dc915dd2af19ed4dbafb6b1b6e86733af5a922d.tar.gz crosvm-7dc915dd2af19ed4dbafb6b1b6e86733af5a922d.tar.bz2 crosvm-7dc915dd2af19ed4dbafb6b1b6e86733af5a922d.tar.lz crosvm-7dc915dd2af19ed4dbafb6b1b6e86733af5a922d.tar.xz crosvm-7dc915dd2af19ed4dbafb6b1b6e86733af5a922d.tar.zst crosvm-7dc915dd2af19ed4dbafb6b1b6e86733af5a922d.zip |
aarch64: Enable PMU in the guest.
This allows us to use perf/simpleperf in the guest. BUG=b:153708112 TEST=Use simpleperf in ARCVM guest on jacuzzi board. Change-Id: Ia3d7dc5bcd3ca033ddf05b5ee2593102c98e8b49 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2156592 Tested-by: kokoro <noreply+kokoro@google.com> Tested-by: Suleiman Souhlal <suleiman@chromium.org> Reviewed-by: Sonny Rao <sonnyrao@chromium.org> Reviewed-by: Dylan Reid <dgreid@chromium.org> Commit-Queue: Suleiman Souhlal <suleiman@chromium.org>
-rw-r--r-- | aarch64/src/fdt.rs | 23 | ||||
-rw-r--r-- | aarch64/src/lib.rs | 17 | ||||
-rw-r--r-- | kvm/src/cap.rs | 1 | ||||
-rw-r--r-- | kvm/src/lib.rs | 44 | ||||
-rw-r--r-- | kvm_sys/src/aarch64/bindings.rs | 5 | ||||
-rw-r--r-- | kvm_sys/src/x86/bindings.rs | 1 |
6 files changed, 89 insertions, 2 deletions
diff --git a/aarch64/src/fdt.rs b/aarch64/src/fdt.rs index fc976ef..19662c6 100644 --- a/aarch64/src/fdt.rs +++ b/aarch64/src/fdt.rs @@ -42,6 +42,8 @@ use crate::AARCH64_MMIO_SIZE; use crate::AARCH64_PCI_CFG_BASE; use crate::AARCH64_PCI_CFG_SIZE; +use crate::AARCH64_PMU_IRQ; + // This is an arbitrary number to specify the node for the GIC. // If we had a more complex interrupt architecture, then we'd need an enum for // these. @@ -137,6 +139,23 @@ fn create_timer_node(fdt: &mut Vec<u8>, num_cpus: u32) -> Result<()> { Ok(()) } +fn create_pmu_node(fdt: &mut Vec<u8>, num_cpus: u32) -> Result<()> { + let compatible = "arm,armv8-pmuv3"; + let cpu_mask: u32 = + (((1 << num_cpus) - 1) << GIC_FDT_IRQ_PPI_CPU_SHIFT) & GIC_FDT_IRQ_PPI_CPU_MASK; + let irq = generate_prop32(&[ + GIC_FDT_IRQ_TYPE_PPI, + AARCH64_PMU_IRQ, + cpu_mask | IRQ_TYPE_LEVEL_HIGH, + ]); + + begin_node(fdt, "pmu")?; + property_string(fdt, "compatible", compatible)?; + property(fdt, "interrupts", &irq)?; + end_node(fdt)?; + Ok(()) +} + fn create_serial_node(fdt: &mut Vec<u8>, addr: u64, irq: u32) -> Result<()> { let serial_reg_prop = generate_prop64(&[addr, AARCH64_SERIAL_SIZE]); let irq = generate_prop32(&[GIC_FDT_IRQ_TYPE_SPI, irq, IRQ_TYPE_EDGE_RISING]); @@ -351,6 +370,7 @@ pub fn create_fdt( initrd: Option<(GuestAddress, usize)>, android_fstab: Option<File>, is_gicv3: bool, + use_pmu: bool, ) -> Result<()> { let mut fdt = vec![0; fdt_max_size]; start_fdt(&mut fdt, fdt_max_size)?; @@ -369,6 +389,9 @@ pub fn create_fdt( create_cpu_nodes(&mut fdt, num_cpus)?; create_gic_node(&mut fdt, is_gicv3, num_cpus as u64)?; create_timer_node(&mut fdt, num_cpus)?; + if use_pmu { + create_pmu_node(&mut fdt, num_cpus)?; + } create_serial_nodes(&mut fdt)?; create_psci_node(&mut fdt)?; create_pci_nodes(&mut fdt, pci_irqs, pci_device_base, pci_device_size)?; diff --git a/aarch64/src/lib.rs b/aarch64/src/lib.rs index 4c8af6b..0a90fd4 100644 --- a/aarch64/src/lib.rs +++ b/aarch64/src/lib.rs @@ -109,6 +109,9 @@ const AARCH64_MMIO_SIZE: u64 = 0x100000; // Virtio devices start at SPI interrupt number 3 const AARCH64_IRQ_BASE: u32 = 3; +// PMU PPI interrupt, same as qemu +const AARCH64_PMU_IRQ: u32 = 7; + #[sorted] #[derive(Debug)] pub enum Error { @@ -237,6 +240,11 @@ impl arch::LinuxArch for AArch64 { let (irq_chip, is_gicv3) = Self::create_irq_chip(&vm, vcpu_count as u64)?; + let mut use_pmu = true; + for vcpu in &vcpus { + use_pmu &= vcpu.arm_pmu_init(AARCH64_PMU_IRQ as u64 + 16).is_ok(); + } + let mut mmio_bus = devices::Bus::new(); let exit_evt = EventFd::new().map_err(Error::CreateEventFd)?; @@ -315,6 +323,7 @@ impl arch::LinuxArch for AArch64 { components.android_fstab, kernel_end, is_gicv3, + use_pmu, )?; Ok(RunnableLinuxVm { @@ -346,6 +355,7 @@ impl AArch64 { android_fstab: Option<File>, kernel_end: u64, is_gicv3: bool, + use_pmu: bool, ) -> Result<()> { let initrd = match initrd_file { Some(initrd_file) => { @@ -374,6 +384,7 @@ impl AArch64 { initrd, android_fstab, is_gicv3, + use_pmu, ) .map_err(Error::CreateFdt)?; Ok(()) @@ -540,7 +551,7 @@ impl AArch64 { fn configure_vcpu( guest_mem: &GuestMemory, - _kvm: &Kvm, + kvm: &Kvm, vm: &Vm, vcpu: &Vcpu, cpu_id: u64, @@ -555,8 +566,10 @@ impl AArch64 { vm.arm_preferred_target(&mut kvi) .map_err(Error::ReadPreferredTarget)?; - // TODO(sonnyrao): need to verify this feature is supported by host kernel kvi.features[0] |= 1 << kvm_sys::KVM_ARM_VCPU_PSCI_0_2; + if kvm.check_extension(Cap::ArmPmuV3) { + kvi.features[0] |= 1 << kvm_sys::KVM_ARM_VCPU_PMU_V3; + } // Non-boot cpus are powered off initially if cpu_id > 0 { diff --git a/kvm/src/cap.rs b/kvm/src/cap.rs index 7dfd965..ff65b59 100644 --- a/kvm/src/cap.rs +++ b/kvm/src/cap.rs @@ -119,4 +119,5 @@ pub enum Cap { CheckExtensionVm = KVM_CAP_CHECK_EXTENSION_VM, S390UserSigp = KVM_CAP_S390_USER_SIGP, ImmediateExit = KVM_CAP_IMMEDIATE_EXIT, + ArmPmuV3 = KVM_CAP_ARM_PMU_V3, } diff --git a/kvm/src/lib.rs b/kvm/src/lib.rs index b8cd12b..8b98b7c 100644 --- a/kvm/src/lib.rs +++ b/kvm/src/lib.rs @@ -1763,6 +1763,50 @@ impl Vcpu { if ret < 0 { return errno_result(); } + + Ok(()) + } + + #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] + pub fn arm_pmu_init(&self, irq: u64) -> Result<()> { + let irq_addr = &irq as *const u64; + + // The in-kernel PMU virtualization is initialized by setting the irq + // with KVM_ARM_VCPU_PMU_V3_IRQ and then by KVM_ARM_VCPU_PMU_V3_INIT. + + let irq_attr = kvm_device_attr { + group: kvm_sys::KVM_ARM_VCPU_PMU_V3_CTRL, + attr: kvm_sys::KVM_ARM_VCPU_PMU_V3_IRQ as u64, + addr: irq_addr as u64, + flags: 0, + }; + // safe becuase we allocated the struct and we know the kernel will read + // exactly the size of the struct + let ret = unsafe { ioctl_with_ref(self, kvm_sys::KVM_HAS_DEVICE_ATTR(), &irq_attr) }; + if ret < 0 { + return errno_result(); + } + + // safe becuase we allocated the struct and we know the kernel will read + // exactly the size of the struct + let ret = unsafe { ioctl_with_ref(self, kvm_sys::KVM_SET_DEVICE_ATTR(), &irq_attr) }; + if ret < 0 { + return errno_result(); + } + + let init_attr = kvm_device_attr { + group: kvm_sys::KVM_ARM_VCPU_PMU_V3_CTRL, + attr: kvm_sys::KVM_ARM_VCPU_PMU_V3_INIT as u64, + addr: 0, + flags: 0, + }; + // safe becuase we allocated the struct and we know the kernel will read + // exactly the size of the struct + let ret = unsafe { ioctl_with_ref(self, kvm_sys::KVM_SET_DEVICE_ATTR(), &init_attr) }; + if ret < 0 { + return errno_result(); + } + Ok(()) } diff --git a/kvm_sys/src/aarch64/bindings.rs b/kvm_sys/src/aarch64/bindings.rs index 084fc13..0dd7f5a 100644 --- a/kvm_sys/src/aarch64/bindings.rs +++ b/kvm_sys/src/aarch64/bindings.rs @@ -157,6 +157,10 @@ pub const KVM_VGIC_V3_ADDR_TYPE_REDIST: ::std::os::raw::c_uint = 3; pub const KVM_ARM_VCPU_POWER_OFF: ::std::os::raw::c_uint = 0; pub const KVM_ARM_VCPU_EL1_32BIT: ::std::os::raw::c_uint = 1; pub const KVM_ARM_VCPU_PSCI_0_2: ::std::os::raw::c_uint = 2; +pub const KVM_ARM_VCPU_PMU_V3: ::std::os::raw::c_uint = 3; +pub const KVM_ARM_VCPU_PMU_V3_CTRL: ::std::os::raw::c_uint = 0; +pub const KVM_ARM_VCPU_PMU_V3_IRQ: ::std::os::raw::c_uint = 0; +pub const KVM_ARM_VCPU_PMU_V3_INIT: ::std::os::raw::c_uint = 1; pub const KVM_ARM_MAX_DBG_REGS: ::std::os::raw::c_uint = 16; pub const KVM_GUESTDBG_USE_SW_BP: ::std::os::raw::c_uint = 65536; pub const KVM_GUESTDBG_USE_HW: ::std::os::raw::c_uint = 131072; @@ -439,6 +443,7 @@ pub const KVM_CAP_GUEST_DEBUG_HW_BPS: ::std::os::raw::c_uint = 119; pub const KVM_CAP_GUEST_DEBUG_HW_WPS: ::std::os::raw::c_uint = 120; pub const KVM_CAP_SPLIT_IRQCHIP: ::std::os::raw::c_uint = 121; pub const KVM_CAP_IOEVENTFD_ANY_LENGTH: ::std::os::raw::c_uint = 122; +pub const KVM_CAP_ARM_PMU_V3: ::std::os::raw::c_uint = 126; pub const KVM_CAP_IMMEDIATE_EXIT: ::std::os::raw::c_uint = 136; pub const KVM_IRQ_ROUTING_IRQCHIP: ::std::os::raw::c_uint = 1; pub const KVM_IRQ_ROUTING_MSI: ::std::os::raw::c_uint = 2; diff --git a/kvm_sys/src/x86/bindings.rs b/kvm_sys/src/x86/bindings.rs index 7236611..629d83a 100644 --- a/kvm_sys/src/x86/bindings.rs +++ b/kvm_sys/src/x86/bindings.rs @@ -426,6 +426,7 @@ pub const KVM_CAP_GUEST_DEBUG_HW_WPS: ::std::os::raw::c_uint = 120; pub const KVM_CAP_SPLIT_IRQCHIP: ::std::os::raw::c_uint = 121; pub const KVM_CAP_IOEVENTFD_ANY_LENGTH: ::std::os::raw::c_uint = 122; pub const KVM_CAP_HYPERV_SYNIC: ::std::os::raw::c_uint = 123; +pub const KVM_CAP_ARM_PMU_V3: ::std::os::raw::c_uint = 126; pub const KVM_CAP_IMMEDIATE_EXIT: ::std::os::raw::c_uint = 136; pub const KVM_CAP_HYPERV_SYNIC2: ::std::os::raw::c_uint = 148; pub const KVM_IRQ_ROUTING_IRQCHIP: ::std::os::raw::c_uint = 1; |