Re: [PATCH v7 15/19] KVM: ARM64: Add access handler for PMUSERENR register

2015-12-15 Thread Marc Zyngier
On 15/12/15 15:59, Shannon Zhao wrote:
> 
> 
> On 2015/12/15 22:58, Marc Zyngier wrote:
>> On 15/12/15 08:49, Shannon Zhao wrote:
 From: Shannon Zhao

 The reset value of PMUSERENR_EL0 is UNKNOWN, use reset_unknown.

 PMUSERENR_EL0 holds some bits which decide whether PMU registers can be
 accessed from EL0. Add some check helpers to handle the access from EL0.

 Signed-off-by: Shannon Zhao
 ---
  arch/arm64/kvm/sys_regs.c | 124 
 --
  1 file changed, 119 insertions(+), 5 deletions(-)

 diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
 index b2ccc25..bad3dfd 100644
 --- a/arch/arm64/kvm/sys_regs.c
 +++ b/arch/arm64/kvm/sys_regs.c
 @@ -452,12 +452,44 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const 
 struct sys_reg_desc *r)
vcpu_sys_reg(vcpu, r->reg) = val;
  }

 +static inline bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
 +{
 +  u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
 +
 +  return !((reg & 0x1) || vcpu_mode_priv(vcpu));
 +}
 +
 +static inline bool pmu_write_swinc_el0_disabled(struct kvm_vcpu *vcpu)
 +{
 +  u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
 +
 +  return !((reg & 0x3) || vcpu_mode_priv(vcpu));
 +}
 +
 +static inline bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu 
 *vcpu)
 +{
 +  u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
 +
 +  return !((reg & 0x5) || vcpu_mode_priv(vcpu));
 +}
 +
 +static inline bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu 
 *vcpu)
 +{
 +  u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
 +
 +  return !((reg & 0x9) || vcpu_mode_priv(vcpu));
 +}
>> Please add #defines for the PMUSERNR_EL0 bits.
>>
 +
  static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
const struct sys_reg_desc *r)
  {
u64 val;
 +  bool unaccessible = pmu_access_el0_disabled(vcpu);

if (p->is_write) {
 +  if (unaccessible)
 +  return ignore_write(vcpu, p);
 +
>> This is not how this is supposed to work. If EL0 is denied access to the
>> PMU, you must inject an exception into EL1 for it to handle the fault.
>> The code should reflect the flow described at D5.11.2 in the ARM ARM.
>>
> Does it need to add a helper to inject an exception into EL1 or is there 
> a existing one?

You can use some of the stuff in inject_fault.c as a starting point.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [PATCH v10 0/6] QEMU support for KVM Guest Debug on arm64

2015-12-15 Thread Peter Maydell
On 8 December 2015 at 18:32, Alex Bennée  wrote:
> Hi,
>
> Here is the latest patch set to support debugging of KVM guests on
> arm64. The main changes are fixing arm32 compiles (mostly with stubs
> for the upcomming arm32 debug) and the usual bunch of minor tweaks and
> clarifications following review.
>
> I've kept the GDB Python based test in tests/guest-debug and cleaned
> it up so it will work with python2/3 linked GDBs. It still isn't
> plumbed it in to the "make check" so can be dropped until we have a
> solution for testing against non-host binaries.
>
> So in summary the changes are:
>
>   - Fixed arm32 compile
>   - Use results of debug capability checks
>   - Whitespace and comment cleanups
>   - Py2/3 cleanliness for test script
>
> More detailed changelogs are attached to each patch.

Thanks, applied to target-arm.next. (I fixed a few typos
in comments and commit messages in a couple of places).

-- PMM
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[PATCH v7 10/19] KVM: ARM64: Add access handler for PMCNTENSET and PMCNTENCLR register

2015-12-15 Thread Shannon Zhao
From: Shannon Zhao 

Since the reset value of PMCNTENSET and PMCNTENCLR is UNKNOWN, use
reset_unknown for its reset handler. Add a handler to emulate writing
PMCNTENSET or PMCNTENCLR register.

When writing to PMCNTENSET, call perf_event_enable to enable the perf
event. When writing to PMCNTENCLR, call perf_event_disable to disable
the perf event.

Signed-off-by: Shannon Zhao 
---
 arch/arm64/kvm/sys_regs.c | 41 +++
 include/kvm/arm_pmu.h |  4 
 virt/kvm/arm/pmu.c| 55 +++
 3 files changed, 96 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index dc6bb26..f216da7 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -615,6 +615,39 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
return true;
 }
 
+static inline u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
+{
+   u64 val = vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMCR_N_SHIFT;
+
+   val &= ARMV8_PMCR_N_MASK;
+   return GENMASK(val - 1, 0) | BIT(ARMV8_CYCLE_IDX);
+}
+
+static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+   u64 val, mask;
+
+   mask = kvm_pmu_valid_counter_mask(vcpu);
+   if (p->is_write) {
+   val = p->regval & mask;
+   if (r->Op2 & 0x1) {
+   /* accessing PMCNTENSET_EL0 */
+   vcpu_sys_reg(vcpu, r->reg) |= val;
+   kvm_pmu_enable_counter(vcpu, val);
+   } else {
+   /* accessing PMCNTENCLR_EL0 */
+   vcpu_sys_reg(vcpu, r->reg) &= mask;
+   vcpu_sys_reg(vcpu, r->reg) &= ~val;
+   kvm_pmu_disable_counter(vcpu, val);
+   }
+   } else {
+   p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
+   }
+
+   return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n) \
/* DBGBVRn_EL1 */   \
@@ -816,10 +849,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
  access_pmcr, reset_pmcr, PMCR_EL0, },
/* PMCNTENSET_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b001),
- trap_raz_wi },
+ access_pmcntenset, reset_unknown, PMCNTENSET_EL0 },
/* PMCNTENCLR_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b010),
- trap_raz_wi },
+ access_pmcntenset, NULL, PMCNTENSET_EL0 },
/* PMOVSCLR_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
  trap_raz_wi },
@@ -1161,8 +1194,8 @@ static const struct sys_reg_desc cp15_regs[] = {
 
/* PMU */
{ Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
-   { Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
-   { Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
+   { Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
+   { Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 14bedb0..43c4117 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -36,6 +36,8 @@ struct kvm_pmu {
 };
 
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
+void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
+void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
u64 select_idx);
 #else
@@ -46,6 +48,8 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 
select_idx)
 {
return 0;
 }
+void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
+void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
u64 select_idx) {}
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index b107fb8..94bff0e 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -75,6 +75,61 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, 
struct kvm_pmc *pmc)
 }
 
 /**
+ * kvm_pmu_enable_counter - enable selected PMU counter
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMCNTENSET register
+ *
+ * Call perf_event_enable to start counting the perf event
+ */
+void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val)
+{
+   int i;
+   struct kvm_pmu *pmu = >arch.pmu;
+   struct kvm_pmc *pmc;
+
+   if 

[PATCH v7 16/19] KVM: ARM64: Add PMU overflow interrupt routing

2015-12-15 Thread Shannon Zhao
From: Shannon Zhao 

When calling perf_event_create_kernel_counter to create perf_event,
assign a overflow handler. Then when the perf event overflows, set the
corresponding bit of guest PMOVSSET register. If this counter is enabled
and its interrupt is enabled as well, kick the vcpu to sync the
interrupt.

On VM entry, if there is counter overflowed, inject the interrupt with
the level set to 1. Otherwise, inject the interrupt with the level set
to 0.

Signed-off-by: Shannon Zhao 
---
 arch/arm/kvm/arm.c|  2 ++
 include/kvm/arm_pmu.h |  2 ++
 virt/kvm/arm/pmu.c| 54 ++-
 3 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index e06fd29..cd696ef 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -28,6 +28,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define CREATE_TRACE_POINTS
 #include "trace.h"
@@ -569,6 +570,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct 
kvm_run *run)
 * non-preemptible context.
 */
preempt_disable();
+   kvm_pmu_flush_hwstate(vcpu);
kvm_timer_flush_hwstate(vcpu);
kvm_vgic_flush_hwstate(vcpu);
 
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 25b5f98..732ccaf 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -35,6 +35,7 @@ struct kvm_pmu {
struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
 };
 
+void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
@@ -47,6 +48,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val);
 struct kvm_pmu {
 };
 
+void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 {
return 0;
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index e664721..eff5b19 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -21,6 +21,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /**
  * kvm_pmu_get_counter_value - get PMU counter value
@@ -75,6 +76,56 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, 
struct kvm_pmc *pmc)
 }
 
 /**
+ * kvm_pmu_flush_hwstate - flush pmu state to cpu
+ * @vcpu: The vcpu pointer
+ *
+ * Inject virtual PMU IRQ if IRQ is pending for this cpu.
+ */
+void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu)
+{
+   struct kvm_pmu *pmu = >arch.pmu;
+   u64 overflow;
+
+   if (pmu->irq_num == -1)
+   return;
+
+   if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E))
+   return;
+
+   overflow = vcpu_sys_reg(vcpu, PMCNTENSET_EL0)
+  & vcpu_sys_reg(vcpu, PMINTENSET_EL1)
+  & vcpu_sys_reg(vcpu, PMOVSSET_EL0);
+
+   kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, pmu->irq_num,
+   overflow ? 1 : 0);
+}
+
+static inline struct kvm_vcpu *kvm_pmc_to_vcpu(struct kvm_pmc *pmc)
+{
+   struct kvm_pmu *pmu;
+   struct kvm_vcpu_arch *vcpu_arch;
+
+   pmc -= pmc->idx;
+   pmu = container_of(pmc, struct kvm_pmu, pmc[0]);
+   vcpu_arch = container_of(pmu, struct kvm_vcpu_arch, pmu);
+   return container_of(vcpu_arch, struct kvm_vcpu, arch);
+}
+
+/**
+ * When perf event overflows, call kvm_pmu_overflow_set to set overflow status.
+ */
+static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
+ struct perf_sample_data *data,
+ struct pt_regs *regs)
+{
+   struct kvm_pmc *pmc = perf_event->overflow_handler_context;
+   struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
+   int idx = pmc->idx;
+
+   kvm_pmu_overflow_set(vcpu, BIT(idx));
+}
+
+/**
  * kvm_pmu_enable_counter - enable selected PMU counter
  * @vcpu: The vcpu pointer
  * @val: the value guest writes to PMCNTENSET register
@@ -258,7 +309,8 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, 
u64 data,
/* The initial sample period (overflow count) of an event. */
attr.sample_period = (-counter) & pmc->bitmask;
 
-   event = perf_event_create_kernel_counter(, -1, current, NULL, pmc);
+   event = perf_event_create_kernel_counter(, -1, current,
+kvm_pmu_perf_overflow, pmc);
if (IS_ERR(event)) {
printk_once("kvm: pmu event creation failed %ld\n",
PTR_ERR(event));
-- 
2.0.4


___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[PATCH v7 00/19] KVM: ARM64: Add guest PMU support

2015-12-15 Thread Shannon Zhao
From: Shannon Zhao 

This patchset adds guest PMU support for KVM on ARM64. It takes
trap-and-emulate approach. When guest wants to monitor one event, it
will be trapped by KVM and KVM will call perf_event API to create a perf
event and call relevant perf_event APIs to get the count value of event.

Use perf to test this patchset in guest. When using "perf list", it
shows the list of the hardware events and hardware cache events perf
supports. Then use "perf stat -e EVENT" to monitor some event. For
example, use "perf stat -e cycles" to count cpu cycles and
"perf stat -e cache-misses" to count cache misses.

Below are the outputs of "perf stat -r 5 sleep 5" when running in host
and guest.

Host:
 Performance counter stats for 'sleep 5' (5 runs):

  0.549456  task-clock (msec) #0.000 CPUs utilized  
  ( +-  5.68% )
 1  context-switches  #0.002 M/sec
 0  cpu-migrations#0.000 K/sec
48  page-faults   #0.088 M/sec  
  ( +-  1.40% )
   1146243  cycles#2.086 GHz
  ( +-  5.71% )
 stalled-cycles-frontend
 stalled-cycles-backend
627195  instructions  #0.55  insns per cycle
  ( +- 15.65% )
 branches
  9826  branch-misses #   17.883 M/sec  
  ( +-  1.10% )

   5.000875516 seconds time elapsed 
 ( +-  0.00% )


Guest:
 Performance counter stats for 'sleep 5' (5 runs):

  0.640712  task-clock (msec) #0.000 CPUs utilized  
  ( +-  0.41% )
 1  context-switches  #0.002 M/sec
 0  cpu-migrations#0.000 K/sec
50  page-faults   #0.077 M/sec  
  ( +-  1.37% )
   1320428  cycles#2.061 GHz
  ( +-  0.29% )
 stalled-cycles-frontend
 stalled-cycles-backend
642373  instructions  #0.49  insns per cycle
  ( +-  0.46% )
 branches
 10399  branch-misses #   16.230 M/sec  
  ( +-  1.57% )

   5.001181020 seconds time elapsed 
 ( +-  0.00% )


Have a cycle counter read test like below in guest and host:

static void test(void)
{
unsigned long count, count1, count2;
count1 = read_cycles();
count++;
count2 = read_cycles();
}

Host:
count1: 3049567104
count2: 3049567247
delta: 143

Guest:
count1: 5281420890
count2: 5281421068
delta: 178

The gap between guest and host is very small. One reason for this I
think is that it doesn't count the cycles in EL2 and host since we add
exclude_hv = 1. So the cycles spent to store/restore registers which
happens at EL2 are not included.

This patchset can be fetched from [1] and the relevant QEMU version for
test can be fetched from [2].

The results of 'perf test' can be found from [3][4].
The results of perf_event_tests test suite can be found from [5][6].

Also, I have tested "perf top" in two VMs and host at the same time. It
works well.

Thanks,
Shannon

[1] https://git.linaro.org/people/shannon.zhao/linux-mainline.git  
KVM_ARM64_PMU_v7
[2] https://git.linaro.org/people/shannon.zhao/qemu.git  virtual_PMU
[3] http://people.linaro.org/~shannon.zhao/PMU/perf-test-host.txt
[4] http://people.linaro.org/~shannon.zhao/PMU/perf-test-guest.txt
[5] http://people.linaro.org/~shannon.zhao/PMU/perf_event_tests-host.txt
[6] http://people.linaro.org/~shannon.zhao/PMU/perf_event_tests-guest.txt

Changes since v6:
* Rebase on v4.4-rc5
* Drop access_pmu_cp15_regs() so that it could use same handler for both
  arch64 and arch32. And it could drop the definitions of CP15 register
  offsets 
* Use vcpu_sys_reg() when accessing PMU registers to avoid endian things
* Add handler for PMUSERENR and some checkers for other registers
* Add kvm_arm_pmu_get_attr()

Changes since v5:
* Rebase on new linux kernel mainline
* Remove state duplications and drop PMOVSCLR, PMCNTENCLR, PMINTENCLR,
  PMXEVCNTR, PMXEVTYPER
* Add a helper to check if vPMU is already initialized
* remove kvm_vcpu from kvm_pmc

Changes since v4:
* Rebase on new linux kernel mainline 
* Drop the reset handler of CP15 registers
* Fix a compile failure on arch ARM due to lack of asm/pmu.h
* Refactor the interrupt injecting flow according to Marc's suggestion
* Check the value of PMSELR register
* Calculate the attr.disabled according to PMCR.E and PMCNTENSET/CLR
* Fix some coding style
* Document the vPMU irq range

Changes since v3:
* Rebase on new linux kernel mainline 
* Use ARMV8_MAX_COUNTERS instead of 32
* Reset PMCR.E to zero.
* Trigger overflow for software increment.
* Optimize PMU 

[PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device

2015-12-15 Thread Shannon Zhao
From: Shannon Zhao 

Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
the kvm_device_ops for it.

Signed-off-by: Shannon Zhao 
---
 Documentation/virtual/kvm/devices/arm-pmu.txt |  16 
 arch/arm64/include/uapi/asm/kvm.h |   3 +
 include/linux/kvm_host.h  |   1 +
 include/uapi/linux/kvm.h  |   2 +
 virt/kvm/arm/pmu.c| 115 ++
 virt/kvm/kvm_main.c   |   4 +
 6 files changed, 141 insertions(+)
 create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt

diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt 
b/Documentation/virtual/kvm/devices/arm-pmu.txt
new file mode 100644
index 000..5121f1f
--- /dev/null
+++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
@@ -0,0 +1,16 @@
+ARM Virtual Performance Monitor Unit (vPMU)
+===
+
+Device types supported:
+  KVM_DEV_TYPE_ARM_PMU_V3 ARM Performance Monitor Unit v3
+
+Instantiate one PMU instance for per VCPU through this API.
+
+Groups:
+  KVM_DEV_ARM_PMU_GRP_IRQ
+  Attributes:
+A value describing the interrupt number of PMU overflow interrupt. This
+interrupt should be a PPI.
+
+  Errors:
+-EINVAL: Value set is out of the expected range (from 16 to 31)
diff --git a/arch/arm64/include/uapi/asm/kvm.h 
b/arch/arm64/include/uapi/asm/kvm.h
index 2d4ca4b..568afa2 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_CTRL  4
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT   0
 
+/* Device Control API: ARM PMU */
+#define KVM_DEV_ARM_PMU_GRP_IRQ0
+
 /* KVM_IRQ_LINE irq field index values */
 #define KVM_ARM_IRQ_TYPE_SHIFT 24
 #define KVM_ARM_IRQ_TYPE_MASK  0xff
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index c923350..608dea6 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
 extern struct kvm_device_ops kvm_xics_ops;
 extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
 extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
+extern struct kvm_device_ops kvm_arm_pmu_ops;
 
 #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
 
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 03f3618..4ba6fdd 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1032,6 +1032,8 @@ enum kvm_device_type {
 #define KVM_DEV_TYPE_FLIC  KVM_DEV_TYPE_FLIC
KVM_DEV_TYPE_ARM_VGIC_V3,
 #define KVM_DEV_TYPE_ARM_VGIC_V3   KVM_DEV_TYPE_ARM_VGIC_V3
+   KVM_DEV_TYPE_ARM_PMU_V3,
+#defineKVM_DEV_TYPE_ARM_PMU_V3 KVM_DEV_TYPE_ARM_PMU_V3
KVM_DEV_TYPE_MAX,
 };
 
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index d113ee4..1965d0d 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -19,6 +19,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu 
*vcpu, u64 data,
 
pmc->perf_event = event;
 }
+
+static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
+{
+   return vcpu->arch.pmu.irq_num != -1;
+}
+
+static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
+{
+   int j;
+   struct kvm_vcpu *vcpu;
+
+   kvm_for_each_vcpu(j, vcpu, kvm) {
+   struct kvm_pmu *pmu = >arch.pmu;
+
+   if (!is_set) {
+   if (!kvm_arm_pmu_initialized(vcpu))
+   return -EBUSY;
+
+   *irq = pmu->irq_num;
+   break;
+   }
+
+   if (kvm_arm_pmu_initialized(vcpu))
+   return -EBUSY;
+
+   kvm_debug("Set kvm ARM PMU irq: %d\n", *irq);
+   pmu->irq_num = *irq;
+   }
+
+   return 0;
+}
+
+static int kvm_arm_pmu_create(struct kvm_device *dev, u32 type)
+{
+   int i;
+   struct kvm_vcpu *vcpu;
+   struct kvm *kvm = dev->kvm;
+
+   kvm_for_each_vcpu(i, vcpu, kvm) {
+   struct kvm_pmu *pmu = >arch.pmu;
+
+   memset(pmu, 0, sizeof(*pmu));
+   kvm_pmu_vcpu_reset(vcpu);
+   pmu->irq_num = -1;
+   }
+
+   return 0;
+}
+
+static void kvm_arm_pmu_destroy(struct kvm_device *dev)
+{
+   kfree(dev);
+}
+
+static int kvm_arm_pmu_set_attr(struct kvm_device *dev,
+   struct kvm_device_attr *attr)
+{
+   switch (attr->group) {
+   case KVM_DEV_ARM_PMU_GRP_IRQ: {
+   int __user *uaddr = (int __user *)(long)attr->addr;
+   int reg;
+
+   if (get_user(reg, uaddr))
+   return -EFAULT;
+
+   if (reg < VGIC_NR_SGIS || reg >= VGIC_NR_PRIVATE_IRQS)
+   

[PATCH v7 17/19] KVM: ARM64: Reset PMU state when resetting vcpu

2015-12-15 Thread Shannon Zhao
From: Shannon Zhao 

When resetting vcpu, it needs to reset the PMU state to initial status.

Signed-off-by: Shannon Zhao 
---
 arch/arm64/kvm/reset.c |  3 +++
 include/kvm/arm_pmu.h  |  2 ++
 virt/kvm/arm/pmu.c | 17 +
 3 files changed, 22 insertions(+)

diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index f34745c..dfbce78 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -120,6 +120,9 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
/* Reset system registers */
kvm_reset_sys_regs(vcpu);
 
+   /* Reset PMU */
+   kvm_pmu_vcpu_reset(vcpu);
+
/* Reset timer */
return kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq);
 }
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 732ccaf..59cb53c 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -35,6 +35,7 @@ struct kvm_pmu {
struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
 };
 
+void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu);
 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
@@ -48,6 +49,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val);
 struct kvm_pmu {
 };
 
