1. 27 Apr, 2022 1 commit
    • Alexandru Elisei's avatar
      KVM/arm64: Don't emulate a PMU for 32-bit guests if feature not set · 8f6379e2
      Alexandru Elisei authored
      kvm->arch.arm_pmu is set when userspace attempts to set the first PMU
      attribute. As certain attributes are mandatory, arm_pmu ends up always
      being set to a valid arm_pmu, otherwise KVM will refuse to run the VCPU.
      However, this only happens if the VCPU has the PMU feature. If the VCPU
      doesn't have the feature bit set, kvm->arch.arm_pmu will be left
      uninitialized and equal to NULL.
      
      KVM doesn't do ID register emulation for 32-bit guests and accesses to the
      PMU registers aren't gated by the pmu_visibility() function. This is done
      to prevent injecting unexpected undefined exceptions in guests which have
      detected the presence of a hardware PMU. But even though the VCPU feature
      is missing, KVM still attempts to emulate certain aspects of the PMU when
      PMU registers are accessed. This leads to a NULL pointer dereference like
      this one, which happens on an odroid-c4 board when running the
      kvm-unit-tests pmu-cycle-counter test with kvmtool and without the PMU
      feature being set:
      
      [  454.402699] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000150
      [  454.405865] Mem abort info:
      [  454.408596]   ESR = 0x96000004
      [  454.411638]   EC = 0x25: DABT (current EL), IL = 32 bits
      [  454.416901]   SET = 0, FnV = 0
      [  454.419909]   EA = 0, S1PTW = 0
      [  454.423010]   FSC = 0x04: level 0 translation fault
      [  454.427841] Data abort info:
      [  454.430687]   ISV = 0, ISS = 0x00000004
      [  454.434484]   CM = 0, WnR = 0
      [  454.437404] user pgtable: 4k pages, 48-bit VAs, pgdp=000000000c924000
      [  454.443800] [0000000000000150] pgd=0000000000000000, p4d=0000000000000000
      [  454.450528] Internal error: Oops: 96000004 [#1] PREEMPT SMP
      [  454.456036] Modules linked in:
      [  454.459053] CPU: 1 PID: 267 Comm: kvm-vcpu-0 Not tainted 5.18.0-rc4 #113
      [  454.465697] Hardware name: Hardkernel ODROID-C4 (DT)
      [  454.470612] pstate: 60400009 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
      [  454.477512] pc : kvm_pmu_event_mask.isra.0+0x14/0x74
      [  454.482427] lr : kvm_pmu_set_counter_event_type+0x2c/0x80
      [  454.487775] sp : ffff80000a9839c0
      [  454.491050] x29: ffff80000a9839c0 x28: ffff000000a83a00 x27: 0000000000000000
      [  454.498127] x26: 0000000000000000 x25: 0000000000000000 x24: ffff00000a510000
      [  454.505198] x23: ffff000000a83a00 x22: ffff000003b01000 x21: 0000000000000000
      [  454.512271] x20: 000000000000001f x19: 00000000000003ff x18: 0000000000000000
      [  454.519343] x17: 000000008003fe98 x16: 0000000000000000 x15: 0000000000000000
      [  454.526416] x14: 0000000000000000 x13: 0000000000000000 x12: 0000000000000000
      [  454.533489] x11: 000000008003fdbc x10: 0000000000009d20 x9 : 000000000000001b
      [  454.540561] x8 : 0000000000000000 x7 : 0000000000000d00 x6 : 0000000000009d00
      [  454.547633] x5 : 0000000000000037 x4 : 0000000000009d00 x3 : 0d09000000000000
      [  454.554705] x2 : 000000000000001f x1 : 0000000000000000 x0 : 0000000000000000
      [  454.561779] Call trace:
      [  454.564191]  kvm_pmu_event_mask.isra.0+0x14/0x74
      [  454.568764]  kvm_pmu_set_counter_event_type+0x2c/0x80
      [  454.573766]  access_pmu_evtyper+0x128/0x170
      [  454.577905]  perform_access+0x34/0x80
      [  454.581527]  kvm_handle_cp_32+0x13c/0x160
      [  454.585495]  kvm_handle_cp15_32+0x1c/0x30
      [  454.589462]  handle_exit+0x70/0x180
      [  454.592912]  kvm_arch_vcpu_ioctl_run+0x1c4/0x5e0
      [  454.597485]  kvm_vcpu_ioctl+0x23c/0x940
      [  454.601280]  __arm64_sys_ioctl+0xa8/0xf0
      [  454.605160]  invoke_syscall+0x48/0x114
      [  454.608869]  el0_svc_common.constprop.0+0xd4/0xfc
      [  454.613527]  do_el0_svc+0x28/0x90
      [  454.616803]  el0_svc+0x34/0xb0
      [  454.619822]  el0t_64_sync_handler+0xa4/0x130
      [  454.624049]  el0t_64_sync+0x18c/0x190
      [  454.627675] Code: a9be7bfd 910003fd f9000bf3 52807ff3 (b9415001)
      [  454.633714] ---[ end trace 0000000000000000 ]---
      
      In this particular case, Linux hasn't detected the presence of a hardware
      PMU because the PMU node is missing from the DTB, so userspace would have
      been unable to set the VCPU PMU feature even if it attempted it. What
      happens is that the 32-bit guest reads ID_DFR0, which advertises the
      presence of the PMU, and when it tries to program a counter, it triggers
      the NULL pointer dereference because kvm->arch.arm_pmu is NULL.
      
      kvm-arch.arm_pmu was introduced by commit 46b18782
      
       ("KVM: arm64:
      Keep a per-VM pointer to the default PMU"). Until that commit, this
      error would be triggered instead:
      
      [   73.388140] ------------[ cut here ]------------
      [   73.388189] Unknown PMU version 0
      [   73.390420] WARNING: CPU: 1 PID: 264 at arch/arm64/kvm/pmu-emul.c:36 kvm_pmu_event_mask.isra.0+0x6c/0x74
      [   73.399821] Modules linked in:
      [   73.402835] CPU: 1 PID: 264 Comm: kvm-vcpu-0 Not tainted 5.17.0 #114
      [   73.409132] Hardware name: Hardkernel ODROID-C4 (DT)
      [   73.414048] pstate: 60400009 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
      [   73.420948] pc : kvm_pmu_event_mask.isra.0+0x6c/0x74
      [   73.425863] lr : kvm_pmu_event_mask.isra.0+0x6c/0x74
      [   73.430779] sp : ffff80000a8db9b0
      [   73.434055] x29: ffff80000a8db9b0 x28: ffff000000dbaac0 x27: 0000000000000000
      [   73.441131] x26: ffff000000dbaac0 x25: 00000000c600000d x24: 0000000000180720
      [   73.448203] x23: ffff800009ffbe10 x22: ffff00000b612000 x21: 0000000000000000
      [   73.455276] x20: 000000000000001f x19: 0000000000000000 x18: ffffffffffffffff
      [   73.462348] x17: 000000008003fe98 x16: 0000000000000000 x15: 0720072007200720
      [   73.469420] x14: 0720072007200720 x13: ffff800009d32488 x12: 00000000000004e6
      [   73.476493] x11: 00000000000001a2 x10: ffff800009d32488 x9 : ffff800009d32488
      [   73.483565] x8 : 00000000ffffefff x7 : ffff800009d8a488 x6 : ffff800009d8a488
      [   73.490638] x5 : ffff0000f461a9d8 x4 : 0000000000000000 x3 : 0000000000000001
      [   73.497710] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff000000dbaac0
      [   73.504784] Call trace:
      [   73.507195]  kvm_pmu_event_mask.isra.0+0x6c/0x74
      [   73.511768]  kvm_pmu_set_counter_event_type+0x2c/0x80
      [   73.516770]  access_pmu_evtyper+0x128/0x16c
      [   73.520910]  perform_access+0x34/0x80
      [   73.524532]  kvm_handle_cp_32+0x13c/0x160
      [   73.528500]  kvm_handle_cp15_32+0x1c/0x30
      [   73.532467]  handle_exit+0x70/0x180
      [   73.535917]  kvm_arch_vcpu_ioctl_run+0x20c/0x6e0
      [   73.540489]  kvm_vcpu_ioctl+0x2b8/0x9e0
      [   73.544283]  __arm64_sys_ioctl+0xa8/0xf0
      [   73.548165]  invoke_syscall+0x48/0x114
      [   73.551874]  el0_svc_common.constprop.0+0xd4/0xfc
      [   73.556531]  do_el0_svc+0x28/0x90
      [   73.559808]  el0_svc+0x28/0x80
      [   73.562826]  el0t_64_sync_handler+0xa4/0x130
      [   73.567054]  el0t_64_sync+0x1a0/0x1a4
      [   73.570676] ---[ end trace 0000000000000000 ]---
      [   73.575382] kvm: pmu event creation failed -2
      
      The root cause remains the same: kvm->arch.pmuver was never set to
      something sensible because the VCPU feature itself was never set.
      
      The odroid-c4 is somewhat of a special case, because Linux doesn't probe
      the PMU. But the above errors can easily be reproduced on any hardware,
      with or without a PMU driver, as long as userspace doesn't set the PMU
      feature.
      
      Work around the fact that KVM advertises a PMU even when the VCPU feature
      is not set by gating all PMU emulation on the feature. The guest can still
      access the registers without KVM injecting an undefined exception.
      Signed-off-by: default avatarAlexandru Elisei <alexandru.elisei@arm.com>
      Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
      Link: https://lore.kernel.org/r/20220425145530.723858-1-alexandru.elisei@arm.com
      8f6379e2
  2. 18 Mar, 2022 1 commit
  3. 08 Feb, 2022 5 commits
  4. 08 Dec, 2021 1 commit
  5. 01 Dec, 2021 1 commit
  6. 17 Nov, 2021 1 commit
  7. 17 Oct, 2021 1 commit
  8. 20 Sep, 2021 1 commit
  9. 11 Aug, 2021 1 commit
  10. 02 Aug, 2021 2 commits
  11. 18 Jun, 2021 2 commits
  12. 22 Apr, 2021 1 commit
  13. 06 Mar, 2021 1 commit
  14. 03 Feb, 2021 2 commits
  15. 21 Jan, 2021 1 commit
  16. 27 Dec, 2020 1 commit
  17. 27 Nov, 2020 5 commits
  18. 29 Sep, 2020 4 commits
    • Marc Zyngier's avatar
      KVM: arm64: Mask out filtered events in PCMEID{0,1}_EL1 · 88865bec
      Marc Zyngier authored
      
      As we can now hide events from the guest, let's also adjust its view of
      PCMEID{0,1}_EL1 so that it can figure out why some common events are not
      counting as they should.
      
      The astute user can still look into the TRM for their CPU and find out
      they've been cheated, though. Nobody's perfect.
      Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
      88865bec
    • Marc Zyngier's avatar
      KVM: arm64: Add PMU event filtering infrastructure · d7eec236
      Marc Zyngier authored
      
      It can be desirable to expose a PMU to a guest, and yet not want the
      guest to be able to count some of the implemented events (because this
      would give information on shared resources, for example.
      
      For this, let's extend the PMUv3 device API, and offer a way to setup a
      bitmap of the allowed events (the default being no bitmap, and thus no
      filtering).
      
      Userspace can thus allow/deny ranges of event. The default policy
      depends on the "polarity" of the first filter setup (default deny if the
      filter allows events, and default allow if the filter denies events).
      This allows to setup exactly what is allowed for a given guest.
      
      Note that although the ioctl is per-vcpu, the map of allowed events is
      global to the VM (it can be setup from any vcpu until the vcpu PMU is
      initialized).
      Reviewed-by: default avatarAndrew Jones <drjones@redhat.com>
      Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
      d7eec236
    • Marc Zyngier's avatar
      KVM: arm64: Use event mask matching architecture revision · fd65a3b5
      Marc Zyngier authored
      
      The PMU code suffers from a small defect where we assume that the event
      number provided by the guest is always 16 bit wide, even if the CPU only
      implements the ARMv8.0 architecture. This isn't really problematic in
      the sense that the event number ends up in a system register, cropping
      it to the right width, but still this needs fixing.
      
      In order to make it work, let's probe the version of the PMU that the
      guest is going to use. This is done by temporarily creating a kernel
      event and looking at the PMUVer field that has been saved at probe time
      in the associated arm_pmu structure. This in turn gets saved in the kvm
      structure, and subsequently used to compute the event mask that gets
      used throughout the PMU code.
      Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
      fd65a3b5
    • Marc Zyngier's avatar
      KVM: arm64: Refactor PMU attribute error handling · 42223fb1
      Marc Zyngier authored
      
      The PMU emulation error handling is pretty messy when dealing with
      attributes. Let's refactor it so that we have less duplication,
      and that it is easy to extend later on.
      
      A functional change is that kvm_arm_pmu_v3_init() used to return
      -ENXIO when the PMU feature wasn't set. The error is now reported
      as -ENODEV, matching the documentation. -ENXIO is still returned
      when the interrupt isn't properly configured.
      Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
      42223fb1
  19. 28 Sep, 2020 1 commit
  20. 16 May, 2020 1 commit
  21. 28 Jan, 2020 4 commits
  22. 20 Oct, 2019 2 commits
    • Marc Zyngier's avatar
      KVM: arm64: pmu: Reset sample period on overflow handling · 8c3252c0
      Marc Zyngier authored
      The PMU emulation code uses the perf event sample period to trigger
      the overflow detection. This works fine  for the *first* overflow
      handling, but results in a huge number of interrupts on the host,
      unrelated to the number of interrupts handled in the guest (a x20
      factor is pretty common for the cycle counter). On a slow system
      (such as a SW model), this can result in the guest only making
      forward progress at a glacial pace.
      
      It turns out that the clue is in the name. The sample period is
      exactly that: a period. And once the an overflow has occured,
      the following period should be the full width of the associated
      counter, instead of whatever the guest had initially programed.
      
      Reset the sample period to the architected value in the overflow
      handler, which now results in a number of host interrupts that is
      much closer to the number of interrupts in the guest.
      
      Fixes: b02386eb
      
       ("arm64: KVM: Add PMU overflow interrupt routing")
      Reviewed-by: default avatarAndrew Murray <andrew.murray@arm.com>
      Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
      8c3252c0
    • Marc Zyngier's avatar
      KVM: arm64: pmu: Set the CHAINED attribute before creating the in-kernel event · 725ce669
      Marc Zyngier authored
      The current convention for KVM to request a chained event from the
      host PMU is to set bit[0] in attr.config1 (PERF_ATTR_CFG1_KVM_PMU_CHAINED).
      
      But as it turns out, this bit gets set *after* we create the kernel
      event that backs our virtual counter, meaning that we never get
      a 64bit counter.
      
      Moving the setting to an earlier point solves the problem.
      
      Fixes: 80f393a2
      
       ("KVM: arm/arm64: Support chained PMU counters")
      Reviewed-by: default avatarAndrew Murray <andrew.murray@arm.com>
      Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
      725ce669