+void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu) {}
 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 {
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index eff5b19..c62e7f5 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -76,6 +76,23 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, 
struct kvm_pmc *pmc)
 }
 
 /**
+ * kvm_pmu_vcpu_reset - reset pmu state for cpu
+ * @vcpu: The vcpu pointer
+ *
+ */
+void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu)
+{
+   int i;
+   struct kvm_pmu *pmu = >arch.pmu;
+
+   for (i = 0; i < ARMV8_MAX_COUNTERS; i++) {
+   kvm_pmu_stop_counter(vcpu, >pmc[i]);
+   pmu->pmc[i].idx = i;
+   pmu->pmc[i].bitmask = 0xUL;
+   }
+}
+
+/**
  * kvm_pmu_flush_hwstate - flush pmu state to cpu
  * @vcpu: The vcpu pointer
  *
-- 
2.0.4


___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[PATCH v7 13/19] KVM: ARM64: Add access handler for PMSWINC register

2015-12-15 Thread Shannon Zhao
From: Shannon Zhao 

Add access handler which emulates writing and reading PMSWINC
register and add support for creating software increment event.

Signed-off-by: Shannon Zhao 
---
 arch/arm64/kvm/sys_regs.c | 14 +-
 include/kvm/arm_pmu.h |  2 ++
 virt/kvm/arm/pmu.c| 32 
 3 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index d1926c4..f09e500 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -690,6 +690,17 @@ static bool access_pmovsset(struct kvm_vcpu *vcpu, struct 
sys_reg_params *p,
return true;
 }
 
+static bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+  const struct sys_reg_desc *r)
+{
+   if (p->is_write) {
+   kvm_pmu_software_increment(vcpu, p->regval);
+   return true;
+   } else {
+   return read_zero(vcpu, p);
+   }
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n) \
/* DBGBVRn_EL1 */   \
@@ -900,7 +911,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
  access_pmovsset, NULL, PMOVSSET_EL0 },
/* PMSWINC_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
- trap_raz_wi },
+ access_pmswinc, reset_unknown, PMSWINC_EL0 },
/* PMSELR_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b101),
  access_pmselr, reset_unknown, PMSELR_EL0 },
@@ -1239,6 +1250,7 @@ static const struct sys_reg_desc cp15_regs[] = {
{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
{ Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovsset },
+   { Op1( 0), CRn( 9), CRm(12), Op2( 4), access_pmswinc },
{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 93aea6a..f5888eb 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -39,6 +39,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 
select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
+void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
u64 select_idx);
 #else
@@ -52,6 +53,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 
select_idx)
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
+void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
u64 select_idx) {}
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 861471d..01af727 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -150,6 +150,34 @@ void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val)
 }
 
 /**
+ * kvm_pmu_software_increment - do software increment
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMSWINC register
+ */
+void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
+{
+   int i;
+   u64 type, enable, reg;
+
+   if (val == 0)
+   return;
+
+   for (i = 0; i < ARMV8_CYCLE_IDX; i++) {
+   if (!((val >> i) & 0x1))
+   continue;
+   type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
+  & ARMV8_EVTYPE_EVENT;
+   enable = vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
+   if ((type == 0) && ((enable >> i) & 0x1)) {
+   vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i)++;
+   reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i);
+   if ((reg & 0x) == 0)
+   kvm_pmu_overflow_set(vcpu, BIT(i));
+   }
+   }
+}
+
+/**
  * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
  * @vcpu: The vcpu pointer
  * @data: The data guest writes to PMXEVTYPER_EL0
@@ -171,6 +199,10 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, 
u64 data,
kvm_pmu_stop_counter(vcpu, pmc);
eventsel = data & ARMV8_EVTYPE_EVENT;
 
+   /* For software increment event it does't need to create perf event */
+   if (eventsel == 0)
+   return;
+
memset(, 

[PATCH v7 01/19] ARM64: Move PMU register related defines to asm/pmu.h

2015-12-15 Thread Shannon Zhao
From: Shannon Zhao 

To use the ARMv8 PMU related register defines from the KVM code,
we move the relevant definitions to asm/pmu.h header file.

Signed-off-by: Anup Patel 
Signed-off-by: Shannon Zhao 
---
 arch/arm64/include/asm/pmu.h   | 64 ++
 arch/arm64/kernel/perf_event.c | 36 +---
 2 files changed, 65 insertions(+), 35 deletions(-)
 create mode 100644 arch/arm64/include/asm/pmu.h

diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h
new file mode 100644
index 000..4264ea0
--- /dev/null
+++ b/arch/arm64/include/asm/pmu.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 Linaro Ltd, Shannon Zhao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see .
+ */
+#ifndef __ASM_PMU_H
+#define __ASM_PMU_H
+
+#define ARMV8_MAX_COUNTERS  32
+#define ARMV8_COUNTER_MASK  (ARMV8_MAX_COUNTERS - 1)
+
+/*
+ * Per-CPU PMCR: config reg
+ */
+#define ARMV8_PMCR_E   (1 << 0) /* Enable all counters */
+#define ARMV8_PMCR_P   (1 << 1) /* Reset all counters */
+#define ARMV8_PMCR_C   (1 << 2) /* Cycle counter reset */
+#define ARMV8_PMCR_D   (1 << 3) /* CCNT counts every 64th cpu cycle */
+#define ARMV8_PMCR_X   (1 << 4) /* Export to ETM */
+#define ARMV8_PMCR_DP  (1 << 5) /* Disable CCNT if non-invasive debug*/
+#defineARMV8_PMCR_N_SHIFT  11   /* Number of counters 
supported */
+#defineARMV8_PMCR_N_MASK   0x1f
+#defineARMV8_PMCR_MASK 0x3f /* Mask for writable bits */
+
+/*
+ * PMCNTEN: counters enable reg
+ */
+#defineARMV8_CNTEN_MASK0x  /* Mask for writable 
bits */
+
+/*
+ * PMINTEN: counters interrupt enable reg
+ */
+#defineARMV8_INTEN_MASK0x  /* Mask for writable 
bits */
+
+/*
+ * PMOVSR: counters overflow flag status reg
+ */
+#defineARMV8_OVSR_MASK 0x  /* Mask for writable 
bits */
+#defineARMV8_OVERFLOWED_MASK   ARMV8_OVSR_MASK
+
+/*
+ * PMXEVTYPER: Event selection reg
+ */
+#defineARMV8_EVTYPE_MASK   0xc80003ff  /* Mask for writable 
bits */
+#defineARMV8_EVTYPE_EVENT  0x3ff   /* Mask for EVENT bits 
*/
+
+/*
+ * Event filters for PMUv3
+ */
+#defineARMV8_EXCLUDE_EL1   (1 << 31)
+#defineARMV8_EXCLUDE_EL0   (1 << 30)
+#defineARMV8_INCLUDE_EL2   (1 << 27)
+
+#endif /* __ASM_PMU_H */
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 5b1897e..7eca5dc 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -24,6 +24,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /*
  * ARMv8 PMUv3 Performance Events handling code.
@@ -187,9 +188,6 @@ static const unsigned 
armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 #defineARMV8_IDX_COUNTER_LAST(cpu_pmu) \
(ARMV8_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1)
 
-#defineARMV8_MAX_COUNTERS  32
-#defineARMV8_COUNTER_MASK  (ARMV8_MAX_COUNTERS - 1)
-
 /*
  * ARMv8 low level PMU access
  */
@@ -200,38 +198,6 @@ static const unsigned 
armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 #defineARMV8_IDX_TO_COUNTER(x) \
(((x) - ARMV8_IDX_COUNTER0) & ARMV8_COUNTER_MASK)
 
-/*
- * Per-CPU PMCR: config reg
- */
-#define ARMV8_PMCR_E   (1 << 0) /* Enable all counters */
-#define ARMV8_PMCR_P   (1 << 1) /* Reset all counters */
-#define ARMV8_PMCR_C   (1 << 2) /* Cycle counter reset */
-#define ARMV8_PMCR_D   (1 << 3) /* CCNT counts every 64th cpu cycle */
-#define ARMV8_PMCR_X   (1 << 4) /* Export to ETM */
-#define ARMV8_PMCR_DP  (1 << 5) /* Disable CCNT if non-invasive debug*/
-#defineARMV8_PMCR_N_SHIFT  11   /* Number of counters 
supported */
-#defineARMV8_PMCR_N_MASK   0x1f
-#defineARMV8_PMCR_MASK 0x3f /* Mask for writable bits */
-
-/*
- * PMOVSR: counters overflow flag status reg
- */
-#defineARMV8_OVSR_MASK 0x  /* Mask for writable 
bits */
-#defineARMV8_OVERFLOWED_MASK   ARMV8_OVSR_MASK
-
-/*
- * PMXEVTYPER: Event selection reg
- */
-#defineARMV8_EVTYPE_MASK   0xc80003ff  /* Mask for writable 
bits */
-#defineARMV8_EVTYPE_EVENT  0x3ff   /* Mask for EVENT bits 

Re: ARM64/KVM: Bad page state in process iperf

2015-12-15 Thread Marc Zyngier
On 15/12/15 03:46, Bhushan Bharat wrote:
> 
> Hi All,
> 
> I am running "iperf" in KVM guest on ARM64 machine and observing below crash.
> 
> =
> $iperf -c 3.3.3.3 -P 4 -t 0 -i 5 -w 90k
> 
> Client connecting to 3.3.3.3, TCP port 5001
> TCP window size:  180 KByte (WARNING: requested 90.0 KByte)
> 
> [  3] local 3.3.3.1 port 51131 connected with 3.3.3.3 port 5001
> [  6] local 3.3.3.1 port 51134 connected with 3.3.3.3 port 5001
> [  5] local 3.3.3.1 port 51133 connected with 3.3.3.3 port 5001
> [  4] local 3.3.3.1 port 51132 connected with 3.3.3.3 port 5001
> [   53.088567] random: nonblocking pool is initialized
> [ ID] Interval   Transfer Bandwidth
> [  3]  0.0- 5.0 sec   638 MBytes  1.07 Gbits/sec
> [  4] 35.0-40.0 sec  1.66 GBytes  2.85 Gbits/sec
> [  5] 40.0-45.0 sec  1.11 GBytes  1.90 Gbits/sec
> [  4] 40.0-45.0 sec  1.16 GBytes  1.99 Gbits/sec
> [   98.895207] BUG: Bad page state in process iperf  pfn:0a584
> [   98.896164] page:78296100 count:-1 mapcount:0 mapping:  
> (null) index:0x0
> [   98.897436] flags: 0x0()
> [   98.897885] page dumped because: nonzero _count
> [   98.898640] Modules linked in:
> [   98.899178] CPU: 0 PID: 1639 Comm: iperf Not tainted 4.1.8-00461-ge5431ad 
> #141
> [   98.900302] Hardware name: linux,dummy-virt (DT)
> [   98.901014] Call trace:
> [   98.901406] [] dump_backtrace+0x0/0x12c
> [   98.902522] [] show_stack+0x10/0x1c
> [   98.903441] [] dump_stack+0x8c/0xdc
> [   98.904202] [] bad_page+0xc4/0x114
> [   98.904945] [] get_page_from_freelist+0x590/0x63c
> [   98.905871] [] __alloc_pages_nodemask+0xec/0x794
> [   98.906791] [] skb_page_frag_refill+0x70/0xa8
> [   98.907678] [] sk_page_frag_refill+0x20/0xd0
> [   98.908550] [] tcp_sendmsg+0x1f8/0x9a8
> [   98.909368] [] inet_sendmsg+0x5c/0xd0
> [   98.910178] [] sock_sendmsg+0x14/0x58
> [   98.911027] [] sock_write_iter+0x64/0xbc
> [   98.912119] [] __vfs_write+0xac/0x10c
> [   98.913126] [] vfs_write+0x90/0x1a0
> [   98.913963] [] SyS_write+0x40/0xa0

This looks quite bad, but I don't see anything here that links it to KVM
(apart from being a guest). Do you have any indication that this is due
to KVM misbehaving? I'd appreciate a few more details.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[PATCH v7 18/19] KVM: ARM64: Free perf event of PMU when destroying vcpu

2015-12-15 Thread Shannon Zhao
From: Shannon Zhao 

When KVM frees VCPU, it needs to free the perf_event of PMU.

Signed-off-by: Shannon Zhao 
---
 arch/arm/kvm/arm.c|  1 +
 include/kvm/arm_pmu.h |  2 ++
 virt/kvm/arm/pmu.c| 21 +
 3 files changed, 24 insertions(+)

diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index cd696ef..cea2176 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -259,6 +259,7 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
kvm_mmu_free_memory_caches(vcpu);
kvm_timer_vcpu_terminate(vcpu);
kvm_vgic_vcpu_destroy(vcpu);
+   kvm_pmu_vcpu_destroy(vcpu);
kmem_cache_free(kvm_vcpu_cache, vcpu);
 }
 
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 59cb53c..b1b63ac 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -36,6 +36,7 @@ struct kvm_pmu {
 };
 
 void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu);
+void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu);
 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
@@ -50,6 +51,7 @@ struct kvm_pmu {
 };
 
 void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu) {}
+void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu) {}
 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 {
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index c62e7f5..d113ee4 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -93,6 +93,27 @@ void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu)
 }
 
 /**
+ * kvm_pmu_vcpu_destroy - free perf event of PMU for cpu
+ * @vcpu: The vcpu pointer
+ *
+ */
+void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu)
+{
+   int i;
+   struct kvm_pmu *pmu = >arch.pmu;
+
+   for (i = 0; i < ARMV8_MAX_COUNTERS; i++) {
+   struct kvm_pmc *pmc = >pmc[i];
+
+   if (pmc->perf_event) {
+   perf_event_disable(pmc->perf_event);
+   perf_event_release_kernel(pmc->perf_event);
+   pmc->perf_event = NULL;
+   }
+   }
+}
+
+/**
  * kvm_pmu_flush_hwstate - flush pmu state to cpu
  * @vcpu: The vcpu pointer
  *
-- 
2.0.4


___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


RE: ARM64/KVM: Bad page state in process iperf

2015-12-15 Thread Bhushan Bharat


> -Original Message-
> From: Christoffer Dall [mailto:christoffer.d...@linaro.org]
> Sent: Tuesday, December 15, 2015 2:59 PM
> To: Bhushan Bharat-R65777 
> Cc: kvmarm@lists.cs.columbia.edu; k...@vger.kernel.org; linux-arm-
> ker...@lists.infradead.org; linux-ker...@vger.kernel.org
> Subject: Re: ARM64/KVM: Bad page state in process iperf
> 
> On Tue, Dec 15, 2015 at 03:46:03AM +, Bhushan Bharat wrote:
> >
> > Hi All,
> >
> > I am running "iperf" in KVM guest on ARM64 machine and observing below
> crash.
> 
> Which host/guest kernel version is this?

We are using Linux-v4.1 for both host (4K page size) and guest (64K page size).

> 
> Which hardware?

This is observed on Freescale LS2085 hardware based on A57 (8 CPUs).

Thanks
-Bharat

> 
> -Christoffer
> 
> >
> > =
> > $iperf -c 3.3.3.3 -P 4 -t 0 -i 5 -w 90k
> > 
> > Client connecting to 3.3.3.3, TCP port 5001 TCP window size:  180
> > KByte (WARNING: requested 90.0 KByte)
> > 
> > [  3] local 3.3.3.1 port 51131 connected with 3.3.3.3 port 5001 [  6]
> > local 3.3.3.1 port 51134 connected with 3.3.3.3 port 5001 [  5] local
> > 3.3.3.1 port 51133 connected with 3.3.3.3 port 5001 [  4] local
> > 3.3.3.1 port 51132 connected with 3.3.3.3 port 5001
> > [   53.088567] random: nonblocking pool is initialized
> > [ ID] Interval   Transfer Bandwidth
> > [  3]  0.0- 5.0 sec   638 MBytes  1.07 Gbits/sec
> > [  4] 35.0-40.0 sec  1.66 GBytes  2.85 Gbits/sec [  5] 40.0-45.0 sec
> > 1.11 GBytes  1.90 Gbits/sec [  4] 40.0-45.0 sec  1.16 GBytes  1.99
> > Gbits/sec
> > [   98.895207] BUG: Bad page state in process iperf  pfn:0a584
> > [   98.896164] page:78296100 count:-1 mapcount:0 mapping:
> (null) index:0x0
> > [   98.897436] flags: 0x0()
> > [   98.897885] page dumped because: nonzero _count
> > [   98.898640] Modules linked in:
> > [   98.899178] CPU: 0 PID: 1639 Comm: iperf Not tainted 4.1.8-00461-
> ge5431ad #141
> > [   98.900302] Hardware name: linux,dummy-virt (DT)
> > [   98.901014] Call trace:
> > [   98.901406] [] dump_backtrace+0x0/0x12c
> > [   98.902522] [] show_stack+0x10/0x1c
> > [   98.903441] [] dump_stack+0x8c/0xdc
> > [   98.904202] [] bad_page+0xc4/0x114
> > [   98.904945] [] get_page_from_freelist+0x590/0x63c
> > [   98.905871] [] __alloc_pages_nodemask+0xec/0x794
> > [   98.906791] [] skb_page_frag_refill+0x70/0xa8
> > [   98.907678] [] sk_page_frag_refill+0x20/0xd0
> > [   98.908550] [] tcp_sendmsg+0x1f8/0x9a8
> > [   98.909368] [] inet_sendmsg+0x5c/0xd0
> > [   98.910178] [] sock_sendmsg+0x14/0x58
> > [   98.911027] [] sock_write_iter+0x64/0xbc
> > [   98.912119] [] __vfs_write+0xac/0x10c
> > [   98.913126] [] vfs_write+0x90/0x1a0
> > [   98.913963] [] SyS_write+0x40/0xa0
> >
> > ---
> > ___
> > kvmarm mailing list
> > kvmarm@lists.cs.columbia.edu
> > https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[PATCH v7 11/19] KVM: ARM64: Add access handler for PMINTENSET and PMINTENCLR register

2015-12-15 Thread Shannon Zhao
From: Shannon Zhao 

Since the reset value of PMINTENSET and PMINTENCLR is UNKNOWN, use
reset_unknown for its reset handler. Add a handler to emulate writing
PMINTENSET or PMINTENCLR register.

Signed-off-by: Shannon Zhao 
---
 arch/arm64/kvm/sys_regs.c | 29 +
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f216da7..594e53f 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -648,6 +648,27 @@ static bool access_pmcntenset(struct kvm_vcpu *vcpu, 
struct sys_reg_params *p,
return true;
 }
 
+static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+   u64 mask = kvm_pmu_valid_counter_mask(vcpu);
+
+   if (p->is_write) {
+   if (r->Op2 & 0x1) {
+   /* accessing PMINTENSET_EL1 */
+   vcpu_sys_reg(vcpu, r->reg) |= (p->regval & mask);
+   } else {
+   /* accessing PMINTENCLR_EL1 */
+   vcpu_sys_reg(vcpu, r->reg) &= mask;
+   vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;
+   }
+   } else {
+   p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
+   }
+
+   return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n) \
/* DBGBVRn_EL1 */   \
@@ -806,10 +827,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
/* PMINTENSET_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b001),
- trap_raz_wi },
+ access_pmintenset, reset_unknown, PMINTENSET_EL1 },
/* PMINTENCLR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b010),
- trap_raz_wi },
+ access_pmintenset, NULL, PMINTENSET_EL1 },
 
/* MAIR_EL1 */
{ Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0010), Op2(0b000),
@@ -1204,8 +1225,8 @@ static const struct sys_reg_desc cp15_regs[] = {
{ Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_evtyper },
{ Op1( 0), CRn( 9), CRm(13), Op2( 2), access_pmu_evcntr },
{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
-   { Op1( 0), CRn( 9), CRm(14), Op2( 1), trap_raz_wi },
-   { Op1( 0), CRn( 9), CRm(14), Op2( 2), trap_raz_wi },
+   { Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
+   { Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
 
{ Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
{ Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
-- 
2.0.4


___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[PATCH v7 09/19] KVM: ARM64: Add access handler for event counter register

2015-12-15 Thread Shannon Zhao
From: Shannon Zhao 

These kind of registers include PMEVCNTRn, PMCCNTR and PMXEVCNTR which
is mapped to PMEVCNTRn.

The access handler translates all aarch32 register offsets to aarch64
ones and uses vcpu_sys_reg() to access their values to avoid taking care
of big endian.

When reading these registers, return the sum of register value and the
value perf event counts.

Signed-off-by: Shannon Zhao 
---
 arch/arm64/kvm/sys_regs.c | 136 --
 1 file changed, 132 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c52ff15..dc6bb26 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -566,6 +566,55 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, 
struct sys_reg_params *p,
return true;
 }
 
+static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
+ struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+   u64 idx, reg, val;
+
+   if (!p->is_aarch32) {
+   if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 2)
+   /* PMXEVCNTR_EL0 */
+   reg = 0;
+   else
+   /* PMEVCNTRn_EL0 or PMCCNTR_EL0 */
+   reg = r->reg;
+   } else {
+   if (r->CRn == 9 && r->CRm == 13) {
+   reg = (r->Op2 & 2) ? 0 : PMCCNTR_EL0;
+   } else {
+   reg = ((r->CRm & 3) << 3) & (r->Op2 & 7);
+   reg += PMEVCNTR0_EL0;
+   }
+   }
+
+   switch (reg) {
+   case PMEVCNTR0_EL0 ... PMEVCNTR30_EL0:
+   idx = reg - PMEVCNTR0_EL0;
+   break;
+   case PMCCNTR_EL0:
+   idx = ARMV8_CYCLE_IDX;
+   break;
+   default:
+   /* PMXEVCNTR_EL0 */
+   idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK;
+   if (!pmu_counter_idx_valid(vcpu, idx))
+   return true;
+
+   reg = (idx == ARMV8_CYCLE_IDX) ? PMCCNTR_EL0
+: PMEVCNTR0_EL0 + idx;
+   break;
+   }
+
+   val = kvm_pmu_get_counter_value(vcpu, idx);
+   if (p->is_write)
+   vcpu_sys_reg(vcpu, reg) += (s64)p->regval - val;
+   else
+   p->regval = val;
+
+   return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n) \
/* DBGBVRn_EL1 */   \
@@ -581,6 +630,13 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, 
struct sys_reg_params *p,
{ Op0(0b10), Op1(0b000), CRn(0b), CRm((n)), Op2(0b111), \
  trap_wcr, reset_wcr, n, 0,  get_wcr, set_wcr }
 
+/* Macro to expand the PMEVCNTRn_EL0 register */
+#define PMU_PMEVCNTR_EL0(n)\
+   /* PMEVCNTRn_EL0 */ \
+   { Op0(0b11), Op1(0b011), CRn(0b1110),   \
+ CRm((0b1000 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)), \
+ access_pmu_evcntr, reset_unknown, (PMEVCNTR0_EL0 + n), }
+
 /* Macro to expand the PMEVTYPERn_EL0 register */
 #define PMU_PMEVTYPER_EL0(n)   \
/* PMEVTYPERn_EL0 */\
@@ -781,13 +837,13 @@ static const struct sys_reg_desc sys_reg_descs[] = {
  access_pmceid },
/* PMCCNTR_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b000),
- trap_raz_wi },
+ access_pmu_evcntr, reset_unknown, PMCCNTR_EL0 },
/* PMXEVTYPER_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b001),
  access_pmu_evtyper },
/* PMXEVCNTR_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b010),
- trap_raz_wi },
+ access_pmu_evcntr },
/* PMUSERENR_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b000),
  trap_raz_wi },
@@ -802,6 +858,38 @@ static const struct sys_reg_desc sys_reg_descs[] = {
{ Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b), Op2(0b011),
  NULL, reset_unknown, TPIDRRO_EL0 },
 
+   /* PMEVCNTRn_EL0 */
+   PMU_PMEVCNTR_EL0(0),
+   PMU_PMEVCNTR_EL0(1),
+   PMU_PMEVCNTR_EL0(2),
+   PMU_PMEVCNTR_EL0(3),
+   PMU_PMEVCNTR_EL0(4),
+   PMU_PMEVCNTR_EL0(5),
+   PMU_PMEVCNTR_EL0(6),
+   PMU_PMEVCNTR_EL0(7),
+   PMU_PMEVCNTR_EL0(8),
+   PMU_PMEVCNTR_EL0(9),
+   PMU_PMEVCNTR_EL0(10),
+   PMU_PMEVCNTR_EL0(11),
+   PMU_PMEVCNTR_EL0(12),
+   PMU_PMEVCNTR_EL0(13),
+   PMU_PMEVCNTR_EL0(14),
+   PMU_PMEVCNTR_EL0(15),
+   PMU_PMEVCNTR_EL0(16),
+   

[PATCH v7 04/19] KVM: ARM64: Add access handler for PMCR register

2015-12-15 Thread Shannon Zhao
From: Shannon Zhao 

Add reset handler which gets host value of PMCR_EL0 and make writable
bits architecturally UNKNOWN except PMCR.E which is zero. Add an access
handler for PMCR.

Signed-off-by: Shannon Zhao 
---
 arch/arm64/kvm/sys_regs.c | 39 +--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index d2650e8..9a06116 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -33,6 +33,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 
@@ -438,6 +439,40 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const 
struct sys_reg_desc *r)
vcpu_sys_reg(vcpu, MPIDR_EL1) = (1ULL << 31) | mpidr;
 }
 
+static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+   u64 pmcr, val;
+
+   asm volatile("mrs %0, pmcr_el0\n" : "=r" (pmcr));
+   /* Writable bits of PMCR_EL0 (ARMV8_PMCR_MASK) is reset to UNKNOWN
+* except PMCR.E resetting to zero.
+*/
+   val = ((pmcr & ~ARMV8_PMCR_MASK) | (ARMV8_PMCR_MASK & 0xdecafbad))
+ & (~ARMV8_PMCR_E);
+   vcpu_sys_reg(vcpu, r->reg) = val;
+}
+
+static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+   const struct sys_reg_desc *r)
+{
+   u64 val;
+
+   if (p->is_write) {
+   /* Only update writeable bits of PMCR */
+   val = vcpu_sys_reg(vcpu, r->reg);
+   val &= ~ARMV8_PMCR_MASK;
+   val |= p->regval & ARMV8_PMCR_MASK;
+   vcpu_sys_reg(vcpu, r->reg) = val;
+   } else {
+   /* PMCR.P & PMCR.C are RAZ */
+   val = vcpu_sys_reg(vcpu, r->reg)
+ & ~(ARMV8_PMCR_P | ARMV8_PMCR_C);
+   p->regval = val;
+   }
+
+   return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n) \
/* DBGBVRn_EL1 */   \
@@ -622,7 +657,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
/* PMCR_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b000),
- trap_raz_wi },
+ access_pmcr, reset_pmcr, PMCR_EL0, },
/* PMCNTENSET_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b001),
  trap_raz_wi },
@@ -884,7 +919,7 @@ static const struct sys_reg_desc cp15_regs[] = {
{ Op1( 0), CRn( 7), CRm(14), Op2( 2), access_dcsw },
 
/* PMU */
-   { Op1( 0), CRn( 9), CRm(12), Op2( 0), trap_raz_wi },
+   { Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
{ Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
{ Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
-- 
2.0.4


___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[PATCH v7 15/19] KVM: ARM64: Add access handler for PMUSERENR register

2015-12-15 Thread Shannon Zhao
From: Shannon Zhao 

The reset value of PMUSERENR_EL0 is UNKNOWN, use reset_unknown.

PMUSERENR_EL0 holds some bits which decide whether PMU registers can be
accessed from EL0. Add some check helpers to handle the access from EL0.

Signed-off-by: Shannon Zhao 
---
 arch/arm64/kvm/sys_regs.c | 124 --
 1 file changed, 119 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index b2ccc25..bad3dfd 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -452,12 +452,44 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const 
struct sys_reg_desc *r)
vcpu_sys_reg(vcpu, r->reg) = val;
 }
 
+static inline bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
+{
+   u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+
+   return !((reg & 0x1) || vcpu_mode_priv(vcpu));
+}
+
+static inline bool pmu_write_swinc_el0_disabled(struct kvm_vcpu *vcpu)
+{
+   u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+
+   return !((reg & 0x3) || vcpu_mode_priv(vcpu));
+}
+
+static inline bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu *vcpu)
+{
+   u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+
+   return !((reg & 0x5) || vcpu_mode_priv(vcpu));
+}
+
+static inline bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu *vcpu)
+{
+   u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+
+   return !((reg & 0x9) || vcpu_mode_priv(vcpu));
+}
+
 static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
const struct sys_reg_desc *r)
 {
u64 val;
+   bool unaccessible = pmu_access_el0_disabled(vcpu);
 
if (p->is_write) {
+   if (unaccessible)
+   return ignore_write(vcpu, p);
+
/* Only update writeable bits of PMCR */
val = vcpu_sys_reg(vcpu, r->reg);
val &= ~ARMV8_PMCR_MASK;
@@ -465,6 +497,9 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct 
sys_reg_params *p,
vcpu_sys_reg(vcpu, r->reg) = val;
kvm_pmu_handle_pmcr(vcpu, val);
} else {
+   if (unaccessible)
+   return read_zero(vcpu, p);
+
/* PMCR.P & PMCR.C are RAZ */
val = vcpu_sys_reg(vcpu, r->reg)
  & ~(ARMV8_PMCR_P | ARMV8_PMCR_C);
@@ -477,9 +512,17 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct 
sys_reg_params *p,
 static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
  const struct sys_reg_desc *r)
 {
+   bool unaccessible = pmu_access_event_counter_el0_disabled(vcpu);
+
if (p->is_write) {
+   if (unaccessible)
+   return ignore_write(vcpu, p);
+
vcpu_sys_reg(vcpu, r->reg) = p->regval;
} else {
+   if (unaccessible)
+   return read_zero(vcpu, p);
+
/* return PMSELR.SEL field */
p->regval = vcpu_sys_reg(vcpu, r->reg) & ARMV8_COUNTER_MASK;
}
@@ -494,6 +537,8 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct 
sys_reg_params *p,
 
if (p->is_write)
return write_to_read_only(vcpu, p);
+   else if (pmu_access_el0_disabled(vcpu))
+   return read_zero(vcpu, p);
 
if (!(p->Op2 & 1))
asm volatile("mrs %0, pmceid0_el0\n" : "=r" (pmceid));
@@ -521,6 +566,7 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, 
struct sys_reg_params *p,
   const struct sys_reg_desc *r)
 {
u64 idx, reg;
+   bool unaccessible = pmu_access_el0_disabled(vcpu);
 
if (r->CRn == 9) {
/* PMXEVTYPER_EL0 */
@@ -558,9 +604,15 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, 
struct sys_reg_params *p,
}
 
if (p->is_write) {
+   if (unaccessible)
+   return ignore_write(vcpu, p);
+
kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_EVTYPE_MASK;
} else {
+   if (unaccessible)
+   return read_zero(vcpu, p);
+
p->regval = vcpu_sys_reg(vcpu, reg) & ARMV8_EVTYPE_MASK;
}
 
@@ -572,6 +624,7 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
  const struct sys_reg_desc *r)
 {
u64 idx, reg, val;
+   bool unaccessible = false;
 
if (!p->is_aarch32) {
if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 2)
@@ -591,13 +644,22 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
 
switch (reg) {
case PMEVCNTR0_EL0 ... PMEVCNTR30_EL0:
+   if (pmu_access_event_counter_el0_disabled(vcpu))
+   unaccessible = true;
+
idx = reg - 

[PATCH v7 07/19] KVM: ARM64: PMU: Add perf event map and introduce perf event creating function

2015-12-15 Thread Shannon Zhao
From: Shannon Zhao 

When we use tools like perf on host, perf passes the event type and the
id of this event type category to kernel, then kernel will map them to
hardware event number and write this number to PMU PMEVTYPER_EL0
register. When getting the event number in KVM, directly use raw event
type to create a perf_event for it.

Signed-off-by: Shannon Zhao 
---
 arch/arm64/include/asm/pmu.h |   3 ++
 arch/arm64/kvm/Makefile  |   1 +
 include/kvm/arm_pmu.h|  11 
 virt/kvm/arm/pmu.c   | 122 +++
 4 files changed, 137 insertions(+)
 create mode 100644 virt/kvm/arm/pmu.c

diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h
index 4264ea0..714edcc 100644
--- a/arch/arm64/include/asm/pmu.h
+++ b/arch/arm64/include/asm/pmu.h
@@ -18,6 +18,7 @@
 
 #define ARMV8_MAX_COUNTERS  32
 #define ARMV8_COUNTER_MASK  (ARMV8_MAX_COUNTERS - 1)
+#define ARMV8_CYCLE_IDX (ARMV8_MAX_COUNTERS - 1)
 
 /*
  * Per-CPU PMCR: config reg
@@ -28,6 +29,8 @@
 #define ARMV8_PMCR_D   (1 << 3) /* CCNT counts every 64th cpu cycle */
 #define ARMV8_PMCR_X   (1 << 4) /* Export to ETM */
 #define ARMV8_PMCR_DP  (1 << 5) /* Disable CCNT if non-invasive debug*/
+/* Determines which PMCCNTR_EL0 bit generates an overflow */
+#define ARMV8_PMCR_LC  (1 << 6)
 #defineARMV8_PMCR_N_SHIFT  11   /* Number of counters 
supported */
 #defineARMV8_PMCR_N_MASK   0x1f
 #defineARMV8_PMCR_MASK 0x3f /* Mask for writable bits */
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 1949fe5..18d56d8 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -27,3 +27,4 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
 kvm-$(CONFIG_KVM_ARM_HOST) += vgic-v3-switch.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
+kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index ddcb5b2..14bedb0 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -34,9 +34,20 @@ struct kvm_pmu {
int irq_num;
struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
 };
+
+u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
+void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
+   u64 select_idx);
 #else
 struct kvm_pmu {
 };
+
+u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
+{
+   return 0;
+}
+void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
+   u64 select_idx) {}
 #endif
 
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
new file mode 100644
index 000..b107fb8
--- /dev/null
+++ b/virt/kvm/arm/pmu.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2015 Linaro Ltd.
+ * Author: Shannon Zhao 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see .
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/**
+ * kvm_pmu_get_counter_value - get PMU counter value
+ * @vcpu: The vcpu pointer
+ * @select_idx: The counter index
+ */
+u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
+{
+   u64 counter, reg, enabled, running;
+   struct kvm_pmu *pmu = >arch.pmu;
+   struct kvm_pmc *pmc = >pmc[select_idx];
+
+   reg = (select_idx == ARMV8_CYCLE_IDX)
+ ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
+   counter = vcpu_sys_reg(vcpu, reg);
+
+   /* The real counter value is equal to the value of counter register plus
+* the value perf event counts.
+*/
+   if (pmc->perf_event)
+   counter += perf_event_read_value(pmc->perf_event, ,
+);
+
+   return counter & pmc->bitmask;
+}
+
+static inline bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu,
+ u64 select_idx)
+{
+   return (vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E) &&
+  (vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
+}
+
+/**
+ * kvm_pmu_stop_counter - stop PMU counter
+ * @pmc: The PMU counter pointer
+ *
+ * If this counter has been configured to monitor some event, release it here.
+ */
+static void kvm_pmu_stop_counter(struct kvm_vcpu 

[PATCH v7 02/19] KVM: ARM64: Define PMU data structure for each vcpu

2015-12-15 Thread Shannon Zhao
From: Shannon Zhao 

Here we plan to support virtual PMU for guest by full software
emulation, so define some basic structs and functions preparing for
futher steps. Define struct kvm_pmc for performance monitor counter and
struct kvm_pmu for performance monitor unit for each vcpu. According to
ARMv8 spec, the PMU contains at most 32(ARMV8_MAX_COUNTERS) counters.

Since this only supports ARM64 (or PMUv3), add a separate config symbol
for it.

Signed-off-by: Shannon Zhao 
---
 arch/arm64/include/asm/kvm_host.h |  2 ++
 arch/arm64/kvm/Kconfig|  7 +++
 include/kvm/arm_pmu.h | 42 +++
 3 files changed, 51 insertions(+)
 create mode 100644 include/kvm/arm_pmu.h

diff --git a/arch/arm64/include/asm/kvm_host.h 
b/arch/arm64/include/asm/kvm_host.h
index a35ce72..42e15bb 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -37,6 +37,7 @@
 
 #include 
 #include 
+#include 
 
 #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
 
@@ -132,6 +133,7 @@ struct kvm_vcpu_arch {
/* VGIC state */
struct vgic_cpu vgic_cpu;
struct arch_timer_cpu timer_cpu;
+   struct kvm_pmu pmu;
 
/*
 * Anything that is not used directly from assembly code goes
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index a5272c0..de7450d 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -36,6 +36,7 @@ config KVM
select HAVE_KVM_EVENTFD
select HAVE_KVM_IRQFD
select KVM_ARM_VGIC_V3
+   select KVM_ARM_PMU if HW_PERF_EVENTS
---help---
  Support hosting virtualized guest machines.
  We don't support KVM with 16K page tables yet, due to the multiple
@@ -48,6 +49,12 @@ config KVM_ARM_HOST
---help---
  Provides host support for ARM processors.
 
+config KVM_ARM_PMU
+   bool
+   ---help---
+ Adds support for a virtual Performance Monitoring Unit (PMU) in
+ virtual machines.
+
 source drivers/vhost/Kconfig
 
 endif # VIRTUALIZATION
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
new file mode 100644
index 000..ddcb5b2
--- /dev/null
+++ b/include/kvm/arm_pmu.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 Linaro Ltd.
+ * Author: Shannon Zhao 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see .
+ */
+
+#ifndef __ASM_ARM_KVM_PMU_H
+#define __ASM_ARM_KVM_PMU_H
+
+#ifdef CONFIG_KVM_ARM_PMU
+
+#include 
+#include 
+
+struct kvm_pmc {
+   u8 idx;/* index into the pmu->pmc array */
+   struct perf_event *perf_event;
+   u64 bitmask;
+};
+
+struct kvm_pmu {
+   /* PMU IRQ Number per VCPU */
+   int irq_num;
+   struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
+};
+#else
+struct kvm_pmu {
+};
+#endif
+
+#endif
-- 
2.0.4


___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[PATCH v7 05/19] KVM: ARM64: Add access handler for PMSELR register

2015-12-15 Thread Shannon Zhao
From: Shannon Zhao 

Since the reset value of PMSELR_EL0 is UNKNOWN, use reset_unknown for
its reset handler. When reading PMSELR, return the PMSELR.SEL field to
guest.

Signed-off-by: Shannon Zhao 
---
 arch/arm64/kvm/sys_regs.c | 17 +++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 9a06116..c21f91b 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -473,6 +473,19 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct 
sys_reg_params *p,
return true;
 }
 
+static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+   if (p->is_write) {
+   vcpu_sys_reg(vcpu, r->reg) = p->regval;
+   } else {
+   /* return PMSELR.SEL field */
+   p->regval = vcpu_sys_reg(vcpu, r->reg) & ARMV8_COUNTER_MASK;
+   }
+
+   return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n) \
/* DBGBVRn_EL1 */   \
@@ -672,7 +685,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
  trap_raz_wi },
/* PMSELR_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b101),
- trap_raz_wi },
+ access_pmselr, reset_unknown, PMSELR_EL0 },
/* PMCEID0_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b110),
  trap_raz_wi },
@@ -923,7 +936,7 @@ static const struct sys_reg_desc cp15_regs[] = {
{ Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
{ Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
-   { Op1( 0), CRn( 9), CRm(12), Op2( 5), trap_raz_wi },
+   { Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
{ Op1( 0), CRn( 9), CRm(12), Op2( 6), trap_raz_wi },
{ Op1( 0), CRn( 9), CRm(12), Op2( 7), trap_raz_wi },
{ Op1( 0), CRn( 9), CRm(13), Op2( 0), trap_raz_wi },
-- 
2.0.4


___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[PATCH v7 14/19] KVM: ARM64: Add helper to handle PMCR register bits

2015-12-15 Thread Shannon Zhao
From: Shannon Zhao 

According to ARMv8 spec, when writing 1 to PMCR.E, all counters are
enabled by PMCNTENSET, while writing 0 to PMCR.E, all counters are
disabled. When writing 1 to PMCR.P, reset all event counters, not
including PMCCNTR, to zero. When writing 1 to PMCR.C, reset PMCCNTR to
zero.

Signed-off-by: Shannon Zhao 
---
 arch/arm64/kvm/sys_regs.c |  1 +
 include/kvm/arm_pmu.h |  2 ++
 virt/kvm/arm/pmu.c| 40 
 3 files changed, 43 insertions(+)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f09e500..b2ccc25 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -463,6 +463,7 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct 
sys_reg_params *p,
val &= ~ARMV8_PMCR_MASK;
val |= p->regval & ARMV8_PMCR_MASK;
vcpu_sys_reg(vcpu, r->reg) = val;
+   kvm_pmu_handle_pmcr(vcpu, val);
} else {
/* PMCR.P & PMCR.C are RAZ */
val = vcpu_sys_reg(vcpu, r->reg)
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index f5888eb..25b5f98 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -42,6 +42,7 @@ void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
u64 select_idx);
+void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val);
 #else
 struct kvm_pmu {
 };
@@ -56,6 +57,7 @@ void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
u64 select_idx) {}
+void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val) {}
 #endif
 
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 01af727..e664721 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -130,6 +130,46 @@ void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 
val)
 }
 
 /**
+ * kvm_pmu_handle_pmcr - handle PMCR register
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMCR register
+ */
+void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
+{
+   struct kvm_pmu *pmu = >arch.pmu;
+   struct kvm_pmc *pmc;
+   int i;
+
+   if (val & ARMV8_PMCR_E) {
+   kvm_pmu_enable_counter(vcpu,
+  vcpu_sys_reg(vcpu, PMCNTENSET_EL0));
+   } else {
+   kvm_pmu_disable_counter(vcpu, 0xUL);
+   }
+
+   if (val & ARMV8_PMCR_C) {
+   pmc = >pmc[ARMV8_CYCLE_IDX];
+   if (pmc->perf_event)
+   local64_set(>perf_event->count, 0);
+   vcpu_sys_reg(vcpu, PMCCNTR_EL0) = 0;
+   }
+
+   if (val & ARMV8_PMCR_P) {
+   for (i = 0; i < ARMV8_CYCLE_IDX; i++) {
+   pmc = >pmc[i];
+   if (pmc->perf_event)
+   local64_set(>perf_event->count, 0);
+   vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = 0;
+   }
+   }
+
+   if (val & ARMV8_PMCR_LC) {
+   pmc = >pmc[ARMV8_CYCLE_IDX];
+   pmc->bitmask = 0xUL;
+   }
+}
+
+/**
  * kvm_pmu_overflow_set - set PMU overflow interrupt
  * @vcpu: The vcpu pointer
  * @val: the value guest writes to PMOVSSET register
-- 
2.0.4


___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[PATCH v7 08/19] KVM: ARM64: Add access handler for event typer register

2015-12-15 Thread Shannon Zhao
From: Shannon Zhao 

These kind of registers include PMEVTYPERn, PMCCFILTR and PMXEVTYPER
which is mapped to PMEVTYPERn or PMCCFILTR.

The access handler translates all aarch32 register offsets to aarch64
ones and uses vcpu_sys_reg() to access their values to avoid taking care
of big endian.

When writing to these registers, create a perf_event for the selected
event type.

Signed-off-by: Shannon Zhao 
---
 arch/arm64/kvm/sys_regs.c | 154 +-
 1 file changed, 152 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index e043224..c52ff15 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -504,6 +504,68 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct 
sys_reg_params *p,
return true;
 }
 
+static inline bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
+{
+   u64 pmcr, val;
+
+   pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
+   val = (pmcr >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK;
+   if (idx >= val && idx != ARMV8_CYCLE_IDX)
+   return false;
+
+   return true;
+}
+
+static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+  const struct sys_reg_desc *r)
+{
+   u64 idx, reg;
+
+   if (r->CRn == 9) {
+   /* PMXEVTYPER_EL0 */
+   reg = 0;
+   } else {
+   if (!p->is_aarch32) {
+   /* PMEVTYPERn_EL0 or PMCCFILTR_EL0 */
+   reg = r->reg;
+   } else {
+   if (r->CRn == 14 && r->CRm == 15 && r->Op2 == 7) {
+   reg = PMCCFILTR_EL0;
+   } else {
+   reg = ((r->CRm & 3) << 3) & (r->Op2 & 7);
+   reg += PMEVTYPER0_EL0;
+   }
+   }
+   }
+
+   switch (reg) {
+   case PMEVTYPER0_EL0 ... PMEVTYPER30_EL0:
+   idx = reg - PMEVTYPER0_EL0;
+   break;
+   case PMCCFILTR_EL0:
+   idx = ARMV8_CYCLE_IDX;
+   break;
+   default:
+   /* PMXEVTYPER_EL0 */
+   idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK;
+   if (!pmu_counter_idx_valid(vcpu, idx))
+   return true;
+
+   reg = (idx == ARMV8_CYCLE_IDX) ? PMCCFILTR_EL0
+: PMEVTYPER0_EL0 + idx;
+   break;
+   }
+
+   if (p->is_write) {
+   kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
+   vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_EVTYPE_MASK;
+   } else {
+   p->regval = vcpu_sys_reg(vcpu, reg) & ARMV8_EVTYPE_MASK;
+   }
+
+   return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n) \
/* DBGBVRn_EL1 */   \
@@ -519,6 +581,13 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct 
sys_reg_params *p,
{ Op0(0b10), Op1(0b000), CRn(0b), CRm((n)), Op2(0b111), \
  trap_wcr, reset_wcr, n, 0,  get_wcr, set_wcr }
 
+/* Macro to expand the PMEVTYPERn_EL0 register */
+#define PMU_PMEVTYPER_EL0(n)   \
+   /* PMEVTYPERn_EL0 */\
+   { Op0(0b11), Op1(0b011), CRn(0b1110),   \
+ CRm((0b1100 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)), \
+ access_pmu_evtyper, reset_unknown, (PMEVTYPER0_EL0 + n), }
+
 /*
  * Architected system registers.
  * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
@@ -715,7 +784,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
  trap_raz_wi },
/* PMXEVTYPER_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b001),
- trap_raz_wi },
+ access_pmu_evtyper },
/* PMXEVCNTR_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b010),
  trap_raz_wi },
@@ -733,6 +802,45 @@ static const struct sys_reg_desc sys_reg_descs[] = {
{ Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b), Op2(0b011),
  NULL, reset_unknown, TPIDRRO_EL0 },
 
+   /* PMEVTYPERn_EL0 */
+   PMU_PMEVTYPER_EL0(0),
+   PMU_PMEVTYPER_EL0(1),
+   PMU_PMEVTYPER_EL0(2),
+   PMU_PMEVTYPER_EL0(3),
+   PMU_PMEVTYPER_EL0(4),
+   PMU_PMEVTYPER_EL0(5),
+   PMU_PMEVTYPER_EL0(6),
+   PMU_PMEVTYPER_EL0(7),
+   PMU_PMEVTYPER_EL0(8),
+   PMU_PMEVTYPER_EL0(9),
+   PMU_PMEVTYPER_EL0(10),
+   PMU_PMEVTYPER_EL0(11),
+   PMU_PMEVTYPER_EL0(12),
+   PMU_PMEVTYPER_EL0(13),
+   PMU_PMEVTYPER_EL0(14),
+   PMU_PMEVTYPER_EL0(15),
+   PMU_PMEVTYPER_EL0(16),

[PATCH v7 12/19] KVM: ARM64: Add access handler for PMOVSSET and PMOVSCLR register

2015-12-15 Thread Shannon Zhao
From: Shannon Zhao 

Since the reset value of PMOVSSET and PMOVSCLR is UNKNOWN, use
reset_unknown for its reset handler. Add a handler to emulate writing
PMOVSSET or PMOVSCLR register.

When writing non-zero value to PMOVSSET, pend PMU interrupt.

Signed-off-by: Shannon Zhao 
---
 arch/arm64/kvm/sys_regs.c | 28 +---
 include/kvm/arm_pmu.h |  2 ++
 virt/kvm/arm/pmu.c| 20 
 3 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 594e53f..d1926c4 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -669,6 +669,27 @@ static bool access_pmintenset(struct kvm_vcpu *vcpu, 
struct sys_reg_params *p,
return true;
 }
 
+static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+   const struct sys_reg_desc *r)
+{
+   u64 mask = kvm_pmu_valid_counter_mask(vcpu);
+
+   if (p->is_write) {
+   if (r->CRm & 0x2) {
+   /* accessing PMOVSSET_EL0 */
+   kvm_pmu_overflow_set(vcpu, p->regval & mask);
+   } else {
+   /* accessing PMOVSCLR_EL0 */
+   vcpu_sys_reg(vcpu, r->reg) &= mask;
+   vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;
+   }
+   } else {
+   p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
+   }
+
+   return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n) \
/* DBGBVRn_EL1 */   \
@@ -876,7 +897,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
  access_pmcntenset, NULL, PMCNTENSET_EL0 },
/* PMOVSCLR_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
- trap_raz_wi },
+ access_pmovsset, NULL, PMOVSSET_EL0 },
/* PMSWINC_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
  trap_raz_wi },
@@ -903,7 +924,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
  trap_raz_wi },
/* PMOVSSET_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b011),
- trap_raz_wi },
+ access_pmovsset, reset_unknown, PMOVSSET_EL0 },
 
/* TPIDR_EL0 */
{ Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b), Op2(0b010),
@@ -1217,7 +1238,7 @@ static const struct sys_reg_desc cp15_regs[] = {
{ Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
-   { Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
+   { Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovsset },
{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
@@ -1227,6 +1248,7 @@ static const struct sys_reg_desc cp15_regs[] = {
{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
{ Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
{ Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
+   { Op1( 0), CRn( 9), CRm(14), Op2( 3), access_pmovsset },
 
{ Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
{ Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 43c4117..93aea6a 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -38,6 +38,7 @@ struct kvm_pmu {
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
+void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
u64 select_idx);
 #else
@@ -50,6 +51,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 
select_idx)
 }
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
+void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
u64 select_idx) {}
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 94bff0e..861471d 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -130,6 +130,26 @@ void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 
val)
 }
 
 /**
+ * kvm_pmu_overflow_set - set PMU overflow interrupt
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMOVSSET register
+ */
+void 

RE: ARM64/KVM: Bad page state in process iperf

2015-12-15 Thread Bhushan Bharat
Hi Mark,

> -Original Message-
> From: Marc Zyngier [mailto:marc.zyng...@arm.com]
> Sent: Tuesday, December 15, 2015 3:05 PM
> To: Bhushan Bharat-R65777 ;
> kvmarm@lists.cs.columbia.edu; k...@vger.kernel.org; linux-arm-
> ker...@lists.infradead.org; linux-ker...@vger.kernel.org
> Subject: Re: ARM64/KVM: Bad page state in process iperf
> 
> On 15/12/15 03:46, Bhushan Bharat wrote:
> >
> > Hi All,
> >
> > I am running "iperf" in KVM guest on ARM64 machine and observing below
> crash.
> >
> > =
> > $iperf -c 3.3.3.3 -P 4 -t 0 -i 5 -w 90k
> > 
> > Client connecting to 3.3.3.3, TCP port 5001 TCP window size:  180
> > KByte (WARNING: requested 90.0 KByte)
> > 
> > [  3] local 3.3.3.1 port 51131 connected with 3.3.3.3 port 5001 [  6]
> > local 3.3.3.1 port 51134 connected with 3.3.3.3 port 5001 [  5] local
> > 3.3.3.1 port 51133 connected with 3.3.3.3 port 5001 [  4] local
> > 3.3.3.1 port 51132 connected with 3.3.3.3 port 5001
> > [   53.088567] random: nonblocking pool is initialized
> > [ ID] Interval   Transfer Bandwidth
> > [  3]  0.0- 5.0 sec   638 MBytes  1.07 Gbits/sec
> > [  4] 35.0-40.0 sec  1.66 GBytes  2.85 Gbits/sec [  5] 40.0-45.0 sec
> > 1.11 GBytes  1.90 Gbits/sec [  4] 40.0-45.0 sec  1.16 GBytes  1.99
> > Gbits/sec
> > [   98.895207] BUG: Bad page state in process iperf  pfn:0a584
> > [   98.896164] page:78296100 count:-1 mapcount:0 mapping:
> (null) index:0x0
> > [   98.897436] flags: 0x0()
> > [   98.897885] page dumped because: nonzero _count
> > [   98.898640] Modules linked in:
> > [   98.899178] CPU: 0 PID: 1639 Comm: iperf Not tainted 4.1.8-00461-
> ge5431ad #141
> > [   98.900302] Hardware name: linux,dummy-virt (DT)
> > [   98.901014] Call trace:
> > [   98.901406] [] dump_backtrace+0x0/0x12c
> > [   98.902522] [] show_stack+0x10/0x1c
> > [   98.903441] [] dump_stack+0x8c/0xdc
> > [   98.904202] [] bad_page+0xc4/0x114
> > [   98.904945] [] get_page_from_freelist+0x590/0x63c
> > [   98.905871] [] __alloc_pages_nodemask+0xec/0x794
> > [   98.906791] [] skb_page_frag_refill+0x70/0xa8
> > [   98.907678] [] sk_page_frag_refill+0x20/0xd0
> > [   98.908550] [] tcp_sendmsg+0x1f8/0x9a8
> > [   98.909368] [] inet_sendmsg+0x5c/0xd0
> > [   98.910178] [] sock_sendmsg+0x14/0x58
> > [   98.911027] [] sock_write_iter+0x64/0xbc
> > [   98.912119] [] __vfs_write+0xac/0x10c
> > [   98.913126] [] vfs_write+0x90/0x1a0
> > [   98.913963] [] SyS_write+0x40/0xa0
> 
> This looks quite bad, but I don't see anything here that links it to KVM 
> (apart
> from being a guest). Do you have any indication that this is due to KVM
> misbehaving? 

I never observed this issue in host Linux but observed this issue always in 
guest Linux. This issue does not comes immediately after I run "iperf" but 
after some time.

> I'd appreciate a few more details.

We have a networking hardware and we are directly assigning the h/w to guest. 
When using the same networking hardware in host it always works as expected 
(tried 100s of times).
Also this issue is not observed when we have only one vCPU in guest but seen 
when we have SMP guest. 

Thanks
-Bharat

> 
> Thanks,
> 
>   M.
> --
> Jazz is not dead. It just smells funny...
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: ARM64/KVM: Bad page state in process iperf

2015-12-15 Thread Marc Zyngier
On 15/12/15 09:53, Bhushan Bharat wrote:
> Hi Mark,
> 
>> -Original Message-
>> From: Marc Zyngier [mailto:marc.zyng...@arm.com]
>> Sent: Tuesday, December 15, 2015 3:05 PM
>> To: Bhushan Bharat-R65777 ;
>> kvmarm@lists.cs.columbia.edu; k...@vger.kernel.org; linux-arm-
>> ker...@lists.infradead.org; linux-ker...@vger.kernel.org
>> Subject: Re: ARM64/KVM: Bad page state in process iperf
>>
>> On 15/12/15 03:46, Bhushan Bharat wrote:
>>>
>>> Hi All,
>>>
>>> I am running "iperf" in KVM guest on ARM64 machine and observing below
>> crash.
>>>
>>> =
>>> $iperf -c 3.3.3.3 -P 4 -t 0 -i 5 -w 90k
>>> 
>>> Client connecting to 3.3.3.3, TCP port 5001 TCP window size:  180
>>> KByte (WARNING: requested 90.0 KByte)
>>> 
>>> [  3] local 3.3.3.1 port 51131 connected with 3.3.3.3 port 5001 [  6]
>>> local 3.3.3.1 port 51134 connected with 3.3.3.3 port 5001 [  5] local
>>> 3.3.3.1 port 51133 connected with 3.3.3.3 port 5001 [  4] local
>>> 3.3.3.1 port 51132 connected with 3.3.3.3 port 5001
>>> [   53.088567] random: nonblocking pool is initialized
>>> [ ID] Interval   Transfer Bandwidth
>>> [  3]  0.0- 5.0 sec   638 MBytes  1.07 Gbits/sec
>>> [  4] 35.0-40.0 sec  1.66 GBytes  2.85 Gbits/sec [  5] 40.0-45.0 sec
>>> 1.11 GBytes  1.90 Gbits/sec [  4] 40.0-45.0 sec  1.16 GBytes  1.99
>>> Gbits/sec
>>> [   98.895207] BUG: Bad page state in process iperf  pfn:0a584
>>> [   98.896164] page:78296100 count:-1 mapcount:0 mapping:
>> (null) index:0x0
>>> [   98.897436] flags: 0x0()
>>> [   98.897885] page dumped because: nonzero _count
>>> [   98.898640] Modules linked in:
>>> [   98.899178] CPU: 0 PID: 1639 Comm: iperf Not tainted 4.1.8-00461-
>> ge5431ad #141
>>> [   98.900302] Hardware name: linux,dummy-virt (DT)
>>> [   98.901014] Call trace:
>>> [   98.901406] [] dump_backtrace+0x0/0x12c
>>> [   98.902522] [] show_stack+0x10/0x1c
>>> [   98.903441] [] dump_stack+0x8c/0xdc
>>> [   98.904202] [] bad_page+0xc4/0x114
>>> [   98.904945] [] get_page_from_freelist+0x590/0x63c
>>> [   98.905871] [] __alloc_pages_nodemask+0xec/0x794
>>> [   98.906791] [] skb_page_frag_refill+0x70/0xa8
>>> [   98.907678] [] sk_page_frag_refill+0x20/0xd0
>>> [   98.908550] [] tcp_sendmsg+0x1f8/0x9a8
>>> [   98.909368] [] inet_sendmsg+0x5c/0xd0
>>> [   98.910178] [] sock_sendmsg+0x14/0x58
>>> [   98.911027] [] sock_write_iter+0x64/0xbc
>>> [   98.912119] [] __vfs_write+0xac/0x10c
>>> [   98.913126] [] vfs_write+0x90/0x1a0
>>> [   98.913963] [] SyS_write+0x40/0xa0
>>
>> This looks quite bad, but I don't see anything here that links it to KVM 
>> (apart
>> from being a guest). Do you have any indication that this is due to KVM
>> misbehaving? 
> 
> I never observed this issue in host Linux but observed this issue always in 
> guest Linux. This issue does not comes immediately after I run "iperf" but 
> after some time.
> 
>> I'd appreciate a few more details.
> 
> We have a networking hardware and we are directly assigning the h/w to guest. 
> When using the same networking hardware in host it always works as expected 
> (tried 100s of times).
> Also this issue is not observed when we have only one vCPU in guest but seen 
> when we have SMP guest. 

Can you reproduce the same issue without VFIO (using virtio, for
example)? Is that platform VFIO? or PCI?

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


RE: ARM64/KVM: Bad page state in process iperf

2015-12-15 Thread Bhushan Bharat


> -Original Message-
> From: Marc Zyngier [mailto:marc.zyng...@arm.com]
> Sent: Tuesday, December 15, 2015 3:50 PM
> To: Bhushan Bharat-R65777 ;
> kvmarm@lists.cs.columbia.edu; k...@vger.kernel.org; linux-arm-
> ker...@lists.infradead.org; linux-ker...@vger.kernel.org
> Subject: Re: ARM64/KVM: Bad page state in process iperf
> 
> On 15/12/15 09:53, Bhushan Bharat wrote:
> > Hi Mark,
> >
> >> -Original Message-
> >> From: Marc Zyngier [mailto:marc.zyng...@arm.com]
> >> Sent: Tuesday, December 15, 2015 3:05 PM
> >> To: Bhushan Bharat-R65777 ;
> >> kvmarm@lists.cs.columbia.edu; k...@vger.kernel.org; linux-arm-
> >> ker...@lists.infradead.org; linux-ker...@vger.kernel.org
> >> Subject: Re: ARM64/KVM: Bad page state in process iperf
> >>
> >> On 15/12/15 03:46, Bhushan Bharat wrote:
> >>>
> >>> Hi All,
> >>>
> >>> I am running "iperf" in KVM guest on ARM64 machine and observing
> >>> below
> >> crash.
> >>>
> >>> =
> >>> $iperf -c 3.3.3.3 -P 4 -t 0 -i 5 -w 90k
> >>> 
> >>> Client connecting to 3.3.3.3, TCP port 5001 TCP window size:  180
> >>> KByte (WARNING: requested 90.0 KByte)
> >>> 
> >>> [  3] local 3.3.3.1 port 51131 connected with 3.3.3.3 port 5001 [
> >>> 6] local 3.3.3.1 port 51134 connected with 3.3.3.3 port 5001 [  5]
> >>> local
> >>> 3.3.3.1 port 51133 connected with 3.3.3.3 port 5001 [  4] local
> >>> 3.3.3.1 port 51132 connected with 3.3.3.3 port 5001
> >>> [   53.088567] random: nonblocking pool is initialized
> >>> [ ID] Interval   Transfer Bandwidth
> >>> [  3]  0.0- 5.0 sec   638 MBytes  1.07 Gbits/sec
> >>> [  4] 35.0-40.0 sec  1.66 GBytes  2.85 Gbits/sec [  5] 40.0-45.0 sec
> >>> 1.11 GBytes  1.90 Gbits/sec [  4] 40.0-45.0 sec  1.16 GBytes  1.99
> >>> Gbits/sec
> >>> [   98.895207] BUG: Bad page state in process iperf  pfn:0a584
> >>> [   98.896164] page:78296100 count:-1 mapcount:0 mapping:
> >> (null) index:0x0
> >>> [   98.897436] flags: 0x0()
> >>> [   98.897885] page dumped because: nonzero _count
> >>> [   98.898640] Modules linked in:
> >>> [   98.899178] CPU: 0 PID: 1639 Comm: iperf Not tainted 4.1.8-00461-
> >> ge5431ad #141
> >>> [   98.900302] Hardware name: linux,dummy-virt (DT)
> >>> [   98.901014] Call trace:
> >>> [   98.901406] [] dump_backtrace+0x0/0x12c
> >>> [   98.902522] [] show_stack+0x10/0x1c
> >>> [   98.903441] [] dump_stack+0x8c/0xdc
> >>> [   98.904202] [] bad_page+0xc4/0x114
> >>> [   98.904945] []
> get_page_from_freelist+0x590/0x63c
> >>> [   98.905871] []
> __alloc_pages_nodemask+0xec/0x794
> >>> [   98.906791] [] skb_page_frag_refill+0x70/0xa8
> >>> [   98.907678] [] sk_page_frag_refill+0x20/0xd0
> >>> [   98.908550] [] tcp_sendmsg+0x1f8/0x9a8
> >>> [   98.909368] [] inet_sendmsg+0x5c/0xd0
> >>> [   98.910178] [] sock_sendmsg+0x14/0x58
> >>> [   98.911027] [] sock_write_iter+0x64/0xbc
> >>> [   98.912119] [] __vfs_write+0xac/0x10c
> >>> [   98.913126] [] vfs_write+0x90/0x1a0
> >>> [   98.913963] [] SyS_write+0x40/0xa0
> >>
> >> This looks quite bad, but I don't see anything here that links it to
> >> KVM (apart from being a guest). Do you have any indication that this
> >> is due to KVM misbehaving?
> >
> > I never observed this issue in host Linux but observed this issue always in
> guest Linux. This issue does not comes immediately after I run "iperf" but
> after some time.
> >
> >> I'd appreciate a few more details.
> >
> > We have a networking hardware and we are directly assigning the h/w to
> guest. When using the same networking hardware in host it always works as
> expected (tried 100s of times).
> > Also this issue is not observed when we have only one vCPU in guest but
> seen when we have SMP guest.
> 
> Can you reproduce the same issue without VFIO (using virtio, for example)?

With virtio I have not observed this issue.

> Is that platform VFIO? or PCI?

It is not vfio-pci and vfio-platform. It is vfio-fls-mc (some Freescale new 
hardware), similar to the lines of vfio-platform uses same set of VFIO APIs 
used by vfio-pci/platform. Do you think this can be some h/w specific issue.

Thanks
-Bharat

> 
> Thanks,
> 
>   M.
> --
> Jazz is not dead. It just smells funny...
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


RE: ARM64/KVM: Bad page state in process iperf

2015-12-15 Thread Bhushan Bharat


> -Original Message-
> From: Marc Zyngier [mailto:marc.zyng...@arm.com]
> Sent: Tuesday, December 15, 2015 4:49 PM
> To: Bhushan Bharat-R65777 ;
> kvmarm@lists.cs.columbia.edu; k...@vger.kernel.org; linux-arm-
> ker...@lists.infradead.org; linux-ker...@vger.kernel.org
> Subject: Re: ARM64/KVM: Bad page state in process iperf
> 
> On 15/12/15 10:57, Bhushan Bharat wrote:
> >
> >
> >> -Original Message-
> >> From: Marc Zyngier [mailto:marc.zyng...@arm.com]
> >> Sent: Tuesday, December 15, 2015 3:50 PM
> >> To: Bhushan Bharat-R65777 ;
> >> kvmarm@lists.cs.columbia.edu; k...@vger.kernel.org; linux-arm-
> >> ker...@lists.infradead.org; linux-ker...@vger.kernel.org
> >> Subject: Re: ARM64/KVM: Bad page state in process iperf
> >>
> >> On 15/12/15 09:53, Bhushan Bharat wrote:
> >>> Hi Mark,
> >>>
>  -Original Message-
>  From: Marc Zyngier [mailto:marc.zyng...@arm.com]
>  Sent: Tuesday, December 15, 2015 3:05 PM
>  To: Bhushan Bharat-R65777 ;
>  kvmarm@lists.cs.columbia.edu; k...@vger.kernel.org; linux-arm-
>  ker...@lists.infradead.org; linux-ker...@vger.kernel.org
>  Subject: Re: ARM64/KVM: Bad page state in process iperf
> 
>  On 15/12/15 03:46, Bhushan Bharat wrote:
> >
> > Hi All,
> >
> > I am running "iperf" in KVM guest on ARM64 machine and observing
> > below
>  crash.
> >
> > =
> > $iperf -c 3.3.3.3 -P 4 -t 0 -i 5 -w 90k
> > 
> > Client connecting to 3.3.3.3, TCP port 5001 TCP window size:  180
> > KByte (WARNING: requested 90.0 KByte)
> > 
> > [  3] local 3.3.3.1 port 51131 connected with 3.3.3.3 port 5001 [
> > 6] local 3.3.3.1 port 51134 connected with 3.3.3.3 port 5001 [  5]
> > local
> > 3.3.3.1 port 51133 connected with 3.3.3.3 port 5001 [  4] local
> > 3.3.3.1 port 51132 connected with 3.3.3.3 port 5001
> > [   53.088567] random: nonblocking pool is initialized
> > [ ID] Interval   Transfer Bandwidth
> > [  3]  0.0- 5.0 sec   638 MBytes  1.07 Gbits/sec
> > [  4] 35.0-40.0 sec  1.66 GBytes  2.85 Gbits/sec [  5] 40.0-45.0
> > sec
> > 1.11 GBytes  1.90 Gbits/sec [  4] 40.0-45.0 sec  1.16 GBytes  1.99
> > Gbits/sec
> > [   98.895207] BUG: Bad page state in process iperf  pfn:0a584
> > [   98.896164] page:78296100 count:-1 mapcount:0 mapping:
>  (null) index:0x0
> > [   98.897436] flags: 0x0()
> > [   98.897885] page dumped because: nonzero _count
> > [   98.898640] Modules linked in:
> > [   98.899178] CPU: 0 PID: 1639 Comm: iperf Not tainted 4.1.8-00461-
>  ge5431ad #141
> > [   98.900302] Hardware name: linux,dummy-virt (DT)
> > [   98.901014] Call trace:
> > [   98.901406] [] dump_backtrace+0x0/0x12c
> > [   98.902522] [] show_stack+0x10/0x1c
> > [   98.903441] [] dump_stack+0x8c/0xdc
> > [   98.904202] [] bad_page+0xc4/0x114
> > [   98.904945] []
> >> get_page_from_freelist+0x590/0x63c
> > [   98.905871] []
> >> __alloc_pages_nodemask+0xec/0x794
> > [   98.906791] [] skb_page_frag_refill+0x70/0xa8
> > [   98.907678] [] sk_page_frag_refill+0x20/0xd0
> > [   98.908550] [] tcp_sendmsg+0x1f8/0x9a8
> > [   98.909368] [] inet_sendmsg+0x5c/0xd0
> > [   98.910178] [] sock_sendmsg+0x14/0x58
> > [   98.911027] [] sock_write_iter+0x64/0xbc
> > [   98.912119] [] __vfs_write+0xac/0x10c
> > [   98.913126] [] vfs_write+0x90/0x1a0
> > [   98.913963] [] SyS_write+0x40/0xa0
> 
>  This looks quite bad, but I don't see anything here that links it
>  to KVM (apart from being a guest). Do you have any indication that
>  this is due to KVM misbehaving?
> >>>
> >>> I never observed this issue in host Linux but observed this issue
> >>> always in
> >> guest Linux. This issue does not comes immediately after I run
> >> "iperf" but after some time.
> >>>
>  I'd appreciate a few more details.
> >>>
> >>> We have a networking hardware and we are directly assigning the h/w
> >>> to
> >> guest. When using the same networking hardware in host it always
> >> works as expected (tried 100s of times).
> >>> Also this issue is not observed when we have only one vCPU in guest
> >>> but
> >> seen when we have SMP guest.
> >>
> >> Can you reproduce the same issue without VFIO (using virtio, for
> example)?
> >
> > With virtio I have not observed this issue.
> >
> >> Is that platform VFIO? or PCI?
> >
> > It is not vfio-pci and vfio-platform. It is vfio-fls-mc (some
> > Freescale new hardware), similar to the lines of vfio-platform uses
> > same set of VFIO APIs used by vfio-pci/platform. Do you think this can
> > be some h/w specific issue.
> 
> I have no idea, but by the look of it, something could be doing 

Re: ARM64/KVM: Bad page state in process iperf

2015-12-15 Thread Marc Zyngier
On 15/12/15 10:57, Bhushan Bharat wrote:
> 
> 
>> -Original Message-
>> From: Marc Zyngier [mailto:marc.zyng...@arm.com]
>> Sent: Tuesday, December 15, 2015 3:50 PM
>> To: Bhushan Bharat-R65777 ;
>> kvmarm@lists.cs.columbia.edu; k...@vger.kernel.org; linux-arm-
>> ker...@lists.infradead.org; linux-ker...@vger.kernel.org
>> Subject: Re: ARM64/KVM: Bad page state in process iperf
>>
>> On 15/12/15 09:53, Bhushan Bharat wrote:
>>> Hi Mark,
>>>
 -Original Message-
 From: Marc Zyngier [mailto:marc.zyng...@arm.com]
 Sent: Tuesday, December 15, 2015 3:05 PM
 To: Bhushan Bharat-R65777 ;
 kvmarm@lists.cs.columbia.edu; k...@vger.kernel.org; linux-arm-
 ker...@lists.infradead.org; linux-ker...@vger.kernel.org
 Subject: Re: ARM64/KVM: Bad page state in process iperf

 On 15/12/15 03:46, Bhushan Bharat wrote:
>
> Hi All,
>
> I am running "iperf" in KVM guest on ARM64 machine and observing
> below
 crash.
>
> =
> $iperf -c 3.3.3.3 -P 4 -t 0 -i 5 -w 90k
> 
> Client connecting to 3.3.3.3, TCP port 5001 TCP window size:  180
> KByte (WARNING: requested 90.0 KByte)
> 
> [  3] local 3.3.3.1 port 51131 connected with 3.3.3.3 port 5001 [
> 6] local 3.3.3.1 port 51134 connected with 3.3.3.3 port 5001 [  5]
> local
> 3.3.3.1 port 51133 connected with 3.3.3.3 port 5001 [  4] local
> 3.3.3.1 port 51132 connected with 3.3.3.3 port 5001
> [   53.088567] random: nonblocking pool is initialized
> [ ID] Interval   Transfer Bandwidth
> [  3]  0.0- 5.0 sec   638 MBytes  1.07 Gbits/sec
> [  4] 35.0-40.0 sec  1.66 GBytes  2.85 Gbits/sec [  5] 40.0-45.0 sec
> 1.11 GBytes  1.90 Gbits/sec [  4] 40.0-45.0 sec  1.16 GBytes  1.99
> Gbits/sec
> [   98.895207] BUG: Bad page state in process iperf  pfn:0a584
> [   98.896164] page:78296100 count:-1 mapcount:0 mapping:
 (null) index:0x0
> [   98.897436] flags: 0x0()
> [   98.897885] page dumped because: nonzero _count
> [   98.898640] Modules linked in:
> [   98.899178] CPU: 0 PID: 1639 Comm: iperf Not tainted 4.1.8-00461-
 ge5431ad #141
> [   98.900302] Hardware name: linux,dummy-virt (DT)
> [   98.901014] Call trace:
> [   98.901406] [] dump_backtrace+0x0/0x12c
> [   98.902522] [] show_stack+0x10/0x1c
> [   98.903441] [] dump_stack+0x8c/0xdc
> [   98.904202] [] bad_page+0xc4/0x114
> [   98.904945] []
>> get_page_from_freelist+0x590/0x63c
> [   98.905871] []
>> __alloc_pages_nodemask+0xec/0x794
> [   98.906791] [] skb_page_frag_refill+0x70/0xa8
> [   98.907678] [] sk_page_frag_refill+0x20/0xd0
> [   98.908550] [] tcp_sendmsg+0x1f8/0x9a8
> [   98.909368] [] inet_sendmsg+0x5c/0xd0
> [   98.910178] [] sock_sendmsg+0x14/0x58
> [   98.911027] [] sock_write_iter+0x64/0xbc
> [   98.912119] [] __vfs_write+0xac/0x10c
> [   98.913126] [] vfs_write+0x90/0x1a0
> [   98.913963] [] SyS_write+0x40/0xa0

 This looks quite bad, but I don't see anything here that links it to
 KVM (apart from being a guest). Do you have any indication that this
 is due to KVM misbehaving?
>>>
>>> I never observed this issue in host Linux but observed this issue always in
>> guest Linux. This issue does not comes immediately after I run "iperf" but
>> after some time.
>>>
 I'd appreciate a few more details.
>>>
>>> We have a networking hardware and we are directly assigning the h/w to
>> guest. When using the same networking hardware in host it always works as
>> expected (tried 100s of times).
>>> Also this issue is not observed when we have only one vCPU in guest but
>> seen when we have SMP guest.
>>
>> Can you reproduce the same issue without VFIO (using virtio, for example)?
> 
> With virtio I have not observed this issue.
> 
>> Is that platform VFIO? or PCI?
> 
> It is not vfio-pci and vfio-platform. It is vfio-fls-mc (some
> Freescale new hardware), similar to the lines of vfio-platform uses
> same set of VFIO APIs used by vfio-pci/platform. Do you think this
> can be some h/w specific issue.

I have no idea, but by the look of it, something could be doing DMA on
top of your guest page tables, which is not really expected. I suggest
you carefully look at:

1) the DMA addresses that are passed to your device
2) the page tables that are programmed into the SMMU
3) the resulting translation

Hopefully this will give you a clue about what is generating this.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device

2015-12-15 Thread Christoffer Dall
On Tue, Dec 15, 2015 at 03:59:31PM +, Marc Zyngier wrote:
> On 15/12/15 15:50, Shannon Zhao wrote:
> > 
> > 
> > On 2015/12/15 23:33, Marc Zyngier wrote:
> >> On 15/12/15 08:49, Shannon Zhao wrote:
>  From: Shannon Zhao
> 
>  Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
>  the kvm_device_ops for it.
> 
>  Signed-off-by: Shannon Zhao
>  ---
>   Documentation/virtual/kvm/devices/arm-pmu.txt |  16 
>   arch/arm64/include/uapi/asm/kvm.h |   3 +
>   include/linux/kvm_host.h  |   1 +
>   include/uapi/linux/kvm.h  |   2 +
>   virt/kvm/arm/pmu.c| 115 
>  ++
>   virt/kvm/kvm_main.c   |   4 +
>   6 files changed, 141 insertions(+)
>   create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
> 
>  diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt 
>  b/Documentation/virtual/kvm/devices/arm-pmu.txt
>  new file mode 100644
>  index 000..5121f1f
>  --- /dev/null
>  +++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
>  @@ -0,0 +1,16 @@
>  +ARM Virtual Performance Monitor Unit (vPMU)
>  +===
>  +
>  +Device types supported:
>  +  KVM_DEV_TYPE_ARM_PMU_V3 ARM Performance Monitor Unit v3
>  +
>  +Instantiate one PMU instance for per VCPU through this API.
>  +
>  +Groups:
>  +  KVM_DEV_ARM_PMU_GRP_IRQ
>  +  Attributes:
>  +A value describing the interrupt number of PMU overflow interrupt. 
>  This
>  +interrupt should be a PPI.
>  +
>  +  Errors:
>  +-EINVAL: Value set is out of the expected range (from 16 to 31)
>  diff --git a/arch/arm64/include/uapi/asm/kvm.h 
>  b/arch/arm64/include/uapi/asm/kvm.h
>  index 2d4ca4b..568afa2 100644
>  --- a/arch/arm64/include/uapi/asm/kvm.h
>  +++ b/arch/arm64/include/uapi/asm/kvm.h
>  @@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
>   #define KVM_DEV_ARM_VGIC_GRP_CTRL   4
>   #define   KVM_DEV_ARM_VGIC_CTRL_INIT0
> 
>  +/* Device Control API: ARM PMU */
>  +#define KVM_DEV_ARM_PMU_GRP_IRQ 0
>  +
>   /* KVM_IRQ_LINE irq field index values */
>   #define KVM_ARM_IRQ_TYPE_SHIFT  24
>   #define KVM_ARM_IRQ_TYPE_MASK   0xff
>  diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
>  index c923350..608dea6 100644
>  --- a/include/linux/kvm_host.h
>  +++ b/include/linux/kvm_host.h
>  @@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
>   extern struct kvm_device_ops kvm_xics_ops;
>   extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
>   extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
>  +extern struct kvm_device_ops kvm_arm_pmu_ops;
> 
>   #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
> 
>  diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>  index 03f3618..4ba6fdd 100644
>  --- a/include/uapi/linux/kvm.h
>  +++ b/include/uapi/linux/kvm.h
>  @@ -1032,6 +1032,8 @@ enum kvm_device_type {
>   #define KVM_DEV_TYPE_FLIC   KVM_DEV_TYPE_FLIC
>   KVM_DEV_TYPE_ARM_VGIC_V3,
>   #define KVM_DEV_TYPE_ARM_VGIC_V3KVM_DEV_TYPE_ARM_VGIC_V3
>  +KVM_DEV_TYPE_ARM_PMU_V3,
>  +#define KVM_DEV_TYPE_ARM_PMU_V3 KVM_DEV_TYPE_ARM_PMU_V3
>   KVM_DEV_TYPE_MAX,
>   };
> 
>  diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
>  index d113ee4..1965d0d 100644
>  --- a/virt/kvm/arm/pmu.c
>  +++ b/virt/kvm/arm/pmu.c
>  @@ -19,6 +19,7 @@
>   #include 
>   #include 
>   #include 
>  +#include 
>   #include 
>   #include 
>   #include 
>  @@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct 
>  kvm_vcpu *vcpu, u64 data,
> 
>   pmc->perf_event = event;
>   }
>  +
>  +static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
>  +{
>  +return vcpu->arch.pmu.irq_num != -1;
>  +}
>  +
>  +static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool 
>  is_set)
>  +{
>  +int j;
>  +struct kvm_vcpu *vcpu;
>  +
>  +kvm_for_each_vcpu(j, vcpu, kvm) {
>  +struct kvm_pmu *pmu = >arch.pmu;
>  +
>  +if (!is_set) {
>  +if (!kvm_arm_pmu_initialized(vcpu))
>  +return -EBUSY;
> >> Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
> >> anyway. Actually, why would you return an error in this case?
> >>
> > While this is a unexpected operation from user space and it's already 
> > initialized and working, so I 

Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device

2015-12-15 Thread Shannon Zhao



On 2015/12/15 23:33, Marc Zyngier wrote:

On 15/12/15 08:49, Shannon Zhao wrote:

>From: Shannon Zhao
>
>Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
>the kvm_device_ops for it.
>
>Signed-off-by: Shannon Zhao
>---
>  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 
>  arch/arm64/include/uapi/asm/kvm.h |   3 +
>  include/linux/kvm_host.h  |   1 +
>  include/uapi/linux/kvm.h  |   2 +
>  virt/kvm/arm/pmu.c| 115 
++
>  virt/kvm/kvm_main.c   |   4 +
>  6 files changed, 141 insertions(+)
>  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
>
>diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt 
b/Documentation/virtual/kvm/devices/arm-pmu.txt
>new file mode 100644
>index 000..5121f1f
>--- /dev/null
>+++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
>@@ -0,0 +1,16 @@
>+ARM Virtual Performance Monitor Unit (vPMU)
>+===
>+
>+Device types supported:
>+  KVM_DEV_TYPE_ARM_PMU_V3 ARM Performance Monitor Unit v3
>+
>+Instantiate one PMU instance for per VCPU through this API.
>+
>+Groups:
>+  KVM_DEV_ARM_PMU_GRP_IRQ
>+  Attributes:
>+A value describing the interrupt number of PMU overflow interrupt. This
>+interrupt should be a PPI.
>+
>+  Errors:
>+-EINVAL: Value set is out of the expected range (from 16 to 31)
>diff --git a/arch/arm64/include/uapi/asm/kvm.h 
b/arch/arm64/include/uapi/asm/kvm.h
>index 2d4ca4b..568afa2 100644
>--- a/arch/arm64/include/uapi/asm/kvm.h
>+++ b/arch/arm64/include/uapi/asm/kvm.h
>@@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
>  #define KVM_DEV_ARM_VGIC_GRP_CTRL 4
>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT  0
>
>+/* Device Control API: ARM PMU */
>+#define KVM_DEV_ARM_PMU_GRP_IRQ0
>+
>  /* KVM_IRQ_LINE irq field index values */
>  #define KVM_ARM_IRQ_TYPE_SHIFT24
>  #define KVM_ARM_IRQ_TYPE_MASK 0xff
>diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
>index c923350..608dea6 100644
>--- a/include/linux/kvm_host.h
>+++ b/include/linux/kvm_host.h
>@@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
>  extern struct kvm_device_ops kvm_xics_ops;
>  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
>  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
>+extern struct kvm_device_ops kvm_arm_pmu_ops;
>
>  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
>
>diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>index 03f3618..4ba6fdd 100644
>--- a/include/uapi/linux/kvm.h
>+++ b/include/uapi/linux/kvm.h
>@@ -1032,6 +1032,8 @@ enum kvm_device_type {
>  #define KVM_DEV_TYPE_FLIC KVM_DEV_TYPE_FLIC
>KVM_DEV_TYPE_ARM_VGIC_V3,
>  #define KVM_DEV_TYPE_ARM_VGIC_V3  KVM_DEV_TYPE_ARM_VGIC_V3
>+   KVM_DEV_TYPE_ARM_PMU_V3,
>+#defineKVM_DEV_TYPE_ARM_PMU_V3 KVM_DEV_TYPE_ARM_PMU_V3
>KVM_DEV_TYPE_MAX,
>  };
>
>diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
>index d113ee4..1965d0d 100644
>--- a/virt/kvm/arm/pmu.c
>+++ b/virt/kvm/arm/pmu.c
>@@ -19,6 +19,7 @@
>  #include 
>  #include 
>  #include 
>+#include 
>  #include 
>  #include 
>  #include 
>@@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu 
*vcpu, u64 data,
>
>pmc->perf_event = event;
>  }
>+
>+static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
>+{
>+   return vcpu->arch.pmu.irq_num != -1;
>+}
>+
>+static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
>+{
>+   int j;
>+   struct kvm_vcpu *vcpu;
>+
>+   kvm_for_each_vcpu(j, vcpu, kvm) {
>+   struct kvm_pmu *pmu = >arch.pmu;
>+
>+   if (!is_set) {
>+   if (!kvm_arm_pmu_initialized(vcpu))
>+   return -EBUSY;

Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
anyway. Actually, why would you return an error in this case?

While this is a unexpected operation from user space and it's already 
initialized and working, so I think it should return an error to user 
and tell user that it's already initialized and working (this should 
mean "busy" ?).


--
Shannon
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [PATCH v7 15/19] KVM: ARM64: Add access handler for PMUSERENR register

2015-12-15 Thread Shannon Zhao



On 2015/12/15 22:58, Marc Zyngier wrote:

On 15/12/15 08:49, Shannon Zhao wrote:

>From: Shannon Zhao
>
>The reset value of PMUSERENR_EL0 is UNKNOWN, use reset_unknown.
>
>PMUSERENR_EL0 holds some bits which decide whether PMU registers can be
>accessed from EL0. Add some check helpers to handle the access from EL0.
>
>Signed-off-by: Shannon Zhao
>---
>  arch/arm64/kvm/sys_regs.c | 124 
--
>  1 file changed, 119 insertions(+), 5 deletions(-)
>
>diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>index b2ccc25..bad3dfd 100644
>--- a/arch/arm64/kvm/sys_regs.c
>+++ b/arch/arm64/kvm/sys_regs.c
>@@ -452,12 +452,44 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const 
struct sys_reg_desc *r)
>vcpu_sys_reg(vcpu, r->reg) = val;
>  }
>
>+static inline bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
>+{
>+   u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>+
>+   return !((reg & 0x1) || vcpu_mode_priv(vcpu));
>+}
>+
>+static inline bool pmu_write_swinc_el0_disabled(struct kvm_vcpu *vcpu)
>+{
>+   u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>+
>+   return !((reg & 0x3) || vcpu_mode_priv(vcpu));
>+}
>+
>+static inline bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu 
*vcpu)
>+{
>+   u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>+
>+   return !((reg & 0x5) || vcpu_mode_priv(vcpu));
>+}
>+
>+static inline bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu 
*vcpu)
>+{
>+   u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>+
>+   return !((reg & 0x9) || vcpu_mode_priv(vcpu));
>+}

Please add #defines for the PMUSERNR_EL0 bits.


>+
>  static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>const struct sys_reg_desc *r)
>  {
>u64 val;
>+   bool unaccessible = pmu_access_el0_disabled(vcpu);
>
>if (p->is_write) {
>+   if (unaccessible)
>+   return ignore_write(vcpu, p);
>+

This is not how this is supposed to work. If EL0 is denied access to the
PMU, you must inject an exception into EL1 for it to handle the fault.
The code should reflect the flow described at D5.11.2 in the ARM ARM.

Does it need to add a helper to inject an exception into EL1 or is there 
a existing one?


Thanks,
--
Shannon
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device

2015-12-15 Thread Marc Zyngier
On 15/12/15 15:50, Shannon Zhao wrote:
> 
> 
> On 2015/12/15 23:33, Marc Zyngier wrote:
>> On 15/12/15 08:49, Shannon Zhao wrote:
 From: Shannon Zhao

 Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
 the kvm_device_ops for it.

 Signed-off-by: Shannon Zhao
 ---
  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 
  arch/arm64/include/uapi/asm/kvm.h |   3 +
  include/linux/kvm_host.h  |   1 +
  include/uapi/linux/kvm.h  |   2 +
  virt/kvm/arm/pmu.c| 115 
 ++
  virt/kvm/kvm_main.c   |   4 +
  6 files changed, 141 insertions(+)
  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt

 diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt 
 b/Documentation/virtual/kvm/devices/arm-pmu.txt
 new file mode 100644
 index 000..5121f1f
 --- /dev/null
 +++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
 @@ -0,0 +1,16 @@
 +ARM Virtual Performance Monitor Unit (vPMU)
 +===
 +
 +Device types supported:
 +  KVM_DEV_TYPE_ARM_PMU_V3 ARM Performance Monitor Unit v3
 +
 +Instantiate one PMU instance for per VCPU through this API.
 +
 +Groups:
 +  KVM_DEV_ARM_PMU_GRP_IRQ
 +  Attributes:
 +A value describing the interrupt number of PMU overflow interrupt. 
 This
 +interrupt should be a PPI.
 +
 +  Errors:
 +-EINVAL: Value set is out of the expected range (from 16 to 31)
 diff --git a/arch/arm64/include/uapi/asm/kvm.h 
 b/arch/arm64/include/uapi/asm/kvm.h
 index 2d4ca4b..568afa2 100644
 --- a/arch/arm64/include/uapi/asm/kvm.h
 +++ b/arch/arm64/include/uapi/asm/kvm.h
 @@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
  #define KVM_DEV_ARM_VGIC_GRP_CTRL 4
  #define   KVM_DEV_ARM_VGIC_CTRL_INIT  0

 +/* Device Control API: ARM PMU */
 +#define KVM_DEV_ARM_PMU_GRP_IRQ   0
 +
  /* KVM_IRQ_LINE irq field index values */
  #define KVM_ARM_IRQ_TYPE_SHIFT24
  #define KVM_ARM_IRQ_TYPE_MASK 0xff
 diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
 index c923350..608dea6 100644
 --- a/include/linux/kvm_host.h
 +++ b/include/linux/kvm_host.h
 @@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
  extern struct kvm_device_ops kvm_xics_ops;
  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
 +extern struct kvm_device_ops kvm_arm_pmu_ops;

  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT

 diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
 index 03f3618..4ba6fdd 100644
 --- a/include/uapi/linux/kvm.h
 +++ b/include/uapi/linux/kvm.h
 @@ -1032,6 +1032,8 @@ enum kvm_device_type {
  #define KVM_DEV_TYPE_FLIC KVM_DEV_TYPE_FLIC
KVM_DEV_TYPE_ARM_VGIC_V3,
  #define KVM_DEV_TYPE_ARM_VGIC_V3  KVM_DEV_TYPE_ARM_VGIC_V3
 +  KVM_DEV_TYPE_ARM_PMU_V3,
 +#define   KVM_DEV_TYPE_ARM_PMU_V3 KVM_DEV_TYPE_ARM_PMU_V3
KVM_DEV_TYPE_MAX,
  };

 diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
 index d113ee4..1965d0d 100644
 --- a/virt/kvm/arm/pmu.c
 +++ b/virt/kvm/arm/pmu.c
 @@ -19,6 +19,7 @@
  #include 
  #include 
  #include 
 +#include 
  #include 
  #include 
  #include 
 @@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu 
 *vcpu, u64 data,

pmc->perf_event = event;
  }
 +
 +static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
 +{
 +  return vcpu->arch.pmu.irq_num != -1;
 +}
 +
 +static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
 +{
 +  int j;
 +  struct kvm_vcpu *vcpu;
 +
 +  kvm_for_each_vcpu(j, vcpu, kvm) {
 +  struct kvm_pmu *pmu = >arch.pmu;
 +
 +  if (!is_set) {
 +  if (!kvm_arm_pmu_initialized(vcpu))
 +  return -EBUSY;
>> Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
>> anyway. Actually, why would you return an error in this case?
>>
> While this is a unexpected operation from user space and it's already 
> initialized and working, so I think it should return an error to user 
> and tell user that it's already initialized and working (this should 
> mean "busy" ?).

But in this case, you're returning an error if it is *not* initialized.
I understand that in that case you cannot return an interrupt number (-1
would be weird), but returning -EBUSY feels even more weird.

I'd settle for -ENOXIO, or something similar. Anyone having a 

Re: [PATCH v7 11/19] KVM: ARM64: Add access handler for PMINTENSET and PMINTENCLR register

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Since the reset value of PMINTENSET and PMINTENCLR is UNKNOWN, use
> reset_unknown for its reset handler. Add a handler to emulate writing
> PMINTENSET or PMINTENCLR register.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 29 +
>  1 file changed, 25 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index f216da7..594e53f 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -648,6 +648,27 @@ static bool access_pmcntenset(struct kvm_vcpu *vcpu, 
> struct sys_reg_params *p,
>   return true;
>  }
>  
> +static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params 
> *p,
> +   const struct sys_reg_desc *r)
> +{
> + u64 mask = kvm_pmu_valid_counter_mask(vcpu);
> +
> + if (p->is_write) {
> + if (r->Op2 & 0x1) {
> + /* accessing PMINTENSET_EL1 */
> + vcpu_sys_reg(vcpu, r->reg) |= (p->regval & mask);
> + } else {
> + /* accessing PMINTENCLR_EL1 */
> + vcpu_sys_reg(vcpu, r->reg) &= mask;
> + vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;

This looks wrong. The first line doesn't have any effect (you shouldn't
be able to set bits that are not in the mask the first place). I'd
prefer something like:

vcpu_sys_reg(vcpu, r->reg) &= ~(p->regval & mask);

which is symmetrical to the SET operator.

> + }
> + } else {
> + p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
> + }
> +
> + return true;
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)   \
>   /* DBGBVRn_EL1 */   \
> @@ -806,10 +827,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  
>   /* PMINTENSET_EL1 */
>   { Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b001),
> -   trap_raz_wi },
> +   access_pmintenset, reset_unknown, PMINTENSET_EL1 },
>   /* PMINTENCLR_EL1 */
>   { Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b010),
> -   trap_raz_wi },
> +   access_pmintenset, NULL, PMINTENSET_EL1 },
>  
>   /* MAIR_EL1 */
>   { Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0010), Op2(0b000),
> @@ -1204,8 +1225,8 @@ static const struct sys_reg_desc cp15_regs[] = {
>   { Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_evtyper },
>   { Op1( 0), CRn( 9), CRm(13), Op2( 2), access_pmu_evcntr },
>   { Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
> - { Op1( 0), CRn( 9), CRm(14), Op2( 1), trap_raz_wi },
> - { Op1( 0), CRn( 9), CRm(14), Op2( 2), trap_raz_wi },
> + { Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
> + { Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
>  
>   { Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
>   { Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
> 

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [PATCH v7 10/19] KVM: ARM64: Add access handler for PMCNTENSET and PMCNTENCLR register

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Since the reset value of PMCNTENSET and PMCNTENCLR is UNKNOWN, use
> reset_unknown for its reset handler. Add a handler to emulate writing
> PMCNTENSET or PMCNTENCLR register.
> 
> When writing to PMCNTENSET, call perf_event_enable to enable the perf
> event. When writing to PMCNTENCLR, call perf_event_disable to disable
> the perf event.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 41 +++
>  include/kvm/arm_pmu.h |  4 
>  virt/kvm/arm/pmu.c| 55 
> +++
>  3 files changed, 96 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index dc6bb26..f216da7 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -615,6 +615,39 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
>   return true;
>  }
>  
> +static inline u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
> +{
> + u64 val = vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMCR_N_SHIFT;
> +
> + val &= ARMV8_PMCR_N_MASK;
> + return GENMASK(val - 1, 0) | BIT(ARMV8_CYCLE_IDX);
> +}
> +
> +static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params 
> *p,
> +   const struct sys_reg_desc *r)
> +{
> + u64 val, mask;
> +
> + mask = kvm_pmu_valid_counter_mask(vcpu);
> + if (p->is_write) {
> + val = p->regval & mask;
> + if (r->Op2 & 0x1) {
> + /* accessing PMCNTENSET_EL0 */
> + vcpu_sys_reg(vcpu, r->reg) |= val;
> + kvm_pmu_enable_counter(vcpu, val);
> + } else {
> + /* accessing PMCNTENCLR_EL0 */
> + vcpu_sys_reg(vcpu, r->reg) &= mask;
> + vcpu_sys_reg(vcpu, r->reg) &= ~val;
> + kvm_pmu_disable_counter(vcpu, val);
> + }
> + } else {
> + p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
> + }
> +
> + return true;
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)   \
>   /* DBGBVRn_EL1 */   \
> @@ -816,10 +849,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> access_pmcr, reset_pmcr, PMCR_EL0, },
>   /* PMCNTENSET_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b001),
> -   trap_raz_wi },
> +   access_pmcntenset, reset_unknown, PMCNTENSET_EL0 },
>   /* PMCNTENCLR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b010),
> -   trap_raz_wi },
> +   access_pmcntenset, NULL, PMCNTENSET_EL0 },
>   /* PMOVSCLR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
> trap_raz_wi },
> @@ -1161,8 +1194,8 @@ static const struct sys_reg_desc cp15_regs[] = {
>  
>   /* PMU */
>   { Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
> - { Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
> - { Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
> + { Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
> + { Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index 14bedb0..43c4117 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -36,6 +36,8 @@ struct kvm_pmu {
>  };
>  
>  u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
> +void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
> +void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>   u64 select_idx);
>  #else
> @@ -46,6 +48,8 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 
> select_idx)
>  {
>   return 0;
>  }
> +void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
> +void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>   u64 select_idx) {}
>  #endif
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index b107fb8..94bff0e 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -75,6 +75,61 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, 
> struct kvm_pmc *pmc)
>  }
>  
>  /**
> + * kvm_pmu_enable_counter - enable selected PMU counter
> + * @vcpu: The vcpu pointer
> + * @val: the value guest writes to PMCNTENSET register
> + *
> + * Call perf_event_enable to start 

Re: [PATCH v7 08/19] KVM: ARM64: Add access handler for event typer register

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> These kind of registers include PMEVTYPERn, PMCCFILTR and PMXEVTYPER
> which is mapped to PMEVTYPERn or PMCCFILTR.
> 
> The access handler translates all aarch32 register offsets to aarch64
> ones and uses vcpu_sys_reg() to access their values to avoid taking care
> of big endian.
> 
> When writing to these registers, create a perf_event for the selected
> event type.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 154 
> +-
>  1 file changed, 152 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index e043224..c52ff15 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -504,6 +504,68 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct 
> sys_reg_params *p,
>   return true;
>  }
>  
> +static inline bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
> +{
> + u64 pmcr, val;
> +
> + pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
> + val = (pmcr >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK;
> + if (idx >= val && idx != ARMV8_CYCLE_IDX)
> + return false;
> +
> + return true;
> +}
> +
> +static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params 
> *p,
> +const struct sys_reg_desc *r)
> +{
> + u64 idx, reg;
> +
> + if (r->CRn == 9) {
> + /* PMXEVTYPER_EL0 */
> + reg = 0;
> + } else {
> + if (!p->is_aarch32) {
> + /* PMEVTYPERn_EL0 or PMCCFILTR_EL0 */
> + reg = r->reg;
> + } else {
> + if (r->CRn == 14 && r->CRm == 15 && r->Op2 == 7) {
> + reg = PMCCFILTR_EL0;
> + } else {
> + reg = ((r->CRm & 3) << 3) & (r->Op2 & 7);
> + reg += PMEVTYPER0_EL0;
> + }
> + }
> + }
> +
> + switch (reg) {
> + case PMEVTYPER0_EL0 ... PMEVTYPER30_EL0:
> + idx = reg - PMEVTYPER0_EL0;
> + break;
> + case PMCCFILTR_EL0:
> + idx = ARMV8_CYCLE_IDX;
> + break;
> + default:
> + /* PMXEVTYPER_EL0 */
> + idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK;
> + if (!pmu_counter_idx_valid(vcpu, idx))
> + return true;

Shouldn't you check the validity of the index in the first case as well?

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [PATCH v7 12/19] KVM: ARM64: Add access handler for PMOVSSET and PMOVSCLR register

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Since the reset value of PMOVSSET and PMOVSCLR is UNKNOWN, use
> reset_unknown for its reset handler. Add a handler to emulate writing
> PMOVSSET or PMOVSCLR register.
> 
> When writing non-zero value to PMOVSSET, pend PMU interrupt.

This comment doesn't match the code anymore

> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 28 +---
>  include/kvm/arm_pmu.h |  2 ++
>  virt/kvm/arm/pmu.c| 20 
>  3 files changed, 47 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 594e53f..d1926c4 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -669,6 +669,27 @@ static bool access_pmintenset(struct kvm_vcpu *vcpu, 
> struct sys_reg_params *p,
>   return true;
>  }
>  
> +static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> + const struct sys_reg_desc *r)
> +{
> + u64 mask = kvm_pmu_valid_counter_mask(vcpu);
> +
> + if (p->is_write) {
> + if (r->CRm & 0x2) {
> + /* accessing PMOVSSET_EL0 */
> + kvm_pmu_overflow_set(vcpu, p->regval & mask);
> + } else {
> + /* accessing PMOVSCLR_EL0 */
> + vcpu_sys_reg(vcpu, r->reg) &= mask;
> + vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;

Same as the previous patch.

> + }
> + } else {
> + p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
> + }
> +
> + return true;
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)   \
>   /* DBGBVRn_EL1 */   \
> @@ -876,7 +897,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> access_pmcntenset, NULL, PMCNTENSET_EL0 },
>   /* PMOVSCLR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
> -   trap_raz_wi },
> +   access_pmovsset, NULL, PMOVSSET_EL0 },
>   /* PMSWINC_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
> trap_raz_wi },
> @@ -903,7 +924,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> trap_raz_wi },
>   /* PMOVSSET_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b011),
> -   trap_raz_wi },
> +   access_pmovsset, reset_unknown, PMOVSSET_EL0 },
>  
>   /* TPIDR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b), Op2(0b010),
> @@ -1217,7 +1238,7 @@ static const struct sys_reg_desc cp15_regs[] = {
>   { Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
> - { Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
> + { Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovsset },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
> @@ -1227,6 +1248,7 @@ static const struct sys_reg_desc cp15_regs[] = {
>   { Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
>   { Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
>   { Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
> + { Op1( 0), CRn( 9), CRm(14), Op2( 3), access_pmovsset },
>  
>   { Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
>   { Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index 43c4117..93aea6a 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -38,6 +38,7 @@ struct kvm_pmu {
>  u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
> +void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>   u64 select_idx);
>  #else
> @@ -50,6 +51,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 
> select_idx)
>  }
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
> +void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>   u64 select_idx) {}
>  #endif
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 94bff0e..861471d 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -130,6 

Re: [PATCH v7 06/19] KVM: ARM64: Add access handler for PMCEID0 and PMCEID1 register

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Add access handler which gets host value of PMCEID0 or PMCEID1 when
> guest access these registers. Writing action to PMCEID0 or PMCEID1 is
> ignored.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 26 ++
>  1 file changed, 22 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index c21f91b..e043224 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -486,6 +486,24 @@ static bool access_pmselr(struct kvm_vcpu *vcpu, struct 
> sys_reg_params *p,
>   return true;
>  }
>  
> +static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +   const struct sys_reg_desc *r)
> +{
> + u64 pmceid;
> +
> + if (p->is_write)
> + return write_to_read_only(vcpu, p);

This register in UNDEFINED in that case. You should call
kvm_inject_undefined() for that vcpu and return.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [PATCH v7 13/19] KVM: ARM64: Add access handler for PMSWINC register

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Add access handler which emulates writing and reading PMSWINC
> register and add support for creating software increment event.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 14 +-
>  include/kvm/arm_pmu.h |  2 ++
>  virt/kvm/arm/pmu.c| 32 
>  3 files changed, 47 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index d1926c4..f09e500 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -690,6 +690,17 @@ static bool access_pmovsset(struct kvm_vcpu *vcpu, 
> struct sys_reg_params *p,
>   return true;
>  }
>  
> +static bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +const struct sys_reg_desc *r)
> +{
> + if (p->is_write) {
> + kvm_pmu_software_increment(vcpu, p->regval);

Shouldn't you filter this with valid counter mask?

> + return true;
> + } else {
> + return read_zero(vcpu, p);

Mark just mentioned to me that reading from this register is UNDEFINED.
Which means you should generate an exception into the guest by calling
kvm_inject_undefined() for that vcpu.

> + }
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)   \
>   /* DBGBVRn_EL1 */   \
> @@ -900,7 +911,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> access_pmovsset, NULL, PMOVSSET_EL0 },
>   /* PMSWINC_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
> -   trap_raz_wi },
> +   access_pmswinc, reset_unknown, PMSWINC_EL0 },
>   /* PMSELR_EL0 */
>   { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b101),
> access_pmselr, reset_unknown, PMSELR_EL0 },
> @@ -1239,6 +1250,7 @@ static const struct sys_reg_desc cp15_regs[] = {
>   { Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovsset },
> + { Op1( 0), CRn( 9), CRm(12), Op2( 4), access_pmswinc },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
>   { Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index 93aea6a..f5888eb 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -39,6 +39,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 
> select_idx);
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
> +void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>   u64 select_idx);
>  #else
> @@ -52,6 +53,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 
> select_idx)
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
> +void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>   u64 select_idx) {}
>  #endif
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 861471d..01af727 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -150,6 +150,34 @@ void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val)
>  }
>  
>  /**
> + * kvm_pmu_software_increment - do software increment
> + * @vcpu: The vcpu pointer
> + * @val: the value guest writes to PMSWINC register
> + */
> +void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
> +{
> + int i;
> + u64 type, enable, reg;
> +
> + if (val == 0)
> + return;
> +
> + for (i = 0; i < ARMV8_CYCLE_IDX; i++) {
> + if (!((val >> i) & 0x1))

Same comment as for the other patches.

> + continue;
> + type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
> +& ARMV8_EVTYPE_EVENT;
> + enable = vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> + if ((type == 0) && ((enable >> i) & 0x1)) {
> + vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i)++;
> + reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i);
> + if ((reg & 0x) == 0)
> + kvm_pmu_overflow_set(vcpu, BIT(i));

The increment handling is not very nice, as you end-up with stuff in the
upper 

Re: [PATCH v7 15/19] KVM: ARM64: Add access handler for PMUSERENR register

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> The reset value of PMUSERENR_EL0 is UNKNOWN, use reset_unknown.
> 
> PMUSERENR_EL0 holds some bits which decide whether PMU registers can be
> accessed from EL0. Add some check helpers to handle the access from EL0.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  arch/arm64/kvm/sys_regs.c | 124 
> --
>  1 file changed, 119 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index b2ccc25..bad3dfd 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -452,12 +452,44 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const 
> struct sys_reg_desc *r)
>   vcpu_sys_reg(vcpu, r->reg) = val;
>  }
>  
> +static inline bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
> +{
> + u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> + return !((reg & 0x1) || vcpu_mode_priv(vcpu));
> +}
> +
> +static inline bool pmu_write_swinc_el0_disabled(struct kvm_vcpu *vcpu)
> +{
> + u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> + return !((reg & 0x3) || vcpu_mode_priv(vcpu));
> +}
> +
> +static inline bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu 
> *vcpu)
> +{
> + u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> + return !((reg & 0x5) || vcpu_mode_priv(vcpu));
> +}
> +
> +static inline bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu 
> *vcpu)
> +{
> + u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> + return !((reg & 0x9) || vcpu_mode_priv(vcpu));
> +}

Please add #defines for the PMUSERNR_EL0 bits.

> +
>  static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>   const struct sys_reg_desc *r)
>  {
>   u64 val;
> + bool unaccessible = pmu_access_el0_disabled(vcpu);
>  
>   if (p->is_write) {
> + if (unaccessible)
> + return ignore_write(vcpu, p);
> +

This is not how this is supposed to work. If EL0 is denied access to the
PMU, you must inject an exception into EL1 for it to handle the fault.
The code should reflect the flow described at D5.11.2 in the ARM ARM.

This whole patch needs to be revisited, I'm afraid.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
> the kvm_device_ops for it.
> 
> Signed-off-by: Shannon Zhao 
> ---
>  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 
>  arch/arm64/include/uapi/asm/kvm.h |   3 +
>  include/linux/kvm_host.h  |   1 +
>  include/uapi/linux/kvm.h  |   2 +
>  virt/kvm/arm/pmu.c| 115 
> ++
>  virt/kvm/kvm_main.c   |   4 +
>  6 files changed, 141 insertions(+)
>  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
> 
> diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt 
> b/Documentation/virtual/kvm/devices/arm-pmu.txt
> new file mode 100644
> index 000..5121f1f
> --- /dev/null
> +++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
> @@ -0,0 +1,16 @@
> +ARM Virtual Performance Monitor Unit (vPMU)
> +===
> +
> +Device types supported:
> +  KVM_DEV_TYPE_ARM_PMU_V3 ARM Performance Monitor Unit v3
> +
> +Instantiate one PMU instance for per VCPU through this API.
> +
> +Groups:
> +  KVM_DEV_ARM_PMU_GRP_IRQ
> +  Attributes:
> +A value describing the interrupt number of PMU overflow interrupt. This
> +interrupt should be a PPI.
> +
> +  Errors:
> +-EINVAL: Value set is out of the expected range (from 16 to 31)
> diff --git a/arch/arm64/include/uapi/asm/kvm.h 
> b/arch/arm64/include/uapi/asm/kvm.h
> index 2d4ca4b..568afa2 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
>  #define KVM_DEV_ARM_VGIC_GRP_CTRL4
>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT 0
>  
> +/* Device Control API: ARM PMU */
> +#define KVM_DEV_ARM_PMU_GRP_IRQ  0
> +
>  /* KVM_IRQ_LINE irq field index values */
>  #define KVM_ARM_IRQ_TYPE_SHIFT   24
>  #define KVM_ARM_IRQ_TYPE_MASK0xff
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index c923350..608dea6 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
>  extern struct kvm_device_ops kvm_xics_ops;
>  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
>  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
> +extern struct kvm_device_ops kvm_arm_pmu_ops;
>  
>  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
>  
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 03f3618..4ba6fdd 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -1032,6 +1032,8 @@ enum kvm_device_type {
>  #define KVM_DEV_TYPE_FLICKVM_DEV_TYPE_FLIC
>   KVM_DEV_TYPE_ARM_VGIC_V3,
>  #define KVM_DEV_TYPE_ARM_VGIC_V3 KVM_DEV_TYPE_ARM_VGIC_V3
> + KVM_DEV_TYPE_ARM_PMU_V3,
> +#define  KVM_DEV_TYPE_ARM_PMU_V3 KVM_DEV_TYPE_ARM_PMU_V3
>   KVM_DEV_TYPE_MAX,
>  };
>  
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index d113ee4..1965d0d 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -19,6 +19,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu 
> *vcpu, u64 data,
>  
>   pmc->perf_event = event;
>  }
> +
> +static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
> +{
> + return vcpu->arch.pmu.irq_num != -1;
> +}
> +
> +static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
> +{
> + int j;
> + struct kvm_vcpu *vcpu;
> +
> + kvm_for_each_vcpu(j, vcpu, kvm) {
> + struct kvm_pmu *pmu = >arch.pmu;
> +
> + if (!is_set) {
> + if (!kvm_arm_pmu_initialized(vcpu))
> + return -EBUSY;

Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
anyway. Actually, why would you return an error in this case?

> +
> + *irq = pmu->irq_num;
> + break;
> + }
> +
> + if (kvm_arm_pmu_initialized(vcpu))
> + return -EBUSY;
> +
> + kvm_debug("Set kvm ARM PMU irq: %d\n", *irq);
> + pmu->irq_num = *irq;
> + }
> +
> + return 0;
> +}
> +
> +static int kvm_arm_pmu_create(struct kvm_device *dev, u32 type)
> +{
> + int i;
> + struct kvm_vcpu *vcpu;
> + struct kvm *kvm = dev->kvm;
> +
> + kvm_for_each_vcpu(i, vcpu, kvm) {
> + struct kvm_pmu *pmu = >arch.pmu;
> +
> + memset(pmu, 0, sizeof(*pmu));
> + kvm_pmu_vcpu_reset(vcpu);
> + pmu->irq_num = -1;
> + }
> +
> + return 0;
> +}
> +
> +static void kvm_arm_pmu_destroy(struct kvm_device *dev)
> +{
> + kfree(dev);
> +}
> +
> +static int kvm_arm_pmu_set_attr(struct 

Re: [PATCH v7 00/19] KVM: ARM64: Add guest PMU support

2015-12-15 Thread Marc Zyngier
On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao 
> 
> This patchset adds guest PMU support for KVM on ARM64. It takes
> trap-and-emulate approach. When guest wants to monitor one event, it
> will be trapped by KVM and KVM will call perf_event API to create a perf
> event and call relevant perf_event APIs to get the count value of event.
> 
> Use perf to test this patchset in guest. When using "perf list", it
> shows the list of the hardware events and hardware cache events perf
> supports. Then use "perf stat -e EVENT" to monitor some event. For
> example, use "perf stat -e cycles" to count cpu cycles and
> "perf stat -e cache-misses" to count cache misses.
> 
> Below are the outputs of "perf stat -r 5 sleep 5" when running in host
> and guest.
> 
> Host:
>  Performance counter stats for 'sleep 5' (5 runs):
> 
>   0.549456  task-clock (msec) #0.000 CPUs utilized
> ( +-  5.68% )
>  1  context-switches  #0.002 M/sec
>  0  cpu-migrations#0.000 K/sec
> 48  page-faults   #0.088 M/sec
> ( +-  1.40% )
>1146243  cycles#2.086 GHz  
> ( +-  5.71% )
>  stalled-cycles-frontend
>  stalled-cycles-backend
> 627195  instructions  #0.55  insns per cycle  
> ( +- 15.65% )
>  branches
>   9826  branch-misses #   17.883 M/sec
> ( +-  1.10% )
> 
>5.000875516 seconds time elapsed   
>( +-  0.00% )
> 
> 
> Guest:
>  Performance counter stats for 'sleep 5' (5 runs):
> 
>   0.640712  task-clock (msec) #0.000 CPUs utilized
> ( +-  0.41% )
>  1  context-switches  #0.002 M/sec
>  0  cpu-migrations#0.000 K/sec
> 50  page-faults   #0.077 M/sec
> ( +-  1.37% )
>1320428  cycles#2.061 GHz  
> ( +-  0.29% )
>  stalled-cycles-frontend
>  stalled-cycles-backend
> 642373  instructions  #0.49  insns per cycle  
> ( +-  0.46% )
>  branches
>  10399  branch-misses #   16.230 M/sec
> ( +-  1.57% )
> 
>5.001181020 seconds time elapsed   
>( +-  0.00% )
> 
> 
> Have a cycle counter read test like below in guest and host:
> 
> static void test(void)
> {
>   unsigned long count, count1, count2;
>   count1 = read_cycles();
>   count++;
>   count2 = read_cycles();
> }
> 
> Host:
> count1: 3049567104
> count2: 3049567247
> delta: 143
> 
> Guest:
> count1: 5281420890
> count2: 5281421068
> delta: 178
> 
> The gap between guest and host is very small. One reason for this I
> think is that it doesn't count the cycles in EL2 and host since we add
> exclude_hv = 1. So the cycles spent to store/restore registers which
> happens at EL2 are not included.
> 
> This patchset can be fetched from [1] and the relevant QEMU version for
> test can be fetched from [2].
> 
> The results of 'perf test' can be found from [3][4].
> The results of perf_event_tests test suite can be found from [5][6].
> 
> Also, I have tested "perf top" in two VMs and host at the same time. It
> works well.

So while things are steadily improving, there is still more things to do
(and the more I review the code, the more I find things, which worries me).

The biggest issue at the moment is the handling of accesses at EL0,
which should be forwarded to EL1 instead of ignoring the access when
denied. There is also the UNDEFINED accesses (which are pretty easy to
solve), and a couple of straightforward bugs and other nits that should
be easy to fix.

If you can fix the above and that the result looks good, I'll try to put
it into -next. But at the moment, it looks like we're not really on
track to make it into 4.5.

Thanks,

M.
-- 
Jazz is not dead. It just smells funny...
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device

2015-12-15 Thread Shannon Zhao


On 2015/12/16 4:47, Christoffer Dall wrote:
> On Tue, Dec 15, 2015 at 03:59:31PM +, Marc Zyngier wrote:
>> > On 15/12/15 15:50, Shannon Zhao wrote:
>>> > > 
>>> > > 
>>> > > On 2015/12/15 23:33, Marc Zyngier wrote:
 > >> On 15/12/15 08:49, Shannon Zhao wrote:
>> >  From: Shannon Zhao
>> > 
>> >  Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. 
>> >  Implement
>> >  the kvm_device_ops for it.
>> > 
>> >  Signed-off-by: Shannon Zhao
>> >  ---
>> >   Documentation/virtual/kvm/devices/arm-pmu.txt |  16 
>> >   arch/arm64/include/uapi/asm/kvm.h |   3 +
>> >   include/linux/kvm_host.h  |   1 +
>> >   include/uapi/linux/kvm.h  |   2 +
>> >   virt/kvm/arm/pmu.c| 115 
>> >  ++
>> >   virt/kvm/kvm_main.c   |   4 +
>> >   6 files changed, 141 insertions(+)
>> >   create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
>> > 
>> >  diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt 
>> >  b/Documentation/virtual/kvm/devices/arm-pmu.txt
>> >  new file mode 100644
>> >  index 000..5121f1f
>> >  --- /dev/null
>> >  +++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
>> >  @@ -0,0 +1,16 @@
>> >  +ARM Virtual Performance Monitor Unit (vPMU)
>> >  +===
>> >  +
>> >  +Device types supported:
>> >  +  KVM_DEV_TYPE_ARM_PMU_V3 ARM Performance Monitor Unit v3
>> >  +
>> >  +Instantiate one PMU instance for per VCPU through this API.
>> >  +
>> >  +Groups:
>> >  +  KVM_DEV_ARM_PMU_GRP_IRQ
>> >  +  Attributes:
>> >  +A value describing the interrupt number of PMU overflow 
>> >  interrupt. This
>> >  +interrupt should be a PPI.
>> >  +
>> >  +  Errors:
>> >  +-EINVAL: Value set is out of the expected range (from 16 to 
>> >  31)
>> >  diff --git a/arch/arm64/include/uapi/asm/kvm.h 
>> >  b/arch/arm64/include/uapi/asm/kvm.h
>> >  index 2d4ca4b..568afa2 100644
>> >  --- a/arch/arm64/include/uapi/asm/kvm.h
>> >  +++ b/arch/arm64/include/uapi/asm/kvm.h
>> >  @@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
>> >   #define KVM_DEV_ARM_VGIC_GRP_CTRL4
>> >   #define   KVM_DEV_ARM_VGIC_CTRL_INIT 0
>> > 
>> >  +/* Device Control API: ARM PMU */
>> >  +#define KVM_DEV_ARM_PMU_GRP_IRQ  0
>> >  +
>> >   /* KVM_IRQ_LINE irq field index values */
>> >   #define KVM_ARM_IRQ_TYPE_SHIFT   24
>> >   #define KVM_ARM_IRQ_TYPE_MASK0xff
>> >  diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
>> >  index c923350..608dea6 100644
>> >  --- a/include/linux/kvm_host.h
>> >  +++ b/include/linux/kvm_host.h
>> >  @@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
>> >   extern struct kvm_device_ops kvm_xics_ops;
>> >   extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
>> >   extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
>> >  +extern struct kvm_device_ops kvm_arm_pmu_ops;
>> > 
>> >   #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
>> > 
>> >  diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>> >  index 03f3618..4ba6fdd 100644
>> >  --- a/include/uapi/linux/kvm.h
>> >  +++ b/include/uapi/linux/kvm.h
>> >  @@ -1032,6 +1032,8 @@ enum kvm_device_type {
>> >   #define KVM_DEV_TYPE_FLICKVM_DEV_TYPE_FLIC
>> >    KVM_DEV_TYPE_ARM_VGIC_V3,
>> >   #define KVM_DEV_TYPE_ARM_VGIC_V3 KVM_DEV_TYPE_ARM_VGIC_V3
>> >  + KVM_DEV_TYPE_ARM_PMU_V3,
>> >  +#define  KVM_DEV_TYPE_ARM_PMU_V3 KVM_DEV_TYPE_ARM_PMU_V3
>> >    KVM_DEV_TYPE_MAX,
>> >   };
>> > 
>> >  diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
>> >  index d113ee4..1965d0d 100644
>> >  --- a/virt/kvm/arm/pmu.c
>> >  +++ b/virt/kvm/arm/pmu.c
>> >  @@ -19,6 +19,7 @@
>> >   #include 
>> >   #include 
>> >   #include 
>> >  +#include 
>> >   #include 
>> >   #include 
>> >   #include 
>> >  @@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct 
>> >  kvm_vcpu *vcpu, u64 data,
>> > 
>> >    pmc->perf_event = event;
>> >   }
>> >  +
>> >  +static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
>> >  +{