All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v9 0/11] arm/arm64: vgic: Implement API for vGICv3 live migration
@ 2016-11-23 13:01 ` vijay.kilari at gmail.com
  0 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari @ 2016-11-23 13:01 UTC (permalink / raw)
  To: marc.zyngier, christoffer.dall, peter.maydell
  Cc: kvmarm, linux-arm-kernel, Vijaya Kumar K

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

This patchset adds API for saving and restoring
of VGICv3 registers to support live migration with new vgic feature.
This API definition is as per version of VGICv3 specification
Documentation/virtual/kvm/devices/arm-vgic-v3.txt

The patch 3 & 4 are picked from the Pavel's previous implementation.
http://www.spinics.net/lists/kvm/msg122040.html

NOTE: Only compilation tested for AArch32. No hardware to test.

v8 => v9:
 - Rebased to kvmarm/next branch
 - Introduce support for save and restore of CPU interface
   registers for AArch32 mode (9,10 and 11 patches).
   Only compilation tested.
 - Fixed vmcr.ctlr format
 - Updated error code for invalid CPU REG value in Documentation
 - Updated commit messages and added comments required
 - Queued IRQ when irq_line is set.
 - Compatibility check on ICC_CTLR_EL1.SEIS and A3V

v7 => v8:
 - Rebased to 4.9-rc3
 - Fixed wrong parameter to VGIC_TO_MPIDR
v6 => v7:
 - Rename all patches heading from vgic-new to vgic
 - Moved caching of priority and ID bits from vgic global struct
   to vgic_cpu struct.

v5 => v6:
 - Collated all register definitions to single patch (4)
 - Introduce macro to convert userspace MPIDR format to MPIDR reg format
 - Check on ICC_CTLR_EL1.CBPR value is made while accessing ICC_BPR1_EL1
 - Cached ich_vtr_el2 and guests priority and ID bits
 - Check on number of priority and ID bits when ICC_CTRL_EL1 write is made
 - Check is made on SRE bit for ICC_SRE_EL1 write

v4 => v5:
 - ICC_CTLR_EL1 access is updated to reflect HW values
 - Updated ICC reg access mask and shift macros
 - Introduced patch 4 for VMCR changes
 - Other minor fixes.
v3 => v4:
 - Rebased to latest code base
 - Moved vgic_uaccess() from vgic-mmio-v2.c to vgic-mmio.c
 - Dropped macro REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED_UACCESS
 - Dropped LE conversion for userspace access
 - Introduced vgic_uaccess_write_pending() for ISPENDR write
 - Change macro KVM_DEV_ARM_VGIC_V3_CPUID_MASK to KVM_DEV_ARM_VGIC_V3_MIDR_MASK
 - Refactored some code as common code.
 - Changed handing of ICC_* registers
 - Allowed ICC_SRE_EL1 read by userspace
 - Fixed KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_* macros

v2 => v3:
 - Implemented separate API for ISPENDR and ICPENDR to
   read soft_pending instead of pending for level triggerred interrupts
 - Implemented ioctl KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO to access line level
 - Rebased on top of Christoffer's patch set
   http://www.spinics.net/lists/kvm/msg136840.html

 NOTE: GICD_STATUSR and GICR_STATUSR are implemented as RAZ/WI.

v1 => v2:
 - The init sequence change patch is no more required.
   Fixed in patch 2 by using static vgic_io_dev regions structure instead
   of using dynamic allocation pointer.
 - Updated commit message of patch 4.
 - Dropped usage of union to manage 32-bit and 64-bit access in patch 1.
   Used local variable for 32-bit access.
 - Updated macro __ARM64_SYS_REG and ARM64_SYS_REG in
   arch/arm64/include/uapi/asm/kvm.h as per qemu requirements.

Vijaya Kumar K (11):
  arm/arm64: vgic: Implement support for userspace access
  arm/arm64: vgic: Add distributor and redistributor access
  arm/arm64: vgic: Introduce find_reg_by_id()
  irqchip/gic-v3: Add missing system register definitions
  arm/arm64: vgic: Introduce VENG0 and VENG1 fields to vmcr struct
  arm/arm64: vgic: Implement VGICv3 CPU interface access
  arm/arm64: vgic: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl
  arm/arm64: Documentation: Update arm-vgic-v3.txt
  arm: coproc: Drop const from coproc reg access function
  arm: coproc: Introduce find_coproc_reg_by_id()
  arm: vgic: Save and restore GICv3 CPU interface regs for AArch32

 Documentation/virtual/kvm/devices/arm-vgic-v3.txt |   2 +-
 arch/arm/include/uapi/asm/kvm.h                   |  13 ++
 arch/arm/kvm/Makefile                             |   2 +
 arch/arm/kvm/coproc.c                             |  42 ++--
 arch/arm/kvm/coproc.h                             |   8 +-
 arch/arm64/include/uapi/asm/kvm.h                 |  13 ++
 arch/arm64/kvm/Makefile                           |   2 +
 arch/arm64/kvm/sys_regs.c                         |  22 +-
 arch/arm64/kvm/sys_regs.h                         |   4 +
 include/kvm/arm_vgic.h                            |   9 +
 include/linux/irqchip/arm-gic-v3.h                |  45 +++-
 virt/kvm/arm/vgic/vgic-coproc-reg-v3.c            | 155 +++++++++++++
 virt/kvm/arm/vgic/vgic-kvm-device.c               | 219 +++++++++++++++++-
 virt/kvm/arm/vgic/vgic-mmio-v2.c                  |  57 +----
 virt/kvm/arm/vgic/vgic-mmio-v3.c                  | 203 +++++++++++++++--
 virt/kvm/arm/vgic/vgic-mmio.c                     | 154 ++++++++++++-
 virt/kvm/arm/vgic/vgic-mmio.h                     |  28 +++
 virt/kvm/arm/vgic/vgic-sys-reg-common.c           | 258 ++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-sys-reg-v3.c               | 142 ++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c                       |  30 ++-
 virt/kvm/arm/vgic/vgic.h                          |  78 ++++++-
 21 files changed, 1365 insertions(+), 121 deletions(-)
 create mode 100644 virt/kvm/arm/vgic/vgic-coproc-reg-v3.c
 create mode 100644 virt/kvm/arm/vgic/vgic-sys-reg-common.c
 create mode 100644 virt/kvm/arm/vgic/vgic-sys-reg-v3.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 0/11] arm/arm64: vgic: Implement API for vGICv3 live migration
@ 2016-11-23 13:01 ` vijay.kilari at gmail.com
  0 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari at gmail.com @ 2016-11-23 13:01 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

This patchset adds API for saving and restoring
of VGICv3 registers to support live migration with new vgic feature.
This API definition is as per version of VGICv3 specification
Documentation/virtual/kvm/devices/arm-vgic-v3.txt

The patch 3 & 4 are picked from the Pavel's previous implementation.
http://www.spinics.net/lists/kvm/msg122040.html

NOTE: Only compilation tested for AArch32. No hardware to test.

v8 => v9:
 - Rebased to kvmarm/next branch
 - Introduce support for save and restore of CPU interface
   registers for AArch32 mode (9,10 and 11 patches).
   Only compilation tested.
 - Fixed vmcr.ctlr format
 - Updated error code for invalid CPU REG value in Documentation
 - Updated commit messages and added comments required
 - Queued IRQ when irq_line is set.
 - Compatibility check on ICC_CTLR_EL1.SEIS and A3V

v7 => v8:
 - Rebased to 4.9-rc3
 - Fixed wrong parameter to VGIC_TO_MPIDR
v6 => v7:
 - Rename all patches heading from vgic-new to vgic
 - Moved caching of priority and ID bits from vgic global struct
   to vgic_cpu struct.

v5 => v6:
 - Collated all register definitions to single patch (4)
 - Introduce macro to convert userspace MPIDR format to MPIDR reg format
 - Check on ICC_CTLR_EL1.CBPR value is made while accessing ICC_BPR1_EL1
 - Cached ich_vtr_el2 and guests priority and ID bits
 - Check on number of priority and ID bits when ICC_CTRL_EL1 write is made
 - Check is made on SRE bit for ICC_SRE_EL1 write

v4 => v5:
 - ICC_CTLR_EL1 access is updated to reflect HW values
 - Updated ICC reg access mask and shift macros
 - Introduced patch 4 for VMCR changes
 - Other minor fixes.
v3 => v4:
 - Rebased to latest code base
 - Moved vgic_uaccess() from vgic-mmio-v2.c to vgic-mmio.c
 - Dropped macro REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED_UACCESS
 - Dropped LE conversion for userspace access
 - Introduced vgic_uaccess_write_pending() for ISPENDR write
 - Change macro KVM_DEV_ARM_VGIC_V3_CPUID_MASK to KVM_DEV_ARM_VGIC_V3_MIDR_MASK
 - Refactored some code as common code.
 - Changed handing of ICC_* registers
 - Allowed ICC_SRE_EL1 read by userspace
 - Fixed KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_* macros

v2 => v3:
 - Implemented separate API for ISPENDR and ICPENDR to
   read soft_pending instead of pending for level triggerred interrupts
 - Implemented ioctl KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO to access line level
 - Rebased on top of Christoffer's patch set
   http://www.spinics.net/lists/kvm/msg136840.html

 NOTE: GICD_STATUSR and GICR_STATUSR are implemented as RAZ/WI.

v1 => v2:
 - The init sequence change patch is no more required.
   Fixed in patch 2 by using static vgic_io_dev regions structure instead
   of using dynamic allocation pointer.
 - Updated commit message of patch 4.
 - Dropped usage of union to manage 32-bit and 64-bit access in patch 1.
   Used local variable for 32-bit access.
 - Updated macro __ARM64_SYS_REG and ARM64_SYS_REG in
   arch/arm64/include/uapi/asm/kvm.h as per qemu requirements.

Vijaya Kumar K (11):
  arm/arm64: vgic: Implement support for userspace access
  arm/arm64: vgic: Add distributor and redistributor access
  arm/arm64: vgic: Introduce find_reg_by_id()
  irqchip/gic-v3: Add missing system register definitions
  arm/arm64: vgic: Introduce VENG0 and VENG1 fields to vmcr struct
  arm/arm64: vgic: Implement VGICv3 CPU interface access
  arm/arm64: vgic: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl
  arm/arm64: Documentation: Update arm-vgic-v3.txt
  arm: coproc: Drop const from coproc reg access function
  arm: coproc: Introduce find_coproc_reg_by_id()
  arm: vgic: Save and restore GICv3 CPU interface regs for AArch32

 Documentation/virtual/kvm/devices/arm-vgic-v3.txt |   2 +-
 arch/arm/include/uapi/asm/kvm.h                   |  13 ++
 arch/arm/kvm/Makefile                             |   2 +
 arch/arm/kvm/coproc.c                             |  42 ++--
 arch/arm/kvm/coproc.h                             |   8 +-
 arch/arm64/include/uapi/asm/kvm.h                 |  13 ++
 arch/arm64/kvm/Makefile                           |   2 +
 arch/arm64/kvm/sys_regs.c                         |  22 +-
 arch/arm64/kvm/sys_regs.h                         |   4 +
 include/kvm/arm_vgic.h                            |   9 +
 include/linux/irqchip/arm-gic-v3.h                |  45 +++-
 virt/kvm/arm/vgic/vgic-coproc-reg-v3.c            | 155 +++++++++++++
 virt/kvm/arm/vgic/vgic-kvm-device.c               | 219 +++++++++++++++++-
 virt/kvm/arm/vgic/vgic-mmio-v2.c                  |  57 +----
 virt/kvm/arm/vgic/vgic-mmio-v3.c                  | 203 +++++++++++++++--
 virt/kvm/arm/vgic/vgic-mmio.c                     | 154 ++++++++++++-
 virt/kvm/arm/vgic/vgic-mmio.h                     |  28 +++
 virt/kvm/arm/vgic/vgic-sys-reg-common.c           | 258 ++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-sys-reg-v3.c               | 142 ++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c                       |  30 ++-
 virt/kvm/arm/vgic/vgic.h                          |  78 ++++++-
 21 files changed, 1365 insertions(+), 121 deletions(-)
 create mode 100644 virt/kvm/arm/vgic/vgic-coproc-reg-v3.c
 create mode 100644 virt/kvm/arm/vgic/vgic-sys-reg-common.c
 create mode 100644 virt/kvm/arm/vgic/vgic-sys-reg-v3.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 01/11] arm/arm64: vgic: Implement support for userspace access
  2016-11-23 13:01 ` vijay.kilari at gmail.com
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  -1 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari @ 2016-11-23 13:01 UTC (permalink / raw)
  To: marc.zyngier, christoffer.dall, peter.maydell
  Cc: kvmarm, linux-arm-kernel, Vijaya Kumar K

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

Read and write of some registers like ISPENDR and ICPENDR
from userspace requires special handling when compared to
guest access for these registers.

Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
for handling of ISPENDR, ICPENDR registers handling.

Add infrastructure to support guest and userspace read
and write for the required registers
Also moved vgic_uaccess from vgic-mmio-v2.c to vgic-mmio.c

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 virt/kvm/arm/vgic/vgic-mmio-v2.c |  25 ----------
 virt/kvm/arm/vgic/vgic-mmio-v3.c | 102 ++++++++++++++++++++++++++++++++-------
 virt/kvm/arm/vgic/vgic-mmio.c    |  78 +++++++++++++++++++++++++++---
 virt/kvm/arm/vgic/vgic-mmio.h    |  19 ++++++++
 4 files changed, 175 insertions(+), 49 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index b44b359..0b32f40 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -406,31 +406,6 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
 	return -ENXIO;
 }
 
-/*
- * When userland tries to access the VGIC register handlers, we need to
- * create a usable struct vgic_io_device to be passed to the handlers and we
- * have to set up a buffer similar to what would have happened if a guest MMIO
- * access occurred, including doing endian conversions on BE systems.
- */
-static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
-			bool is_write, int offset, u32 *val)
-{
-	unsigned int len = 4;
-	u8 buf[4];
-	int ret;
-
-	if (is_write) {
-		vgic_data_host_to_mmio_bus(buf, len, *val);
-		ret = kvm_io_gic_ops.write(vcpu, &dev->dev, offset, len, buf);
-	} else {
-		ret = kvm_io_gic_ops.read(vcpu, &dev->dev, offset, len, buf);
-		if (!ret)
-			*val = vgic_data_mmio_bus_to_host(buf, len);
-	}
-
-	return ret;
-}
-
 int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			  int offset, u32 *val)
 {
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 50f42f0..8e76d04 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -207,6 +207,66 @@ static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+static unsigned long vgic_v3_uaccess_read_pending(struct kvm_vcpu *vcpu,
+						  gpa_t addr, unsigned int len)
+{
+	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
+	u32 value = 0;
+	int i;
+
+	/*
+	 * A level triggerred interrupt pending state is latched in both
+	 * "soft_pending" and "line_level" variables. Userspace will save
+	 * and restore soft_pending and line_level separately.
+	 * Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
+	 * handling of ISPENDR and ICPENDR.
+	 */
+	for (i = 0; i < len * 8; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (irq->config == VGIC_CONFIG_LEVEL && irq->soft_pending)
+			value |= (1U << i);
+		if (irq->config == VGIC_CONFIG_EDGE && irq->pending)
+			value |= (1U << i);
+
+		vgic_put_irq(vcpu->kvm, irq);
+	}
+
+	return value;
+}
+
+static void vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu,
+					  gpa_t addr, unsigned int len,
+					  unsigned long val)
+{
+	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
+	int i;
+
+	for (i = 0; i < len * 8; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		if (test_bit(i, &val)) {
+			/* soft_pending is set irrespective of irq type
+			 * (level or edge) to avoid dependency that VM should
+			 * restore irq config before pending info.
+			 */
+			irq->pending = true;
+			irq->soft_pending = true;
+			vgic_queue_irq_unlock(vcpu->kvm, irq);
+		} else {
+			irq->soft_pending = false;
+			if (irq->config == VGIC_CONFIG_EDGE ||
+			    (irq->config == VGIC_CONFIG_LEVEL &&
+			    !irq->line_level))
+				irq->pending = false;
+			spin_unlock(&irq->irq_lock);
+		}
+
+		vgic_put_irq(vcpu->kvm, irq);
+	}
+}
+
 /* We want to avoid outer shareable. */
 u64 vgic_sanitise_shareability(u64 field)
 {
@@ -356,7 +416,7 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
  * We take some special care here to fix the calculation of the register
  * offset.
  */
-#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, bpi, acc)	\
+#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, ur, uw, bpi, acc) \
 	{								\
 		.reg_offset = off,					\
 		.bits_per_irq = bpi,					\
@@ -371,6 +431,8 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
 		.access_flags = acc,					\
 		.read = rd,						\
 		.write = wr,						\
+		.uaccess_read = ur,					\
+		.uaccess_write = uw,					\
 	}
 
 static const struct vgic_register_region vgic_v3_dist_registers[] = {
@@ -378,40 +440,42 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
 		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
-		vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
+		vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
-		vgic_mmio_read_enable, vgic_mmio_write_senable, 1,
+		vgic_mmio_read_enable, vgic_mmio_write_senable, NULL, NULL, 1,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
-		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
+		vgic_mmio_read_enable, vgic_mmio_write_cenable, NULL, NULL, 1,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
-		vgic_mmio_read_pending, vgic_mmio_write_spending, 1,
+		vgic_mmio_read_pending, vgic_mmio_write_spending,
+		vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 1,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
-		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1,
+		vgic_mmio_read_pending, vgic_mmio_write_cpending,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
-		vgic_mmio_read_active, vgic_mmio_write_sactive, 1,
+		vgic_mmio_read_active, vgic_mmio_write_sactive, NULL, NULL, 1,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
-		vgic_mmio_read_active, vgic_mmio_write_cactive, 1,
+		vgic_mmio_read_active, vgic_mmio_write_cactive, NULL, NULL, 1,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
-		vgic_mmio_read_priority, vgic_mmio_write_priority, 8,
-		VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
+		vgic_mmio_read_priority, vgic_mmio_write_priority, NULL, NULL,
+		8, VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 8,
 		VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
-		vgic_mmio_read_config, vgic_mmio_write_config, 2,
+		vgic_mmio_read_config, vgic_mmio_write_config, NULL, NULL, 2,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
-		vgic_mmio_read_irouter, vgic_mmio_write_irouter, 64,
+		vgic_mmio_read_irouter, vgic_mmio_write_irouter, NULL, NULL, 64,
 		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
 		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48,
@@ -449,11 +513,13 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
 	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
 		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4,
 		VGIC_ACCESS_32bit),
-	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
-		vgic_mmio_read_pending, vgic_mmio_write_spending, 4,
+	REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ISPENDR0,
+		vgic_mmio_read_pending, vgic_mmio_write_spending,
+		vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 4,
 		VGIC_ACCESS_32bit),
-	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
-		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4,
+	REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ICPENDR0,
+		vgic_mmio_read_pending, vgic_mmio_write_cpending,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
 		vgic_mmio_read_active, vgic_mmio_write_sactive, 4,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index ebe1b9f..d5f3ee2 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -484,6 +484,74 @@ static bool check_region(const struct kvm *kvm,
 	return false;
 }
 
+static const struct vgic_register_region *
+vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev,
+		     gpa_t addr, int len)
+{
+	const struct vgic_register_region *region;
+
+	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
+				       addr - iodev->base_addr);
+	if (!region || !check_region(vcpu->kvm, region, addr, len))
+		return NULL;
+
+	return region;
+}
+
+static int vgic_uaccess_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+			     gpa_t addr, u32 *val)
+{
+	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
+	const struct vgic_register_region *region;
+	struct kvm_vcpu *r_vcpu;
+
+	region = vgic_get_mmio_region(vcpu, iodev, addr, sizeof(u32));
+	if (!region) {
+		*val = 0;
+		return 0;
+	}
+
+	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
+	if (region->uaccess_read)
+		*val = region->uaccess_read(r_vcpu, addr, sizeof(u32));
+	else
+		*val = region->read(r_vcpu, addr, sizeof(u32));
+
+	return 0;
+}
+
+static int vgic_uaccess_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+			      gpa_t addr, const u32 *val)
+{
+	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
+	const struct vgic_register_region *region;
+	struct kvm_vcpu *r_vcpu;
+
+	region = vgic_get_mmio_region(vcpu, iodev, addr, sizeof(u32));
+	if (!region)
+		return 0;
+
+	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
+	if (region->uaccess_write)
+		region->uaccess_write(r_vcpu, addr, sizeof(u32), *val);
+	else
+		region->write(r_vcpu, addr, sizeof(u32), *val);
+
+	return 0;
+}
+
+/*
+ * Userland access to VGIC registers.
+ */
+int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
+		 bool is_write, int offset, u32 *val)
+{
+	if (is_write)
+		return vgic_uaccess_write(vcpu, &dev->dev, offset, val);
+	else
+		return vgic_uaccess_read(vcpu, &dev->dev, offset, val);
+}
+
 static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
 			      gpa_t addr, int len, void *val)
 {
@@ -491,9 +559,8 @@ static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
 	const struct vgic_register_region *region;
 	unsigned long data = 0;
 
-	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
-				       addr - iodev->base_addr);
-	if (!region || !check_region(vcpu->kvm, region, addr, len)) {
+	region = vgic_get_mmio_region(vcpu, iodev, addr, len);
+	if (!region) {
 		memset(val, 0, len);
 		return 0;
 	}
@@ -524,9 +591,8 @@ static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
 	const struct vgic_register_region *region;
 	unsigned long data = vgic_data_mmio_bus_to_host(val, len);
 
-	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
-				       addr - iodev->base_addr);
-	if (!region || !check_region(vcpu->kvm, region, addr, len))
+	region = vgic_get_mmio_region(vcpu, iodev, addr, len);
+	if (!region)
 		return 0;
 
 	switch (iodev->iodev_type) {
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 84961b4..7b30296 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -34,6 +34,10 @@ struct vgic_register_region {
 				  gpa_t addr, unsigned int len,
 				  unsigned long val);
 	};
+	unsigned long (*uaccess_read)(struct kvm_vcpu *vcpu, gpa_t addr,
+				      unsigned int len);
+	void (*uaccess_write)(struct kvm_vcpu *vcpu, gpa_t addr,
+			      unsigned int len, unsigned long val);
 };
 
 extern struct kvm_io_device_ops kvm_io_gic_ops;
@@ -86,6 +90,18 @@ struct vgic_register_region {
 		.write = wr,						\
 	}
 
+#define REGISTER_DESC_WITH_LENGTH_UACCESS(off, rd, wr, urd, uwr, length, acc) \
+	{								\
+		.reg_offset = off,					\
+		.bits_per_irq = 0,					\
+		.len = length,						\
+		.access_flags = acc,					\
+		.read = rd,						\
+		.write = wr,						\
+		.uaccess_read = urd,					\
+		.uaccess_write = uwr,					\
+	}
+
 int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
 				  struct vgic_register_region *reg_desc,
 				  struct vgic_io_device *region,
@@ -158,6 +174,9 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
 			    gpa_t addr, unsigned int len,
 			    unsigned long val);
 
+int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
+		 bool is_write, int offset, u32 *val);
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 01/11] arm/arm64: vgic: Implement support for userspace access
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  0 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari at gmail.com @ 2016-11-23 13:01 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

Read and write of some registers like ISPENDR and ICPENDR
from userspace requires special handling when compared to
guest access for these registers.

Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
for handling of ISPENDR, ICPENDR registers handling.

Add infrastructure to support guest and userspace read
and write for the required registers
Also moved vgic_uaccess from vgic-mmio-v2.c to vgic-mmio.c

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 virt/kvm/arm/vgic/vgic-mmio-v2.c |  25 ----------
 virt/kvm/arm/vgic/vgic-mmio-v3.c | 102 ++++++++++++++++++++++++++++++++-------
 virt/kvm/arm/vgic/vgic-mmio.c    |  78 +++++++++++++++++++++++++++---
 virt/kvm/arm/vgic/vgic-mmio.h    |  19 ++++++++
 4 files changed, 175 insertions(+), 49 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index b44b359..0b32f40 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -406,31 +406,6 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
 	return -ENXIO;
 }
 
-/*
- * When userland tries to access the VGIC register handlers, we need to
- * create a usable struct vgic_io_device to be passed to the handlers and we
- * have to set up a buffer similar to what would have happened if a guest MMIO
- * access occurred, including doing endian conversions on BE systems.
- */
-static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
-			bool is_write, int offset, u32 *val)
-{
-	unsigned int len = 4;
-	u8 buf[4];
-	int ret;
-
-	if (is_write) {
-		vgic_data_host_to_mmio_bus(buf, len, *val);
-		ret = kvm_io_gic_ops.write(vcpu, &dev->dev, offset, len, buf);
-	} else {
-		ret = kvm_io_gic_ops.read(vcpu, &dev->dev, offset, len, buf);
-		if (!ret)
-			*val = vgic_data_mmio_bus_to_host(buf, len);
-	}
-
-	return ret;
-}
-
 int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			  int offset, u32 *val)
 {
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 50f42f0..8e76d04 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -207,6 +207,66 @@ static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+static unsigned long vgic_v3_uaccess_read_pending(struct kvm_vcpu *vcpu,
+						  gpa_t addr, unsigned int len)
+{
+	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
+	u32 value = 0;
+	int i;
+
+	/*
+	 * A level triggerred interrupt pending state is latched in both
+	 * "soft_pending" and "line_level" variables. Userspace will save
+	 * and restore soft_pending and line_level separately.
+	 * Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
+	 * handling of ISPENDR and ICPENDR.
+	 */
+	for (i = 0; i < len * 8; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (irq->config == VGIC_CONFIG_LEVEL && irq->soft_pending)
+			value |= (1U << i);
+		if (irq->config == VGIC_CONFIG_EDGE && irq->pending)
+			value |= (1U << i);
+
+		vgic_put_irq(vcpu->kvm, irq);
+	}
+
+	return value;
+}
+
+static void vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu,
+					  gpa_t addr, unsigned int len,
+					  unsigned long val)
+{
+	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
+	int i;
+
+	for (i = 0; i < len * 8; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		if (test_bit(i, &val)) {
+			/* soft_pending is set irrespective of irq type
+			 * (level or edge) to avoid dependency that VM should
+			 * restore irq config before pending info.
+			 */
+			irq->pending = true;
+			irq->soft_pending = true;
+			vgic_queue_irq_unlock(vcpu->kvm, irq);
+		} else {
+			irq->soft_pending = false;
+			if (irq->config == VGIC_CONFIG_EDGE ||
+			    (irq->config == VGIC_CONFIG_LEVEL &&
+			    !irq->line_level))
+				irq->pending = false;
+			spin_unlock(&irq->irq_lock);
+		}
+
+		vgic_put_irq(vcpu->kvm, irq);
+	}
+}
+
 /* We want to avoid outer shareable. */
 u64 vgic_sanitise_shareability(u64 field)
 {
@@ -356,7 +416,7 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
  * We take some special care here to fix the calculation of the register
  * offset.
  */
-#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, bpi, acc)	\
+#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, ur, uw, bpi, acc) \
 	{								\
 		.reg_offset = off,					\
 		.bits_per_irq = bpi,					\
@@ -371,6 +431,8 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
 		.access_flags = acc,					\
 		.read = rd,						\
 		.write = wr,						\
+		.uaccess_read = ur,					\
+		.uaccess_write = uw,					\
 	}
 
 static const struct vgic_register_region vgic_v3_dist_registers[] = {
@@ -378,40 +440,42 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
 		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
-		vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
+		vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
-		vgic_mmio_read_enable, vgic_mmio_write_senable, 1,
+		vgic_mmio_read_enable, vgic_mmio_write_senable, NULL, NULL, 1,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
-		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
+		vgic_mmio_read_enable, vgic_mmio_write_cenable, NULL, NULL, 1,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
-		vgic_mmio_read_pending, vgic_mmio_write_spending, 1,
+		vgic_mmio_read_pending, vgic_mmio_write_spending,
+		vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 1,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
-		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1,
+		vgic_mmio_read_pending, vgic_mmio_write_cpending,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
-		vgic_mmio_read_active, vgic_mmio_write_sactive, 1,
+		vgic_mmio_read_active, vgic_mmio_write_sactive, NULL, NULL, 1,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
-		vgic_mmio_read_active, vgic_mmio_write_cactive, 1,
+		vgic_mmio_read_active, vgic_mmio_write_cactive, NULL, NULL, 1,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
-		vgic_mmio_read_priority, vgic_mmio_write_priority, 8,
-		VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
+		vgic_mmio_read_priority, vgic_mmio_write_priority, NULL, NULL,
+		8, VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 8,
 		VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
-		vgic_mmio_read_config, vgic_mmio_write_config, 2,
+		vgic_mmio_read_config, vgic_mmio_write_config, NULL, NULL, 2,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
-		vgic_mmio_read_irouter, vgic_mmio_write_irouter, 64,
+		vgic_mmio_read_irouter, vgic_mmio_write_irouter, NULL, NULL, 64,
 		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
 		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48,
@@ -449,11 +513,13 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
 	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
 		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4,
 		VGIC_ACCESS_32bit),
-	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
-		vgic_mmio_read_pending, vgic_mmio_write_spending, 4,
+	REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ISPENDR0,
+		vgic_mmio_read_pending, vgic_mmio_write_spending,
+		vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 4,
 		VGIC_ACCESS_32bit),
-	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
-		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4,
+	REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ICPENDR0,
+		vgic_mmio_read_pending, vgic_mmio_write_cpending,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
 		vgic_mmio_read_active, vgic_mmio_write_sactive, 4,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index ebe1b9f..d5f3ee2 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -484,6 +484,74 @@ static bool check_region(const struct kvm *kvm,
 	return false;
 }
 
+static const struct vgic_register_region *
+vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev,
+		     gpa_t addr, int len)
+{
+	const struct vgic_register_region *region;
+
+	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
+				       addr - iodev->base_addr);
+	if (!region || !check_region(vcpu->kvm, region, addr, len))
+		return NULL;
+
+	return region;
+}
+
+static int vgic_uaccess_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+			     gpa_t addr, u32 *val)
+{
+	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
+	const struct vgic_register_region *region;
+	struct kvm_vcpu *r_vcpu;
+
+	region = vgic_get_mmio_region(vcpu, iodev, addr, sizeof(u32));
+	if (!region) {
+		*val = 0;
+		return 0;
+	}
+
+	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
+	if (region->uaccess_read)
+		*val = region->uaccess_read(r_vcpu, addr, sizeof(u32));
+	else
+		*val = region->read(r_vcpu, addr, sizeof(u32));
+
+	return 0;
+}
+
+static int vgic_uaccess_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+			      gpa_t addr, const u32 *val)
+{
+	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
+	const struct vgic_register_region *region;
+	struct kvm_vcpu *r_vcpu;
+
+	region = vgic_get_mmio_region(vcpu, iodev, addr, sizeof(u32));
+	if (!region)
+		return 0;
+
+	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
+	if (region->uaccess_write)
+		region->uaccess_write(r_vcpu, addr, sizeof(u32), *val);
+	else
+		region->write(r_vcpu, addr, sizeof(u32), *val);
+
+	return 0;
+}
+
+/*
+ * Userland access to VGIC registers.
+ */
+int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
+		 bool is_write, int offset, u32 *val)
+{
+	if (is_write)
+		return vgic_uaccess_write(vcpu, &dev->dev, offset, val);
+	else
+		return vgic_uaccess_read(vcpu, &dev->dev, offset, val);
+}
+
 static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
 			      gpa_t addr, int len, void *val)
 {
@@ -491,9 +559,8 @@ static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
 	const struct vgic_register_region *region;
 	unsigned long data = 0;
 
-	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
-				       addr - iodev->base_addr);
-	if (!region || !check_region(vcpu->kvm, region, addr, len)) {
+	region = vgic_get_mmio_region(vcpu, iodev, addr, len);
+	if (!region) {
 		memset(val, 0, len);
 		return 0;
 	}
@@ -524,9 +591,8 @@ static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
 	const struct vgic_register_region *region;
 	unsigned long data = vgic_data_mmio_bus_to_host(val, len);
 
-	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
-				       addr - iodev->base_addr);
-	if (!region || !check_region(vcpu->kvm, region, addr, len))
+	region = vgic_get_mmio_region(vcpu, iodev, addr, len);
+	if (!region)
 		return 0;
 
 	switch (iodev->iodev_type) {
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 84961b4..7b30296 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -34,6 +34,10 @@ struct vgic_register_region {
 				  gpa_t addr, unsigned int len,
 				  unsigned long val);
 	};
+	unsigned long (*uaccess_read)(struct kvm_vcpu *vcpu, gpa_t addr,
+				      unsigned int len);
+	void (*uaccess_write)(struct kvm_vcpu *vcpu, gpa_t addr,
+			      unsigned int len, unsigned long val);
 };
 
 extern struct kvm_io_device_ops kvm_io_gic_ops;
@@ -86,6 +90,18 @@ struct vgic_register_region {
 		.write = wr,						\
 	}
 
+#define REGISTER_DESC_WITH_LENGTH_UACCESS(off, rd, wr, urd, uwr, length, acc) \
+	{								\
+		.reg_offset = off,					\
+		.bits_per_irq = 0,					\
+		.len = length,						\
+		.access_flags = acc,					\
+		.read = rd,						\
+		.write = wr,						\
+		.uaccess_read = urd,					\
+		.uaccess_write = uwr,					\
+	}
+
 int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
 				  struct vgic_register_region *reg_desc,
 				  struct vgic_io_device *region,
@@ -158,6 +174,9 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
 			    gpa_t addr, unsigned int len,
 			    unsigned long val);
 
+int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
+		 bool is_write, int offset, u32 *val);
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 02/11] arm/arm64: vgic: Add distributor and redistributor access
  2016-11-23 13:01 ` vijay.kilari at gmail.com
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  -1 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari @ 2016-11-23 13:01 UTC (permalink / raw)
  To: marc.zyngier, christoffer.dall, peter.maydell
  Cc: kvmarm, linux-arm-kernel, Vijaya Kumar K

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

VGICv3 Distributor and Redistributor registers are accessed using
KVM_DEV_ARM_VGIC_GRP_DIST_REGS and KVM_DEV_ARM_VGIC_GRP_REDIST_REGS
with KVM_SET_DEVICE_ATTR and KVM_GET_DEVICE_ATTR ioctls.
These registers are accessed as 32-bit and cpu mpidr
value passed along with register offset is used to identify the
cpu for redistributor registers access.

The version of VGIC v3 specification is define here
Documentation/virtual/kvm/devices/arm-vgic-v3.txt

Also update arch/arm/include/uapi/asm/kvm.h to compile for
AArch32 mode.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 arch/arm/include/uapi/asm/kvm.h     |   4 +
 arch/arm64/include/uapi/asm/kvm.h   |   4 +
 virt/kvm/arm/vgic/vgic-kvm-device.c | 144 ++++++++++++++++++++++++++++++++++--
 virt/kvm/arm/vgic/vgic-mmio-v2.c    |  16 +---
 virt/kvm/arm/vgic/vgic-mmio-v3.c    |  72 ++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.c       |  22 ++++++
 virt/kvm/arm/vgic/vgic-mmio.h       |   4 +
 virt/kvm/arm/vgic/vgic.h            |  49 +++++++++++-
 8 files changed, 292 insertions(+), 23 deletions(-)

diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index af05f8e..0ae6035 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -181,10 +181,14 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_CPU_REGS	2
 #define   KVM_DEV_ARM_VGIC_CPUID_SHIFT	32
 #define   KVM_DEV_ARM_VGIC_CPUID_MASK	(0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
+#define   KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32
+#define   KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \
+			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
 #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
 #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
 #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
 #define KVM_DEV_ARM_VGIC_GRP_CTRL       4
+#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
 
 /* KVM_IRQ_LINE irq field index values */
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 3051f86..56dc08d 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -201,10 +201,14 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_CPU_REGS	2
 #define   KVM_DEV_ARM_VGIC_CPUID_SHIFT	32
 #define   KVM_DEV_ARM_VGIC_CPUID_MASK	(0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
+#define   KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32
+#define   KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \
+			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
 #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
 #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
 #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
 #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
+#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
 
 /* Device Control API on vcpu fd */
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index fbe87a6..bc7de95 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -235,7 +235,7 @@ struct vgic_reg_attr {
 	gpa_t addr;
 };
 
-static int parse_vgic_v2_attr(struct kvm_device *dev,
+static int vgic_v2_parse_attr(struct kvm_device *dev,
 			      struct kvm_device_attr *attr,
 			      struct vgic_reg_attr *reg_attr)
 {
@@ -292,14 +292,14 @@ static bool lock_all_vcpus(struct kvm *kvm)
 }
 
 /**
- * vgic_attr_regs_access_v2 - allows user space to access VGIC v2 state
+ * vgic_v2_attr_regs_access - allows user space to access VGIC v2 state
  *
  * @dev:      kvm device handle
  * @attr:     kvm device attribute
  * @reg:      address the value is read or written
  * @is_write: true if userspace is writing a register
  */
-static int vgic_attr_regs_access_v2(struct kvm_device *dev,
+static int vgic_v2_attr_regs_access(struct kvm_device *dev,
 				    struct kvm_device_attr *attr,
 				    u32 *reg, bool is_write)
 {
@@ -308,7 +308,7 @@ static int vgic_attr_regs_access_v2(struct kvm_device *dev,
 	struct kvm_vcpu *vcpu;
 	int ret;
 
-	ret = parse_vgic_v2_attr(dev, attr, &reg_attr);
+	ret = vgic_v2_parse_attr(dev, attr, &reg_attr);
 	if (ret)
 		return ret;
 
@@ -362,7 +362,7 @@ static int vgic_v2_set_attr(struct kvm_device *dev,
 		if (get_user(reg, uaddr))
 			return -EFAULT;
 
-		return vgic_attr_regs_access_v2(dev, attr, &reg, true);
+		return vgic_v2_attr_regs_access(dev, attr, &reg, true);
 	}
 	}
 
@@ -384,7 +384,7 @@ static int vgic_v2_get_attr(struct kvm_device *dev,
 		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
 		u32 reg = 0;
 
-		ret = vgic_attr_regs_access_v2(dev, attr, &reg, false);
+		ret = vgic_v2_attr_regs_access(dev, attr, &reg, false);
 		if (ret)
 			return ret;
 		return put_user(reg, uaddr);
@@ -428,16 +428,141 @@ struct kvm_device_ops kvm_arm_vgic_v2_ops = {
 	.has_attr = vgic_v2_has_attr,
 };
 
+static int vgic_v3_parse_attr(struct kvm_device *dev,
+			      struct kvm_device_attr *attr,
+			      struct vgic_reg_attr *reg_attr)
+{
+	unsigned long vgic_mpidr, mpidr_reg;
+
+	vgic_mpidr = (attr->attr & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) >>
+		      KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT;
+
+	mpidr_reg = VGIC_TO_MPIDR(vgic_mpidr);
+	reg_attr->vcpu = kvm_mpidr_to_vcpu(dev->kvm, mpidr_reg);
+	if (!reg_attr->vcpu)
+		return -EINVAL;
+
+	reg_attr->addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+	return 0;
+}
+
+/*
+ * vgic_v3_attr_regs_access - allows user space to access VGIC v3 state
+ *
+ * @dev:      kvm device handle
+ * @attr:     kvm device attribute
+ * @reg:      address the value is read or written
+ * @is_write: true if userspace is writing a register
+ */
+static int vgic_v3_attr_regs_access(struct kvm_device *dev,
+				    struct kvm_device_attr *attr,
+				    u64 *reg, bool is_write)
+{
+	struct vgic_reg_attr reg_attr;
+	gpa_t addr;
+	struct kvm_vcpu *vcpu;
+	int ret;
+	u32 tmp32;
+
+	ret = vgic_v3_parse_attr(dev, attr, &reg_attr);
+	if (ret)
+		return ret;
+
+	vcpu = reg_attr.vcpu;
+	addr = reg_attr.addr;
+
+	mutex_lock(&dev->kvm->lock);
+
+	if (unlikely(!vgic_initialized(dev->kvm))) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	if (!lock_all_vcpus(dev->kvm)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+		if (is_write)
+			tmp32 = *reg;
+
+		ret = vgic_v3_dist_uaccess(vcpu, is_write, addr, &tmp32);
+		if (!is_write)
+			*reg = tmp32;
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
+		if (is_write)
+			tmp32 = *reg;
+
+		ret = vgic_v3_redist_uaccess(vcpu, is_write, addr, &tmp32);
+		if (!is_write)
+			*reg = tmp32;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	unlock_all_vcpus(dev->kvm);
+out:
+	mutex_unlock(&dev->kvm->lock);
+	return ret;
+}
+
 static int vgic_v3_set_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return vgic_set_common_attr(dev, attr);
+	int ret;
+
+	ret = vgic_set_common_attr(dev, attr);
+	if (ret != -ENXIO)
+		return ret;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+		u32 tmp32;
+		u64 reg;
+
+		if (get_user(tmp32, uaddr))
+			return -EFAULT;
+
+		reg = tmp32;
+		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
+	}
+	}
+	return -ENXIO;
 }
 
 static int vgic_v3_get_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return vgic_get_common_attr(dev, attr);
+	int ret;
+
+	ret = vgic_get_common_attr(dev, attr);
+	if (ret != -ENXIO)
+		return ret;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+		u64 reg;
+		u32 tmp32;
+
+		ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
+		if (ret)
+			return ret;
+		tmp32 = reg;
+		return put_user(tmp32, uaddr);
+	}
+	}
+
+	return -ENXIO;
 }
 
 static int vgic_v3_has_attr(struct kvm_device *dev,
@@ -451,6 +576,9 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
 			return 0;
 		}
 		break;
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
+		return vgic_v3_has_attr_regs(dev, attr);
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
 	case KVM_DEV_ARM_VGIC_GRP_CTRL:
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 0b32f40..2cb04b7 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -368,10 +368,9 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
 
 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
 {
-	int nr_irqs = dev->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
 	const struct vgic_register_region *regions;
 	gpa_t addr;
-	int nr_regions, i, len;
+	int nr_regions;
 
 	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
 
@@ -392,18 +391,7 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
 	if (addr & 3)
 		return -ENXIO;
 
-	for (i = 0; i < nr_regions; i++) {
-		if (regions[i].bits_per_irq)
-			len = (regions[i].bits_per_irq * nr_irqs) / 8;
-		else
-			len = regions[i].len;
-
-		if (regions[i].reg_offset <= addr &&
-		    regions[i].reg_offset + len > addr)
-			return 0;
-	}
-
-	return -ENXIO;
+	return vgic_validate_mmio_region_addr(dev, regions, nr_regions, addr);
 }
 
 int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 8e76d04..2a7cd62 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -18,6 +18,8 @@
 #include <kvm/arm_vgic.h>
 
 #include <asm/kvm_emulate.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_mmu.h>
 
 #include "vgic.h"
 #include "vgic-mmio.h"
@@ -439,6 +441,9 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
 	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
 		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16,
 		VGIC_ACCESS_32bit),
+	REGISTER_DESC_WITH_LENGTH(GICD_STATUSR,
+		vgic_mmio_read_rao, vgic_mmio_write_wi, 4,
+		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
 		vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
 		VGIC_ACCESS_32bit),
@@ -486,12 +491,18 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
 	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
 		vgic_mmio_read_v3r_ctlr, vgic_mmio_write_v3r_ctlr, 4,
 		VGIC_ACCESS_32bit),
+	REGISTER_DESC_WITH_LENGTH(GICR_STATUSR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
+		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
 		vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
 		vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8,
 		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
+	REGISTER_DESC_WITH_LENGTH(GICR_WAKER,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
+		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
 		vgic_mmio_read_propbase, vgic_mmio_write_propbase, 8,
 		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
@@ -612,6 +623,34 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
 	return ret;
 }
 
+int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
+{
+	const struct vgic_register_region *regions;
+	gpa_t addr;
+	int nr_regions;
+
+	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+		regions = vgic_v3_dist_registers;
+		nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:{
+		regions = vgic_v3_rdbase_registers;
+		nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
+		break;
+	}
+	default:
+		return -ENXIO;
+	}
+
+	/* We only support aligned 32-bit accesses. */
+	if (addr & 3)
+		return -ENXIO;
+
+	return vgic_validate_mmio_region_addr(dev, regions, nr_regions, addr);
+}
 /*
  * Compare a given affinity (level 1-3 and a level 0 mask, from the SGI
  * generation register ICC_SGI1R_EL1) with a given VCPU.
@@ -718,3 +757,36 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
 		vgic_put_irq(vcpu->kvm, irq);
 	}
 }
+
+int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+			 int offset, u32 *val)
+{
+	struct vgic_io_device dev = {
+		.regions = vgic_v3_dist_registers,
+		.nr_regions = ARRAY_SIZE(vgic_v3_dist_registers),
+	};
+
+	return vgic_uaccess(vcpu, &dev, is_write, offset, val);
+}
+
+int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+			   int offset, u32 *val)
+{
+	struct vgic_io_device rd_dev = {
+		.regions = vgic_v3_rdbase_registers,
+		.nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers),
+	};
+
+	struct vgic_io_device sgi_dev = {
+		.regions = vgic_v3_sgibase_registers,
+		.nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers),
+	};
+
+	/* SGI_base is the next 64K frame after RD_base */
+	if (offset >= SZ_64K)
+		return vgic_uaccess(vcpu, &sgi_dev, is_write,
+				    offset - SZ_64K, val);
+	else
+		return vgic_uaccess(vcpu, &rd_dev, is_write,
+				    offset, val);
+}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index d5f3ee2..0d1bc98 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -394,6 +394,28 @@ static int match_region(const void *key, const void *elt)
 		       sizeof(region[0]), match_region);
 }
 
+/* Check if address falls within the region */
+int vgic_validate_mmio_region_addr(struct kvm_device *dev,
+				   const struct vgic_register_region *regions,
+				   int nr_regions, gpa_t addr)
+{
+	int i, len;
+	int nr_irqs = dev->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+
+	for (i = 0; i < nr_regions; i++) {
+		if (regions[i].bits_per_irq)
+			len = (regions[i].bits_per_irq * nr_irqs) / 8;
+		else
+			len = regions[i].len;
+
+		if (regions[i].reg_offset <= addr &&
+		    regions[i].reg_offset + len > addr)
+			return 0;
+	}
+
+	return -ENXIO;
+}
+
 /*
  * kvm_mmio_read_buf() returns a value in a format where it can be converted
  * to a byte array and be directly observed as the guest wanted it to appear
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 7b30296..1cc7faf 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -177,6 +177,10 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
 int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
 		 bool is_write, int offset, u32 *val);
 
+int vgic_validate_mmio_region_addr(struct kvm_device *dev,
+				   const struct vgic_register_region *regions,
+				   int nr_regions, gpa_t addr);
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 859f65c..91f58b2 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -30,6 +30,49 @@
 
 #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
 
+#define VGIC_AFFINITY_0_SHIFT 0
+#define VGIC_AFFINITY_0_MASK (0xffUL << VGIC_AFFINITY_0_SHIFT)
+#define VGIC_AFFINITY_1_SHIFT 8
+#define VGIC_AFFINITY_1_MASK (0xffUL << VGIC_AFFINITY_1_SHIFT)
+#define VGIC_AFFINITY_2_SHIFT 16
+#define VGIC_AFFINITY_2_MASK (0xffUL << VGIC_AFFINITY_2_SHIFT)
+#define VGIC_AFFINITY_3_SHIFT 24
+#define VGIC_AFFINITY_3_MASK (0xffUL << VGIC_AFFINITY_3_SHIFT)
+
+#define VGIC_AFFINITY_LEVEL(reg, level) \
+	((((reg) & VGIC_AFFINITY_## level ##_MASK) \
+	>> VGIC_AFFINITY_## level ##_SHIFT) << MPIDR_LEVEL_SHIFT(level))
+
+/*
+ * The Userspace encodes the affinity differently from the MPIDR,
+ * Below macro converts vgic userspace format to MPIDR reg format.
+ */
+#define VGIC_TO_MPIDR(val) (VGIC_AFFINITY_LEVEL(val, 0) | \
+			    VGIC_AFFINITY_LEVEL(val, 1) | \
+			    VGIC_AFFINITY_LEVEL(val, 2) | \
+			    VGIC_AFFINITY_LEVEL(val, 3))
+
+/*
+ * As per Documentation/virtual/kvm/devices/arm-vgic-v3.txt,
+ * below macros are defined for CPUREG encoding.
+ */
+#define KVM_REG_ARM_VGIC_SYSREG_OP0_MASK   0x000000000000c000
+#define KVM_REG_ARM_VGIC_SYSREG_OP0_SHIFT  14
+#define KVM_REG_ARM_VGIC_SYSREG_OP1_MASK   0x0000000000003800
+#define KVM_REG_ARM_VGIC_SYSREG_OP1_SHIFT  11
+#define KVM_REG_ARM_VGIC_SYSREG_CRN_MASK   0x0000000000000780
+#define KVM_REG_ARM_VGIC_SYSREG_CRN_SHIFT  7
+#define KVM_REG_ARM_VGIC_SYSREG_CRM_MASK   0x0000000000000078
+#define KVM_REG_ARM_VGIC_SYSREG_CRM_SHIFT  3
+#define KVM_REG_ARM_VGIC_SYSREG_OP2_MASK   0x0000000000000007
+#define KVM_REG_ARM_VGIC_SYSREG_OP2_SHIFT  0
+
+#define KVM_DEV_ARM_VGIC_SYSREG_MASK (KVM_REG_ARM_VGIC_SYSREG_OP0_MASK | \
+				      KVM_REG_ARM_VGIC_SYSREG_OP1_MASK | \
+				      KVM_REG_ARM_VGIC_SYSREG_CRN_MASK | \
+				      KVM_REG_ARM_VGIC_SYSREG_CRM_MASK | \
+				      KVM_REG_ARM_VGIC_SYSREG_OP2_MASK)
+
 struct vgic_vmcr {
 	u32	ctlr;
 	u32	abpr;
@@ -89,7 +132,11 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq)
 int kvm_vgic_register_its_device(void);
 void vgic_enable_lpis(struct kvm_vcpu *vcpu);
 int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi);
-
+int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
+int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+			 int offset, u32 *val);
+int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+			 int offset, u32 *val);
 int kvm_register_vgic_device(unsigned long type);
 int vgic_lazy_init(struct kvm *kvm);
 int vgic_init(struct kvm *kvm);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 02/11] arm/arm64: vgic: Add distributor and redistributor access
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  0 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari at gmail.com @ 2016-11-23 13:01 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

VGICv3 Distributor and Redistributor registers are accessed using
KVM_DEV_ARM_VGIC_GRP_DIST_REGS and KVM_DEV_ARM_VGIC_GRP_REDIST_REGS
with KVM_SET_DEVICE_ATTR and KVM_GET_DEVICE_ATTR ioctls.
These registers are accessed as 32-bit and cpu mpidr
value passed along with register offset is used to identify the
cpu for redistributor registers access.

The version of VGIC v3 specification is define here
Documentation/virtual/kvm/devices/arm-vgic-v3.txt

Also update arch/arm/include/uapi/asm/kvm.h to compile for
AArch32 mode.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 arch/arm/include/uapi/asm/kvm.h     |   4 +
 arch/arm64/include/uapi/asm/kvm.h   |   4 +
 virt/kvm/arm/vgic/vgic-kvm-device.c | 144 ++++++++++++++++++++++++++++++++++--
 virt/kvm/arm/vgic/vgic-mmio-v2.c    |  16 +---
 virt/kvm/arm/vgic/vgic-mmio-v3.c    |  72 ++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.c       |  22 ++++++
 virt/kvm/arm/vgic/vgic-mmio.h       |   4 +
 virt/kvm/arm/vgic/vgic.h            |  49 +++++++++++-
 8 files changed, 292 insertions(+), 23 deletions(-)

diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index af05f8e..0ae6035 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -181,10 +181,14 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_CPU_REGS	2
 #define   KVM_DEV_ARM_VGIC_CPUID_SHIFT	32
 #define   KVM_DEV_ARM_VGIC_CPUID_MASK	(0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
+#define   KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32
+#define   KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \
+			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
 #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
 #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
 #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
 #define KVM_DEV_ARM_VGIC_GRP_CTRL       4
+#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
 
 /* KVM_IRQ_LINE irq field index values */
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 3051f86..56dc08d 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -201,10 +201,14 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_CPU_REGS	2
 #define   KVM_DEV_ARM_VGIC_CPUID_SHIFT	32
 #define   KVM_DEV_ARM_VGIC_CPUID_MASK	(0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
+#define   KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32
+#define   KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \
+			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
 #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
 #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
 #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
 #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
+#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
 
 /* Device Control API on vcpu fd */
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index fbe87a6..bc7de95 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -235,7 +235,7 @@ struct vgic_reg_attr {
 	gpa_t addr;
 };
 
-static int parse_vgic_v2_attr(struct kvm_device *dev,
+static int vgic_v2_parse_attr(struct kvm_device *dev,
 			      struct kvm_device_attr *attr,
 			      struct vgic_reg_attr *reg_attr)
 {
@@ -292,14 +292,14 @@ static bool lock_all_vcpus(struct kvm *kvm)
 }
 
 /**
- * vgic_attr_regs_access_v2 - allows user space to access VGIC v2 state
+ * vgic_v2_attr_regs_access - allows user space to access VGIC v2 state
  *
  * @dev:      kvm device handle
  * @attr:     kvm device attribute
  * @reg:      address the value is read or written
  * @is_write: true if userspace is writing a register
  */
-static int vgic_attr_regs_access_v2(struct kvm_device *dev,
+static int vgic_v2_attr_regs_access(struct kvm_device *dev,
 				    struct kvm_device_attr *attr,
 				    u32 *reg, bool is_write)
 {
@@ -308,7 +308,7 @@ static int vgic_attr_regs_access_v2(struct kvm_device *dev,
 	struct kvm_vcpu *vcpu;
 	int ret;
 
-	ret = parse_vgic_v2_attr(dev, attr, &reg_attr);
+	ret = vgic_v2_parse_attr(dev, attr, &reg_attr);
 	if (ret)
 		return ret;
 
@@ -362,7 +362,7 @@ static int vgic_v2_set_attr(struct kvm_device *dev,
 		if (get_user(reg, uaddr))
 			return -EFAULT;
 
-		return vgic_attr_regs_access_v2(dev, attr, &reg, true);
+		return vgic_v2_attr_regs_access(dev, attr, &reg, true);
 	}
 	}
 
@@ -384,7 +384,7 @@ static int vgic_v2_get_attr(struct kvm_device *dev,
 		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
 		u32 reg = 0;
 
-		ret = vgic_attr_regs_access_v2(dev, attr, &reg, false);
+		ret = vgic_v2_attr_regs_access(dev, attr, &reg, false);
 		if (ret)
 			return ret;
 		return put_user(reg, uaddr);
@@ -428,16 +428,141 @@ struct kvm_device_ops kvm_arm_vgic_v2_ops = {
 	.has_attr = vgic_v2_has_attr,
 };
 
+static int vgic_v3_parse_attr(struct kvm_device *dev,
+			      struct kvm_device_attr *attr,
+			      struct vgic_reg_attr *reg_attr)
+{
+	unsigned long vgic_mpidr, mpidr_reg;
+
+	vgic_mpidr = (attr->attr & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) >>
+		      KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT;
+
+	mpidr_reg = VGIC_TO_MPIDR(vgic_mpidr);
+	reg_attr->vcpu = kvm_mpidr_to_vcpu(dev->kvm, mpidr_reg);
+	if (!reg_attr->vcpu)
+		return -EINVAL;
+
+	reg_attr->addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+	return 0;
+}
+
+/*
+ * vgic_v3_attr_regs_access - allows user space to access VGIC v3 state
+ *
+ * @dev:      kvm device handle
+ * @attr:     kvm device attribute
+ * @reg:      address the value is read or written
+ * @is_write: true if userspace is writing a register
+ */
+static int vgic_v3_attr_regs_access(struct kvm_device *dev,
+				    struct kvm_device_attr *attr,
+				    u64 *reg, bool is_write)
+{
+	struct vgic_reg_attr reg_attr;
+	gpa_t addr;
+	struct kvm_vcpu *vcpu;
+	int ret;
+	u32 tmp32;
+
+	ret = vgic_v3_parse_attr(dev, attr, &reg_attr);
+	if (ret)
+		return ret;
+
+	vcpu = reg_attr.vcpu;
+	addr = reg_attr.addr;
+
+	mutex_lock(&dev->kvm->lock);
+
+	if (unlikely(!vgic_initialized(dev->kvm))) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	if (!lock_all_vcpus(dev->kvm)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+		if (is_write)
+			tmp32 = *reg;
+
+		ret = vgic_v3_dist_uaccess(vcpu, is_write, addr, &tmp32);
+		if (!is_write)
+			*reg = tmp32;
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
+		if (is_write)
+			tmp32 = *reg;
+
+		ret = vgic_v3_redist_uaccess(vcpu, is_write, addr, &tmp32);
+		if (!is_write)
+			*reg = tmp32;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	unlock_all_vcpus(dev->kvm);
+out:
+	mutex_unlock(&dev->kvm->lock);
+	return ret;
+}
+
 static int vgic_v3_set_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return vgic_set_common_attr(dev, attr);
+	int ret;
+
+	ret = vgic_set_common_attr(dev, attr);
+	if (ret != -ENXIO)
+		return ret;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+		u32 tmp32;
+		u64 reg;
+
+		if (get_user(tmp32, uaddr))
+			return -EFAULT;
+
+		reg = tmp32;
+		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
+	}
+	}
+	return -ENXIO;
 }
 
 static int vgic_v3_get_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return vgic_get_common_attr(dev, attr);
+	int ret;
+
+	ret = vgic_get_common_attr(dev, attr);
+	if (ret != -ENXIO)
+		return ret;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+		u64 reg;
+		u32 tmp32;
+
+		ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
+		if (ret)
+			return ret;
+		tmp32 = reg;
+		return put_user(tmp32, uaddr);
+	}
+	}
+
+	return -ENXIO;
 }
 
 static int vgic_v3_has_attr(struct kvm_device *dev,
@@ -451,6 +576,9 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
 			return 0;
 		}
 		break;
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
+		return vgic_v3_has_attr_regs(dev, attr);
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
 	case KVM_DEV_ARM_VGIC_GRP_CTRL:
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 0b32f40..2cb04b7 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -368,10 +368,9 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
 
 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
 {
-	int nr_irqs = dev->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
 	const struct vgic_register_region *regions;
 	gpa_t addr;
-	int nr_regions, i, len;
+	int nr_regions;
 
 	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
 
@@ -392,18 +391,7 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
 	if (addr & 3)
 		return -ENXIO;
 
-	for (i = 0; i < nr_regions; i++) {
-		if (regions[i].bits_per_irq)
-			len = (regions[i].bits_per_irq * nr_irqs) / 8;
-		else
-			len = regions[i].len;
-
-		if (regions[i].reg_offset <= addr &&
-		    regions[i].reg_offset + len > addr)
-			return 0;
-	}
-
-	return -ENXIO;
+	return vgic_validate_mmio_region_addr(dev, regions, nr_regions, addr);
 }
 
 int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 8e76d04..2a7cd62 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -18,6 +18,8 @@
 #include <kvm/arm_vgic.h>
 
 #include <asm/kvm_emulate.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_mmu.h>
 
 #include "vgic.h"
 #include "vgic-mmio.h"
@@ -439,6 +441,9 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
 	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
 		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16,
 		VGIC_ACCESS_32bit),
+	REGISTER_DESC_WITH_LENGTH(GICD_STATUSR,
+		vgic_mmio_read_rao, vgic_mmio_write_wi, 4,
+		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
 		vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
 		VGIC_ACCESS_32bit),
@@ -486,12 +491,18 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
 	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
 		vgic_mmio_read_v3r_ctlr, vgic_mmio_write_v3r_ctlr, 4,
 		VGIC_ACCESS_32bit),
+	REGISTER_DESC_WITH_LENGTH(GICR_STATUSR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
+		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
 		vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4,
 		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
 		vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8,
 		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
+	REGISTER_DESC_WITH_LENGTH(GICR_WAKER,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
+		VGIC_ACCESS_32bit),
 	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
 		vgic_mmio_read_propbase, vgic_mmio_write_propbase, 8,
 		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
@@ -612,6 +623,34 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
 	return ret;
 }
 
+int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
+{
+	const struct vgic_register_region *regions;
+	gpa_t addr;
+	int nr_regions;
+
+	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+		regions = vgic_v3_dist_registers;
+		nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:{
+		regions = vgic_v3_rdbase_registers;
+		nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
+		break;
+	}
+	default:
+		return -ENXIO;
+	}
+
+	/* We only support aligned 32-bit accesses. */
+	if (addr & 3)
+		return -ENXIO;
+
+	return vgic_validate_mmio_region_addr(dev, regions, nr_regions, addr);
+}
 /*
  * Compare a given affinity (level 1-3 and a level 0 mask, from the SGI
  * generation register ICC_SGI1R_EL1) with a given VCPU.
@@ -718,3 +757,36 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
 		vgic_put_irq(vcpu->kvm, irq);
 	}
 }
+
+int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+			 int offset, u32 *val)
+{
+	struct vgic_io_device dev = {
+		.regions = vgic_v3_dist_registers,
+		.nr_regions = ARRAY_SIZE(vgic_v3_dist_registers),
+	};
+
+	return vgic_uaccess(vcpu, &dev, is_write, offset, val);
+}
+
+int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+			   int offset, u32 *val)
+{
+	struct vgic_io_device rd_dev = {
+		.regions = vgic_v3_rdbase_registers,
+		.nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers),
+	};
+
+	struct vgic_io_device sgi_dev = {
+		.regions = vgic_v3_sgibase_registers,
+		.nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers),
+	};
+
+	/* SGI_base is the next 64K frame after RD_base */
+	if (offset >= SZ_64K)
+		return vgic_uaccess(vcpu, &sgi_dev, is_write,
+				    offset - SZ_64K, val);
+	else
+		return vgic_uaccess(vcpu, &rd_dev, is_write,
+				    offset, val);
+}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index d5f3ee2..0d1bc98 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -394,6 +394,28 @@ static int match_region(const void *key, const void *elt)
 		       sizeof(region[0]), match_region);
 }
 
+/* Check if address falls within the region */
+int vgic_validate_mmio_region_addr(struct kvm_device *dev,
+				   const struct vgic_register_region *regions,
+				   int nr_regions, gpa_t addr)
+{
+	int i, len;
+	int nr_irqs = dev->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+
+	for (i = 0; i < nr_regions; i++) {
+		if (regions[i].bits_per_irq)
+			len = (regions[i].bits_per_irq * nr_irqs) / 8;
+		else
+			len = regions[i].len;
+
+		if (regions[i].reg_offset <= addr &&
+		    regions[i].reg_offset + len > addr)
+			return 0;
+	}
+
+	return -ENXIO;
+}
+
 /*
  * kvm_mmio_read_buf() returns a value in a format where it can be converted
  * to a byte array and be directly observed as the guest wanted it to appear
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 7b30296..1cc7faf 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -177,6 +177,10 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
 int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
 		 bool is_write, int offset, u32 *val);
 
+int vgic_validate_mmio_region_addr(struct kvm_device *dev,
+				   const struct vgic_register_region *regions,
+				   int nr_regions, gpa_t addr);
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 859f65c..91f58b2 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -30,6 +30,49 @@
 
 #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
 
+#define VGIC_AFFINITY_0_SHIFT 0
+#define VGIC_AFFINITY_0_MASK (0xffUL << VGIC_AFFINITY_0_SHIFT)
+#define VGIC_AFFINITY_1_SHIFT 8
+#define VGIC_AFFINITY_1_MASK (0xffUL << VGIC_AFFINITY_1_SHIFT)
+#define VGIC_AFFINITY_2_SHIFT 16
+#define VGIC_AFFINITY_2_MASK (0xffUL << VGIC_AFFINITY_2_SHIFT)
+#define VGIC_AFFINITY_3_SHIFT 24
+#define VGIC_AFFINITY_3_MASK (0xffUL << VGIC_AFFINITY_3_SHIFT)
+
+#define VGIC_AFFINITY_LEVEL(reg, level) \
+	((((reg) & VGIC_AFFINITY_## level ##_MASK) \
+	>> VGIC_AFFINITY_## level ##_SHIFT) << MPIDR_LEVEL_SHIFT(level))
+
+/*
+ * The Userspace encodes the affinity differently from the MPIDR,
+ * Below macro converts vgic userspace format to MPIDR reg format.
+ */
+#define VGIC_TO_MPIDR(val) (VGIC_AFFINITY_LEVEL(val, 0) | \
+			    VGIC_AFFINITY_LEVEL(val, 1) | \
+			    VGIC_AFFINITY_LEVEL(val, 2) | \
+			    VGIC_AFFINITY_LEVEL(val, 3))
+
+/*
+ * As per Documentation/virtual/kvm/devices/arm-vgic-v3.txt,
+ * below macros are defined for CPUREG encoding.
+ */
+#define KVM_REG_ARM_VGIC_SYSREG_OP0_MASK   0x000000000000c000
+#define KVM_REG_ARM_VGIC_SYSREG_OP0_SHIFT  14
+#define KVM_REG_ARM_VGIC_SYSREG_OP1_MASK   0x0000000000003800
+#define KVM_REG_ARM_VGIC_SYSREG_OP1_SHIFT  11
+#define KVM_REG_ARM_VGIC_SYSREG_CRN_MASK   0x0000000000000780
+#define KVM_REG_ARM_VGIC_SYSREG_CRN_SHIFT  7
+#define KVM_REG_ARM_VGIC_SYSREG_CRM_MASK   0x0000000000000078
+#define KVM_REG_ARM_VGIC_SYSREG_CRM_SHIFT  3
+#define KVM_REG_ARM_VGIC_SYSREG_OP2_MASK   0x0000000000000007
+#define KVM_REG_ARM_VGIC_SYSREG_OP2_SHIFT  0
+
+#define KVM_DEV_ARM_VGIC_SYSREG_MASK (KVM_REG_ARM_VGIC_SYSREG_OP0_MASK | \
+				      KVM_REG_ARM_VGIC_SYSREG_OP1_MASK | \
+				      KVM_REG_ARM_VGIC_SYSREG_CRN_MASK | \
+				      KVM_REG_ARM_VGIC_SYSREG_CRM_MASK | \
+				      KVM_REG_ARM_VGIC_SYSREG_OP2_MASK)
+
 struct vgic_vmcr {
 	u32	ctlr;
 	u32	abpr;
@@ -89,7 +132,11 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq)
 int kvm_vgic_register_its_device(void);
 void vgic_enable_lpis(struct kvm_vcpu *vcpu);
 int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi);
-
+int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
+int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+			 int offset, u32 *val);
+int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+			 int offset, u32 *val);
 int kvm_register_vgic_device(unsigned long type);
 int vgic_lazy_init(struct kvm *kvm);
 int vgic_init(struct kvm *kvm);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 03/11] arm/arm64: vgic: Introduce find_reg_by_id()
  2016-11-23 13:01 ` vijay.kilari at gmail.com
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  -1 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari @ 2016-11-23 13:01 UTC (permalink / raw)
  To: marc.zyngier, christoffer.dall, peter.maydell
  Cc: kvmarm, linux-arm-kernel, Vijaya Kumar K

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

In order to implement vGICv3 CPU interface access, we will need to perform
table lookup of system registers. We would need both index_to_params() and
find_reg() exported for that purpose, but instead we export a single
function which combines them both.

Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 22 +++++++++++++++-------
 arch/arm64/kvm/sys_regs.h |  4 ++++
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f302fdb..1330d4c 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1789,6 +1789,17 @@ static bool index_to_params(u64 id, struct sys_reg_params *params)
 	}
 }
 
+const struct sys_reg_desc *find_reg_by_id(u64 id,
+					  struct sys_reg_params *params,
+					  const struct sys_reg_desc table[],
+					  unsigned int num)
+{
+	if (!index_to_params(id, params))
+		return NULL;
+
+	return find_reg(params, table, num);
+}
+
 /* Decode an index value, and find the sys_reg_desc entry. */
 static const struct sys_reg_desc *index_to_sys_reg_desc(struct kvm_vcpu *vcpu,
 						    u64 id)
@@ -1912,10 +1923,8 @@ static int get_invariant_sys_reg(u64 id, void __user *uaddr)
 	struct sys_reg_params params;
 	const struct sys_reg_desc *r;
 
-	if (!index_to_params(id, &params))
-		return -ENOENT;
-
-	r = find_reg(&params, invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs));
+	r = find_reg_by_id(id, &params, invariant_sys_regs,
+			   ARRAY_SIZE(invariant_sys_regs));
 	if (!r)
 		return -ENOENT;
 
@@ -1929,9 +1938,8 @@ static int set_invariant_sys_reg(u64 id, void __user *uaddr)
 	int err;
 	u64 val = 0; /* Make sure high bits are 0 for 32-bit regs */
 
-	if (!index_to_params(id, &params))
-		return -ENOENT;
-	r = find_reg(&params, invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs));
+	r = find_reg_by_id(id, &params, invariant_sys_regs,
+			   ARRAY_SIZE(invariant_sys_regs));
 	if (!r)
 		return -ENOENT;
 
diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
index dbbb01c..9c6ffd0 100644
--- a/arch/arm64/kvm/sys_regs.h
+++ b/arch/arm64/kvm/sys_regs.h
@@ -136,6 +136,10 @@ static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
 	return i1->Op2 - i2->Op2;
 }
 
+const struct sys_reg_desc *find_reg_by_id(u64 id,
+					  struct sys_reg_params *params,
+					  const struct sys_reg_desc table[],
+					  unsigned int num);
 
 #define Op0(_x) 	.Op0 = _x
 #define Op1(_x) 	.Op1 = _x
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 03/11] arm/arm64: vgic: Introduce find_reg_by_id()
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  0 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari at gmail.com @ 2016-11-23 13:01 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

In order to implement vGICv3 CPU interface access, we will need to perform
table lookup of system registers. We would need both index_to_params() and
find_reg() exported for that purpose, but instead we export a single
function which combines them both.

Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 22 +++++++++++++++-------
 arch/arm64/kvm/sys_regs.h |  4 ++++
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f302fdb..1330d4c 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1789,6 +1789,17 @@ static bool index_to_params(u64 id, struct sys_reg_params *params)
 	}
 }
 
+const struct sys_reg_desc *find_reg_by_id(u64 id,
+					  struct sys_reg_params *params,
+					  const struct sys_reg_desc table[],
+					  unsigned int num)
+{
+	if (!index_to_params(id, params))
+		return NULL;
+
+	return find_reg(params, table, num);
+}
+
 /* Decode an index value, and find the sys_reg_desc entry. */
 static const struct sys_reg_desc *index_to_sys_reg_desc(struct kvm_vcpu *vcpu,
 						    u64 id)
@@ -1912,10 +1923,8 @@ static int get_invariant_sys_reg(u64 id, void __user *uaddr)
 	struct sys_reg_params params;
 	const struct sys_reg_desc *r;
 
-	if (!index_to_params(id, &params))
-		return -ENOENT;
-
-	r = find_reg(&params, invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs));
+	r = find_reg_by_id(id, &params, invariant_sys_regs,
+			   ARRAY_SIZE(invariant_sys_regs));
 	if (!r)
 		return -ENOENT;
 
@@ -1929,9 +1938,8 @@ static int set_invariant_sys_reg(u64 id, void __user *uaddr)
 	int err;
 	u64 val = 0; /* Make sure high bits are 0 for 32-bit regs */
 
-	if (!index_to_params(id, &params))
-		return -ENOENT;
-	r = find_reg(&params, invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs));
+	r = find_reg_by_id(id, &params, invariant_sys_regs,
+			   ARRAY_SIZE(invariant_sys_regs));
 	if (!r)
 		return -ENOENT;
 
diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
index dbbb01c..9c6ffd0 100644
--- a/arch/arm64/kvm/sys_regs.h
+++ b/arch/arm64/kvm/sys_regs.h
@@ -136,6 +136,10 @@ static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
 	return i1->Op2 - i2->Op2;
 }
 
+const struct sys_reg_desc *find_reg_by_id(u64 id,
+					  struct sys_reg_params *params,
+					  const struct sys_reg_desc table[],
+					  unsigned int num);
 
 #define Op0(_x) 	.Op0 = _x
 #define Op1(_x) 	.Op1 = _x
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 04/11] irqchip/gic-v3: Add missing system register definitions
  2016-11-23 13:01 ` vijay.kilari at gmail.com
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  -1 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari @ 2016-11-23 13:01 UTC (permalink / raw)
  To: marc.zyngier, christoffer.dall, peter.maydell
  Cc: kvmarm, linux-arm-kernel, Vijaya Kumar K

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

Define register definitions for ICH_VMCR_EL2, ICC_CTLR_EL1 and
ICH_VTR_EL2, ICC_BPR0_EL1, ICC_BPR1_EL1 registers.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 include/linux/irqchip/arm-gic-v3.h | 43 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 41 insertions(+), 2 deletions(-)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 0deea34..b4f8287 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -352,8 +352,30 @@
 /*
  * CPU interface registers
  */
-#define ICC_CTLR_EL1_EOImode_drop_dir	(0U << 1)
-#define ICC_CTLR_EL1_EOImode_drop	(1U << 1)
+#define ICC_CTLR_EL1_EOImode_SHIFT	(1)
+#define ICC_CTLR_EL1_EOImode_drop_dir	(0U << ICC_CTLR_EL1_EOImode_SHIFT)
+#define ICC_CTLR_EL1_EOImode_drop	(1U << ICC_CTLR_EL1_EOImode_SHIFT)
+#define ICC_CTLR_EL1_EOImode_MASK	(1 << ICC_CTLR_EL1_EOImode_SHIFT)
+#define ICC_CTLR_EL1_CBPR_SHIFT		0
+#define ICC_CTLR_EL1_CBPR_MASK		(1 << ICC_CTLR_EL1_CBPR_SHIFT)
+#define ICC_CTLR_EL1_PRI_BITS_SHIFT	8
+#define ICC_CTLR_EL1_PRI_BITS_MASK	(0x7 << ICC_CTLR_EL1_PRI_BITS_SHIFT)
+#define ICC_CTLR_EL1_ID_BITS_SHIFT	11
+#define ICC_CTLR_EL1_ID_BITS_MASK	(0x7 << ICC_CTLR_EL1_ID_BITS_SHIFT)
+#define ICC_CTLR_EL1_SEIS_SHIFT		14
+#define ICC_CTLR_EL1_SEIS_MASK		(0x1 << ICC_CTLR_EL1_SEIS_SHIFT)
+#define ICC_CTLR_EL1_A3V_SHIFT		15
+#define ICC_CTLR_EL1_A3V_MASK		(0x1 << ICC_CTLR_EL1_A3V_SHIFT)
+#define ICC_PMR_EL1_SHIFT		0
+#define ICC_PMR_EL1_MASK		(0xff << ICC_PMR_EL1_SHIFT)
+#define ICC_BPR0_EL1_SHIFT		0
+#define ICC_BPR0_EL1_MASK		(0x7 << ICC_BPR0_EL1_SHIFT)
+#define ICC_BPR1_EL1_SHIFT		0
+#define ICC_BPR1_EL1_MASK		(0x7 << ICC_BPR1_EL1_SHIFT)
+#define ICC_IGRPEN0_EL1_SHIFT		0
+#define ICC_IGRPEN0_EL1_MASK		(1 << ICC_IGRPEN0_EL1_SHIFT)
+#define ICC_IGRPEN1_EL1_SHIFT		0
+#define ICC_IGRPEN1_EL1_MASK		(1 << ICC_IGRPEN1_EL1_SHIFT)
 #define ICC_SRE_EL1_SRE			(1U << 0)
 
 /*
@@ -384,12 +406,29 @@
 
 #define ICH_VMCR_CTLR_SHIFT		0
 #define ICH_VMCR_CTLR_MASK		(0x21f << ICH_VMCR_CTLR_SHIFT)
+#define ICH_VMCR_CBPR_SHIFT		4
+#define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
+#define ICH_VMCR_EOIM_SHIFT		9
+#define ICH_VMCR_EOIM_MASK		(1 << ICH_VMCR_EOIM_SHIFT)
 #define ICH_VMCR_BPR1_SHIFT		18
 #define ICH_VMCR_BPR1_MASK		(7 << ICH_VMCR_BPR1_SHIFT)
 #define ICH_VMCR_BPR0_SHIFT		21
 #define ICH_VMCR_BPR0_MASK		(7 << ICH_VMCR_BPR0_SHIFT)
 #define ICH_VMCR_PMR_SHIFT		24
 #define ICH_VMCR_PMR_MASK		(0xffUL << ICH_VMCR_PMR_SHIFT)
+#define ICH_VMCR_ENG0_SHIFT		0
+#define ICH_VMCR_ENG0_MASK		(1 << ICH_VMCR_ENG0_SHIFT)
+#define ICH_VMCR_ENG1_SHIFT		1
+#define ICH_VMCR_ENG1_MASK		(1 << ICH_VMCR_ENG1_SHIFT)
+
+#define ICH_VTR_PRI_BITS_SHIFT		29
+#define ICH_VTR_PRI_BITS_MASK		(7 << ICH_VTR_PRI_BITS_SHIFT)
+#define ICH_VTR_ID_BITS_SHIFT		23
+#define ICH_VTR_ID_BITS_MASK		(7 << ICH_VTR_ID_BITS_SHIFT)
+#define ICH_VTR_SEIS_SHIFT		22
+#define ICH_VTR_SEIS_MASK		(1 << ICH_VTR_SEIS_SHIFT)
+#define ICH_VTR_A3V_SHIFT		21
+#define ICH_VTR_A3V_MASK		(1 << ICH_VTR_A3V_SHIFT)
 
 #define ICC_IAR1_EL1_SPURIOUS		0x3ff
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 04/11] irqchip/gic-v3: Add missing system register definitions
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  0 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari at gmail.com @ 2016-11-23 13:01 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

Define register definitions for ICH_VMCR_EL2, ICC_CTLR_EL1 and
ICH_VTR_EL2, ICC_BPR0_EL1, ICC_BPR1_EL1 registers.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 include/linux/irqchip/arm-gic-v3.h | 43 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 41 insertions(+), 2 deletions(-)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 0deea34..b4f8287 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -352,8 +352,30 @@
 /*
  * CPU interface registers
  */
-#define ICC_CTLR_EL1_EOImode_drop_dir	(0U << 1)
-#define ICC_CTLR_EL1_EOImode_drop	(1U << 1)
+#define ICC_CTLR_EL1_EOImode_SHIFT	(1)
+#define ICC_CTLR_EL1_EOImode_drop_dir	(0U << ICC_CTLR_EL1_EOImode_SHIFT)
+#define ICC_CTLR_EL1_EOImode_drop	(1U << ICC_CTLR_EL1_EOImode_SHIFT)
+#define ICC_CTLR_EL1_EOImode_MASK	(1 << ICC_CTLR_EL1_EOImode_SHIFT)
+#define ICC_CTLR_EL1_CBPR_SHIFT		0
+#define ICC_CTLR_EL1_CBPR_MASK		(1 << ICC_CTLR_EL1_CBPR_SHIFT)
+#define ICC_CTLR_EL1_PRI_BITS_SHIFT	8
+#define ICC_CTLR_EL1_PRI_BITS_MASK	(0x7 << ICC_CTLR_EL1_PRI_BITS_SHIFT)
+#define ICC_CTLR_EL1_ID_BITS_SHIFT	11
+#define ICC_CTLR_EL1_ID_BITS_MASK	(0x7 << ICC_CTLR_EL1_ID_BITS_SHIFT)
+#define ICC_CTLR_EL1_SEIS_SHIFT		14
+#define ICC_CTLR_EL1_SEIS_MASK		(0x1 << ICC_CTLR_EL1_SEIS_SHIFT)
+#define ICC_CTLR_EL1_A3V_SHIFT		15
+#define ICC_CTLR_EL1_A3V_MASK		(0x1 << ICC_CTLR_EL1_A3V_SHIFT)
+#define ICC_PMR_EL1_SHIFT		0
+#define ICC_PMR_EL1_MASK		(0xff << ICC_PMR_EL1_SHIFT)
+#define ICC_BPR0_EL1_SHIFT		0
+#define ICC_BPR0_EL1_MASK		(0x7 << ICC_BPR0_EL1_SHIFT)
+#define ICC_BPR1_EL1_SHIFT		0
+#define ICC_BPR1_EL1_MASK		(0x7 << ICC_BPR1_EL1_SHIFT)
+#define ICC_IGRPEN0_EL1_SHIFT		0
+#define ICC_IGRPEN0_EL1_MASK		(1 << ICC_IGRPEN0_EL1_SHIFT)
+#define ICC_IGRPEN1_EL1_SHIFT		0
+#define ICC_IGRPEN1_EL1_MASK		(1 << ICC_IGRPEN1_EL1_SHIFT)
 #define ICC_SRE_EL1_SRE			(1U << 0)
 
 /*
@@ -384,12 +406,29 @@
 
 #define ICH_VMCR_CTLR_SHIFT		0
 #define ICH_VMCR_CTLR_MASK		(0x21f << ICH_VMCR_CTLR_SHIFT)
+#define ICH_VMCR_CBPR_SHIFT		4
+#define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
+#define ICH_VMCR_EOIM_SHIFT		9
+#define ICH_VMCR_EOIM_MASK		(1 << ICH_VMCR_EOIM_SHIFT)
 #define ICH_VMCR_BPR1_SHIFT		18
 #define ICH_VMCR_BPR1_MASK		(7 << ICH_VMCR_BPR1_SHIFT)
 #define ICH_VMCR_BPR0_SHIFT		21
 #define ICH_VMCR_BPR0_MASK		(7 << ICH_VMCR_BPR0_SHIFT)
 #define ICH_VMCR_PMR_SHIFT		24
 #define ICH_VMCR_PMR_MASK		(0xffUL << ICH_VMCR_PMR_SHIFT)
+#define ICH_VMCR_ENG0_SHIFT		0
+#define ICH_VMCR_ENG0_MASK		(1 << ICH_VMCR_ENG0_SHIFT)
+#define ICH_VMCR_ENG1_SHIFT		1
+#define ICH_VMCR_ENG1_MASK		(1 << ICH_VMCR_ENG1_SHIFT)
+
+#define ICH_VTR_PRI_BITS_SHIFT		29
+#define ICH_VTR_PRI_BITS_MASK		(7 << ICH_VTR_PRI_BITS_SHIFT)
+#define ICH_VTR_ID_BITS_SHIFT		23
+#define ICH_VTR_ID_BITS_MASK		(7 << ICH_VTR_ID_BITS_SHIFT)
+#define ICH_VTR_SEIS_SHIFT		22
+#define ICH_VTR_SEIS_MASK		(1 << ICH_VTR_SEIS_SHIFT)
+#define ICH_VTR_A3V_SHIFT		21
+#define ICH_VTR_A3V_MASK		(1 << ICH_VTR_A3V_SHIFT)
 
 #define ICC_IAR1_EL1_SPURIOUS		0x3ff
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 05/11] arm/arm64: vgic: Introduce VENG0 and VENG1 fields to vmcr struct
  2016-11-23 13:01 ` vijay.kilari at gmail.com
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  -1 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari @ 2016-11-23 13:01 UTC (permalink / raw)
  To: marc.zyngier, christoffer.dall, peter.maydell
  Cc: kvmarm, linux-arm-kernel, Vijaya Kumar K

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

ICC_VMCR_EL2 supports virtual access to ICC_IGRPEN1_EL1.Enable
and ICC_IGRPEN0_EL1.Enable fields. Add grpen0 and grpen1 member
variables to struct vmcr to support read and write of these fields.

Also refactor vgic_set_vmcr and vgic_get_vmcr() code.
Drop ICH_VMCR_CTLR_SHIFT and ICH_VMCR_CTLR_MASK macros and instead
use ICH_VMCR_EOI* and ICH_VMCR_CBPR* macros
.
Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 include/linux/irqchip/arm-gic-v3.h |  2 --
 virt/kvm/arm/vgic/vgic-mmio-v2.c   | 16 ----------------
 virt/kvm/arm/vgic/vgic-mmio.c      | 16 ++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c        | 22 ++++++++++++++++++++--
 virt/kvm/arm/vgic/vgic.h           |  5 +++++
 5 files changed, 41 insertions(+), 20 deletions(-)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index b4f8287..406fc3e 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -404,8 +404,6 @@
 #define ICH_HCR_EN			(1 << 0)
 #define ICH_HCR_UIE			(1 << 1)
 
-#define ICH_VMCR_CTLR_SHIFT		0
-#define ICH_VMCR_CTLR_MASK		(0x21f << ICH_VMCR_CTLR_SHIFT)
 #define ICH_VMCR_CBPR_SHIFT		4
 #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
 #define ICH_VMCR_EOIM_SHIFT		9
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 2cb04b7..ad353b5 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -212,22 +212,6 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
 	}
 }
 
-static void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
-{
-	if (kvm_vgic_global_state.type == VGIC_V2)
-		vgic_v2_set_vmcr(vcpu, vmcr);
-	else
-		vgic_v3_set_vmcr(vcpu, vmcr);
-}
-
-static void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
-{
-	if (kvm_vgic_global_state.type == VGIC_V2)
-		vgic_v2_get_vmcr(vcpu, vmcr);
-	else
-		vgic_v3_get_vmcr(vcpu, vmcr);
-}
-
 #define GICC_ARCH_VERSION_V2	0x2
 
 /* These are for userland accesses only, there is no guest-facing emulation. */
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 0d1bc98..f81e0e5 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -416,6 +416,22 @@ int vgic_validate_mmio_region_addr(struct kvm_device *dev,
 	return -ENXIO;
 }
 
+void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_set_vmcr(vcpu, vmcr);
+	else
+		vgic_v3_set_vmcr(vcpu, vmcr);
+}
+
+void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_get_vmcr(vcpu, vmcr);
+	else
+		vgic_v3_get_vmcr(vcpu, vmcr);
+}
+
 /*
  * kvm_mmio_read_buf() returns a value in a format where it can be converted
  * to a byte array and be directly observed as the guest wanted it to appear
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 9f0dae3..a3ff04b 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -175,10 +175,19 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 {
 	u32 vmcr;
 
-	vmcr  = (vmcrp->ctlr << ICH_VMCR_CTLR_SHIFT) & ICH_VMCR_CTLR_MASK;
+	/*
+	 * Ignore the FIQen bit, because GIC emulation always implies
+	 * SRE=1 which means the vFIQEn bit is also RES1.
+	 */
+	vmcr = (vmcrp->ctlr & ICC_CTLR_EL1_EOImode_MASK) >>
+		ICC_CTLR_EL1_EOImode_SHIFT;
+	vmcr = (vmcr << ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;
+	vmcr |= (vmcrp->ctlr << ICH_VMCR_CBPR_SHIFT) & ICH_VMCR_CBPR_MASK;
 	vmcr |= (vmcrp->abpr << ICH_VMCR_BPR1_SHIFT) & ICH_VMCR_BPR1_MASK;
 	vmcr |= (vmcrp->bpr << ICH_VMCR_BPR0_SHIFT) & ICH_VMCR_BPR0_MASK;
 	vmcr |= (vmcrp->pmr << ICH_VMCR_PMR_SHIFT) & ICH_VMCR_PMR_MASK;
+	vmcr |= (vmcrp->grpen0 << ICH_VMCR_ENG0_SHIFT) & ICH_VMCR_ENG0_MASK;
+	vmcr |= (vmcrp->grpen1 << ICH_VMCR_ENG1_SHIFT) & ICH_VMCR_ENG1_MASK;
 
 	vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
 }
@@ -187,10 +196,19 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 {
 	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr;
 
-	vmcrp->ctlr = (vmcr & ICH_VMCR_CTLR_MASK) >> ICH_VMCR_CTLR_SHIFT;
+	/*
+	 * Ignore the FIQen bit, because GIC emulation always implies
+	 * SRE=1 which means the vFIQEn bit is also RES1.
+	 */
+	vmcrp->ctlr = (vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT;
+	vmcrp->ctlr = (vmcrp->ctlr << ICC_CTLR_EL1_EOImode_SHIFT) &
+		       ICC_CTLR_EL1_EOImode_MASK;
+	vmcrp->ctlr |= (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT;
 	vmcrp->abpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
 	vmcrp->bpr  = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
 	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
+	vmcrp->grpen0 = (vmcr & ICH_VMCR_ENG0_MASK) >> ICH_VMCR_ENG0_SHIFT;
+	vmcrp->grpen1 = (vmcr & ICH_VMCR_ENG1_MASK) >> ICH_VMCR_ENG1_SHIFT;
 }
 
 #define INITIAL_PENDBASER_VALUE						  \
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 91f58b2..9232791 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -78,6 +78,9 @@ struct vgic_vmcr {
 	u32	abpr;
 	u32	bpr;
 	u32	pmr;
+	/* Below member variable are valid only for GICv3 */
+	u32	grpen0;
+	u32	grpen1;
 };
 
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
@@ -138,6 +141,8 @@ int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			 int offset, u32 *val);
 int kvm_register_vgic_device(unsigned long type);
+void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 int vgic_lazy_init(struct kvm *kvm);
 int vgic_init(struct kvm *kvm);
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 05/11] arm/arm64: vgic: Introduce VENG0 and VENG1 fields to vmcr struct
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  0 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari at gmail.com @ 2016-11-23 13:01 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

ICC_VMCR_EL2 supports virtual access to ICC_IGRPEN1_EL1.Enable
and ICC_IGRPEN0_EL1.Enable fields. Add grpen0 and grpen1 member
variables to struct vmcr to support read and write of these fields.

Also refactor vgic_set_vmcr and vgic_get_vmcr() code.
Drop ICH_VMCR_CTLR_SHIFT and ICH_VMCR_CTLR_MASK macros and instead
use ICH_VMCR_EOI* and ICH_VMCR_CBPR* macros
.
Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 include/linux/irqchip/arm-gic-v3.h |  2 --
 virt/kvm/arm/vgic/vgic-mmio-v2.c   | 16 ----------------
 virt/kvm/arm/vgic/vgic-mmio.c      | 16 ++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c        | 22 ++++++++++++++++++++--
 virt/kvm/arm/vgic/vgic.h           |  5 +++++
 5 files changed, 41 insertions(+), 20 deletions(-)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index b4f8287..406fc3e 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -404,8 +404,6 @@
 #define ICH_HCR_EN			(1 << 0)
 #define ICH_HCR_UIE			(1 << 1)
 
-#define ICH_VMCR_CTLR_SHIFT		0
-#define ICH_VMCR_CTLR_MASK		(0x21f << ICH_VMCR_CTLR_SHIFT)
 #define ICH_VMCR_CBPR_SHIFT		4
 #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
 #define ICH_VMCR_EOIM_SHIFT		9
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 2cb04b7..ad353b5 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -212,22 +212,6 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
 	}
 }
 
-static void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
-{
-	if (kvm_vgic_global_state.type == VGIC_V2)
-		vgic_v2_set_vmcr(vcpu, vmcr);
-	else
-		vgic_v3_set_vmcr(vcpu, vmcr);
-}
-
-static void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
-{
-	if (kvm_vgic_global_state.type == VGIC_V2)
-		vgic_v2_get_vmcr(vcpu, vmcr);
-	else
-		vgic_v3_get_vmcr(vcpu, vmcr);
-}
-
 #define GICC_ARCH_VERSION_V2	0x2
 
 /* These are for userland accesses only, there is no guest-facing emulation. */
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 0d1bc98..f81e0e5 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -416,6 +416,22 @@ int vgic_validate_mmio_region_addr(struct kvm_device *dev,
 	return -ENXIO;
 }
 
+void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_set_vmcr(vcpu, vmcr);
+	else
+		vgic_v3_set_vmcr(vcpu, vmcr);
+}
+
+void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_get_vmcr(vcpu, vmcr);
+	else
+		vgic_v3_get_vmcr(vcpu, vmcr);
+}
+
 /*
  * kvm_mmio_read_buf() returns a value in a format where it can be converted
  * to a byte array and be directly observed as the guest wanted it to appear
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 9f0dae3..a3ff04b 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -175,10 +175,19 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 {
 	u32 vmcr;
 
-	vmcr  = (vmcrp->ctlr << ICH_VMCR_CTLR_SHIFT) & ICH_VMCR_CTLR_MASK;
+	/*
+	 * Ignore the FIQen bit, because GIC emulation always implies
+	 * SRE=1 which means the vFIQEn bit is also RES1.
+	 */
+	vmcr = (vmcrp->ctlr & ICC_CTLR_EL1_EOImode_MASK) >>
+		ICC_CTLR_EL1_EOImode_SHIFT;
+	vmcr = (vmcr << ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;
+	vmcr |= (vmcrp->ctlr << ICH_VMCR_CBPR_SHIFT) & ICH_VMCR_CBPR_MASK;
 	vmcr |= (vmcrp->abpr << ICH_VMCR_BPR1_SHIFT) & ICH_VMCR_BPR1_MASK;
 	vmcr |= (vmcrp->bpr << ICH_VMCR_BPR0_SHIFT) & ICH_VMCR_BPR0_MASK;
 	vmcr |= (vmcrp->pmr << ICH_VMCR_PMR_SHIFT) & ICH_VMCR_PMR_MASK;
+	vmcr |= (vmcrp->grpen0 << ICH_VMCR_ENG0_SHIFT) & ICH_VMCR_ENG0_MASK;
+	vmcr |= (vmcrp->grpen1 << ICH_VMCR_ENG1_SHIFT) & ICH_VMCR_ENG1_MASK;
 
 	vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
 }
@@ -187,10 +196,19 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 {
 	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr;
 
-	vmcrp->ctlr = (vmcr & ICH_VMCR_CTLR_MASK) >> ICH_VMCR_CTLR_SHIFT;
+	/*
+	 * Ignore the FIQen bit, because GIC emulation always implies
+	 * SRE=1 which means the vFIQEn bit is also RES1.
+	 */
+	vmcrp->ctlr = (vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT;
+	vmcrp->ctlr = (vmcrp->ctlr << ICC_CTLR_EL1_EOImode_SHIFT) &
+		       ICC_CTLR_EL1_EOImode_MASK;
+	vmcrp->ctlr |= (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT;
 	vmcrp->abpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
 	vmcrp->bpr  = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
 	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
+	vmcrp->grpen0 = (vmcr & ICH_VMCR_ENG0_MASK) >> ICH_VMCR_ENG0_SHIFT;
+	vmcrp->grpen1 = (vmcr & ICH_VMCR_ENG1_MASK) >> ICH_VMCR_ENG1_SHIFT;
 }
 
 #define INITIAL_PENDBASER_VALUE						  \
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 91f58b2..9232791 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -78,6 +78,9 @@ struct vgic_vmcr {
 	u32	abpr;
 	u32	bpr;
 	u32	pmr;
+	/* Below member variable are valid only for GICv3 */
+	u32	grpen0;
+	u32	grpen1;
 };
 
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
@@ -138,6 +141,8 @@ int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			 int offset, u32 *val);
 int kvm_register_vgic_device(unsigned long type);
+void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 int vgic_lazy_init(struct kvm *kvm);
 int vgic_init(struct kvm *kvm);
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 06/11] arm/arm64: vgic: Implement VGICv3 CPU interface access
  2016-11-23 13:01 ` vijay.kilari at gmail.com
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  -1 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari @ 2016-11-23 13:01 UTC (permalink / raw)
  To: marc.zyngier, christoffer.dall, peter.maydell
  Cc: kvmarm, linux-arm-kernel, Vijaya Kumar K

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

VGICv3 CPU interface registers are accessed using
KVM_DEV_ARM_VGIC_CPU_SYSREGS ioctl. These registers are accessed
as 64-bit. The cpu MPIDR value is passed along with register id.
is used to identify the cpu for registers access.

The VM that supports SEIs expect it on destination machine to handle
guest aborts and hence checked for ICC_CTLR_EL1.SEIS compatibility.
Similarly, VM that supports Affinity Level 3 that is required for AArch64
mode, is required to be supported on destination machine. Hence checked
for ICC_CTLR_EL1.A3V compatibility.

The CPU system register handling is spitted into two files
vgic-sys-reg-common.c and vgic-sys-reg-v3.c.
The vgic-sys-reg-common.c handles read and write of VGIC CPU registers
for both AArch64 and AArch32 mode. The vgic-sys-reg-v3.c handles AArch64
mode and is compiled only for AArch64 mode.

Updated arch/arm/include/uapi/asm/kvm.h with new definitions
required to compile for AArch32.

The version of VGIC v3 specification is define here
Documentation/virtual/kvm/devices/arm-vgic-v3.txt

Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 arch/arm/include/uapi/asm/kvm.h         |   2 +
 arch/arm64/include/uapi/asm/kvm.h       |   3 +
 arch/arm64/kvm/Makefile                 |   2 +
 include/kvm/arm_vgic.h                  |   9 ++
 virt/kvm/arm/vgic/vgic-kvm-device.c     |  28 ++++
 virt/kvm/arm/vgic/vgic-mmio-v3.c        |  18 +++
 virt/kvm/arm/vgic/vgic-sys-reg-common.c | 258 ++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-sys-reg-v3.c     | 142 ++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c             |   8 +
 virt/kvm/arm/vgic/vgic.h                |  22 +++
 10 files changed, 492 insertions(+)

diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index 0ae6035..98658d9d 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -186,9 +186,11 @@ struct kvm_arch_memory_slot {
 			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
 #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
 #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
+#define   KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK (0xffff)
 #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
 #define KVM_DEV_ARM_VGIC_GRP_CTRL       4
 #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
+#define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
 
 /* KVM_IRQ_LINE irq field index values */
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 56dc08d..91c7137 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -206,9 +206,12 @@ struct kvm_arch_memory_slot {
 			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
 #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
 #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
+#define   KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK (0xffff)
 #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
 #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
 #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
+#define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
+
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
 
 /* Device Control API on vcpu fd */
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index d50a82a..5c8580e 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -32,5 +32,7 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-kvm-device.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-its.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/irqchip.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-sys-reg-common.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-sys-reg-v3.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_vgic.h b/include/kvm/arm_vgic.h
index 002f092..730a18a 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -71,6 +71,9 @@ struct vgic_global {
 
 	/* GIC system register CPU interface */
 	struct static_key_false gicv3_cpuif;
+
+	/* Cache ICH_VTR_EL2 reg value */
+	u32			ich_vtr_el2;
 };
 
 extern struct vgic_global kvm_vgic_global_state;
@@ -269,6 +272,12 @@ struct vgic_cpu {
 	u64 pendbaser;
 
 	bool lpis_enabled;
+
+	/* Cache guest priority bits */
+	u32 num_pri_bits;
+
+	/* Cache guest interrupt ID bits */
+	u32 num_id_bits;
 };
 
 extern struct static_key_false vgic_v2_cpuif_trap;
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index bc7de95..b6266fe 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -16,6 +16,7 @@
 #include <linux/kvm_host.h>
 #include <kvm/arm_vgic.h>
 #include <linux/uaccess.h>
+#include <asm/kvm_emulate.h>
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
@@ -501,6 +502,14 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
 		if (!is_write)
 			*reg = tmp32;
 		break;
+	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
+		u64 regid;
+
+		regid = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK);
+		ret = vgic_v3_cpu_sysregs_uaccess(vcpu, is_write,
+						  regid, reg);
+		break;
+	}
 	default:
 		ret = -EINVAL;
 		break;
@@ -534,6 +543,15 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
 		reg = tmp32;
 		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
 	}
+	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
+		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+		u64 reg;
+
+		if (get_user(reg, uaddr))
+			return -EFAULT;
+
+		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
+	}
 	}
 	return -ENXIO;
 }
@@ -560,6 +578,15 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
 		tmp32 = reg;
 		return put_user(tmp32, uaddr);
 	}
+	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
+		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+		u64 reg;
+
+		ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
+		if (ret)
+			return ret;
+		return put_user(reg, uaddr);
+	}
 	}
 
 	return -ENXIO;
@@ -578,6 +605,7 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
 		break;
 	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
 	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
+	case KVM_DEV_ARM_VGIC_CPU_SYSREGS:
 		return vgic_v3_has_attr_regs(dev, attr);
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 2a7cd62..2f7b4ed 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -641,6 +641,24 @@ int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
 		nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
 		break;
 	}
+	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
+		u64 reg, id;
+		unsigned long vgic_mpidr, mpidr_reg;
+		struct kvm_vcpu *vcpu;
+
+		vgic_mpidr = (attr->attr & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) >>
+			      KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT;
+
+		/* Convert plain mpidr value to MPIDR reg format */
+		mpidr_reg = VGIC_TO_MPIDR(vgic_mpidr);
+
+		vcpu = kvm_mpidr_to_vcpu(dev->kvm, mpidr_reg);
+		if (!vcpu)
+			return -EINVAL;
+
+		id = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK);
+		return vgic_v3_has_cpu_sysregs_attr(vcpu, 0, id, &reg);
+	}
 	default:
 		return -ENXIO;
 	}
diff --git a/virt/kvm/arm/vgic/vgic-sys-reg-common.c b/virt/kvm/arm/vgic/vgic-sys-reg-common.c
new file mode 100644
index 0000000..a1fc370c
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-sys-reg-common.c
@@ -0,0 +1,258 @@
+/*
+ * VGIC system registers handling functions
+ *
+ * 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.
+ */
+
+#include <linux/irqchip/arm-gic-v3.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <asm/kvm_emulate.h>
+#include "vgic.h"
+
+bool access_gic_ctlr_reg(struct kvm_vcpu *vcpu, bool is_write,
+			 unsigned long *reg)
+{
+	struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
+	struct vgic_vmcr vmcr;
+	u64 val;
+	u32 valid_bits, seis, a3v;
+
+	vgic_get_vmcr(vcpu, &vmcr);
+	if (is_write) {
+		val = *reg;
+
+		/*
+		 * Disallow restoring VM state if not supported by this
+		 * hardware.
+		 */
+		valid_bits = ((val & ICC_CTLR_EL1_PRI_BITS_MASK) >>
+				ICC_CTLR_EL1_PRI_BITS_SHIFT) + 1;
+		if (valid_bits > vgic_v3_cpu->num_pri_bits)
+			return false;
+
+		vgic_v3_cpu->num_pri_bits = valid_bits;
+
+		valid_bits = (val & ICC_CTLR_EL1_ID_BITS_MASK) >>
+			       ICC_CTLR_EL1_ID_BITS_SHIFT;
+		if (valid_bits > vgic_v3_cpu->num_id_bits)
+			return false;
+
+		vgic_v3_cpu->num_id_bits = valid_bits;
+
+		valid_bits = ((kvm_vgic_global_state.ich_vtr_el2 &
+			ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT);
+		seis = (val & ICC_CTLR_EL1_SEIS_MASK) >>
+			ICC_CTLR_EL1_SEIS_SHIFT;
+		if (valid_bits != seis)
+			return false;
+
+		valid_bits = ((kvm_vgic_global_state.ich_vtr_el2 &
+			ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT);
+		a3v = (val & ICC_CTLR_EL1_A3V_MASK) >>
+			ICC_CTLR_EL1_A3V_SHIFT;
+		if (valid_bits != a3v)
+			return false;
+
+		vmcr.ctlr = (val & ICC_CTLR_EL1_CBPR_MASK);
+		vmcr.ctlr |= (val & ICC_CTLR_EL1_EOImode_MASK);
+		vgic_set_vmcr(vcpu, &vmcr);
+	} else {
+		val = 0;
+		val |= (vgic_v3_cpu->num_pri_bits - 1) <<
+			ICC_CTLR_EL1_PRI_BITS_SHIFT;
+		val |= vgic_v3_cpu->num_id_bits <<
+			ICC_CTLR_EL1_ID_BITS_SHIFT;
+		val |= ((kvm_vgic_global_state.ich_vtr_el2 &
+			ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT) <<
+			ICC_CTLR_EL1_SEIS_SHIFT;
+		val |= ((kvm_vgic_global_state.ich_vtr_el2 &
+			ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT) <<
+			ICC_CTLR_EL1_A3V_SHIFT;
+		val |= (vmcr.ctlr & ICC_CTLR_EL1_CBPR_MASK);
+		val |= (vmcr.ctlr & ICC_CTLR_EL1_EOImode_MASK);
+
+		*reg = val;
+	}
+
+	return true;
+}
+
+bool access_gic_pmr_reg(struct kvm_vcpu *vcpu, bool is_write,
+			unsigned long *reg)
+{
+	struct vgic_vmcr vmcr;
+
+	vgic_get_vmcr(vcpu, &vmcr);
+	if (is_write) {
+		vmcr.pmr = (*reg & ICC_PMR_EL1_MASK) >> ICC_PMR_EL1_SHIFT;
+		vgic_set_vmcr(vcpu, &vmcr);
+	} else {
+		*reg = (vmcr.pmr << ICC_PMR_EL1_SHIFT) & ICC_PMR_EL1_MASK;
+	}
+
+	return true;
+}
+
+bool access_gic_bpr0_reg(struct kvm_vcpu *vcpu, bool is_write,
+			 unsigned long *reg)
+{
+	struct vgic_vmcr vmcr;
+
+	vgic_get_vmcr(vcpu, &vmcr);
+	if (is_write) {
+		vmcr.bpr = (*reg & ICC_BPR0_EL1_MASK) >>
+			    ICC_BPR0_EL1_SHIFT;
+		vgic_set_vmcr(vcpu, &vmcr);
+	} else {
+		*reg = (vmcr.bpr << ICC_BPR0_EL1_SHIFT) & ICC_BPR0_EL1_MASK;
+	}
+
+	return true;
+}
+
+bool access_gic_bpr1_reg(struct kvm_vcpu *vcpu, bool is_write,
+			 unsigned long *reg)
+{
+	struct vgic_vmcr vmcr;
+
+	if (!is_write)
+		*reg = 0;
+
+	vgic_get_vmcr(vcpu, &vmcr);
+	if (!((vmcr.ctlr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT)) {
+		if (is_write) {
+			vmcr.abpr = (*reg & ICC_BPR1_EL1_MASK) >>
+				     ICC_BPR1_EL1_SHIFT;
+			vgic_set_vmcr(vcpu, &vmcr);
+		} else {
+			*reg = (vmcr.abpr << ICC_BPR1_EL1_SHIFT) &
+				ICC_BPR1_EL1_MASK;
+		}
+	} else {
+		if (!is_write)
+			*reg = min((vmcr.bpr + 1), 7U);
+	}
+
+	return true;
+}
+
+bool access_gic_grpen0_reg(struct kvm_vcpu *vcpu, bool is_write,
+			   unsigned long *reg)
+{
+	struct vgic_vmcr vmcr;
+
+	vgic_get_vmcr(vcpu, &vmcr);
+	if (is_write) {
+		vmcr.grpen0 = (*reg & ICC_IGRPEN0_EL1_MASK) >>
+			       ICC_IGRPEN0_EL1_SHIFT;
+		vgic_set_vmcr(vcpu, &vmcr);
+	} else {
+		*reg = (vmcr.grpen0 << ICC_IGRPEN0_EL1_SHIFT) &
+			ICC_IGRPEN0_EL1_MASK;
+	}
+
+	return true;
+}
+
+bool access_gic_grpen1_reg(struct kvm_vcpu *vcpu, bool is_write,
+			   unsigned long *reg)
+{
+	struct vgic_vmcr vmcr;
+
+	vgic_get_vmcr(vcpu, &vmcr);
+	if (is_write) {
+		vmcr.grpen1 = (*reg & ICC_IGRPEN1_EL1_MASK) >>
+			       ICC_IGRPEN1_EL1_SHIFT;
+		vgic_set_vmcr(vcpu, &vmcr);
+	} else {
+		*reg = (vmcr.grpen1 << ICC_IGRPEN1_EL1_SHIFT) &
+			ICC_IGRPEN1_EL1_MASK;
+	}
+
+	return true;
+}
+
+static void vgic_v3_access_apr_reg(struct kvm_vcpu *vcpu, bool is_write,
+				   u8 apr, u8 idx, unsigned long *reg)
+{
+	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
+	uint32_t *ap_reg;
+
+	if (apr)
+		ap_reg = &vgicv3->vgic_ap1r[idx];
+	else
+		ap_reg = &vgicv3->vgic_ap0r[idx];
+
+	if (is_write)
+		*ap_reg = *reg;
+	else
+		*reg = *ap_reg;
+}
+
+static bool access_gic_aprn(struct kvm_vcpu *vcpu, bool is_write, u8 apr,
+			    u8 idx, unsigned long *reg)
+{
+	struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
+
+	/* num_pri_bits are initialized with HW supported values.
+	 * We can rely safely on num_pri_bits even if VM has not
+	 * restored ICC_CTLR_EL1 before restoring APnR registers.
+	 */
+	switch (vgic_v3_cpu->num_pri_bits) {
+	case 7:
+		vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
+		break;
+	case 6:
+		if (idx > 1)
+			goto err;
+		vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
+		break;
+	default:
+		if (idx > 0)
+			goto err;
+		vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
+	}
+
+	return true;
+err:
+	if (!is_write)
+		*reg = 0;
+
+	return false;
+}
+
+bool access_gic_ap0r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
+			 unsigned long *reg)
+{
+	return access_gic_aprn(vcpu, is_write, 0, idx, reg);
+}
+
+bool access_gic_ap1r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
+			 unsigned long *reg)
+{
+	return access_gic_aprn(vcpu, is_write, 1, idx, reg);
+}
+
+bool access_gic_sre_reg(struct kvm_vcpu *vcpu, bool is_write,
+			unsigned long *reg)
+{
+	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	/* Validate SRE bit */
+	if (is_write) {
+		if (!(*reg & ICC_SRE_EL1_SRE))
+			return false;
+	} else {
+		*reg = vgicv3->vgic_sre;
+	}
+
+	return true;
+}
diff --git a/virt/kvm/arm/vgic/vgic-sys-reg-v3.c b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
new file mode 100644
index 0000000..82c2f02
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
@@ -0,0 +1,142 @@
+/*
+ * VGIC system registers handling functions
+ *
+ * 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.
+ */
+
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <asm/kvm_emulate.h>
+#include "vgic.h"
+#include "sys_regs.h"
+
+#define ACCESS_SYS_REG(REG)						\
+static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,		\
+				    struct sys_reg_params *p,		\
+				    const struct sys_reg_desc *r)	\
+{									\
+	unsigned long tmp;						\
+	bool ret;							\
+									\
+	if (p->is_write)						\
+		tmp = p->regval;					\
+	ret = access_gic_##REG##_reg(vcpu, p->is_write, &tmp);		\
+	if (!p->is_write)						\
+		p->regval = tmp;					\
+									\
+	return ret;							\
+}
+
+ACCESS_SYS_REG(ctlr)
+ACCESS_SYS_REG(pmr)
+ACCESS_SYS_REG(bpr0)
+ACCESS_SYS_REG(bpr1)
+ACCESS_SYS_REG(sre)
+ACCESS_SYS_REG(grpen0)
+ACCESS_SYS_REG(grpen1)
+
+#define ACCESS_APNR_SYS_REG(REG)					\
+static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,		\
+				    struct sys_reg_params *p,		\
+				    const struct sys_reg_desc *r)	\
+{									\
+	unsigned long tmp;						\
+	u8 idx = p->Op2 & 3;						\
+	bool ret;							\
+									\
+	if (p->is_write)						\
+		tmp = p->regval;					\
+	ret = access_gic_##REG##_reg(vcpu, p->is_write, idx, &tmp);	\
+	if (!p->is_write)						\
+		p->regval = tmp;					\
+									\
+	return ret;							\
+}
+
+ACCESS_APNR_SYS_REG(ap0r)
+ACCESS_APNR_SYS_REG(ap1r)
+
+static const struct sys_reg_desc gic_v3_icc_reg_descs[] = {
+	/* ICC_PMR_EL1 */
+	{ Op0(3), Op1(0), CRn(4), CRm(6), Op2(0), access_gic_pmr_sys_reg },
+	/* ICC_BPR0_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(3), access_gic_bpr0_sys_reg },
+	/* ICC_AP0R0_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(4), access_gic_ap0r_sys_reg },
+	/* ICC_AP0R1_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(5), access_gic_ap0r_sys_reg },
+	/* ICC_AP0R2_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(6), access_gic_ap0r_sys_reg },
+	/* ICC_AP0R3_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(7), access_gic_ap0r_sys_reg },
+	/* ICC_AP1R0_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(0), access_gic_ap1r_sys_reg },
+	/* ICC_AP1R1_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(1), access_gic_ap1r_sys_reg },
+	/* ICC_AP1R2_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(2), access_gic_ap1r_sys_reg },
+	/* ICC_AP1R3_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(3), access_gic_ap1r_sys_reg },
+	/* ICC_BPR1_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(3), access_gic_bpr1_sys_reg },
+	/* ICC_CTLR_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(4), access_gic_ctlr_sys_reg },
+	/* ICC_SRE_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(5), access_gic_sre_sys_reg },
+	/* ICC_IGRPEN0_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(6), access_gic_grpen0_sys_reg },
+	/* ICC_GRPEN1_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(7), access_gic_grpen1_sys_reg },
+};
+
+int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
+				u64 *reg)
+{
+	struct sys_reg_params params;
+	u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64;
+
+	params.regval = *reg;
+	params.is_write = is_write;
+	params.is_aarch32 = false;
+	params.is_32bit = false;
+
+	if (find_reg_by_id(sysreg, &params, gic_v3_icc_reg_descs,
+			      ARRAY_SIZE(gic_v3_icc_reg_descs)))
+		return 0;
+
+	return -ENXIO;
+}
+
+int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
+				u64 *reg)
+{
+	struct sys_reg_params params;
+	const struct sys_reg_desc *r;
+	u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64;
+
+	if (is_write)
+		params.regval = *reg;
+	params.is_write = is_write;
+	params.is_aarch32 = false;
+	params.is_32bit = false;
+
+	r = find_reg_by_id(sysreg, &params, gic_v3_icc_reg_descs,
+			   ARRAY_SIZE(gic_v3_icc_reg_descs));
+	if (!r)
+		return -ENXIO;
+
+	if (!r->access(vcpu, &params, r))
+		return -EINVAL;
+
+	if (!is_write)
+		*reg = params.regval;
+
+	return 0;
+}
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index a3ff04b..6e7400e 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -240,6 +240,13 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 		vgic_v3->vgic_sre = 0;
 	}
 
+	vcpu->arch.vgic_cpu.num_id_bits = (kvm_vgic_global_state.ich_vtr_el2 &
+					   ICH_VTR_ID_BITS_MASK) >>
+					   ICH_VTR_ID_BITS_SHIFT;
+	vcpu->arch.vgic_cpu.num_pri_bits = ((kvm_vgic_global_state.ich_vtr_el2 &
+					    ICH_VTR_PRI_BITS_MASK) >>
+					    ICH_VTR_PRI_BITS_SHIFT) + 1;
+
 	/* Get the show on the road... */
 	vgic_v3->vgic_hcr = ICH_HCR_EN;
 }
@@ -340,6 +347,7 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
 	 */
 	kvm_vgic_global_state.nr_lr = (ich_vtr_el2 & 0xf) + 1;
 	kvm_vgic_global_state.can_emulate_gicv2 = false;
+	kvm_vgic_global_state.ich_vtr_el2 = ich_vtr_el2;
 
 	if (!info->vcpu.start) {
 		kvm_info("GICv3: no GICV resource entry\n");
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 9232791..af23399 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -140,6 +140,28 @@ int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			 int offset, u32 *val);
 int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			 int offset, u32 *val);
+int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+			 u64 id, u64 *val);
+int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
+				u64 *reg);
+bool access_gic_ctlr_reg(struct kvm_vcpu *vcpu, bool is_write,
+			 unsigned long *reg);
+bool access_gic_pmr_reg(struct kvm_vcpu *vcpu, bool is_write,
+			unsigned long *reg);
+bool access_gic_bpr0_reg(struct kvm_vcpu *vcpu, bool is_write,
+			 unsigned long *reg);
+bool access_gic_bpr1_reg(struct kvm_vcpu *vcpu, bool is_write,
+			 unsigned long *reg);
+bool access_gic_grpen0_reg(struct kvm_vcpu *vcpu, bool is_write,
+			   unsigned long *reg);
+bool access_gic_grpen1_reg(struct kvm_vcpu *vcpu, bool is_write,
+			   unsigned long *reg);
+bool access_gic_ap0r_reg(struct kvm_vcpu *vcpu, bool is_write,
+			 u8 idx, unsigned long *reg);
+bool access_gic_ap1r_reg(struct kvm_vcpu *vcpu, bool is_write,
+			 u8 idx, unsigned long *reg);
+bool access_gic_sre_reg(struct kvm_vcpu *vcpu, bool is_write,
+			unsigned long *reg);
 int kvm_register_vgic_device(unsigned long type);
 void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 06/11] arm/arm64: vgic: Implement VGICv3 CPU interface access
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  0 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari at gmail.com @ 2016-11-23 13:01 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

VGICv3 CPU interface registers are accessed using
KVM_DEV_ARM_VGIC_CPU_SYSREGS ioctl. These registers are accessed
as 64-bit. The cpu MPIDR value is passed along with register id.
is used to identify the cpu for registers access.

The VM that supports SEIs expect it on destination machine to handle
guest aborts and hence checked for ICC_CTLR_EL1.SEIS compatibility.
Similarly, VM that supports Affinity Level 3 that is required for AArch64
mode, is required to be supported on destination machine. Hence checked
for ICC_CTLR_EL1.A3V compatibility.

The CPU system register handling is spitted into two files
vgic-sys-reg-common.c and vgic-sys-reg-v3.c.
The vgic-sys-reg-common.c handles read and write of VGIC CPU registers
for both AArch64 and AArch32 mode. The vgic-sys-reg-v3.c handles AArch64
mode and is compiled only for AArch64 mode.

Updated arch/arm/include/uapi/asm/kvm.h with new definitions
required to compile for AArch32.

The version of VGIC v3 specification is define here
Documentation/virtual/kvm/devices/arm-vgic-v3.txt

Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 arch/arm/include/uapi/asm/kvm.h         |   2 +
 arch/arm64/include/uapi/asm/kvm.h       |   3 +
 arch/arm64/kvm/Makefile                 |   2 +
 include/kvm/arm_vgic.h                  |   9 ++
 virt/kvm/arm/vgic/vgic-kvm-device.c     |  28 ++++
 virt/kvm/arm/vgic/vgic-mmio-v3.c        |  18 +++
 virt/kvm/arm/vgic/vgic-sys-reg-common.c | 258 ++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-sys-reg-v3.c     | 142 ++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c             |   8 +
 virt/kvm/arm/vgic/vgic.h                |  22 +++
 10 files changed, 492 insertions(+)

diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index 0ae6035..98658d9d 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -186,9 +186,11 @@ struct kvm_arch_memory_slot {
 			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
 #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
 #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
+#define   KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK (0xffff)
 #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
 #define KVM_DEV_ARM_VGIC_GRP_CTRL       4
 #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
+#define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
 
 /* KVM_IRQ_LINE irq field index values */
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 56dc08d..91c7137 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -206,9 +206,12 @@ struct kvm_arch_memory_slot {
 			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
 #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
 #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
+#define   KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK (0xffff)
 #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
 #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
 #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
+#define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
+
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
 
 /* Device Control API on vcpu fd */
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index d50a82a..5c8580e 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -32,5 +32,7 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-kvm-device.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-its.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/irqchip.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-sys-reg-common.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-sys-reg-v3.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_vgic.h b/include/kvm/arm_vgic.h
index 002f092..730a18a 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -71,6 +71,9 @@ struct vgic_global {
 
 	/* GIC system register CPU interface */
 	struct static_key_false gicv3_cpuif;
+
+	/* Cache ICH_VTR_EL2 reg value */
+	u32			ich_vtr_el2;
 };
 
 extern struct vgic_global kvm_vgic_global_state;
@@ -269,6 +272,12 @@ struct vgic_cpu {
 	u64 pendbaser;
 
 	bool lpis_enabled;
+
+	/* Cache guest priority bits */
+	u32 num_pri_bits;
+
+	/* Cache guest interrupt ID bits */
+	u32 num_id_bits;
 };
 
 extern struct static_key_false vgic_v2_cpuif_trap;
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index bc7de95..b6266fe 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -16,6 +16,7 @@
 #include <linux/kvm_host.h>
 #include <kvm/arm_vgic.h>
 #include <linux/uaccess.h>
+#include <asm/kvm_emulate.h>
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
@@ -501,6 +502,14 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
 		if (!is_write)
 			*reg = tmp32;
 		break;
+	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
+		u64 regid;
+
+		regid = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK);
+		ret = vgic_v3_cpu_sysregs_uaccess(vcpu, is_write,
+						  regid, reg);
+		break;
+	}
 	default:
 		ret = -EINVAL;
 		break;
@@ -534,6 +543,15 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
 		reg = tmp32;
 		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
 	}
+	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
+		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+		u64 reg;
+
+		if (get_user(reg, uaddr))
+			return -EFAULT;
+
+		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
+	}
 	}
 	return -ENXIO;
 }
@@ -560,6 +578,15 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
 		tmp32 = reg;
 		return put_user(tmp32, uaddr);
 	}
+	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
+		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+		u64 reg;
+
+		ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
+		if (ret)
+			return ret;
+		return put_user(reg, uaddr);
+	}
 	}
 
 	return -ENXIO;
@@ -578,6 +605,7 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
 		break;
 	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
 	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
+	case KVM_DEV_ARM_VGIC_CPU_SYSREGS:
 		return vgic_v3_has_attr_regs(dev, attr);
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 2a7cd62..2f7b4ed 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -641,6 +641,24 @@ int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
 		nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
 		break;
 	}
+	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
+		u64 reg, id;
+		unsigned long vgic_mpidr, mpidr_reg;
+		struct kvm_vcpu *vcpu;
+
+		vgic_mpidr = (attr->attr & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) >>
+			      KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT;
+
+		/* Convert plain mpidr value to MPIDR reg format */
+		mpidr_reg = VGIC_TO_MPIDR(vgic_mpidr);
+
+		vcpu = kvm_mpidr_to_vcpu(dev->kvm, mpidr_reg);
+		if (!vcpu)
+			return -EINVAL;
+
+		id = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK);
+		return vgic_v3_has_cpu_sysregs_attr(vcpu, 0, id, &reg);
+	}
 	default:
 		return -ENXIO;
 	}
diff --git a/virt/kvm/arm/vgic/vgic-sys-reg-common.c b/virt/kvm/arm/vgic/vgic-sys-reg-common.c
new file mode 100644
index 0000000..a1fc370c
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-sys-reg-common.c
@@ -0,0 +1,258 @@
+/*
+ * VGIC system registers handling functions
+ *
+ * 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.
+ */
+
+#include <linux/irqchip/arm-gic-v3.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <asm/kvm_emulate.h>
+#include "vgic.h"
+
+bool access_gic_ctlr_reg(struct kvm_vcpu *vcpu, bool is_write,
+			 unsigned long *reg)
+{
+	struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
+	struct vgic_vmcr vmcr;
+	u64 val;
+	u32 valid_bits, seis, a3v;
+
+	vgic_get_vmcr(vcpu, &vmcr);
+	if (is_write) {
+		val = *reg;
+
+		/*
+		 * Disallow restoring VM state if not supported by this
+		 * hardware.
+		 */
+		valid_bits = ((val & ICC_CTLR_EL1_PRI_BITS_MASK) >>
+				ICC_CTLR_EL1_PRI_BITS_SHIFT) + 1;
+		if (valid_bits > vgic_v3_cpu->num_pri_bits)
+			return false;
+
+		vgic_v3_cpu->num_pri_bits = valid_bits;
+
+		valid_bits = (val & ICC_CTLR_EL1_ID_BITS_MASK) >>
+			       ICC_CTLR_EL1_ID_BITS_SHIFT;
+		if (valid_bits > vgic_v3_cpu->num_id_bits)
+			return false;
+
+		vgic_v3_cpu->num_id_bits = valid_bits;
+
+		valid_bits = ((kvm_vgic_global_state.ich_vtr_el2 &
+			ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT);
+		seis = (val & ICC_CTLR_EL1_SEIS_MASK) >>
+			ICC_CTLR_EL1_SEIS_SHIFT;
+		if (valid_bits != seis)
+			return false;
+
+		valid_bits = ((kvm_vgic_global_state.ich_vtr_el2 &
+			ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT);
+		a3v = (val & ICC_CTLR_EL1_A3V_MASK) >>
+			ICC_CTLR_EL1_A3V_SHIFT;
+		if (valid_bits != a3v)
+			return false;
+
+		vmcr.ctlr = (val & ICC_CTLR_EL1_CBPR_MASK);
+		vmcr.ctlr |= (val & ICC_CTLR_EL1_EOImode_MASK);
+		vgic_set_vmcr(vcpu, &vmcr);
+	} else {
+		val = 0;
+		val |= (vgic_v3_cpu->num_pri_bits - 1) <<
+			ICC_CTLR_EL1_PRI_BITS_SHIFT;
+		val |= vgic_v3_cpu->num_id_bits <<
+			ICC_CTLR_EL1_ID_BITS_SHIFT;
+		val |= ((kvm_vgic_global_state.ich_vtr_el2 &
+			ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT) <<
+			ICC_CTLR_EL1_SEIS_SHIFT;
+		val |= ((kvm_vgic_global_state.ich_vtr_el2 &
+			ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT) <<
+			ICC_CTLR_EL1_A3V_SHIFT;
+		val |= (vmcr.ctlr & ICC_CTLR_EL1_CBPR_MASK);
+		val |= (vmcr.ctlr & ICC_CTLR_EL1_EOImode_MASK);
+
+		*reg = val;
+	}
+
+	return true;
+}
+
+bool access_gic_pmr_reg(struct kvm_vcpu *vcpu, bool is_write,
+			unsigned long *reg)
+{
+	struct vgic_vmcr vmcr;
+
+	vgic_get_vmcr(vcpu, &vmcr);
+	if (is_write) {
+		vmcr.pmr = (*reg & ICC_PMR_EL1_MASK) >> ICC_PMR_EL1_SHIFT;
+		vgic_set_vmcr(vcpu, &vmcr);
+	} else {
+		*reg = (vmcr.pmr << ICC_PMR_EL1_SHIFT) & ICC_PMR_EL1_MASK;
+	}
+
+	return true;
+}
+
+bool access_gic_bpr0_reg(struct kvm_vcpu *vcpu, bool is_write,
+			 unsigned long *reg)
+{
+	struct vgic_vmcr vmcr;
+
+	vgic_get_vmcr(vcpu, &vmcr);
+	if (is_write) {
+		vmcr.bpr = (*reg & ICC_BPR0_EL1_MASK) >>
+			    ICC_BPR0_EL1_SHIFT;
+		vgic_set_vmcr(vcpu, &vmcr);
+	} else {
+		*reg = (vmcr.bpr << ICC_BPR0_EL1_SHIFT) & ICC_BPR0_EL1_MASK;
+	}
+
+	return true;
+}
+
+bool access_gic_bpr1_reg(struct kvm_vcpu *vcpu, bool is_write,
+			 unsigned long *reg)
+{
+	struct vgic_vmcr vmcr;
+
+	if (!is_write)
+		*reg = 0;
+
+	vgic_get_vmcr(vcpu, &vmcr);
+	if (!((vmcr.ctlr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT)) {
+		if (is_write) {
+			vmcr.abpr = (*reg & ICC_BPR1_EL1_MASK) >>
+				     ICC_BPR1_EL1_SHIFT;
+			vgic_set_vmcr(vcpu, &vmcr);
+		} else {
+			*reg = (vmcr.abpr << ICC_BPR1_EL1_SHIFT) &
+				ICC_BPR1_EL1_MASK;
+		}
+	} else {
+		if (!is_write)
+			*reg = min((vmcr.bpr + 1), 7U);
+	}
+
+	return true;
+}
+
+bool access_gic_grpen0_reg(struct kvm_vcpu *vcpu, bool is_write,
+			   unsigned long *reg)
+{
+	struct vgic_vmcr vmcr;
+
+	vgic_get_vmcr(vcpu, &vmcr);
+	if (is_write) {
+		vmcr.grpen0 = (*reg & ICC_IGRPEN0_EL1_MASK) >>
+			       ICC_IGRPEN0_EL1_SHIFT;
+		vgic_set_vmcr(vcpu, &vmcr);
+	} else {
+		*reg = (vmcr.grpen0 << ICC_IGRPEN0_EL1_SHIFT) &
+			ICC_IGRPEN0_EL1_MASK;
+	}
+
+	return true;
+}
+
+bool access_gic_grpen1_reg(struct kvm_vcpu *vcpu, bool is_write,
+			   unsigned long *reg)
+{
+	struct vgic_vmcr vmcr;
+
+	vgic_get_vmcr(vcpu, &vmcr);
+	if (is_write) {
+		vmcr.grpen1 = (*reg & ICC_IGRPEN1_EL1_MASK) >>
+			       ICC_IGRPEN1_EL1_SHIFT;
+		vgic_set_vmcr(vcpu, &vmcr);
+	} else {
+		*reg = (vmcr.grpen1 << ICC_IGRPEN1_EL1_SHIFT) &
+			ICC_IGRPEN1_EL1_MASK;
+	}
+
+	return true;
+}
+
+static void vgic_v3_access_apr_reg(struct kvm_vcpu *vcpu, bool is_write,
+				   u8 apr, u8 idx, unsigned long *reg)
+{
+	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
+	uint32_t *ap_reg;
+
+	if (apr)
+		ap_reg = &vgicv3->vgic_ap1r[idx];
+	else
+		ap_reg = &vgicv3->vgic_ap0r[idx];
+
+	if (is_write)
+		*ap_reg = *reg;
+	else
+		*reg = *ap_reg;
+}
+
+static bool access_gic_aprn(struct kvm_vcpu *vcpu, bool is_write, u8 apr,
+			    u8 idx, unsigned long *reg)
+{
+	struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
+
+	/* num_pri_bits are initialized with HW supported values.
+	 * We can rely safely on num_pri_bits even if VM has not
+	 * restored ICC_CTLR_EL1 before restoring APnR registers.
+	 */
+	switch (vgic_v3_cpu->num_pri_bits) {
+	case 7:
+		vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
+		break;
+	case 6:
+		if (idx > 1)
+			goto err;
+		vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
+		break;
+	default:
+		if (idx > 0)
+			goto err;
+		vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
+	}
+
+	return true;
+err:
+	if (!is_write)
+		*reg = 0;
+
+	return false;
+}
+
+bool access_gic_ap0r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
+			 unsigned long *reg)
+{
+	return access_gic_aprn(vcpu, is_write, 0, idx, reg);
+}
+
+bool access_gic_ap1r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
+			 unsigned long *reg)
+{
+	return access_gic_aprn(vcpu, is_write, 1, idx, reg);
+}
+
+bool access_gic_sre_reg(struct kvm_vcpu *vcpu, bool is_write,
+			unsigned long *reg)
+{
+	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	/* Validate SRE bit */
+	if (is_write) {
+		if (!(*reg & ICC_SRE_EL1_SRE))
+			return false;
+	} else {
+		*reg = vgicv3->vgic_sre;
+	}
+
+	return true;
+}
diff --git a/virt/kvm/arm/vgic/vgic-sys-reg-v3.c b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
new file mode 100644
index 0000000..82c2f02
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
@@ -0,0 +1,142 @@
+/*
+ * VGIC system registers handling functions
+ *
+ * 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.
+ */
+
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <asm/kvm_emulate.h>
+#include "vgic.h"
+#include "sys_regs.h"
+
+#define ACCESS_SYS_REG(REG)						\
+static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,		\
+				    struct sys_reg_params *p,		\
+				    const struct sys_reg_desc *r)	\
+{									\
+	unsigned long tmp;						\
+	bool ret;							\
+									\
+	if (p->is_write)						\
+		tmp = p->regval;					\
+	ret = access_gic_##REG##_reg(vcpu, p->is_write, &tmp);		\
+	if (!p->is_write)						\
+		p->regval = tmp;					\
+									\
+	return ret;							\
+}
+
+ACCESS_SYS_REG(ctlr)
+ACCESS_SYS_REG(pmr)
+ACCESS_SYS_REG(bpr0)
+ACCESS_SYS_REG(bpr1)
+ACCESS_SYS_REG(sre)
+ACCESS_SYS_REG(grpen0)
+ACCESS_SYS_REG(grpen1)
+
+#define ACCESS_APNR_SYS_REG(REG)					\
+static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,		\
+				    struct sys_reg_params *p,		\
+				    const struct sys_reg_desc *r)	\
+{									\
+	unsigned long tmp;						\
+	u8 idx = p->Op2 & 3;						\
+	bool ret;							\
+									\
+	if (p->is_write)						\
+		tmp = p->regval;					\
+	ret = access_gic_##REG##_reg(vcpu, p->is_write, idx, &tmp);	\
+	if (!p->is_write)						\
+		p->regval = tmp;					\
+									\
+	return ret;							\
+}
+
+ACCESS_APNR_SYS_REG(ap0r)
+ACCESS_APNR_SYS_REG(ap1r)
+
+static const struct sys_reg_desc gic_v3_icc_reg_descs[] = {
+	/* ICC_PMR_EL1 */
+	{ Op0(3), Op1(0), CRn(4), CRm(6), Op2(0), access_gic_pmr_sys_reg },
+	/* ICC_BPR0_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(3), access_gic_bpr0_sys_reg },
+	/* ICC_AP0R0_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(4), access_gic_ap0r_sys_reg },
+	/* ICC_AP0R1_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(5), access_gic_ap0r_sys_reg },
+	/* ICC_AP0R2_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(6), access_gic_ap0r_sys_reg },
+	/* ICC_AP0R3_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(7), access_gic_ap0r_sys_reg },
+	/* ICC_AP1R0_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(0), access_gic_ap1r_sys_reg },
+	/* ICC_AP1R1_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(1), access_gic_ap1r_sys_reg },
+	/* ICC_AP1R2_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(2), access_gic_ap1r_sys_reg },
+	/* ICC_AP1R3_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(3), access_gic_ap1r_sys_reg },
+	/* ICC_BPR1_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(3), access_gic_bpr1_sys_reg },
+	/* ICC_CTLR_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(4), access_gic_ctlr_sys_reg },
+	/* ICC_SRE_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(5), access_gic_sre_sys_reg },
+	/* ICC_IGRPEN0_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(6), access_gic_grpen0_sys_reg },
+	/* ICC_GRPEN1_EL1 */
+	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(7), access_gic_grpen1_sys_reg },
+};
+
+int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
+				u64 *reg)
+{
+	struct sys_reg_params params;
+	u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64;
+
+	params.regval = *reg;
+	params.is_write = is_write;
+	params.is_aarch32 = false;
+	params.is_32bit = false;
+
+	if (find_reg_by_id(sysreg, &params, gic_v3_icc_reg_descs,
+			      ARRAY_SIZE(gic_v3_icc_reg_descs)))
+		return 0;
+
+	return -ENXIO;
+}
+
+int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
+				u64 *reg)
+{
+	struct sys_reg_params params;
+	const struct sys_reg_desc *r;
+	u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64;
+
+	if (is_write)
+		params.regval = *reg;
+	params.is_write = is_write;
+	params.is_aarch32 = false;
+	params.is_32bit = false;
+
+	r = find_reg_by_id(sysreg, &params, gic_v3_icc_reg_descs,
+			   ARRAY_SIZE(gic_v3_icc_reg_descs));
+	if (!r)
+		return -ENXIO;
+
+	if (!r->access(vcpu, &params, r))
+		return -EINVAL;
+
+	if (!is_write)
+		*reg = params.regval;
+
+	return 0;
+}
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index a3ff04b..6e7400e 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -240,6 +240,13 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 		vgic_v3->vgic_sre = 0;
 	}
 
+	vcpu->arch.vgic_cpu.num_id_bits = (kvm_vgic_global_state.ich_vtr_el2 &
+					   ICH_VTR_ID_BITS_MASK) >>
+					   ICH_VTR_ID_BITS_SHIFT;
+	vcpu->arch.vgic_cpu.num_pri_bits = ((kvm_vgic_global_state.ich_vtr_el2 &
+					    ICH_VTR_PRI_BITS_MASK) >>
+					    ICH_VTR_PRI_BITS_SHIFT) + 1;
+
 	/* Get the show on the road... */
 	vgic_v3->vgic_hcr = ICH_HCR_EN;
 }
@@ -340,6 +347,7 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
 	 */
 	kvm_vgic_global_state.nr_lr = (ich_vtr_el2 & 0xf) + 1;
 	kvm_vgic_global_state.can_emulate_gicv2 = false;
+	kvm_vgic_global_state.ich_vtr_el2 = ich_vtr_el2;
 
 	if (!info->vcpu.start) {
 		kvm_info("GICv3: no GICV resource entry\n");
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 9232791..af23399 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -140,6 +140,28 @@ int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			 int offset, u32 *val);
 int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			 int offset, u32 *val);
+int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+			 u64 id, u64 *val);
+int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
+				u64 *reg);
+bool access_gic_ctlr_reg(struct kvm_vcpu *vcpu, bool is_write,
+			 unsigned long *reg);
+bool access_gic_pmr_reg(struct kvm_vcpu *vcpu, bool is_write,
+			unsigned long *reg);
+bool access_gic_bpr0_reg(struct kvm_vcpu *vcpu, bool is_write,
+			 unsigned long *reg);
+bool access_gic_bpr1_reg(struct kvm_vcpu *vcpu, bool is_write,
+			 unsigned long *reg);
+bool access_gic_grpen0_reg(struct kvm_vcpu *vcpu, bool is_write,
+			   unsigned long *reg);
+bool access_gic_grpen1_reg(struct kvm_vcpu *vcpu, bool is_write,
+			   unsigned long *reg);
+bool access_gic_ap0r_reg(struct kvm_vcpu *vcpu, bool is_write,
+			 u8 idx, unsigned long *reg);
+bool access_gic_ap1r_reg(struct kvm_vcpu *vcpu, bool is_write,
+			 u8 idx, unsigned long *reg);
+bool access_gic_sre_reg(struct kvm_vcpu *vcpu, bool is_write,
+			unsigned long *reg);
 int kvm_register_vgic_device(unsigned long type);
 void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 07/11] arm/arm64: vgic: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl
  2016-11-23 13:01 ` vijay.kilari at gmail.com
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  -1 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari @ 2016-11-23 13:01 UTC (permalink / raw)
  To: marc.zyngier, christoffer.dall, peter.maydell
  Cc: kvmarm, linux-arm-kernel, Vijaya Kumar K

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

Userspace requires to store and restore of line_level for
level triggered interrupts using ioctl KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 arch/arm/include/uapi/asm/kvm.h     |  7 ++++++
 arch/arm64/include/uapi/asm/kvm.h   |  6 +++++
 virt/kvm/arm/vgic/vgic-kvm-device.c | 49 ++++++++++++++++++++++++++++++++++++-
 virt/kvm/arm/vgic/vgic-mmio-v3.c    | 11 +++++++++
 virt/kvm/arm/vgic/vgic-mmio.c       | 38 ++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.h       |  5 ++++
 virt/kvm/arm/vgic/vgic.h            |  2 ++
 7 files changed, 117 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index 98658d9d..f347779 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -191,6 +191,13 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_CTRL       4
 #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
 #define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
+#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
+#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT	10
+#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
+			(0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
+#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK	0x3ff
+#define VGIC_LEVEL_INFO_LINE_LEVEL	0
+
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
 
 /* KVM_IRQ_LINE irq field index values */
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 91c7137..4100f8c 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -211,6 +211,12 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
 #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
 #define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
+#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
+#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT	10
+#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
+			(0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
+#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK	0x3ff
+#define VGIC_LEVEL_INFO_LINE_LEVEL	0
 
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
 
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index b6266fe..52ed00b 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -510,6 +510,25 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
 						  regid, reg);
 		break;
 	}
+	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
+		unsigned int info, intid;
+
+		info = (attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
+			KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT;
+		if (info == VGIC_LEVEL_INFO_LINE_LEVEL) {
+			if (is_write)
+				tmp32 = *reg;
+			intid = attr->attr &
+				KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK;
+			ret = vgic_v3_line_level_info_uaccess(vcpu, is_write,
+							      intid, &tmp32);
+			if (!is_write)
+				*reg = tmp32;
+		} else {
+			ret = -EINVAL;
+		}
+		break;
+	}
 	default:
 		ret = -EINVAL;
 		break;
@@ -552,6 +571,17 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
 
 		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
 	}
+	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+		u64 reg;
+		u32 tmp32;
+
+		if (get_user(tmp32, uaddr))
+			return -EFAULT;
+
+		reg = tmp32;
+		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
+	}
 	}
 	return -ENXIO;
 }
@@ -587,8 +617,18 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
 			return ret;
 		return put_user(reg, uaddr);
 	}
-	}
+	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+		u64 reg;
+		u32 tmp32;
 
+		ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
+		if (ret)
+			return ret;
+		tmp32 = reg;
+		return put_user(tmp32, uaddr);
+	}
+	}
 	return -ENXIO;
 }
 
@@ -609,6 +649,13 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
 		return vgic_v3_has_attr_regs(dev, attr);
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
+	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
+		if (((attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
+		      KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) ==
+		      VGIC_LEVEL_INFO_LINE_LEVEL)
+			return 0;
+		break;
+	}
 	case KVM_DEV_ARM_VGIC_GRP_CTRL:
 		switch (attr->attr) {
 		case KVM_DEV_ARM_VGIC_CTRL_INIT:
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 2f7b4ed..4d7d93d 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -808,3 +808,14 @@ int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 		return vgic_uaccess(vcpu, &rd_dev, is_write,
 				    offset, val);
 }
+
+int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+				    u32 intid, u32 *val)
+{
+	if (is_write)
+		vgic_write_irq_line_level_info(vcpu, intid, *val);
+	else
+		*val = vgic_read_irq_line_level_info(vcpu, intid);
+
+	return 0;
+}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index f81e0e5..d602081 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -371,6 +371,44 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
 	}
 }
 
+unsigned long vgic_read_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid)
+{
+	int i;
+	unsigned long val = 0;
+
+	for (i = 0; i < 32; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (irq->line_level)
+			val |= (1U << i);
+
+		vgic_put_irq(vcpu->kvm, irq);
+	}
+
+	return val;
+}
+
+void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid,
+				    const unsigned long val)
+{
+	int i;
+
+	for (i = 0; i < 32; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		if (val & (1U << i)) {
+			irq->line_level = true;
+			vgic_queue_irq_unlock(vcpu->kvm, irq);
+		} else {
+			irq->line_level = false;
+			spin_unlock(&irq->irq_lock);
+		}
+
+		vgic_put_irq(vcpu->kvm, irq);
+	}
+}
+
 static int match_region(const void *key, const void *elt)
 {
 	const unsigned int offset = (unsigned long)key;
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 1cc7faf..f16d510 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -181,6 +181,11 @@ int vgic_validate_mmio_region_addr(struct kvm_device *dev,
 				   const struct vgic_register_region *regions,
 				   int nr_regions, gpa_t addr);
 
+unsigned long vgic_read_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid);
+
+void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid,
+				    const unsigned long val);
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index af23399..a6de38f 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -144,6 +144,8 @@ int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			 u64 id, u64 *val);
 int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
 				u64 *reg);
+int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+				    u32 intid, u32 *val);
 bool access_gic_ctlr_reg(struct kvm_vcpu *vcpu, bool is_write,
 			 unsigned long *reg);
 bool access_gic_pmr_reg(struct kvm_vcpu *vcpu, bool is_write,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 07/11] arm/arm64: vgic: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  0 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari at gmail.com @ 2016-11-23 13:01 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

Userspace requires to store and restore of line_level for
level triggered interrupts using ioctl KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 arch/arm/include/uapi/asm/kvm.h     |  7 ++++++
 arch/arm64/include/uapi/asm/kvm.h   |  6 +++++
 virt/kvm/arm/vgic/vgic-kvm-device.c | 49 ++++++++++++++++++++++++++++++++++++-
 virt/kvm/arm/vgic/vgic-mmio-v3.c    | 11 +++++++++
 virt/kvm/arm/vgic/vgic-mmio.c       | 38 ++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.h       |  5 ++++
 virt/kvm/arm/vgic/vgic.h            |  2 ++
 7 files changed, 117 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index 98658d9d..f347779 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -191,6 +191,13 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_CTRL       4
 #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
 #define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
+#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
+#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT	10
+#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
+			(0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
+#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK	0x3ff
+#define VGIC_LEVEL_INFO_LINE_LEVEL	0
+
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
 
 /* KVM_IRQ_LINE irq field index values */
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 91c7137..4100f8c 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -211,6 +211,12 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
 #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
 #define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
+#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
+#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT	10
+#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
+			(0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
+#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK	0x3ff
+#define VGIC_LEVEL_INFO_LINE_LEVEL	0
 
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
 
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index b6266fe..52ed00b 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -510,6 +510,25 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
 						  regid, reg);
 		break;
 	}
+	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
+		unsigned int info, intid;
+
+		info = (attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
+			KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT;
+		if (info == VGIC_LEVEL_INFO_LINE_LEVEL) {
+			if (is_write)
+				tmp32 = *reg;
+			intid = attr->attr &
+				KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK;
+			ret = vgic_v3_line_level_info_uaccess(vcpu, is_write,
+							      intid, &tmp32);
+			if (!is_write)
+				*reg = tmp32;
+		} else {
+			ret = -EINVAL;
+		}
+		break;
+	}
 	default:
 		ret = -EINVAL;
 		break;
@@ -552,6 +571,17 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
 
 		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
 	}
+	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+		u64 reg;
+		u32 tmp32;
+
+		if (get_user(tmp32, uaddr))
+			return -EFAULT;
+
+		reg = tmp32;
+		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
+	}
 	}
 	return -ENXIO;
 }
@@ -587,8 +617,18 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
 			return ret;
 		return put_user(reg, uaddr);
 	}
-	}
+	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+		u64 reg;
+		u32 tmp32;
 
+		ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
+		if (ret)
+			return ret;
+		tmp32 = reg;
+		return put_user(tmp32, uaddr);
+	}
+	}
 	return -ENXIO;
 }
 
@@ -609,6 +649,13 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
 		return vgic_v3_has_attr_regs(dev, attr);
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
+	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
+		if (((attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
+		      KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) ==
+		      VGIC_LEVEL_INFO_LINE_LEVEL)
+			return 0;
+		break;
+	}
 	case KVM_DEV_ARM_VGIC_GRP_CTRL:
 		switch (attr->attr) {
 		case KVM_DEV_ARM_VGIC_CTRL_INIT:
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 2f7b4ed..4d7d93d 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -808,3 +808,14 @@ int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 		return vgic_uaccess(vcpu, &rd_dev, is_write,
 				    offset, val);
 }
+
+int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+				    u32 intid, u32 *val)
+{
+	if (is_write)
+		vgic_write_irq_line_level_info(vcpu, intid, *val);
+	else
+		*val = vgic_read_irq_line_level_info(vcpu, intid);
+
+	return 0;
+}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index f81e0e5..d602081 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -371,6 +371,44 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
 	}
 }
 
+unsigned long vgic_read_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid)
+{
+	int i;
+	unsigned long val = 0;
+
+	for (i = 0; i < 32; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (irq->line_level)
+			val |= (1U << i);
+
+		vgic_put_irq(vcpu->kvm, irq);
+	}
+
+	return val;
+}
+
+void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid,
+				    const unsigned long val)
+{
+	int i;
+
+	for (i = 0; i < 32; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		if (val & (1U << i)) {
+			irq->line_level = true;
+			vgic_queue_irq_unlock(vcpu->kvm, irq);
+		} else {
+			irq->line_level = false;
+			spin_unlock(&irq->irq_lock);
+		}
+
+		vgic_put_irq(vcpu->kvm, irq);
+	}
+}
+
 static int match_region(const void *key, const void *elt)
 {
 	const unsigned int offset = (unsigned long)key;
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 1cc7faf..f16d510 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -181,6 +181,11 @@ int vgic_validate_mmio_region_addr(struct kvm_device *dev,
 				   const struct vgic_register_region *regions,
 				   int nr_regions, gpa_t addr);
 
+unsigned long vgic_read_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid);
+
+void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid,
+				    const unsigned long val);
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index af23399..a6de38f 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -144,6 +144,8 @@ int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			 u64 id, u64 *val);
 int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
 				u64 *reg);
+int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+				    u32 intid, u32 *val);
 bool access_gic_ctlr_reg(struct kvm_vcpu *vcpu, bool is_write,
 			 unsigned long *reg);
 bool access_gic_pmr_reg(struct kvm_vcpu *vcpu, bool is_write,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 08/11] arm/arm64: Documentation: Update arm-vgic-v3.txt
  2016-11-23 13:01 ` vijay.kilari at gmail.com
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  -1 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari @ 2016-11-23 13:01 UTC (permalink / raw)
  To: marc.zyngier, christoffer.dall, peter.maydell
  Cc: kvmarm, linux-arm-kernel, Vijaya Kumar K

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

Update error code returned for Invalid CPU interface register
value.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 Documentation/virtual/kvm/devices/arm-vgic-v3.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/virtual/kvm/devices/arm-vgic-v3.txt b/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
index 9348b3c..bff2898 100644
--- a/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
+++ b/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
@@ -145,7 +145,7 @@ Groups:
   Errors:
     -ENXIO: Getting or setting this register is not yet supported
     -EBUSY: VCPU is running
-    -EINVAL: Invalid mpidr supplied
+    -EINVAL: Invalid mpidr or register value supplied
 
 
   KVM_DEV_ARM_VGIC_GRP_NR_IRQS
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 08/11] arm/arm64: Documentation: Update arm-vgic-v3.txt
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  0 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari at gmail.com @ 2016-11-23 13:01 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

Update error code returned for Invalid CPU interface register
value.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 Documentation/virtual/kvm/devices/arm-vgic-v3.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/virtual/kvm/devices/arm-vgic-v3.txt b/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
index 9348b3c..bff2898 100644
--- a/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
+++ b/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
@@ -145,7 +145,7 @@ Groups:
   Errors:
     -ENXIO: Getting or setting this register is not yet supported
     -EBUSY: VCPU is running
-    -EINVAL: Invalid mpidr supplied
+    -EINVAL: Invalid mpidr or register value supplied
 
 
   KVM_DEV_ARM_VGIC_GRP_NR_IRQS
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 09/11] arm: coproc: Drop const from coproc reg access function
  2016-11-23 13:01 ` vijay.kilari at gmail.com
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  -1 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari @ 2016-11-23 13:01 UTC (permalink / raw)
  To: marc.zyngier, christoffer.dall, peter.maydell
  Cc: kvmarm, linux-arm-kernel, Vijaya Kumar K

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

In order to read or write to coproc regiter, the
access function is should allow the coproc_param to be non
constant.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 arch/arm/kvm/coproc.c | 20 ++++++++++----------
 arch/arm/kvm/coproc.h |  4 ++--
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
index 3e5e419..5753926 100644
--- a/arch/arm/kvm/coproc.c
+++ b/arch/arm/kvm/coproc.c
@@ -113,7 +113,7 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
 
 /* TRM entries A7:4.3.31 A15:4.3.28 - RO WI */
 static bool access_actlr(struct kvm_vcpu *vcpu,
-			 const struct coproc_params *p,
+			 struct coproc_params *p,
 			 const struct coproc_reg *r)
 {
 	if (p->is_write)
@@ -125,7 +125,7 @@ static bool access_actlr(struct kvm_vcpu *vcpu,
 
 /* TRM entries A7:4.3.56, A15:4.3.60 - R/O. */
 static bool access_cbar(struct kvm_vcpu *vcpu,
-			const struct coproc_params *p,
+			struct coproc_params *p,
 			const struct coproc_reg *r)
 {
 	if (p->is_write)
@@ -135,7 +135,7 @@ static bool access_cbar(struct kvm_vcpu *vcpu,
 
 /* TRM entries A7:4.3.49, A15:4.3.48 - R/O WI */
 static bool access_l2ctlr(struct kvm_vcpu *vcpu,
-			  const struct coproc_params *p,
+			  struct coproc_params *p,
 			  const struct coproc_reg *r)
 {
 	if (p->is_write)
@@ -181,7 +181,7 @@ static void reset_actlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
  * R/O WI (even if NSACR.NS_L2ERR, a write of 1 is ignored).
  */
 static bool access_l2ectlr(struct kvm_vcpu *vcpu,
-			   const struct coproc_params *p,
+			   struct coproc_params *p,
 			   const struct coproc_reg *r)
 {
 	if (p->is_write)
@@ -195,7 +195,7 @@ static bool access_l2ectlr(struct kvm_vcpu *vcpu,
  * See note at ARMv7 ARM B1.14.4 (TL;DR: S/W ops are not easily virtualized).
  */
 static bool access_dcsw(struct kvm_vcpu *vcpu,
-			const struct coproc_params *p,
+			struct coproc_params *p,
 			const struct coproc_reg *r)
 {
 	if (!p->is_write)
@@ -213,7 +213,7 @@ static bool access_dcsw(struct kvm_vcpu *vcpu,
  * Used by the cpu-specific code.
  */
 bool access_vm_reg(struct kvm_vcpu *vcpu,
-		   const struct coproc_params *p,
+		   struct coproc_params *p,
 		   const struct coproc_reg *r)
 {
 	bool was_enabled = vcpu_has_cache_enabled(vcpu);
@@ -229,7 +229,7 @@ bool access_vm_reg(struct kvm_vcpu *vcpu,
 }
 
 static bool access_gic_sgi(struct kvm_vcpu *vcpu,
-			   const struct coproc_params *p,
+			   struct coproc_params *p,
 			   const struct coproc_reg *r)
 {
 	u64 reg;
@@ -246,7 +246,7 @@ static bool access_gic_sgi(struct kvm_vcpu *vcpu,
 }
 
 static bool access_gic_sre(struct kvm_vcpu *vcpu,
-			   const struct coproc_params *p,
+			   struct coproc_params *p,
 			   const struct coproc_reg *r)
 {
 	if (p->is_write)
@@ -267,7 +267,7 @@ static bool access_gic_sre(struct kvm_vcpu *vcpu,
  * all PM registers, which doesn't crash the guest kernel at least.
  */
 static bool pm_fake(struct kvm_vcpu *vcpu,
-		    const struct coproc_params *p,
+		    struct coproc_params *p,
 		    const struct coproc_reg *r)
 {
 	if (p->is_write)
@@ -480,7 +480,7 @@ static const struct coproc_reg *find_reg(const struct coproc_params *params,
 }
 
 static int emulate_cp15(struct kvm_vcpu *vcpu,
-			const struct coproc_params *params)
+			struct coproc_params *params)
 {
 	size_t num;
 	const struct coproc_reg *table, *r;
diff --git a/arch/arm/kvm/coproc.h b/arch/arm/kvm/coproc.h
index eef1759..bbeff2a 100644
--- a/arch/arm/kvm/coproc.h
+++ b/arch/arm/kvm/coproc.h
@@ -41,7 +41,7 @@ struct coproc_reg {
 
 	/* Trapped access from guest, if non-NULL. */
 	bool (*access)(struct kvm_vcpu *,
-		       const struct coproc_params *,
+		       struct coproc_params *,
 		       const struct coproc_reg *);
 
 	/* Initialization for vcpu. */
@@ -154,7 +154,7 @@ static inline int cmp_reg(const struct coproc_reg *i1,
 #define is32		.is_64bit = false
 
 bool access_vm_reg(struct kvm_vcpu *vcpu,
-		   const struct coproc_params *p,
+		   struct coproc_params *p,
 		   const struct coproc_reg *r);
 
 #endif /* __ARM_KVM_COPROC_LOCAL_H__ */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 09/11] arm: coproc: Drop const from coproc reg access function
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  0 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari at gmail.com @ 2016-11-23 13:01 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

In order to read or write to coproc regiter, the
access function is should allow the coproc_param to be non
constant.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 arch/arm/kvm/coproc.c | 20 ++++++++++----------
 arch/arm/kvm/coproc.h |  4 ++--
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
index 3e5e419..5753926 100644
--- a/arch/arm/kvm/coproc.c
+++ b/arch/arm/kvm/coproc.c
@@ -113,7 +113,7 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
 
 /* TRM entries A7:4.3.31 A15:4.3.28 - RO WI */
 static bool access_actlr(struct kvm_vcpu *vcpu,
-			 const struct coproc_params *p,
+			 struct coproc_params *p,
 			 const struct coproc_reg *r)
 {
 	if (p->is_write)
@@ -125,7 +125,7 @@ static bool access_actlr(struct kvm_vcpu *vcpu,
 
 /* TRM entries A7:4.3.56, A15:4.3.60 - R/O. */
 static bool access_cbar(struct kvm_vcpu *vcpu,
-			const struct coproc_params *p,
+			struct coproc_params *p,
 			const struct coproc_reg *r)
 {
 	if (p->is_write)
@@ -135,7 +135,7 @@ static bool access_cbar(struct kvm_vcpu *vcpu,
 
 /* TRM entries A7:4.3.49, A15:4.3.48 - R/O WI */
 static bool access_l2ctlr(struct kvm_vcpu *vcpu,
-			  const struct coproc_params *p,
+			  struct coproc_params *p,
 			  const struct coproc_reg *r)
 {
 	if (p->is_write)
@@ -181,7 +181,7 @@ static void reset_actlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
  * R/O WI (even if NSACR.NS_L2ERR, a write of 1 is ignored).
  */
 static bool access_l2ectlr(struct kvm_vcpu *vcpu,
-			   const struct coproc_params *p,
+			   struct coproc_params *p,
 			   const struct coproc_reg *r)
 {
 	if (p->is_write)
@@ -195,7 +195,7 @@ static bool access_l2ectlr(struct kvm_vcpu *vcpu,
  * See note at ARMv7 ARM B1.14.4 (TL;DR: S/W ops are not easily virtualized).
  */
 static bool access_dcsw(struct kvm_vcpu *vcpu,
-			const struct coproc_params *p,
+			struct coproc_params *p,
 			const struct coproc_reg *r)
 {
 	if (!p->is_write)
@@ -213,7 +213,7 @@ static bool access_dcsw(struct kvm_vcpu *vcpu,
  * Used by the cpu-specific code.
  */
 bool access_vm_reg(struct kvm_vcpu *vcpu,
-		   const struct coproc_params *p,
+		   struct coproc_params *p,
 		   const struct coproc_reg *r)
 {
 	bool was_enabled = vcpu_has_cache_enabled(vcpu);
@@ -229,7 +229,7 @@ bool access_vm_reg(struct kvm_vcpu *vcpu,
 }
 
 static bool access_gic_sgi(struct kvm_vcpu *vcpu,
-			   const struct coproc_params *p,
+			   struct coproc_params *p,
 			   const struct coproc_reg *r)
 {
 	u64 reg;
@@ -246,7 +246,7 @@ static bool access_gic_sgi(struct kvm_vcpu *vcpu,
 }
 
 static bool access_gic_sre(struct kvm_vcpu *vcpu,
-			   const struct coproc_params *p,
+			   struct coproc_params *p,
 			   const struct coproc_reg *r)
 {
 	if (p->is_write)
@@ -267,7 +267,7 @@ static bool access_gic_sre(struct kvm_vcpu *vcpu,
  * all PM registers, which doesn't crash the guest kernel at least.
  */
 static bool pm_fake(struct kvm_vcpu *vcpu,
-		    const struct coproc_params *p,
+		    struct coproc_params *p,
 		    const struct coproc_reg *r)
 {
 	if (p->is_write)
@@ -480,7 +480,7 @@ static const struct coproc_reg *find_reg(const struct coproc_params *params,
 }
 
 static int emulate_cp15(struct kvm_vcpu *vcpu,
-			const struct coproc_params *params)
+			struct coproc_params *params)
 {
 	size_t num;
 	const struct coproc_reg *table, *r;
diff --git a/arch/arm/kvm/coproc.h b/arch/arm/kvm/coproc.h
index eef1759..bbeff2a 100644
--- a/arch/arm/kvm/coproc.h
+++ b/arch/arm/kvm/coproc.h
@@ -41,7 +41,7 @@ struct coproc_reg {
 
 	/* Trapped access from guest, if non-NULL. */
 	bool (*access)(struct kvm_vcpu *,
-		       const struct coproc_params *,
+		       struct coproc_params *,
 		       const struct coproc_reg *);
 
 	/* Initialization for vcpu. */
@@ -154,7 +154,7 @@ static inline int cmp_reg(const struct coproc_reg *i1,
 #define is32		.is_64bit = false
 
 bool access_vm_reg(struct kvm_vcpu *vcpu,
-		   const struct coproc_params *p,
+		   struct coproc_params *p,
 		   const struct coproc_reg *r);
 
 #endif /* __ARM_KVM_COPROC_LOCAL_H__ */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 10/11] arm: coproc: Introduce find_coproc_reg_by_id()
  2016-11-23 13:01 ` vijay.kilari at gmail.com
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  -1 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari @ 2016-11-23 13:01 UTC (permalink / raw)
  To: marc.zyngier, christoffer.dall, peter.maydell
  Cc: kvmarm, linux-arm-kernel, Vijaya Kumar K

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

To access CPU interface access in AArch32 mode, we need to
perform coproc_reg table lookup. For this introduce
find_coproc_reg_by_id() and export.

Also use this function internally in coproc.c wherever
required.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 arch/arm/kvm/coproc.c | 22 +++++++++++++++-------
 arch/arm/kvm/coproc.h |  4 ++++
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
index 5753926..7d05700 100644
--- a/arch/arm/kvm/coproc.c
+++ b/arch/arm/kvm/coproc.c
@@ -616,6 +616,17 @@ static bool index_to_params(u64 id, struct coproc_params *params)
 	}
 }
 
+const struct coproc_reg *
+find_coproc_reg_by_id(u64 id, struct coproc_params *params,
+		      const struct coproc_reg table[],
+		      unsigned int num)
+{
+	if (!index_to_params(id, params))
+		return NULL;
+
+	return find_reg(params, table, num);
+}
+
 /* Decode an index value, and find the cp15 coproc_reg entry. */
 static const struct coproc_reg *index_to_coproc_reg(struct kvm_vcpu *vcpu,
 						    u64 id)
@@ -742,10 +753,8 @@ static int get_invariant_cp15(u64 id, void __user *uaddr)
 	const struct coproc_reg *r;
 	int ret;
 
-	if (!index_to_params(id, &params))
-		return -ENOENT;
-
-	r = find_reg(&params, invariant_cp15, ARRAY_SIZE(invariant_cp15));
+	r = find_coproc_reg_by_id(id, &params, invariant_cp15,
+				  ARRAY_SIZE(invariant_cp15));
 	if (!r)
 		return -ENOENT;
 
@@ -767,9 +776,8 @@ static int set_invariant_cp15(u64 id, void __user *uaddr)
 	int err;
 	u64 val;
 
-	if (!index_to_params(id, &params))
-		return -ENOENT;
-	r = find_reg(&params, invariant_cp15, ARRAY_SIZE(invariant_cp15));
+	r = find_coproc_reg_by_id(id, &params, invariant_cp15,
+				  ARRAY_SIZE(invariant_cp15));
 	if (!r)
 		return -ENOENT;
 
diff --git a/arch/arm/kvm/coproc.h b/arch/arm/kvm/coproc.h
index bbeff2a..2accd9d 100644
--- a/arch/arm/kvm/coproc.h
+++ b/arch/arm/kvm/coproc.h
@@ -157,4 +157,8 @@ bool access_vm_reg(struct kvm_vcpu *vcpu,
 		   struct coproc_params *p,
 		   const struct coproc_reg *r);
 
+const struct coproc_reg *
+find_coproc_reg_by_id(u64 id, struct coproc_params *params,
+		      const struct coproc_reg table[],
+		      unsigned int num);
 #endif /* __ARM_KVM_COPROC_LOCAL_H__ */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 10/11] arm: coproc: Introduce find_coproc_reg_by_id()
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  0 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari at gmail.com @ 2016-11-23 13:01 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

To access CPU interface access in AArch32 mode, we need to
perform coproc_reg table lookup. For this introduce
find_coproc_reg_by_id() and export.

Also use this function internally in coproc.c wherever
required.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 arch/arm/kvm/coproc.c | 22 +++++++++++++++-------
 arch/arm/kvm/coproc.h |  4 ++++
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
index 5753926..7d05700 100644
--- a/arch/arm/kvm/coproc.c
+++ b/arch/arm/kvm/coproc.c
@@ -616,6 +616,17 @@ static bool index_to_params(u64 id, struct coproc_params *params)
 	}
 }
 
+const struct coproc_reg *
+find_coproc_reg_by_id(u64 id, struct coproc_params *params,
+		      const struct coproc_reg table[],
+		      unsigned int num)
+{
+	if (!index_to_params(id, params))
+		return NULL;
+
+	return find_reg(params, table, num);
+}
+
 /* Decode an index value, and find the cp15 coproc_reg entry. */
 static const struct coproc_reg *index_to_coproc_reg(struct kvm_vcpu *vcpu,
 						    u64 id)
@@ -742,10 +753,8 @@ static int get_invariant_cp15(u64 id, void __user *uaddr)
 	const struct coproc_reg *r;
 	int ret;
 
-	if (!index_to_params(id, &params))
-		return -ENOENT;
-
-	r = find_reg(&params, invariant_cp15, ARRAY_SIZE(invariant_cp15));
+	r = find_coproc_reg_by_id(id, &params, invariant_cp15,
+				  ARRAY_SIZE(invariant_cp15));
 	if (!r)
 		return -ENOENT;
 
@@ -767,9 +776,8 @@ static int set_invariant_cp15(u64 id, void __user *uaddr)
 	int err;
 	u64 val;
 
-	if (!index_to_params(id, &params))
-		return -ENOENT;
-	r = find_reg(&params, invariant_cp15, ARRAY_SIZE(invariant_cp15));
+	r = find_coproc_reg_by_id(id, &params, invariant_cp15,
+				  ARRAY_SIZE(invariant_cp15));
 	if (!r)
 		return -ENOENT;
 
diff --git a/arch/arm/kvm/coproc.h b/arch/arm/kvm/coproc.h
index bbeff2a..2accd9d 100644
--- a/arch/arm/kvm/coproc.h
+++ b/arch/arm/kvm/coproc.h
@@ -157,4 +157,8 @@ bool access_vm_reg(struct kvm_vcpu *vcpu,
 		   struct coproc_params *p,
 		   const struct coproc_reg *r);
 
+const struct coproc_reg *
+find_coproc_reg_by_id(u64 id, struct coproc_params *params,
+		      const struct coproc_reg table[],
+		      unsigned int num);
 #endif /* __ARM_KVM_COPROC_LOCAL_H__ */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 11/11] arm: vgic: Save and restore GICv3 CPU interface regs for AArch32
  2016-11-23 13:01 ` vijay.kilari at gmail.com
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  -1 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari @ 2016-11-23 13:01 UTC (permalink / raw)
  To: marc.zyngier, christoffer.dall, peter.maydell
  Cc: kvmarm, linux-arm-kernel, Vijaya Kumar K

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

Use coproc_reg infrastructure to save and restore CPU
interface register of GICv3 for AArch32 host.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 arch/arm/kvm/Makefile                  |   2 +
 virt/kvm/arm/vgic/vgic-coproc-reg-v3.c | 155 +++++++++++++++++++++++++++++++++
 2 files changed, 157 insertions(+)

diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
index d571243..451e666 100644
--- a/arch/arm/kvm/Makefile
+++ b/arch/arm/kvm/Makefile
@@ -32,6 +32,8 @@ obj-y += $(KVM)/arm/vgic/vgic-mmio.o
 obj-y += $(KVM)/arm/vgic/vgic-mmio-v2.o
 obj-y += $(KVM)/arm/vgic/vgic-mmio-v3.o
 obj-y += $(KVM)/arm/vgic/vgic-kvm-device.o
+obj-y += $(KVM)/arm/vgic/vgic-sys-reg-common.o
+obj-y += $(KVM)/arm/vgic/vgic-coproc-reg-v3.o
 obj-y += $(KVM)/arm/vgic/vgic-its.o
 obj-y += $(KVM)/irqchip.o
 obj-y += $(KVM)/arm/arch_timer.o
diff --git a/virt/kvm/arm/vgic/vgic-coproc-reg-v3.c b/virt/kvm/arm/vgic/vgic-coproc-reg-v3.c
new file mode 100644
index 0000000..25d00e5
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-coproc-reg-v3.c
@@ -0,0 +1,155 @@
+/*
+ * VGIC system registers handling functions
+ *
+ * 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.
+ */
+
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <kvm/arm_vgic.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_arm.h>
+
+#include "vgic.h"
+#include "coproc.h"
+
+#define ACCESS_COPROC_REG(REG)						\
+static bool access_gic_##REG##_coproc_reg(struct kvm_vcpu *vcpu,	\
+				   struct coproc_params *p,		\
+				   const struct coproc_reg *r)		\
+{									\
+	return  access_gic_##REG##_reg(vcpu, p->is_write, &p->Rt1);	\
+}
+
+ACCESS_COPROC_REG(ctlr)
+ACCESS_COPROC_REG(pmr)
+ACCESS_COPROC_REG(bpr0)
+ACCESS_COPROC_REG(bpr1)
+ACCESS_COPROC_REG(sre)
+ACCESS_COPROC_REG(grpen0)
+ACCESS_COPROC_REG(grpen1)
+
+#define ACCESS_COPROC_APNR_REG(REG)					\
+static bool access_gic_##REG##_coproc_reg(struct kvm_vcpu *vcpu,	\
+				   struct coproc_params *p,		\
+				   const struct coproc_reg *r)		\
+{									\
+	u8 idx = p->Op2 & 3;						\
+									\
+	return access_gic_##REG##_reg(vcpu, p->is_write, idx, &p->Rt1);	\
+}
+
+ACCESS_COPROC_APNR_REG(ap0r)
+ACCESS_COPROC_APNR_REG(ap1r)
+
+static const struct coproc_reg gic_v3_icc_coproc_reg_descs[] = {
+	/* ICC_PMR_EL1 */
+	{ CRn(0), CRm(6), Op1(0), Op2(0), is32, access_gic_pmr_coproc_reg },
+	/* ICC_BPR0_EL1 */
+	{ CRn(12), CRm(8), Op1(0), Op2(3), is32, access_gic_bpr0_coproc_reg },
+	/* ICC_AP0R0_EL1 */
+	{ CRn(12), CRm(8), Op1(0), Op2(4), is32, access_gic_ap0r_coproc_reg },
+	/* ICC_AP0R1_EL1 */
+	{ CRn(12), CRm(8), Op1(0), Op2(5), is32, access_gic_ap0r_coproc_reg },
+	/* ICC_AP0R2_EL1 */
+	{ CRn(12), CRm(8), Op1(0), Op2(6), is32, access_gic_ap0r_coproc_reg },
+	/* ICC_AP0R3_EL1 */
+	{ CRn(12), CRm(8), Op1(0), Op2(7), is32, access_gic_ap0r_coproc_reg },
+	/* ICC_AP1R0_EL1 */
+	{ CRn(12), CRm(9), Op1(0), Op2(0), is32, access_gic_ap1r_coproc_reg },
+	/* ICC_AP1R1_EL1 */
+	{ CRn(12), CRm(9), Op1(0), Op2(1), is32, access_gic_ap1r_coproc_reg },
+	/* ICC_AP1R2_EL1 */
+	{ CRn(12), CRm(9), Op1(0), Op2(2), is32, access_gic_ap1r_coproc_reg },
+	/* ICC_AP1R3_EL1 */
+	{ CRn(12), CRm(9), Op1(0), Op2(3), is32, access_gic_ap1r_coproc_reg },
+	/* ICC_BPR1_EL1 */
+	{ CRn(12), CRm(12), Op1(0), Op2(3), is32, access_gic_bpr1_coproc_reg },
+	/* ICC_CTLR_EL1 */
+	{ CRn(12), CRm(12), Op1(0), Op2(4), is32, access_gic_ctlr_coproc_reg },
+	/* ICC_SRE_EL1 */
+	{ CRn(12), CRm(12), Op1(0), Op2(5), is32, access_gic_sre_coproc_reg },
+	/* ICC_IGRPEN0_EL1 */
+	{ CRn(12), CRm(12), Op1(0), Op2(6), is32,
+	  access_gic_grpen0_coproc_reg },
+	/* ICC_GRPEN1_EL1 */
+	{ CRn(12), CRm(12), Op1(0), Op2(7), is32,
+	  access_gic_grpen1_coproc_reg },
+};
+
+
+#define KVM_DEV_ARM_VGIC_COPROC_MASK 0x3fff
+
+/* As per Documentation/virtual/kvm/devices/arm-vgic-v3.txt,
+ * CPUREGs id is passed in AArch64 system register encoding format.
+ * Format to COPROC register format for AArch32 mode before using.
+ */
+static u64 vgic_to_cpreg(u64 id)
+{
+	u64 cpreg = 0;
+
+	id = id & KVM_DEV_ARM_VGIC_COPROC_MASK;
+	cpreg = ((id & KVM_REG_ARM_VGIC_SYSREG_OP2_MASK) >>
+		  KVM_REG_ARM_VGIC_SYSREG_OP2_SHIFT) <<
+		  KVM_REG_ARM_32_OPC2_SHIFT;
+	cpreg |= ((id & KVM_REG_ARM_VGIC_SYSREG_CRM_MASK) >>
+		  KVM_REG_ARM_VGIC_SYSREG_CRM_SHIFT) << KVM_REG_ARM_CRM_SHIFT;
+	cpreg |= ((id & KVM_REG_ARM_VGIC_SYSREG_CRN_MASK) >>
+		   KVM_REG_ARM_VGIC_SYSREG_CRN_SHIFT) <<
+		   KVM_REG_ARM_32_CRN_SHIFT;
+	cpreg |= ((id & KVM_REG_ARM_VGIC_SYSREG_OP1_MASK) >>
+		   KVM_REG_ARM_VGIC_SYSREG_OP1_SHIFT) << KVM_REG_ARM_OPC1_SHIFT;
+	id |= (KVM_REG_ARM_COPROC_MASK | KVM_REG_SIZE_U32);
+
+	return cpreg;
+}
+
+int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
+				 u64 *reg)
+{
+	struct coproc_params params;
+	u64 cpreg = vgic_to_cpreg(id);
+
+	params.Rt1 = *reg;
+	params.is_write = is_write;
+	params.is_64bit = false;
+
+	if (find_coproc_reg_by_id(cpreg, &params, gic_v3_icc_coproc_reg_descs,
+				  ARRAY_SIZE(gic_v3_icc_coproc_reg_descs)))
+		return 0;
+
+	return -ENOENT;
+}
+
+int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
+				u64 *reg)
+{
+	struct coproc_params params;
+	const struct coproc_reg *r;
+	u64 cpreg = vgic_to_cpreg(id);
+
+	if (is_write)
+		params.Rt1 = *reg;
+	params.is_write = is_write;
+	params.is_64bit = false;
+
+	r = find_coproc_reg_by_id(cpreg, &params, gic_v3_icc_coproc_reg_descs,
+				  ARRAY_SIZE(gic_v3_icc_coproc_reg_descs));
+	if (!r)
+		return -ENXIO;
+
+	if (!r->access(vcpu, &params, r))
+		return -EINVAL;
+
+	if (!is_write)
+		*reg = params.Rt1;
+
+	return 0;
+}
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 11/11] arm: vgic: Save and restore GICv3 CPU interface regs for AArch32
@ 2016-11-23 13:01   ` vijay.kilari at gmail.com
  0 siblings, 0 replies; 78+ messages in thread
From: vijay.kilari at gmail.com @ 2016-11-23 13:01 UTC (permalink / raw)
  To: linux-arm-kernel

From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

Use coproc_reg infrastructure to save and restore CPU
interface register of GICv3 for AArch32 host.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
---
 arch/arm/kvm/Makefile                  |   2 +
 virt/kvm/arm/vgic/vgic-coproc-reg-v3.c | 155 +++++++++++++++++++++++++++++++++
 2 files changed, 157 insertions(+)

diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
index d571243..451e666 100644
--- a/arch/arm/kvm/Makefile
+++ b/arch/arm/kvm/Makefile
@@ -32,6 +32,8 @@ obj-y += $(KVM)/arm/vgic/vgic-mmio.o
 obj-y += $(KVM)/arm/vgic/vgic-mmio-v2.o
 obj-y += $(KVM)/arm/vgic/vgic-mmio-v3.o
 obj-y += $(KVM)/arm/vgic/vgic-kvm-device.o
+obj-y += $(KVM)/arm/vgic/vgic-sys-reg-common.o
+obj-y += $(KVM)/arm/vgic/vgic-coproc-reg-v3.o
 obj-y += $(KVM)/arm/vgic/vgic-its.o
 obj-y += $(KVM)/irqchip.o
 obj-y += $(KVM)/arm/arch_timer.o
diff --git a/virt/kvm/arm/vgic/vgic-coproc-reg-v3.c b/virt/kvm/arm/vgic/vgic-coproc-reg-v3.c
new file mode 100644
index 0000000..25d00e5
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-coproc-reg-v3.c
@@ -0,0 +1,155 @@
+/*
+ * VGIC system registers handling functions
+ *
+ * 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.
+ */
+
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <kvm/arm_vgic.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_arm.h>
+
+#include "vgic.h"
+#include "coproc.h"
+
+#define ACCESS_COPROC_REG(REG)						\
+static bool access_gic_##REG##_coproc_reg(struct kvm_vcpu *vcpu,	\
+				   struct coproc_params *p,		\
+				   const struct coproc_reg *r)		\
+{									\
+	return  access_gic_##REG##_reg(vcpu, p->is_write, &p->Rt1);	\
+}
+
+ACCESS_COPROC_REG(ctlr)
+ACCESS_COPROC_REG(pmr)
+ACCESS_COPROC_REG(bpr0)
+ACCESS_COPROC_REG(bpr1)
+ACCESS_COPROC_REG(sre)
+ACCESS_COPROC_REG(grpen0)
+ACCESS_COPROC_REG(grpen1)
+
+#define ACCESS_COPROC_APNR_REG(REG)					\
+static bool access_gic_##REG##_coproc_reg(struct kvm_vcpu *vcpu,	\
+				   struct coproc_params *p,		\
+				   const struct coproc_reg *r)		\
+{									\
+	u8 idx = p->Op2 & 3;						\
+									\
+	return access_gic_##REG##_reg(vcpu, p->is_write, idx, &p->Rt1);	\
+}
+
+ACCESS_COPROC_APNR_REG(ap0r)
+ACCESS_COPROC_APNR_REG(ap1r)
+
+static const struct coproc_reg gic_v3_icc_coproc_reg_descs[] = {
+	/* ICC_PMR_EL1 */
+	{ CRn(0), CRm(6), Op1(0), Op2(0), is32, access_gic_pmr_coproc_reg },
+	/* ICC_BPR0_EL1 */
+	{ CRn(12), CRm(8), Op1(0), Op2(3), is32, access_gic_bpr0_coproc_reg },
+	/* ICC_AP0R0_EL1 */
+	{ CRn(12), CRm(8), Op1(0), Op2(4), is32, access_gic_ap0r_coproc_reg },
+	/* ICC_AP0R1_EL1 */
+	{ CRn(12), CRm(8), Op1(0), Op2(5), is32, access_gic_ap0r_coproc_reg },
+	/* ICC_AP0R2_EL1 */
+	{ CRn(12), CRm(8), Op1(0), Op2(6), is32, access_gic_ap0r_coproc_reg },
+	/* ICC_AP0R3_EL1 */
+	{ CRn(12), CRm(8), Op1(0), Op2(7), is32, access_gic_ap0r_coproc_reg },
+	/* ICC_AP1R0_EL1 */
+	{ CRn(12), CRm(9), Op1(0), Op2(0), is32, access_gic_ap1r_coproc_reg },
+	/* ICC_AP1R1_EL1 */
+	{ CRn(12), CRm(9), Op1(0), Op2(1), is32, access_gic_ap1r_coproc_reg },
+	/* ICC_AP1R2_EL1 */
+	{ CRn(12), CRm(9), Op1(0), Op2(2), is32, access_gic_ap1r_coproc_reg },
+	/* ICC_AP1R3_EL1 */
+	{ CRn(12), CRm(9), Op1(0), Op2(3), is32, access_gic_ap1r_coproc_reg },
+	/* ICC_BPR1_EL1 */
+	{ CRn(12), CRm(12), Op1(0), Op2(3), is32, access_gic_bpr1_coproc_reg },
+	/* ICC_CTLR_EL1 */
+	{ CRn(12), CRm(12), Op1(0), Op2(4), is32, access_gic_ctlr_coproc_reg },
+	/* ICC_SRE_EL1 */
+	{ CRn(12), CRm(12), Op1(0), Op2(5), is32, access_gic_sre_coproc_reg },
+	/* ICC_IGRPEN0_EL1 */
+	{ CRn(12), CRm(12), Op1(0), Op2(6), is32,
+	  access_gic_grpen0_coproc_reg },
+	/* ICC_GRPEN1_EL1 */
+	{ CRn(12), CRm(12), Op1(0), Op2(7), is32,
+	  access_gic_grpen1_coproc_reg },
+};
+
+
+#define KVM_DEV_ARM_VGIC_COPROC_MASK 0x3fff
+
+/* As per Documentation/virtual/kvm/devices/arm-vgic-v3.txt,
+ * CPUREGs id is passed in AArch64 system register encoding format.
+ * Format to COPROC register format for AArch32 mode before using.
+ */
+static u64 vgic_to_cpreg(u64 id)
+{
+	u64 cpreg = 0;
+
+	id = id & KVM_DEV_ARM_VGIC_COPROC_MASK;
+	cpreg = ((id & KVM_REG_ARM_VGIC_SYSREG_OP2_MASK) >>
+		  KVM_REG_ARM_VGIC_SYSREG_OP2_SHIFT) <<
+		  KVM_REG_ARM_32_OPC2_SHIFT;
+	cpreg |= ((id & KVM_REG_ARM_VGIC_SYSREG_CRM_MASK) >>
+		  KVM_REG_ARM_VGIC_SYSREG_CRM_SHIFT) << KVM_REG_ARM_CRM_SHIFT;
+	cpreg |= ((id & KVM_REG_ARM_VGIC_SYSREG_CRN_MASK) >>
+		   KVM_REG_ARM_VGIC_SYSREG_CRN_SHIFT) <<
+		   KVM_REG_ARM_32_CRN_SHIFT;
+	cpreg |= ((id & KVM_REG_ARM_VGIC_SYSREG_OP1_MASK) >>
+		   KVM_REG_ARM_VGIC_SYSREG_OP1_SHIFT) << KVM_REG_ARM_OPC1_SHIFT;
+	id |= (KVM_REG_ARM_COPROC_MASK | KVM_REG_SIZE_U32);
+
+	return cpreg;
+}
+
+int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
+				 u64 *reg)
+{
+	struct coproc_params params;
+	u64 cpreg = vgic_to_cpreg(id);
+
+	params.Rt1 = *reg;
+	params.is_write = is_write;
+	params.is_64bit = false;
+
+	if (find_coproc_reg_by_id(cpreg, &params, gic_v3_icc_coproc_reg_descs,
+				  ARRAY_SIZE(gic_v3_icc_coproc_reg_descs)))
+		return 0;
+
+	return -ENOENT;
+}
+
+int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
+				u64 *reg)
+{
+	struct coproc_params params;
+	const struct coproc_reg *r;
+	u64 cpreg = vgic_to_cpreg(id);
+
+	if (is_write)
+		params.Rt1 = *reg;
+	params.is_write = is_write;
+	params.is_64bit = false;
+
+	r = find_coproc_reg_by_id(cpreg, &params, gic_v3_icc_coproc_reg_descs,
+				  ARRAY_SIZE(gic_v3_icc_coproc_reg_descs));
+	if (!r)
+		return -ENXIO;
+
+	if (!r->access(vcpu, &params, r))
+		return -EINVAL;
+
+	if (!is_write)
+		*reg = params.Rt1;
+
+	return 0;
+}
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 01/11] arm/arm64: vgic: Implement support for userspace access
  2016-11-23 13:01   ` vijay.kilari at gmail.com
@ 2016-11-28 13:05     ` Christoffer Dall
  -1 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-28 13:05 UTC (permalink / raw)
  To: vijay.kilari; +Cc: marc.zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

On Wed, Nov 23, 2016 at 06:31:48PM +0530, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> 
> Read and write of some registers like ISPENDR and ICPENDR
> from userspace requires special handling when compared to
> guest access for these registers.
> 
> Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
> for handling of ISPENDR, ICPENDR registers handling.
> 
> Add infrastructure to support guest and userspace read
> and write for the required registers
> Also moved vgic_uaccess from vgic-mmio-v2.c to vgic-mmio.c
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> ---
>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  25 ----------
>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 102 ++++++++++++++++++++++++++++++++-------
>  virt/kvm/arm/vgic/vgic-mmio.c    |  78 +++++++++++++++++++++++++++---
>  virt/kvm/arm/vgic/vgic-mmio.h    |  19 ++++++++
>  4 files changed, 175 insertions(+), 49 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index b44b359..0b32f40 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -406,31 +406,6 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>  	return -ENXIO;
>  }
>  
> -/*
> - * When userland tries to access the VGIC register handlers, we need to
> - * create a usable struct vgic_io_device to be passed to the handlers and we
> - * have to set up a buffer similar to what would have happened if a guest MMIO
> - * access occurred, including doing endian conversions on BE systems.
> - */
> -static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
> -			bool is_write, int offset, u32 *val)
> -{
> -	unsigned int len = 4;
> -	u8 buf[4];
> -	int ret;
> -
> -	if (is_write) {
> -		vgic_data_host_to_mmio_bus(buf, len, *val);
> -		ret = kvm_io_gic_ops.write(vcpu, &dev->dev, offset, len, buf);
> -	} else {
> -		ret = kvm_io_gic_ops.read(vcpu, &dev->dev, offset, len, buf);
> -		if (!ret)
> -			*val = vgic_data_mmio_bus_to_host(buf, len);
> -	}
> -
> -	return ret;
> -}
> -
>  int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			  int offset, u32 *val)
>  {
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index 50f42f0..8e76d04 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -207,6 +207,66 @@ static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +static unsigned long vgic_v3_uaccess_read_pending(struct kvm_vcpu *vcpu,
> +						  gpa_t addr, unsigned int len)
> +{
> +	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
> +	u32 value = 0;
> +	int i;
> +
> +	/*
> +	 * A level triggerred interrupt pending state is latched in both
> +	 * "soft_pending" and "line_level" variables. Userspace will save
> +	 * and restore soft_pending and line_level separately.
> +	 * Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
> +	 * handling of ISPENDR and ICPENDR.
> +	 */
> +	for (i = 0; i < len * 8; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (irq->config == VGIC_CONFIG_LEVEL && irq->soft_pending)
> +			value |= (1U << i);
> +		if (irq->config == VGIC_CONFIG_EDGE && irq->pending)
> +			value |= (1U << i);
> +
> +		vgic_put_irq(vcpu->kvm, irq);
> +	}
> +
> +	return value;
> +}
> +
> +static void vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu,
> +					  gpa_t addr, unsigned int len,
> +					  unsigned long val)
> +{
> +	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
> +	int i;
> +
> +	for (i = 0; i < len * 8; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		if (test_bit(i, &val)) {
> +			/* soft_pending is set irrespective of irq type
> +			 * (level or edge) to avoid dependency that VM should
> +			 * restore irq config before pending info.
> +			 */

nit: kernel commenting style

> +			irq->pending = true;
> +			irq->soft_pending = true;
> +			vgic_queue_irq_unlock(vcpu->kvm, irq);
> +		} else {
> +			irq->soft_pending = false;
> +			if (irq->config == VGIC_CONFIG_EDGE ||
> +			    (irq->config == VGIC_CONFIG_LEVEL &&
> +			    !irq->line_level))
> +				irq->pending = false;
> +			spin_unlock(&irq->irq_lock);
> +		}
> +
> +		vgic_put_irq(vcpu->kvm, irq);
> +	}
> +}
> +
>  /* We want to avoid outer shareable. */
>  u64 vgic_sanitise_shareability(u64 field)
>  {
> @@ -356,7 +416,7 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>   * We take some special care here to fix the calculation of the register
>   * offset.
>   */
> -#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, bpi, acc)	\
> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, ur, uw, bpi, acc) \
>  	{								\
>  		.reg_offset = off,					\
>  		.bits_per_irq = bpi,					\
> @@ -371,6 +431,8 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>  		.access_flags = acc,					\
>  		.read = rd,						\
>  		.write = wr,						\
> +		.uaccess_read = ur,					\
> +		.uaccess_write = uw,					\
>  	}
>  
>  static const struct vgic_register_region vgic_v3_dist_registers[] = {
> @@ -378,40 +440,42 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>  		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
> -		vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
> +		vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
> -		vgic_mmio_read_enable, vgic_mmio_write_senable, 1,
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, NULL, NULL, 1,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
> -		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, NULL, NULL, 1,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
> -		vgic_mmio_read_pending, vgic_mmio_write_spending, 1,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending,
> +		vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 1,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
> -		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
> -		vgic_mmio_read_active, vgic_mmio_write_sactive, 1,
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, NULL, NULL, 1,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
> -		vgic_mmio_read_active, vgic_mmio_write_cactive, 1,
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, NULL, NULL, 1,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
> -		vgic_mmio_read_priority, vgic_mmio_write_priority, 8,
> -		VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, NULL, NULL,
> +		8, VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 8,
>  		VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
> -		vgic_mmio_read_config, vgic_mmio_write_config, 2,
> +		vgic_mmio_read_config, vgic_mmio_write_config, NULL, NULL, 2,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
> -		vgic_mmio_read_irouter, vgic_mmio_write_irouter, 64,
> +		vgic_mmio_read_irouter, vgic_mmio_write_irouter, NULL, NULL, 64,
>  		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>  		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48,
> @@ -449,11 +513,13 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>  	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
>  		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4,
>  		VGIC_ACCESS_32bit),
> -	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
> -		vgic_mmio_read_pending, vgic_mmio_write_spending, 4,
> +	REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ISPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending,
> +		vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 4,
>  		VGIC_ACCESS_32bit),
> -	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
> -		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4,
> +	REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ICPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
>  		vgic_mmio_read_active, vgic_mmio_write_sactive, 4,
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index ebe1b9f..d5f3ee2 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -484,6 +484,74 @@ static bool check_region(const struct kvm *kvm,
>  	return false;
>  }
>  
> +static const struct vgic_register_region *
> +vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev,
> +		     gpa_t addr, int len)
> +{
> +	const struct vgic_register_region *region;
> +
> +	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
> +				       addr - iodev->base_addr);
> +	if (!region || !check_region(vcpu->kvm, region, addr, len))
> +		return NULL;
> +
> +	return region;
> +}
> +
> +static int vgic_uaccess_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
> +			     gpa_t addr, u32 *val)
> +{
> +	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
> +	const struct vgic_register_region *region;
> +	struct kvm_vcpu *r_vcpu;
> +
> +	region = vgic_get_mmio_region(vcpu, iodev, addr, sizeof(u32));
> +	if (!region) {
> +		*val = 0;
> +		return 0;
> +	}
> +
> +	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
> +	if (region->uaccess_read)
> +		*val = region->uaccess_read(r_vcpu, addr, sizeof(u32));
> +	else
> +		*val = region->read(r_vcpu, addr, sizeof(u32));
> +
> +	return 0;
> +}
> +
> +static int vgic_uaccess_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
> +			      gpa_t addr, const u32 *val)
> +{
> +	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
> +	const struct vgic_register_region *region;
> +	struct kvm_vcpu *r_vcpu;
> +
> +	region = vgic_get_mmio_region(vcpu, iodev, addr, sizeof(u32));
> +	if (!region)
> +		return 0;
> +
> +	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
> +	if (region->uaccess_write)
> +		region->uaccess_write(r_vcpu, addr, sizeof(u32), *val);
> +	else
> +		region->write(r_vcpu, addr, sizeof(u32), *val);
> +
> +	return 0;
> +}
> +
> +/*
> + * Userland access to VGIC registers.
> + */
> +int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
> +		 bool is_write, int offset, u32 *val)
> +{
> +	if (is_write)
> +		return vgic_uaccess_write(vcpu, &dev->dev, offset, val);
> +	else
> +		return vgic_uaccess_read(vcpu, &dev->dev, offset, val);
> +}
> +
>  static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>  			      gpa_t addr, int len, void *val)
>  {
> @@ -491,9 +559,8 @@ static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>  	const struct vgic_register_region *region;
>  	unsigned long data = 0;
>  
> -	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
> -				       addr - iodev->base_addr);
> -	if (!region || !check_region(vcpu->kvm, region, addr, len)) {
> +	region = vgic_get_mmio_region(vcpu, iodev, addr, len);
> +	if (!region) {
>  		memset(val, 0, len);
>  		return 0;
>  	}
> @@ -524,9 +591,8 @@ static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>  	const struct vgic_register_region *region;
>  	unsigned long data = vgic_data_mmio_bus_to_host(val, len);
>  
> -	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
> -				       addr - iodev->base_addr);
> -	if (!region || !check_region(vcpu->kvm, region, addr, len))
> +	region = vgic_get_mmio_region(vcpu, iodev, addr, len);
> +	if (!region)
>  		return 0;
>  
>  	switch (iodev->iodev_type) {
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
> index 84961b4..7b30296 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -34,6 +34,10 @@ struct vgic_register_region {
>  				  gpa_t addr, unsigned int len,
>  				  unsigned long val);
>  	};
> +	unsigned long (*uaccess_read)(struct kvm_vcpu *vcpu, gpa_t addr,
> +				      unsigned int len);
> +	void (*uaccess_write)(struct kvm_vcpu *vcpu, gpa_t addr,
> +			      unsigned int len, unsigned long val);
>  };
>  
>  extern struct kvm_io_device_ops kvm_io_gic_ops;
> @@ -86,6 +90,18 @@ struct vgic_register_region {
>  		.write = wr,						\
>  	}
>  
> +#define REGISTER_DESC_WITH_LENGTH_UACCESS(off, rd, wr, urd, uwr, length, acc) \
> +	{								\
> +		.reg_offset = off,					\
> +		.bits_per_irq = 0,					\
> +		.len = length,						\
> +		.access_flags = acc,					\
> +		.read = rd,						\
> +		.write = wr,						\
> +		.uaccess_read = urd,					\
> +		.uaccess_write = uwr,					\
> +	}
> +
>  int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  				  struct vgic_register_region *reg_desc,
>  				  struct vgic_io_device *region,
> @@ -158,6 +174,9 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>  			    gpa_t addr, unsigned int len,
>  			    unsigned long val);
>  
> +int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
> +		 bool is_write, int offset, u32 *val);
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
>  unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
> -- 
> 1.9.1
> 

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 01/11] arm/arm64: vgic: Implement support for userspace access
@ 2016-11-28 13:05     ` Christoffer Dall
  0 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-28 13:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 23, 2016 at 06:31:48PM +0530, vijay.kilari at gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> 
> Read and write of some registers like ISPENDR and ICPENDR
> from userspace requires special handling when compared to
> guest access for these registers.
> 
> Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
> for handling of ISPENDR, ICPENDR registers handling.
> 
> Add infrastructure to support guest and userspace read
> and write for the required registers
> Also moved vgic_uaccess from vgic-mmio-v2.c to vgic-mmio.c
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> ---
>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  25 ----------
>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 102 ++++++++++++++++++++++++++++++++-------
>  virt/kvm/arm/vgic/vgic-mmio.c    |  78 +++++++++++++++++++++++++++---
>  virt/kvm/arm/vgic/vgic-mmio.h    |  19 ++++++++
>  4 files changed, 175 insertions(+), 49 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index b44b359..0b32f40 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -406,31 +406,6 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>  	return -ENXIO;
>  }
>  
> -/*
> - * When userland tries to access the VGIC register handlers, we need to
> - * create a usable struct vgic_io_device to be passed to the handlers and we
> - * have to set up a buffer similar to what would have happened if a guest MMIO
> - * access occurred, including doing endian conversions on BE systems.
> - */
> -static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
> -			bool is_write, int offset, u32 *val)
> -{
> -	unsigned int len = 4;
> -	u8 buf[4];
> -	int ret;
> -
> -	if (is_write) {
> -		vgic_data_host_to_mmio_bus(buf, len, *val);
> -		ret = kvm_io_gic_ops.write(vcpu, &dev->dev, offset, len, buf);
> -	} else {
> -		ret = kvm_io_gic_ops.read(vcpu, &dev->dev, offset, len, buf);
> -		if (!ret)
> -			*val = vgic_data_mmio_bus_to_host(buf, len);
> -	}
> -
> -	return ret;
> -}
> -
>  int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			  int offset, u32 *val)
>  {
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index 50f42f0..8e76d04 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -207,6 +207,66 @@ static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
>  	return 0;
>  }
>  
> +static unsigned long vgic_v3_uaccess_read_pending(struct kvm_vcpu *vcpu,
> +						  gpa_t addr, unsigned int len)
> +{
> +	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
> +	u32 value = 0;
> +	int i;
> +
> +	/*
> +	 * A level triggerred interrupt pending state is latched in both
> +	 * "soft_pending" and "line_level" variables. Userspace will save
> +	 * and restore soft_pending and line_level separately.
> +	 * Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
> +	 * handling of ISPENDR and ICPENDR.
> +	 */
> +	for (i = 0; i < len * 8; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (irq->config == VGIC_CONFIG_LEVEL && irq->soft_pending)
> +			value |= (1U << i);
> +		if (irq->config == VGIC_CONFIG_EDGE && irq->pending)
> +			value |= (1U << i);
> +
> +		vgic_put_irq(vcpu->kvm, irq);
> +	}
> +
> +	return value;
> +}
> +
> +static void vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu,
> +					  gpa_t addr, unsigned int len,
> +					  unsigned long val)
> +{
> +	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
> +	int i;
> +
> +	for (i = 0; i < len * 8; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		if (test_bit(i, &val)) {
> +			/* soft_pending is set irrespective of irq type
> +			 * (level or edge) to avoid dependency that VM should
> +			 * restore irq config before pending info.
> +			 */

nit: kernel commenting style

> +			irq->pending = true;
> +			irq->soft_pending = true;
> +			vgic_queue_irq_unlock(vcpu->kvm, irq);
> +		} else {
> +			irq->soft_pending = false;
> +			if (irq->config == VGIC_CONFIG_EDGE ||
> +			    (irq->config == VGIC_CONFIG_LEVEL &&
> +			    !irq->line_level))
> +				irq->pending = false;
> +			spin_unlock(&irq->irq_lock);
> +		}
> +
> +		vgic_put_irq(vcpu->kvm, irq);
> +	}
> +}
> +
>  /* We want to avoid outer shareable. */
>  u64 vgic_sanitise_shareability(u64 field)
>  {
> @@ -356,7 +416,7 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>   * We take some special care here to fix the calculation of the register
>   * offset.
>   */
> -#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, bpi, acc)	\
> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, ur, uw, bpi, acc) \
>  	{								\
>  		.reg_offset = off,					\
>  		.bits_per_irq = bpi,					\
> @@ -371,6 +431,8 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>  		.access_flags = acc,					\
>  		.read = rd,						\
>  		.write = wr,						\
> +		.uaccess_read = ur,					\
> +		.uaccess_write = uw,					\
>  	}
>  
>  static const struct vgic_register_region vgic_v3_dist_registers[] = {
> @@ -378,40 +440,42 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>  		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
> -		vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
> +		vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
> -		vgic_mmio_read_enable, vgic_mmio_write_senable, 1,
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, NULL, NULL, 1,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
> -		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, NULL, NULL, 1,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
> -		vgic_mmio_read_pending, vgic_mmio_write_spending, 1,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending,
> +		vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 1,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
> -		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
> -		vgic_mmio_read_active, vgic_mmio_write_sactive, 1,
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, NULL, NULL, 1,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
> -		vgic_mmio_read_active, vgic_mmio_write_cactive, 1,
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, NULL, NULL, 1,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
> -		vgic_mmio_read_priority, vgic_mmio_write_priority, 8,
> -		VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, NULL, NULL,
> +		8, VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 8,
>  		VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
> -		vgic_mmio_read_config, vgic_mmio_write_config, 2,
> +		vgic_mmio_read_config, vgic_mmio_write_config, NULL, NULL, 2,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
> -		vgic_mmio_read_irouter, vgic_mmio_write_irouter, 64,
> +		vgic_mmio_read_irouter, vgic_mmio_write_irouter, NULL, NULL, 64,
>  		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>  		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48,
> @@ -449,11 +513,13 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>  	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
>  		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4,
>  		VGIC_ACCESS_32bit),
> -	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
> -		vgic_mmio_read_pending, vgic_mmio_write_spending, 4,
> +	REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ISPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending,
> +		vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 4,
>  		VGIC_ACCESS_32bit),
> -	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
> -		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4,
> +	REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ICPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
>  		vgic_mmio_read_active, vgic_mmio_write_sactive, 4,
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index ebe1b9f..d5f3ee2 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -484,6 +484,74 @@ static bool check_region(const struct kvm *kvm,
>  	return false;
>  }
>  
> +static const struct vgic_register_region *
> +vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev,
> +		     gpa_t addr, int len)
> +{
> +	const struct vgic_register_region *region;
> +
> +	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
> +				       addr - iodev->base_addr);
> +	if (!region || !check_region(vcpu->kvm, region, addr, len))
> +		return NULL;
> +
> +	return region;
> +}
> +
> +static int vgic_uaccess_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
> +			     gpa_t addr, u32 *val)
> +{
> +	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
> +	const struct vgic_register_region *region;
> +	struct kvm_vcpu *r_vcpu;
> +
> +	region = vgic_get_mmio_region(vcpu, iodev, addr, sizeof(u32));
> +	if (!region) {
> +		*val = 0;
> +		return 0;
> +	}
> +
> +	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
> +	if (region->uaccess_read)
> +		*val = region->uaccess_read(r_vcpu, addr, sizeof(u32));
> +	else
> +		*val = region->read(r_vcpu, addr, sizeof(u32));
> +
> +	return 0;
> +}
> +
> +static int vgic_uaccess_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
> +			      gpa_t addr, const u32 *val)
> +{
> +	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
> +	const struct vgic_register_region *region;
> +	struct kvm_vcpu *r_vcpu;
> +
> +	region = vgic_get_mmio_region(vcpu, iodev, addr, sizeof(u32));
> +	if (!region)
> +		return 0;
> +
> +	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
> +	if (region->uaccess_write)
> +		region->uaccess_write(r_vcpu, addr, sizeof(u32), *val);
> +	else
> +		region->write(r_vcpu, addr, sizeof(u32), *val);
> +
> +	return 0;
> +}
> +
> +/*
> + * Userland access to VGIC registers.
> + */
> +int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
> +		 bool is_write, int offset, u32 *val)
> +{
> +	if (is_write)
> +		return vgic_uaccess_write(vcpu, &dev->dev, offset, val);
> +	else
> +		return vgic_uaccess_read(vcpu, &dev->dev, offset, val);
> +}
> +
>  static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>  			      gpa_t addr, int len, void *val)
>  {
> @@ -491,9 +559,8 @@ static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>  	const struct vgic_register_region *region;
>  	unsigned long data = 0;
>  
> -	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
> -				       addr - iodev->base_addr);
> -	if (!region || !check_region(vcpu->kvm, region, addr, len)) {
> +	region = vgic_get_mmio_region(vcpu, iodev, addr, len);
> +	if (!region) {
>  		memset(val, 0, len);
>  		return 0;
>  	}
> @@ -524,9 +591,8 @@ static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>  	const struct vgic_register_region *region;
>  	unsigned long data = vgic_data_mmio_bus_to_host(val, len);
>  
> -	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
> -				       addr - iodev->base_addr);
> -	if (!region || !check_region(vcpu->kvm, region, addr, len))
> +	region = vgic_get_mmio_region(vcpu, iodev, addr, len);
> +	if (!region)
>  		return 0;
>  
>  	switch (iodev->iodev_type) {
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
> index 84961b4..7b30296 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -34,6 +34,10 @@ struct vgic_register_region {
>  				  gpa_t addr, unsigned int len,
>  				  unsigned long val);
>  	};
> +	unsigned long (*uaccess_read)(struct kvm_vcpu *vcpu, gpa_t addr,
> +				      unsigned int len);
> +	void (*uaccess_write)(struct kvm_vcpu *vcpu, gpa_t addr,
> +			      unsigned int len, unsigned long val);
>  };
>  
>  extern struct kvm_io_device_ops kvm_io_gic_ops;
> @@ -86,6 +90,18 @@ struct vgic_register_region {
>  		.write = wr,						\
>  	}
>  
> +#define REGISTER_DESC_WITH_LENGTH_UACCESS(off, rd, wr, urd, uwr, length, acc) \
> +	{								\
> +		.reg_offset = off,					\
> +		.bits_per_irq = 0,					\
> +		.len = length,						\
> +		.access_flags = acc,					\
> +		.read = rd,						\
> +		.write = wr,						\
> +		.uaccess_read = urd,					\
> +		.uaccess_write = uwr,					\
> +	}
> +
>  int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  				  struct vgic_register_region *reg_desc,
>  				  struct vgic_io_device *region,
> @@ -158,6 +174,9 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>  			    gpa_t addr, unsigned int len,
>  			    unsigned long val);
>  
> +int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
> +		 bool is_write, int offset, u32 *val);
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
>  unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
> -- 
> 1.9.1
> 

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 02/11] arm/arm64: vgic: Add distributor and redistributor access
  2016-11-23 13:01   ` vijay.kilari at gmail.com
@ 2016-11-28 13:08     ` Christoffer Dall
  -1 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-28 13:08 UTC (permalink / raw)
  To: vijay.kilari; +Cc: marc.zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

On Wed, Nov 23, 2016 at 06:31:49PM +0530, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> 
> VGICv3 Distributor and Redistributor registers are accessed using
> KVM_DEV_ARM_VGIC_GRP_DIST_REGS and KVM_DEV_ARM_VGIC_GRP_REDIST_REGS
> with KVM_SET_DEVICE_ATTR and KVM_GET_DEVICE_ATTR ioctls.
> These registers are accessed as 32-bit and cpu mpidr
> value passed along with register offset is used to identify the
> cpu for redistributor registers access.
> 
> The version of VGIC v3 specification is define here
> Documentation/virtual/kvm/devices/arm-vgic-v3.txt
> 
> Also update arch/arm/include/uapi/asm/kvm.h to compile for
> AArch32 mode.
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> ---
>  arch/arm/include/uapi/asm/kvm.h     |   4 +
>  arch/arm64/include/uapi/asm/kvm.h   |   4 +
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 144 ++++++++++++++++++++++++++++++++++--
>  virt/kvm/arm/vgic/vgic-mmio-v2.c    |  16 +---
>  virt/kvm/arm/vgic/vgic-mmio-v3.c    |  72 ++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.c       |  22 ++++++
>  virt/kvm/arm/vgic/vgic-mmio.h       |   4 +
>  virt/kvm/arm/vgic/vgic.h            |  49 +++++++++++-
>  8 files changed, 292 insertions(+), 23 deletions(-)
> 
> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
> index af05f8e..0ae6035 100644
> --- a/arch/arm/include/uapi/asm/kvm.h
> +++ b/arch/arm/include/uapi/asm/kvm.h
> @@ -181,10 +181,14 @@ struct kvm_arch_memory_slot {
>  #define KVM_DEV_ARM_VGIC_GRP_CPU_REGS	2
>  #define   KVM_DEV_ARM_VGIC_CPUID_SHIFT	32
>  #define   KVM_DEV_ARM_VGIC_CPUID_MASK	(0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
> +#define   KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32
> +#define   KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \
> +			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
>  #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
>  #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
>  #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
>  #define KVM_DEV_ARM_VGIC_GRP_CTRL       4
> +#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
>  
>  /* KVM_IRQ_LINE irq field index values */
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 3051f86..56dc08d 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -201,10 +201,14 @@ struct kvm_arch_memory_slot {
>  #define KVM_DEV_ARM_VGIC_GRP_CPU_REGS	2
>  #define   KVM_DEV_ARM_VGIC_CPUID_SHIFT	32
>  #define   KVM_DEV_ARM_VGIC_CPUID_MASK	(0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
> +#define   KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32
> +#define   KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \
> +			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
>  #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
>  #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
>  #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
> +#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
>  
>  /* Device Control API on vcpu fd */
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index fbe87a6..bc7de95 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -235,7 +235,7 @@ struct vgic_reg_attr {
>  	gpa_t addr;
>  };
>  
> -static int parse_vgic_v2_attr(struct kvm_device *dev,
> +static int vgic_v2_parse_attr(struct kvm_device *dev,
>  			      struct kvm_device_attr *attr,
>  			      struct vgic_reg_attr *reg_attr)
>  {
> @@ -292,14 +292,14 @@ static bool lock_all_vcpus(struct kvm *kvm)
>  }
>  
>  /**
> - * vgic_attr_regs_access_v2 - allows user space to access VGIC v2 state
> + * vgic_v2_attr_regs_access - allows user space to access VGIC v2 state
>   *
>   * @dev:      kvm device handle
>   * @attr:     kvm device attribute
>   * @reg:      address the value is read or written
>   * @is_write: true if userspace is writing a register
>   */
> -static int vgic_attr_regs_access_v2(struct kvm_device *dev,
> +static int vgic_v2_attr_regs_access(struct kvm_device *dev,
>  				    struct kvm_device_attr *attr,
>  				    u32 *reg, bool is_write)
>  {
> @@ -308,7 +308,7 @@ static int vgic_attr_regs_access_v2(struct kvm_device *dev,
>  	struct kvm_vcpu *vcpu;
>  	int ret;
>  
> -	ret = parse_vgic_v2_attr(dev, attr, &reg_attr);
> +	ret = vgic_v2_parse_attr(dev, attr, &reg_attr);
>  	if (ret)
>  		return ret;
>  
> @@ -362,7 +362,7 @@ static int vgic_v2_set_attr(struct kvm_device *dev,
>  		if (get_user(reg, uaddr))
>  			return -EFAULT;
>  
> -		return vgic_attr_regs_access_v2(dev, attr, &reg, true);
> +		return vgic_v2_attr_regs_access(dev, attr, &reg, true);
>  	}
>  	}
>  
> @@ -384,7 +384,7 @@ static int vgic_v2_get_attr(struct kvm_device *dev,
>  		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
>  		u32 reg = 0;
>  
> -		ret = vgic_attr_regs_access_v2(dev, attr, &reg, false);
> +		ret = vgic_v2_attr_regs_access(dev, attr, &reg, false);
>  		if (ret)
>  			return ret;
>  		return put_user(reg, uaddr);
> @@ -428,16 +428,141 @@ struct kvm_device_ops kvm_arm_vgic_v2_ops = {
>  	.has_attr = vgic_v2_has_attr,
>  };
>  
> +static int vgic_v3_parse_attr(struct kvm_device *dev,
> +			      struct kvm_device_attr *attr,
> +			      struct vgic_reg_attr *reg_attr)
> +{
> +	unsigned long vgic_mpidr, mpidr_reg;
> +
> +	vgic_mpidr = (attr->attr & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) >>
> +		      KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT;
> +
> +	mpidr_reg = VGIC_TO_MPIDR(vgic_mpidr);
> +	reg_attr->vcpu = kvm_mpidr_to_vcpu(dev->kvm, mpidr_reg);
> +	if (!reg_attr->vcpu)
> +		return -EINVAL;
> +
> +	reg_attr->addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
> +
> +	return 0;
> +}
> +
> +/*
> + * vgic_v3_attr_regs_access - allows user space to access VGIC v3 state
> + *
> + * @dev:      kvm device handle
> + * @attr:     kvm device attribute
> + * @reg:      address the value is read or written
> + * @is_write: true if userspace is writing a register
> + */
> +static int vgic_v3_attr_regs_access(struct kvm_device *dev,
> +				    struct kvm_device_attr *attr,
> +				    u64 *reg, bool is_write)
> +{
> +	struct vgic_reg_attr reg_attr;
> +	gpa_t addr;
> +	struct kvm_vcpu *vcpu;
> +	int ret;
> +	u32 tmp32;
> +
> +	ret = vgic_v3_parse_attr(dev, attr, &reg_attr);
> +	if (ret)
> +		return ret;
> +
> +	vcpu = reg_attr.vcpu;
> +	addr = reg_attr.addr;
> +
> +	mutex_lock(&dev->kvm->lock);
> +
> +	if (unlikely(!vgic_initialized(dev->kvm))) {
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	if (!lock_all_vcpus(dev->kvm)) {
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> +		if (is_write)
> +			tmp32 = *reg;
> +
> +		ret = vgic_v3_dist_uaccess(vcpu, is_write, addr, &tmp32);
> +		if (!is_write)
> +			*reg = tmp32;
> +		break;
> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
> +		if (is_write)
> +			tmp32 = *reg;
> +
> +		ret = vgic_v3_redist_uaccess(vcpu, is_write, addr, &tmp32);
> +		if (!is_write)
> +			*reg = tmp32;
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	unlock_all_vcpus(dev->kvm);
> +out:
> +	mutex_unlock(&dev->kvm->lock);
> +	return ret;
> +}
> +
>  static int vgic_v3_set_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
> -	return vgic_set_common_attr(dev, attr);
> +	int ret;
> +
> +	ret = vgic_set_common_attr(dev, attr);
> +	if (ret != -ENXIO)
> +		return ret;
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: {
> +		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
> +		u32 tmp32;
> +		u64 reg;
> +
> +		if (get_user(tmp32, uaddr))
> +			return -EFAULT;
> +
> +		reg = tmp32;
> +		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
> +	}
> +	}
> +	return -ENXIO;
>  }
>  
>  static int vgic_v3_get_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
> -	return vgic_get_common_attr(dev, attr);
> +	int ret;
> +
> +	ret = vgic_get_common_attr(dev, attr);
> +	if (ret != -ENXIO)
> +		return ret;
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: {
> +		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
> +		u64 reg;
> +		u32 tmp32;
> +
> +		ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
> +		if (ret)
> +			return ret;
> +		tmp32 = reg;
> +		return put_user(tmp32, uaddr);
> +	}
> +	}
> +
> +	return -ENXIO;
>  }
>  
>  static int vgic_v3_has_attr(struct kvm_device *dev,
> @@ -451,6 +576,9 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
>  			return 0;
>  		}
>  		break;
> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
> +		return vgic_v3_has_attr_regs(dev, attr);
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>  		return 0;
>  	case KVM_DEV_ARM_VGIC_GRP_CTRL:
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 0b32f40..2cb04b7 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -368,10 +368,9 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
>  
>  int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>  {
> -	int nr_irqs = dev->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>  	const struct vgic_register_region *regions;
>  	gpa_t addr;
> -	int nr_regions, i, len;
> +	int nr_regions;
>  
>  	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
>  
> @@ -392,18 +391,7 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>  	if (addr & 3)
>  		return -ENXIO;
>  
> -	for (i = 0; i < nr_regions; i++) {
> -		if (regions[i].bits_per_irq)
> -			len = (regions[i].bits_per_irq * nr_irqs) / 8;
> -		else
> -			len = regions[i].len;
> -
> -		if (regions[i].reg_offset <= addr &&
> -		    regions[i].reg_offset + len > addr)
> -			return 0;
> -	}
> -
> -	return -ENXIO;
> +	return vgic_validate_mmio_region_addr(dev, regions, nr_regions, addr);
>  }
>  
>  int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index 8e76d04..2a7cd62 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -18,6 +18,8 @@
>  #include <kvm/arm_vgic.h>
>  
>  #include <asm/kvm_emulate.h>
> +#include <asm/kvm_arm.h>
> +#include <asm/kvm_mmu.h>
>  
>  #include "vgic.h"
>  #include "vgic-mmio.h"
> @@ -439,6 +441,9 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>  	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>  		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16,
>  		VGIC_ACCESS_32bit),
> +	REGISTER_DESC_WITH_LENGTH(GICD_STATUSR,
> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 4,
> +		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>  		vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
>  		VGIC_ACCESS_32bit),
> @@ -486,12 +491,18 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>  	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
>  		vgic_mmio_read_v3r_ctlr, vgic_mmio_write_v3r_ctlr, 4,
>  		VGIC_ACCESS_32bit),
> +	REGISTER_DESC_WITH_LENGTH(GICR_STATUSR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
> +		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
>  		vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
>  		vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8,
>  		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
> +	REGISTER_DESC_WITH_LENGTH(GICR_WAKER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
> +		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
>  		vgic_mmio_read_propbase, vgic_mmio_write_propbase, 8,
>  		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
> @@ -612,6 +623,34 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
>  	return ret;
>  }
>  
> +int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
> +{
> +	const struct vgic_register_region *regions;
> +	gpa_t addr;
> +	int nr_regions;
> +
> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> +		regions = vgic_v3_dist_registers;
> +		nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
> +		break;
> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:{
> +		regions = vgic_v3_rdbase_registers;
> +		nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
> +		break;
> +	}
> +	default:
> +		return -ENXIO;
> +	}
> +
> +	/* We only support aligned 32-bit accesses. */
> +	if (addr & 3)
> +		return -ENXIO;
> +
> +	return vgic_validate_mmio_region_addr(dev, regions, nr_regions, addr);
> +}
>  /*
>   * Compare a given affinity (level 1-3 and a level 0 mask, from the SGI
>   * generation register ICC_SGI1R_EL1) with a given VCPU.
> @@ -718,3 +757,36 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
>  		vgic_put_irq(vcpu->kvm, irq);
>  	}
>  }
> +
> +int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +			 int offset, u32 *val)
> +{
> +	struct vgic_io_device dev = {
> +		.regions = vgic_v3_dist_registers,
> +		.nr_regions = ARRAY_SIZE(vgic_v3_dist_registers),
> +	};
> +
> +	return vgic_uaccess(vcpu, &dev, is_write, offset, val);
> +}
> +
> +int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +			   int offset, u32 *val)
> +{
> +	struct vgic_io_device rd_dev = {
> +		.regions = vgic_v3_rdbase_registers,
> +		.nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers),
> +	};
> +
> +	struct vgic_io_device sgi_dev = {
> +		.regions = vgic_v3_sgibase_registers,
> +		.nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers),
> +	};
> +
> +	/* SGI_base is the next 64K frame after RD_base */
> +	if (offset >= SZ_64K)
> +		return vgic_uaccess(vcpu, &sgi_dev, is_write,
> +				    offset - SZ_64K, val);
> +	else
> +		return vgic_uaccess(vcpu, &rd_dev, is_write,
> +				    offset, val);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index d5f3ee2..0d1bc98 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -394,6 +394,28 @@ static int match_region(const void *key, const void *elt)
>  		       sizeof(region[0]), match_region);
>  }
>  
> +/* Check if address falls within the region */
> +int vgic_validate_mmio_region_addr(struct kvm_device *dev,
> +				   const struct vgic_register_region *regions,
> +				   int nr_regions, gpa_t addr)
> +{
> +	int i, len;
> +	int nr_irqs = dev->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> +
> +	for (i = 0; i < nr_regions; i++) {
> +		if (regions[i].bits_per_irq)
> +			len = (regions[i].bits_per_irq * nr_irqs) / 8;
> +		else
> +			len = regions[i].len;
> +
> +		if (regions[i].reg_offset <= addr &&
> +		    regions[i].reg_offset + len > addr)
> +			return 0;
> +	}
> +
> +	return -ENXIO;
> +}
> +
>  /*
>   * kvm_mmio_read_buf() returns a value in a format where it can be converted
>   * to a byte array and be directly observed as the guest wanted it to appear
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
> index 7b30296..1cc7faf 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -177,6 +177,10 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>  int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>  		 bool is_write, int offset, u32 *val);
>  
> +int vgic_validate_mmio_region_addr(struct kvm_device *dev,
> +				   const struct vgic_register_region *regions,
> +				   int nr_regions, gpa_t addr);
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
>  unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 859f65c..91f58b2 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -30,6 +30,49 @@
>  
>  #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
>  
> +#define VGIC_AFFINITY_0_SHIFT 0
> +#define VGIC_AFFINITY_0_MASK (0xffUL << VGIC_AFFINITY_0_SHIFT)
> +#define VGIC_AFFINITY_1_SHIFT 8
> +#define VGIC_AFFINITY_1_MASK (0xffUL << VGIC_AFFINITY_1_SHIFT)
> +#define VGIC_AFFINITY_2_SHIFT 16
> +#define VGIC_AFFINITY_2_MASK (0xffUL << VGIC_AFFINITY_2_SHIFT)
> +#define VGIC_AFFINITY_3_SHIFT 24
> +#define VGIC_AFFINITY_3_MASK (0xffUL << VGIC_AFFINITY_3_SHIFT)
> +
> +#define VGIC_AFFINITY_LEVEL(reg, level) \
> +	((((reg) & VGIC_AFFINITY_## level ##_MASK) \
> +	>> VGIC_AFFINITY_## level ##_SHIFT) << MPIDR_LEVEL_SHIFT(level))
> +
> +/*
> + * The Userspace encodes the affinity differently from the MPIDR,
> + * Below macro converts vgic userspace format to MPIDR reg format.
> + */
> +#define VGIC_TO_MPIDR(val) (VGIC_AFFINITY_LEVEL(val, 0) | \
> +			    VGIC_AFFINITY_LEVEL(val, 1) | \
> +			    VGIC_AFFINITY_LEVEL(val, 2) | \
> +			    VGIC_AFFINITY_LEVEL(val, 3))
> +
> +/*
> + * As per Documentation/virtual/kvm/devices/arm-vgic-v3.txt,
> + * below macros are defined for CPUREG encoding.
> + */
> +#define KVM_REG_ARM_VGIC_SYSREG_OP0_MASK   0x000000000000c000
> +#define KVM_REG_ARM_VGIC_SYSREG_OP0_SHIFT  14
> +#define KVM_REG_ARM_VGIC_SYSREG_OP1_MASK   0x0000000000003800
> +#define KVM_REG_ARM_VGIC_SYSREG_OP1_SHIFT  11
> +#define KVM_REG_ARM_VGIC_SYSREG_CRN_MASK   0x0000000000000780
> +#define KVM_REG_ARM_VGIC_SYSREG_CRN_SHIFT  7
> +#define KVM_REG_ARM_VGIC_SYSREG_CRM_MASK   0x0000000000000078
> +#define KVM_REG_ARM_VGIC_SYSREG_CRM_SHIFT  3
> +#define KVM_REG_ARM_VGIC_SYSREG_OP2_MASK   0x0000000000000007
> +#define KVM_REG_ARM_VGIC_SYSREG_OP2_SHIFT  0
> +
> +#define KVM_DEV_ARM_VGIC_SYSREG_MASK (KVM_REG_ARM_VGIC_SYSREG_OP0_MASK | \
> +				      KVM_REG_ARM_VGIC_SYSREG_OP1_MASK | \
> +				      KVM_REG_ARM_VGIC_SYSREG_CRN_MASK | \
> +				      KVM_REG_ARM_VGIC_SYSREG_CRM_MASK | \
> +				      KVM_REG_ARM_VGIC_SYSREG_OP2_MASK)
> +
>  struct vgic_vmcr {
>  	u32	ctlr;
>  	u32	abpr;
> @@ -89,7 +132,11 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq)
>  int kvm_vgic_register_its_device(void);
>  void vgic_enable_lpis(struct kvm_vcpu *vcpu);
>  int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi);
> -
> +int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
> +int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +			 int offset, u32 *val);
> +int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +			 int offset, u32 *val);
>  int kvm_register_vgic_device(unsigned long type);
>  int vgic_lazy_init(struct kvm *kvm);
>  int vgic_init(struct kvm *kvm);
> -- 
> 1.9.1
> 

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 02/11] arm/arm64: vgic: Add distributor and redistributor access
@ 2016-11-28 13:08     ` Christoffer Dall
  0 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-28 13:08 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 23, 2016 at 06:31:49PM +0530, vijay.kilari at gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> 
> VGICv3 Distributor and Redistributor registers are accessed using
> KVM_DEV_ARM_VGIC_GRP_DIST_REGS and KVM_DEV_ARM_VGIC_GRP_REDIST_REGS
> with KVM_SET_DEVICE_ATTR and KVM_GET_DEVICE_ATTR ioctls.
> These registers are accessed as 32-bit and cpu mpidr
> value passed along with register offset is used to identify the
> cpu for redistributor registers access.
> 
> The version of VGIC v3 specification is define here
> Documentation/virtual/kvm/devices/arm-vgic-v3.txt
> 
> Also update arch/arm/include/uapi/asm/kvm.h to compile for
> AArch32 mode.
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> ---
>  arch/arm/include/uapi/asm/kvm.h     |   4 +
>  arch/arm64/include/uapi/asm/kvm.h   |   4 +
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 144 ++++++++++++++++++++++++++++++++++--
>  virt/kvm/arm/vgic/vgic-mmio-v2.c    |  16 +---
>  virt/kvm/arm/vgic/vgic-mmio-v3.c    |  72 ++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.c       |  22 ++++++
>  virt/kvm/arm/vgic/vgic-mmio.h       |   4 +
>  virt/kvm/arm/vgic/vgic.h            |  49 +++++++++++-
>  8 files changed, 292 insertions(+), 23 deletions(-)
> 
> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
> index af05f8e..0ae6035 100644
> --- a/arch/arm/include/uapi/asm/kvm.h
> +++ b/arch/arm/include/uapi/asm/kvm.h
> @@ -181,10 +181,14 @@ struct kvm_arch_memory_slot {
>  #define KVM_DEV_ARM_VGIC_GRP_CPU_REGS	2
>  #define   KVM_DEV_ARM_VGIC_CPUID_SHIFT	32
>  #define   KVM_DEV_ARM_VGIC_CPUID_MASK	(0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
> +#define   KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32
> +#define   KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \
> +			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
>  #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
>  #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
>  #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
>  #define KVM_DEV_ARM_VGIC_GRP_CTRL       4
> +#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
>  
>  /* KVM_IRQ_LINE irq field index values */
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 3051f86..56dc08d 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -201,10 +201,14 @@ struct kvm_arch_memory_slot {
>  #define KVM_DEV_ARM_VGIC_GRP_CPU_REGS	2
>  #define   KVM_DEV_ARM_VGIC_CPUID_SHIFT	32
>  #define   KVM_DEV_ARM_VGIC_CPUID_MASK	(0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
> +#define   KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32
> +#define   KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \
> +			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
>  #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
>  #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
>  #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
> +#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
>  
>  /* Device Control API on vcpu fd */
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index fbe87a6..bc7de95 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -235,7 +235,7 @@ struct vgic_reg_attr {
>  	gpa_t addr;
>  };
>  
> -static int parse_vgic_v2_attr(struct kvm_device *dev,
> +static int vgic_v2_parse_attr(struct kvm_device *dev,
>  			      struct kvm_device_attr *attr,
>  			      struct vgic_reg_attr *reg_attr)
>  {
> @@ -292,14 +292,14 @@ static bool lock_all_vcpus(struct kvm *kvm)
>  }
>  
>  /**
> - * vgic_attr_regs_access_v2 - allows user space to access VGIC v2 state
> + * vgic_v2_attr_regs_access - allows user space to access VGIC v2 state
>   *
>   * @dev:      kvm device handle
>   * @attr:     kvm device attribute
>   * @reg:      address the value is read or written
>   * @is_write: true if userspace is writing a register
>   */
> -static int vgic_attr_regs_access_v2(struct kvm_device *dev,
> +static int vgic_v2_attr_regs_access(struct kvm_device *dev,
>  				    struct kvm_device_attr *attr,
>  				    u32 *reg, bool is_write)
>  {
> @@ -308,7 +308,7 @@ static int vgic_attr_regs_access_v2(struct kvm_device *dev,
>  	struct kvm_vcpu *vcpu;
>  	int ret;
>  
> -	ret = parse_vgic_v2_attr(dev, attr, &reg_attr);
> +	ret = vgic_v2_parse_attr(dev, attr, &reg_attr);
>  	if (ret)
>  		return ret;
>  
> @@ -362,7 +362,7 @@ static int vgic_v2_set_attr(struct kvm_device *dev,
>  		if (get_user(reg, uaddr))
>  			return -EFAULT;
>  
> -		return vgic_attr_regs_access_v2(dev, attr, &reg, true);
> +		return vgic_v2_attr_regs_access(dev, attr, &reg, true);
>  	}
>  	}
>  
> @@ -384,7 +384,7 @@ static int vgic_v2_get_attr(struct kvm_device *dev,
>  		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
>  		u32 reg = 0;
>  
> -		ret = vgic_attr_regs_access_v2(dev, attr, &reg, false);
> +		ret = vgic_v2_attr_regs_access(dev, attr, &reg, false);
>  		if (ret)
>  			return ret;
>  		return put_user(reg, uaddr);
> @@ -428,16 +428,141 @@ struct kvm_device_ops kvm_arm_vgic_v2_ops = {
>  	.has_attr = vgic_v2_has_attr,
>  };
>  
> +static int vgic_v3_parse_attr(struct kvm_device *dev,
> +			      struct kvm_device_attr *attr,
> +			      struct vgic_reg_attr *reg_attr)
> +{
> +	unsigned long vgic_mpidr, mpidr_reg;
> +
> +	vgic_mpidr = (attr->attr & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) >>
> +		      KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT;
> +
> +	mpidr_reg = VGIC_TO_MPIDR(vgic_mpidr);
> +	reg_attr->vcpu = kvm_mpidr_to_vcpu(dev->kvm, mpidr_reg);
> +	if (!reg_attr->vcpu)
> +		return -EINVAL;
> +
> +	reg_attr->addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
> +
> +	return 0;
> +}
> +
> +/*
> + * vgic_v3_attr_regs_access - allows user space to access VGIC v3 state
> + *
> + * @dev:      kvm device handle
> + * @attr:     kvm device attribute
> + * @reg:      address the value is read or written
> + * @is_write: true if userspace is writing a register
> + */
> +static int vgic_v3_attr_regs_access(struct kvm_device *dev,
> +				    struct kvm_device_attr *attr,
> +				    u64 *reg, bool is_write)
> +{
> +	struct vgic_reg_attr reg_attr;
> +	gpa_t addr;
> +	struct kvm_vcpu *vcpu;
> +	int ret;
> +	u32 tmp32;
> +
> +	ret = vgic_v3_parse_attr(dev, attr, &reg_attr);
> +	if (ret)
> +		return ret;
> +
> +	vcpu = reg_attr.vcpu;
> +	addr = reg_attr.addr;
> +
> +	mutex_lock(&dev->kvm->lock);
> +
> +	if (unlikely(!vgic_initialized(dev->kvm))) {
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	if (!lock_all_vcpus(dev->kvm)) {
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> +		if (is_write)
> +			tmp32 = *reg;
> +
> +		ret = vgic_v3_dist_uaccess(vcpu, is_write, addr, &tmp32);
> +		if (!is_write)
> +			*reg = tmp32;
> +		break;
> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
> +		if (is_write)
> +			tmp32 = *reg;
> +
> +		ret = vgic_v3_redist_uaccess(vcpu, is_write, addr, &tmp32);
> +		if (!is_write)
> +			*reg = tmp32;
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	unlock_all_vcpus(dev->kvm);
> +out:
> +	mutex_unlock(&dev->kvm->lock);
> +	return ret;
> +}
> +
>  static int vgic_v3_set_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
> -	return vgic_set_common_attr(dev, attr);
> +	int ret;
> +
> +	ret = vgic_set_common_attr(dev, attr);
> +	if (ret != -ENXIO)
> +		return ret;
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: {
> +		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
> +		u32 tmp32;
> +		u64 reg;
> +
> +		if (get_user(tmp32, uaddr))
> +			return -EFAULT;
> +
> +		reg = tmp32;
> +		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
> +	}
> +	}
> +	return -ENXIO;
>  }
>  
>  static int vgic_v3_get_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
> -	return vgic_get_common_attr(dev, attr);
> +	int ret;
> +
> +	ret = vgic_get_common_attr(dev, attr);
> +	if (ret != -ENXIO)
> +		return ret;
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: {
> +		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
> +		u64 reg;
> +		u32 tmp32;
> +
> +		ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
> +		if (ret)
> +			return ret;
> +		tmp32 = reg;
> +		return put_user(tmp32, uaddr);
> +	}
> +	}
> +
> +	return -ENXIO;
>  }
>  
>  static int vgic_v3_has_attr(struct kvm_device *dev,
> @@ -451,6 +576,9 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
>  			return 0;
>  		}
>  		break;
> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
> +		return vgic_v3_has_attr_regs(dev, attr);
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>  		return 0;
>  	case KVM_DEV_ARM_VGIC_GRP_CTRL:
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 0b32f40..2cb04b7 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -368,10 +368,9 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
>  
>  int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>  {
> -	int nr_irqs = dev->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>  	const struct vgic_register_region *regions;
>  	gpa_t addr;
> -	int nr_regions, i, len;
> +	int nr_regions;
>  
>  	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
>  
> @@ -392,18 +391,7 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>  	if (addr & 3)
>  		return -ENXIO;
>  
> -	for (i = 0; i < nr_regions; i++) {
> -		if (regions[i].bits_per_irq)
> -			len = (regions[i].bits_per_irq * nr_irqs) / 8;
> -		else
> -			len = regions[i].len;
> -
> -		if (regions[i].reg_offset <= addr &&
> -		    regions[i].reg_offset + len > addr)
> -			return 0;
> -	}
> -
> -	return -ENXIO;
> +	return vgic_validate_mmio_region_addr(dev, regions, nr_regions, addr);
>  }
>  
>  int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index 8e76d04..2a7cd62 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -18,6 +18,8 @@
>  #include <kvm/arm_vgic.h>
>  
>  #include <asm/kvm_emulate.h>
> +#include <asm/kvm_arm.h>
> +#include <asm/kvm_mmu.h>
>  
>  #include "vgic.h"
>  #include "vgic-mmio.h"
> @@ -439,6 +441,9 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>  	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>  		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16,
>  		VGIC_ACCESS_32bit),
> +	REGISTER_DESC_WITH_LENGTH(GICD_STATUSR,
> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 4,
> +		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>  		vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
>  		VGIC_ACCESS_32bit),
> @@ -486,12 +491,18 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>  	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
>  		vgic_mmio_read_v3r_ctlr, vgic_mmio_write_v3r_ctlr, 4,
>  		VGIC_ACCESS_32bit),
> +	REGISTER_DESC_WITH_LENGTH(GICR_STATUSR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
> +		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
>  		vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
>  		vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8,
>  		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
> +	REGISTER_DESC_WITH_LENGTH(GICR_WAKER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
> +		VGIC_ACCESS_32bit),
>  	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
>  		vgic_mmio_read_propbase, vgic_mmio_write_propbase, 8,
>  		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
> @@ -612,6 +623,34 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
>  	return ret;
>  }
>  
> +int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
> +{
> +	const struct vgic_register_region *regions;
> +	gpa_t addr;
> +	int nr_regions;
> +
> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> +		regions = vgic_v3_dist_registers;
> +		nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
> +		break;
> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:{
> +		regions = vgic_v3_rdbase_registers;
> +		nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
> +		break;
> +	}
> +	default:
> +		return -ENXIO;
> +	}
> +
> +	/* We only support aligned 32-bit accesses. */
> +	if (addr & 3)
> +		return -ENXIO;
> +
> +	return vgic_validate_mmio_region_addr(dev, regions, nr_regions, addr);
> +}
>  /*
>   * Compare a given affinity (level 1-3 and a level 0 mask, from the SGI
>   * generation register ICC_SGI1R_EL1) with a given VCPU.
> @@ -718,3 +757,36 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
>  		vgic_put_irq(vcpu->kvm, irq);
>  	}
>  }
> +
> +int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +			 int offset, u32 *val)
> +{
> +	struct vgic_io_device dev = {
> +		.regions = vgic_v3_dist_registers,
> +		.nr_regions = ARRAY_SIZE(vgic_v3_dist_registers),
> +	};
> +
> +	return vgic_uaccess(vcpu, &dev, is_write, offset, val);
> +}
> +
> +int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +			   int offset, u32 *val)
> +{
> +	struct vgic_io_device rd_dev = {
> +		.regions = vgic_v3_rdbase_registers,
> +		.nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers),
> +	};
> +
> +	struct vgic_io_device sgi_dev = {
> +		.regions = vgic_v3_sgibase_registers,
> +		.nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers),
> +	};
> +
> +	/* SGI_base is the next 64K frame after RD_base */
> +	if (offset >= SZ_64K)
> +		return vgic_uaccess(vcpu, &sgi_dev, is_write,
> +				    offset - SZ_64K, val);
> +	else
> +		return vgic_uaccess(vcpu, &rd_dev, is_write,
> +				    offset, val);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index d5f3ee2..0d1bc98 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -394,6 +394,28 @@ static int match_region(const void *key, const void *elt)
>  		       sizeof(region[0]), match_region);
>  }
>  
> +/* Check if address falls within the region */
> +int vgic_validate_mmio_region_addr(struct kvm_device *dev,
> +				   const struct vgic_register_region *regions,
> +				   int nr_regions, gpa_t addr)
> +{
> +	int i, len;
> +	int nr_irqs = dev->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> +
> +	for (i = 0; i < nr_regions; i++) {
> +		if (regions[i].bits_per_irq)
> +			len = (regions[i].bits_per_irq * nr_irqs) / 8;
> +		else
> +			len = regions[i].len;
> +
> +		if (regions[i].reg_offset <= addr &&
> +		    regions[i].reg_offset + len > addr)
> +			return 0;
> +	}
> +
> +	return -ENXIO;
> +}
> +
>  /*
>   * kvm_mmio_read_buf() returns a value in a format where it can be converted
>   * to a byte array and be directly observed as the guest wanted it to appear
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
> index 7b30296..1cc7faf 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -177,6 +177,10 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>  int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>  		 bool is_write, int offset, u32 *val);
>  
> +int vgic_validate_mmio_region_addr(struct kvm_device *dev,
> +				   const struct vgic_register_region *regions,
> +				   int nr_regions, gpa_t addr);
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
>  unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 859f65c..91f58b2 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -30,6 +30,49 @@
>  
>  #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
>  
> +#define VGIC_AFFINITY_0_SHIFT 0
> +#define VGIC_AFFINITY_0_MASK (0xffUL << VGIC_AFFINITY_0_SHIFT)
> +#define VGIC_AFFINITY_1_SHIFT 8
> +#define VGIC_AFFINITY_1_MASK (0xffUL << VGIC_AFFINITY_1_SHIFT)
> +#define VGIC_AFFINITY_2_SHIFT 16
> +#define VGIC_AFFINITY_2_MASK (0xffUL << VGIC_AFFINITY_2_SHIFT)
> +#define VGIC_AFFINITY_3_SHIFT 24
> +#define VGIC_AFFINITY_3_MASK (0xffUL << VGIC_AFFINITY_3_SHIFT)
> +
> +#define VGIC_AFFINITY_LEVEL(reg, level) \
> +	((((reg) & VGIC_AFFINITY_## level ##_MASK) \
> +	>> VGIC_AFFINITY_## level ##_SHIFT) << MPIDR_LEVEL_SHIFT(level))
> +
> +/*
> + * The Userspace encodes the affinity differently from the MPIDR,
> + * Below macro converts vgic userspace format to MPIDR reg format.
> + */
> +#define VGIC_TO_MPIDR(val) (VGIC_AFFINITY_LEVEL(val, 0) | \
> +			    VGIC_AFFINITY_LEVEL(val, 1) | \
> +			    VGIC_AFFINITY_LEVEL(val, 2) | \
> +			    VGIC_AFFINITY_LEVEL(val, 3))
> +
> +/*
> + * As per Documentation/virtual/kvm/devices/arm-vgic-v3.txt,
> + * below macros are defined for CPUREG encoding.
> + */
> +#define KVM_REG_ARM_VGIC_SYSREG_OP0_MASK   0x000000000000c000
> +#define KVM_REG_ARM_VGIC_SYSREG_OP0_SHIFT  14
> +#define KVM_REG_ARM_VGIC_SYSREG_OP1_MASK   0x0000000000003800
> +#define KVM_REG_ARM_VGIC_SYSREG_OP1_SHIFT  11
> +#define KVM_REG_ARM_VGIC_SYSREG_CRN_MASK   0x0000000000000780
> +#define KVM_REG_ARM_VGIC_SYSREG_CRN_SHIFT  7
> +#define KVM_REG_ARM_VGIC_SYSREG_CRM_MASK   0x0000000000000078
> +#define KVM_REG_ARM_VGIC_SYSREG_CRM_SHIFT  3
> +#define KVM_REG_ARM_VGIC_SYSREG_OP2_MASK   0x0000000000000007
> +#define KVM_REG_ARM_VGIC_SYSREG_OP2_SHIFT  0
> +
> +#define KVM_DEV_ARM_VGIC_SYSREG_MASK (KVM_REG_ARM_VGIC_SYSREG_OP0_MASK | \
> +				      KVM_REG_ARM_VGIC_SYSREG_OP1_MASK | \
> +				      KVM_REG_ARM_VGIC_SYSREG_CRN_MASK | \
> +				      KVM_REG_ARM_VGIC_SYSREG_CRM_MASK | \
> +				      KVM_REG_ARM_VGIC_SYSREG_OP2_MASK)
> +
>  struct vgic_vmcr {
>  	u32	ctlr;
>  	u32	abpr;
> @@ -89,7 +132,11 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq)
>  int kvm_vgic_register_its_device(void);
>  void vgic_enable_lpis(struct kvm_vcpu *vcpu);
>  int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi);
> -
> +int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
> +int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +			 int offset, u32 *val);
> +int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +			 int offset, u32 *val);
>  int kvm_register_vgic_device(unsigned long type);
>  int vgic_lazy_init(struct kvm *kvm);
>  int vgic_init(struct kvm *kvm);
> -- 
> 1.9.1
> 

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 05/11] arm/arm64: vgic: Introduce VENG0 and VENG1 fields to vmcr struct
  2016-11-23 13:01   ` vijay.kilari at gmail.com
@ 2016-11-28 14:28     ` Christoffer Dall
  -1 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-28 14:28 UTC (permalink / raw)
  To: vijay.kilari; +Cc: marc.zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

On Wed, Nov 23, 2016 at 06:31:52PM +0530, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> 
> ICC_VMCR_EL2 supports virtual access to ICC_IGRPEN1_EL1.Enable
> and ICC_IGRPEN0_EL1.Enable fields. Add grpen0 and grpen1 member
> variables to struct vmcr to support read and write of these fields.
> 
> Also refactor vgic_set_vmcr and vgic_get_vmcr() code.
> Drop ICH_VMCR_CTLR_SHIFT and ICH_VMCR_CTLR_MASK macros and instead
> use ICH_VMCR_EOI* and ICH_VMCR_CBPR* macros
> .
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> ---
>  include/linux/irqchip/arm-gic-v3.h |  2 --
>  virt/kvm/arm/vgic/vgic-mmio-v2.c   | 16 ----------------
>  virt/kvm/arm/vgic/vgic-mmio.c      | 16 ++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c        | 22 ++++++++++++++++++++--
>  virt/kvm/arm/vgic/vgic.h           |  5 +++++
>  5 files changed, 41 insertions(+), 20 deletions(-)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index b4f8287..406fc3e 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -404,8 +404,6 @@
>  #define ICH_HCR_EN			(1 << 0)
>  #define ICH_HCR_UIE			(1 << 1)
>  
> -#define ICH_VMCR_CTLR_SHIFT		0
> -#define ICH_VMCR_CTLR_MASK		(0x21f << ICH_VMCR_CTLR_SHIFT)
>  #define ICH_VMCR_CBPR_SHIFT		4
>  #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
>  #define ICH_VMCR_EOIM_SHIFT		9
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 2cb04b7..ad353b5 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -212,22 +212,6 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
>  	}
>  }
>  
> -static void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> -{
> -	if (kvm_vgic_global_state.type == VGIC_V2)
> -		vgic_v2_set_vmcr(vcpu, vmcr);
> -	else
> -		vgic_v3_set_vmcr(vcpu, vmcr);
> -}
> -
> -static void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> -{
> -	if (kvm_vgic_global_state.type == VGIC_V2)
> -		vgic_v2_get_vmcr(vcpu, vmcr);
> -	else
> -		vgic_v3_get_vmcr(vcpu, vmcr);
> -}
> -
>  #define GICC_ARCH_VERSION_V2	0x2
>  
>  /* These are for userland accesses only, there is no guest-facing emulation. */
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index 0d1bc98..f81e0e5 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -416,6 +416,22 @@ int vgic_validate_mmio_region_addr(struct kvm_device *dev,
>  	return -ENXIO;
>  }
>  
> +void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_set_vmcr(vcpu, vmcr);
> +	else
> +		vgic_v3_set_vmcr(vcpu, vmcr);
> +}
> +
> +void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_get_vmcr(vcpu, vmcr);
> +	else
> +		vgic_v3_get_vmcr(vcpu, vmcr);
> +}
> +
>  /*
>   * kvm_mmio_read_buf() returns a value in a format where it can be converted
>   * to a byte array and be directly observed as the guest wanted it to appear
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 9f0dae3..a3ff04b 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -175,10 +175,19 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  {
>  	u32 vmcr;
>  
> -	vmcr  = (vmcrp->ctlr << ICH_VMCR_CTLR_SHIFT) & ICH_VMCR_CTLR_MASK;
> +	/*
> +	 * Ignore the FIQen bit, because GIC emulation always implies
> +	 * SRE=1 which means the vFIQEn bit is also RES1.
> +	 */
> +	vmcr = (vmcrp->ctlr & ICC_CTLR_EL1_EOImode_MASK) >>
> +		ICC_CTLR_EL1_EOImode_SHIFT;
> +	vmcr = (vmcr << ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;

Nit: I think this can be written more nicely as:
	vmcr = ((vmcrp->ctlr >> ICC_CTLR_EL1_EOImode_SHIFT)
		<< ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;

> +	vmcr |= (vmcrp->ctlr << ICH_VMCR_CBPR_SHIFT) & ICH_VMCR_CBPR_MASK;
>  	vmcr |= (vmcrp->abpr << ICH_VMCR_BPR1_SHIFT) & ICH_VMCR_BPR1_MASK;
>  	vmcr |= (vmcrp->bpr << ICH_VMCR_BPR0_SHIFT) & ICH_VMCR_BPR0_MASK;
>  	vmcr |= (vmcrp->pmr << ICH_VMCR_PMR_SHIFT) & ICH_VMCR_PMR_MASK;
> +	vmcr |= (vmcrp->grpen0 << ICH_VMCR_ENG0_SHIFT) & ICH_VMCR_ENG0_MASK;
> +	vmcr |= (vmcrp->grpen1 << ICH_VMCR_ENG1_SHIFT) & ICH_VMCR_ENG1_MASK;
>  
>  	vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
>  }
> @@ -187,10 +196,19 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  {
>  	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr;
>  
> -	vmcrp->ctlr = (vmcr & ICH_VMCR_CTLR_MASK) >> ICH_VMCR_CTLR_SHIFT;
> +	/*
> +	 * Ignore the FIQen bit, because GIC emulation always implies
> +	 * SRE=1 which means the vFIQEn bit is also RES1.
> +	 */
> +	vmcrp->ctlr = (vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT;
> +	vmcrp->ctlr = (vmcrp->ctlr << ICC_CTLR_EL1_EOImode_SHIFT) &
> +		       ICC_CTLR_EL1_EOImode_MASK;

similarly, this could be written as:
	vmcrp->ctlr = ((vmcr >> ICH_VMCR_EOIM_SHIFT) <<
			ICC_CTLR_EL1_EOImode_SHIFT) & ICC_CTLR_EL1_EOImode_MASK;

> +	vmcrp->ctlr |= (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT;
>  	vmcrp->abpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
>  	vmcrp->bpr  = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
>  	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
> +	vmcrp->grpen0 = (vmcr & ICH_VMCR_ENG0_MASK) >> ICH_VMCR_ENG0_SHIFT;
> +	vmcrp->grpen1 = (vmcr & ICH_VMCR_ENG1_MASK) >> ICH_VMCR_ENG1_SHIFT;
>  }
>  
>  #define INITIAL_PENDBASER_VALUE						  \
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 91f58b2..9232791 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -78,6 +78,9 @@ struct vgic_vmcr {
>  	u32	abpr;
>  	u32	bpr;
>  	u32	pmr;
> +	/* Below member variable are valid only for GICv3 */
> +	u32	grpen0;
> +	u32	grpen1;
>  };
>  
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> @@ -138,6 +141,8 @@ int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			 int offset, u32 *val);
>  int kvm_register_vgic_device(unsigned long type);
> +void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> +void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  int vgic_lazy_init(struct kvm *kvm);
>  int vgic_init(struct kvm *kvm);
>  
> -- 
> 1.9.1
> 
My comments on style above notwithstanding:

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 05/11] arm/arm64: vgic: Introduce VENG0 and VENG1 fields to vmcr struct
@ 2016-11-28 14:28     ` Christoffer Dall
  0 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-28 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 23, 2016 at 06:31:52PM +0530, vijay.kilari at gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> 
> ICC_VMCR_EL2 supports virtual access to ICC_IGRPEN1_EL1.Enable
> and ICC_IGRPEN0_EL1.Enable fields. Add grpen0 and grpen1 member
> variables to struct vmcr to support read and write of these fields.
> 
> Also refactor vgic_set_vmcr and vgic_get_vmcr() code.
> Drop ICH_VMCR_CTLR_SHIFT and ICH_VMCR_CTLR_MASK macros and instead
> use ICH_VMCR_EOI* and ICH_VMCR_CBPR* macros
> .
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> ---
>  include/linux/irqchip/arm-gic-v3.h |  2 --
>  virt/kvm/arm/vgic/vgic-mmio-v2.c   | 16 ----------------
>  virt/kvm/arm/vgic/vgic-mmio.c      | 16 ++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c        | 22 ++++++++++++++++++++--
>  virt/kvm/arm/vgic/vgic.h           |  5 +++++
>  5 files changed, 41 insertions(+), 20 deletions(-)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index b4f8287..406fc3e 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -404,8 +404,6 @@
>  #define ICH_HCR_EN			(1 << 0)
>  #define ICH_HCR_UIE			(1 << 1)
>  
> -#define ICH_VMCR_CTLR_SHIFT		0
> -#define ICH_VMCR_CTLR_MASK		(0x21f << ICH_VMCR_CTLR_SHIFT)
>  #define ICH_VMCR_CBPR_SHIFT		4
>  #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
>  #define ICH_VMCR_EOIM_SHIFT		9
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 2cb04b7..ad353b5 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -212,22 +212,6 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
>  	}
>  }
>  
> -static void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> -{
> -	if (kvm_vgic_global_state.type == VGIC_V2)
> -		vgic_v2_set_vmcr(vcpu, vmcr);
> -	else
> -		vgic_v3_set_vmcr(vcpu, vmcr);
> -}
> -
> -static void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> -{
> -	if (kvm_vgic_global_state.type == VGIC_V2)
> -		vgic_v2_get_vmcr(vcpu, vmcr);
> -	else
> -		vgic_v3_get_vmcr(vcpu, vmcr);
> -}
> -
>  #define GICC_ARCH_VERSION_V2	0x2
>  
>  /* These are for userland accesses only, there is no guest-facing emulation. */
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index 0d1bc98..f81e0e5 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -416,6 +416,22 @@ int vgic_validate_mmio_region_addr(struct kvm_device *dev,
>  	return -ENXIO;
>  }
>  
> +void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_set_vmcr(vcpu, vmcr);
> +	else
> +		vgic_v3_set_vmcr(vcpu, vmcr);
> +}
> +
> +void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> +{
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_get_vmcr(vcpu, vmcr);
> +	else
> +		vgic_v3_get_vmcr(vcpu, vmcr);
> +}
> +
>  /*
>   * kvm_mmio_read_buf() returns a value in a format where it can be converted
>   * to a byte array and be directly observed as the guest wanted it to appear
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 9f0dae3..a3ff04b 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -175,10 +175,19 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  {
>  	u32 vmcr;
>  
> -	vmcr  = (vmcrp->ctlr << ICH_VMCR_CTLR_SHIFT) & ICH_VMCR_CTLR_MASK;
> +	/*
> +	 * Ignore the FIQen bit, because GIC emulation always implies
> +	 * SRE=1 which means the vFIQEn bit is also RES1.
> +	 */
> +	vmcr = (vmcrp->ctlr & ICC_CTLR_EL1_EOImode_MASK) >>
> +		ICC_CTLR_EL1_EOImode_SHIFT;
> +	vmcr = (vmcr << ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;

Nit: I think this can be written more nicely as:
	vmcr = ((vmcrp->ctlr >> ICC_CTLR_EL1_EOImode_SHIFT)
		<< ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;

> +	vmcr |= (vmcrp->ctlr << ICH_VMCR_CBPR_SHIFT) & ICH_VMCR_CBPR_MASK;
>  	vmcr |= (vmcrp->abpr << ICH_VMCR_BPR1_SHIFT) & ICH_VMCR_BPR1_MASK;
>  	vmcr |= (vmcrp->bpr << ICH_VMCR_BPR0_SHIFT) & ICH_VMCR_BPR0_MASK;
>  	vmcr |= (vmcrp->pmr << ICH_VMCR_PMR_SHIFT) & ICH_VMCR_PMR_MASK;
> +	vmcr |= (vmcrp->grpen0 << ICH_VMCR_ENG0_SHIFT) & ICH_VMCR_ENG0_MASK;
> +	vmcr |= (vmcrp->grpen1 << ICH_VMCR_ENG1_SHIFT) & ICH_VMCR_ENG1_MASK;
>  
>  	vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
>  }
> @@ -187,10 +196,19 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  {
>  	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr;
>  
> -	vmcrp->ctlr = (vmcr & ICH_VMCR_CTLR_MASK) >> ICH_VMCR_CTLR_SHIFT;
> +	/*
> +	 * Ignore the FIQen bit, because GIC emulation always implies
> +	 * SRE=1 which means the vFIQEn bit is also RES1.
> +	 */
> +	vmcrp->ctlr = (vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT;
> +	vmcrp->ctlr = (vmcrp->ctlr << ICC_CTLR_EL1_EOImode_SHIFT) &
> +		       ICC_CTLR_EL1_EOImode_MASK;

similarly, this could be written as:
	vmcrp->ctlr = ((vmcr >> ICH_VMCR_EOIM_SHIFT) <<
			ICC_CTLR_EL1_EOImode_SHIFT) & ICC_CTLR_EL1_EOImode_MASK;

> +	vmcrp->ctlr |= (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT;
>  	vmcrp->abpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
>  	vmcrp->bpr  = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
>  	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
> +	vmcrp->grpen0 = (vmcr & ICH_VMCR_ENG0_MASK) >> ICH_VMCR_ENG0_SHIFT;
> +	vmcrp->grpen1 = (vmcr & ICH_VMCR_ENG1_MASK) >> ICH_VMCR_ENG1_SHIFT;
>  }
>  
>  #define INITIAL_PENDBASER_VALUE						  \
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 91f58b2..9232791 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -78,6 +78,9 @@ struct vgic_vmcr {
>  	u32	abpr;
>  	u32	bpr;
>  	u32	pmr;
> +	/* Below member variable are valid only for GICv3 */
> +	u32	grpen0;
> +	u32	grpen1;
>  };
>  
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> @@ -138,6 +141,8 @@ int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			 int offset, u32 *val);
>  int kvm_register_vgic_device(unsigned long type);
> +void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> +void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  int vgic_lazy_init(struct kvm *kvm);
>  int vgic_init(struct kvm *kvm);
>  
> -- 
> 1.9.1
> 
My comments on style above notwithstanding:

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 06/11] arm/arm64: vgic: Implement VGICv3 CPU interface access
  2016-11-23 13:01   ` vijay.kilari at gmail.com
@ 2016-11-28 19:39     ` Christoffer Dall
  -1 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-28 19:39 UTC (permalink / raw)
  To: vijay.kilari; +Cc: marc.zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

On Wed, Nov 23, 2016 at 06:31:53PM +0530, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> 
> VGICv3 CPU interface registers are accessed using
> KVM_DEV_ARM_VGIC_CPU_SYSREGS ioctl. These registers are accessed
> as 64-bit. The cpu MPIDR value is passed along with register id.
> is used to identify the cpu for registers access.
> 
> The VM that supports SEIs expect it on destination machine to handle
> guest aborts and hence checked for ICC_CTLR_EL1.SEIS compatibility.
> Similarly, VM that supports Affinity Level 3 that is required for AArch64
> mode, is required to be supported on destination machine. Hence checked
> for ICC_CTLR_EL1.A3V compatibility.
> 
> The CPU system register handling is spitted into two files

spitted?  Did you mean 'split into' ?

> vgic-sys-reg-common.c and vgic-sys-reg-v3.c.
> The vgic-sys-reg-common.c handles read and write of VGIC CPU registers

So this is weird because everything in virt/kvm/arm/ is exactly supposed
to be common between arm and arm64 already.

I would rather that you had a copy of vgic-sys-reg-v3.c in arch/arm/kvm/
and in arch/arm64/kvm/ each taking care of its own architecture.

But note that I didn't actually require that you implemented support for
GICv3 migration on AArch32 hosts for these patches, I just didn't want
thigns to silently break.

If we cannot test the AArch32 implementation, we should potentially just
make sure that is not supported yet, return a proper error to userspace
and get the AArch64 host implementation correct.

I suggest you move your:
  virt/kvm/arm/vgic/vgic-sys-reg-v3.c to
  arch/arm64/kvm/vgic-sys-reg-v3.c
  
and rename
  virt/kvm/arm/vgic/vgic-sys-reg-common.c to
  virt/kvm/arm/vgic/vgic-sys-reg-v3.c

And then wait with the AArch32 host side for now, but just make sure it
compiles and returns an error as opposed to crashing the system if
someone tries to excercise this interface on an AArch32 host.

> for both AArch64 and AArch32 mode. The vgic-sys-reg-v3.c handles AArch64
> mode and is compiled only for AArch64 mode.
> 
> Updated arch/arm/include/uapi/asm/kvm.h with new definitions
> required to compile for AArch32.
> 
> The version of VGIC v3 specification is define here
> Documentation/virtual/kvm/devices/arm-vgic-v3.txt
> 
> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> ---
>  arch/arm/include/uapi/asm/kvm.h         |   2 +
>  arch/arm64/include/uapi/asm/kvm.h       |   3 +
>  arch/arm64/kvm/Makefile                 |   2 +
>  include/kvm/arm_vgic.h                  |   9 ++
>  virt/kvm/arm/vgic/vgic-kvm-device.c     |  28 ++++
>  virt/kvm/arm/vgic/vgic-mmio-v3.c        |  18 +++
>  virt/kvm/arm/vgic/vgic-sys-reg-common.c | 258 ++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-sys-reg-v3.c     | 142 ++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c             |   8 +
>  virt/kvm/arm/vgic/vgic.h                |  22 +++
>  10 files changed, 492 insertions(+)
> 
> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
> index 0ae6035..98658d9d 100644
> --- a/arch/arm/include/uapi/asm/kvm.h
> +++ b/arch/arm/include/uapi/asm/kvm.h
> @@ -186,9 +186,11 @@ struct kvm_arch_memory_slot {
>  			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
>  #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
>  #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
> +#define   KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK (0xffff)
>  #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
>  #define KVM_DEV_ARM_VGIC_GRP_CTRL       4
>  #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
> +#define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
>  
>  /* KVM_IRQ_LINE irq field index values */
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 56dc08d..91c7137 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -206,9 +206,12 @@ struct kvm_arch_memory_slot {
>  			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
>  #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
>  #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
> +#define   KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK (0xffff)
>  #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
>  #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
> +#define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
> +
>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
>  
>  /* Device Control API on vcpu fd */
> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
> index d50a82a..5c8580e 100644
> --- a/arch/arm64/kvm/Makefile
> +++ b/arch/arm64/kvm/Makefile
> @@ -32,5 +32,7 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-kvm-device.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-its.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/irqchip.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-sys-reg-common.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-sys-reg-v3.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_vgic.h b/include/kvm/arm_vgic.h
> index 002f092..730a18a 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -71,6 +71,9 @@ struct vgic_global {
>  
>  	/* GIC system register CPU interface */
>  	struct static_key_false gicv3_cpuif;
> +
> +	/* Cache ICH_VTR_EL2 reg value */
> +	u32			ich_vtr_el2;
>  };
>  
>  extern struct vgic_global kvm_vgic_global_state;
> @@ -269,6 +272,12 @@ struct vgic_cpu {
>  	u64 pendbaser;
>  
>  	bool lpis_enabled;
> +
> +	/* Cache guest priority bits */
> +	u32 num_pri_bits;
> +
> +	/* Cache guest interrupt ID bits */
> +	u32 num_id_bits;
>  };
>  
>  extern struct static_key_false vgic_v2_cpuif_trap;
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index bc7de95..b6266fe 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -16,6 +16,7 @@
>  #include <linux/kvm_host.h>
>  #include <kvm/arm_vgic.h>
>  #include <linux/uaccess.h>
> +#include <asm/kvm_emulate.h>
>  #include <asm/kvm_mmu.h>
>  #include "vgic.h"
>  
> @@ -501,6 +502,14 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
>  		if (!is_write)
>  			*reg = tmp32;
>  		break;
> +	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
> +		u64 regid;
> +
> +		regid = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK);
> +		ret = vgic_v3_cpu_sysregs_uaccess(vcpu, is_write,
> +						  regid, reg);
> +		break;
> +	}
>  	default:
>  		ret = -EINVAL;
>  		break;
> @@ -534,6 +543,15 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
>  		reg = tmp32;
>  		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
>  	}
> +	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
> +		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
> +		u64 reg;
> +
> +		if (get_user(reg, uaddr))
> +			return -EFAULT;
> +
> +		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
> +	}
>  	}
>  	return -ENXIO;
>  }
> @@ -560,6 +578,15 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
>  		tmp32 = reg;
>  		return put_user(tmp32, uaddr);
>  	}
> +	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
> +		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
> +		u64 reg;
> +
> +		ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
> +		if (ret)
> +			return ret;
> +		return put_user(reg, uaddr);
> +	}
>  	}
>  
>  	return -ENXIO;
> @@ -578,6 +605,7 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
>  		break;
>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>  	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
> +	case KVM_DEV_ARM_VGIC_CPU_SYSREGS:
>  		return vgic_v3_has_attr_regs(dev, attr);
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>  		return 0;
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index 2a7cd62..2f7b4ed 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -641,6 +641,24 @@ int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>  		nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
>  		break;
>  	}
> +	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
> +		u64 reg, id;
> +		unsigned long vgic_mpidr, mpidr_reg;
> +		struct kvm_vcpu *vcpu;
> +
> +		vgic_mpidr = (attr->attr & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) >>
> +			      KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT;
> +
> +		/* Convert plain mpidr value to MPIDR reg format */
> +		mpidr_reg = VGIC_TO_MPIDR(vgic_mpidr);
> +
> +		vcpu = kvm_mpidr_to_vcpu(dev->kvm, mpidr_reg);
> +		if (!vcpu)
> +			return -EINVAL;
> +
> +		id = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK);
> +		return vgic_v3_has_cpu_sysregs_attr(vcpu, 0, id, &reg);
> +	}
>  	default:
>  		return -ENXIO;
>  	}
> diff --git a/virt/kvm/arm/vgic/vgic-sys-reg-common.c b/virt/kvm/arm/vgic/vgic-sys-reg-common.c
> new file mode 100644
> index 0000000..a1fc370c
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-sys-reg-common.c
> @@ -0,0 +1,258 @@
> +/*
> + * VGIC system registers handling functions
> + *
> + * 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.
> + */
> +
> +#include <linux/irqchip/arm-gic-v3.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <asm/kvm_emulate.h>
> +#include "vgic.h"
> +
> +bool access_gic_ctlr_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			 unsigned long *reg)
> +{
> +	struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_vmcr vmcr;
> +	u64 val;
> +	u32 valid_bits, seis, a3v;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +	if (is_write) {
> +		val = *reg;
> +
> +		/*
> +		 * Disallow restoring VM state if not supported by this
> +		 * hardware.
> +		 */
> +		valid_bits = ((val & ICC_CTLR_EL1_PRI_BITS_MASK) >>
> +				ICC_CTLR_EL1_PRI_BITS_SHIFT) + 1;
> +		if (valid_bits > vgic_v3_cpu->num_pri_bits)
> +			return false;
> +
> +		vgic_v3_cpu->num_pri_bits = valid_bits;
> +
> +		valid_bits = (val & ICC_CTLR_EL1_ID_BITS_MASK) >>
> +			       ICC_CTLR_EL1_ID_BITS_SHIFT;
> +		if (valid_bits > vgic_v3_cpu->num_id_bits)
> +			return false;
> +
> +		vgic_v3_cpu->num_id_bits = valid_bits;

nit: could you just define the variables your need instead of reusing
this valid_bits thing, that would make the code a lot more readable.


> +
> +		valid_bits = ((kvm_vgic_global_state.ich_vtr_el2 &
> +			ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT);

it's especially confusing that you now use valid_bits for the host's
values...

> +		seis = (val & ICC_CTLR_EL1_SEIS_MASK) >>
> +			ICC_CTLR_EL1_SEIS_SHIFT;
> +		if (valid_bits != seis)
> +			return false;



> +
> +		valid_bits = ((kvm_vgic_global_state.ich_vtr_el2 &
> +			ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT);
> +		a3v = (val & ICC_CTLR_EL1_A3V_MASK) >>
> +			ICC_CTLR_EL1_A3V_SHIFT;
> +		if (valid_bits != a3v)
> +			return false;
> +
> +		vmcr.ctlr = (val & ICC_CTLR_EL1_CBPR_MASK);
> +		vmcr.ctlr |= (val & ICC_CTLR_EL1_EOImode_MASK);
> +		vgic_set_vmcr(vcpu, &vmcr);
> +	} else {
> +		val = 0;
> +		val |= (vgic_v3_cpu->num_pri_bits - 1) <<
> +			ICC_CTLR_EL1_PRI_BITS_SHIFT;
> +		val |= vgic_v3_cpu->num_id_bits <<
> +			ICC_CTLR_EL1_ID_BITS_SHIFT;
> +		val |= ((kvm_vgic_global_state.ich_vtr_el2 &
> +			ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT) <<
> +			ICC_CTLR_EL1_SEIS_SHIFT;
> +		val |= ((kvm_vgic_global_state.ich_vtr_el2 &
> +			ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT) <<
> +			ICC_CTLR_EL1_A3V_SHIFT;
> +		val |= (vmcr.ctlr & ICC_CTLR_EL1_CBPR_MASK);
> +		val |= (vmcr.ctlr & ICC_CTLR_EL1_EOImode_MASK);
> +
> +		*reg = val;
> +	}
> +
> +	return true;
> +}
> +
> +bool access_gic_pmr_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			unsigned long *reg)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +	if (is_write) {
> +		vmcr.pmr = (*reg & ICC_PMR_EL1_MASK) >> ICC_PMR_EL1_SHIFT;
> +		vgic_set_vmcr(vcpu, &vmcr);
> +	} else {
> +		*reg = (vmcr.pmr << ICC_PMR_EL1_SHIFT) & ICC_PMR_EL1_MASK;
> +	}
> +
> +	return true;
> +}
> +
> +bool access_gic_bpr0_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			 unsigned long *reg)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +	if (is_write) {
> +		vmcr.bpr = (*reg & ICC_BPR0_EL1_MASK) >>
> +			    ICC_BPR0_EL1_SHIFT;
> +		vgic_set_vmcr(vcpu, &vmcr);
> +	} else {
> +		*reg = (vmcr.bpr << ICC_BPR0_EL1_SHIFT) & ICC_BPR0_EL1_MASK;
> +	}
> +
> +	return true;
> +}
> +
> +bool access_gic_bpr1_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			 unsigned long *reg)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	if (!is_write)
> +		*reg = 0;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +	if (!((vmcr.ctlr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT)) {
> +		if (is_write) {
> +			vmcr.abpr = (*reg & ICC_BPR1_EL1_MASK) >>
> +				     ICC_BPR1_EL1_SHIFT;
> +			vgic_set_vmcr(vcpu, &vmcr);
> +		} else {
> +			*reg = (vmcr.abpr << ICC_BPR1_EL1_SHIFT) &
> +				ICC_BPR1_EL1_MASK;
> +		}
> +	} else {
> +		if (!is_write)
> +			*reg = min((vmcr.bpr + 1), 7U);
> +	}
> +
> +	return true;
> +}
> +
> +bool access_gic_grpen0_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			   unsigned long *reg)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +	if (is_write) {
> +		vmcr.grpen0 = (*reg & ICC_IGRPEN0_EL1_MASK) >>
> +			       ICC_IGRPEN0_EL1_SHIFT;
> +		vgic_set_vmcr(vcpu, &vmcr);
> +	} else {
> +		*reg = (vmcr.grpen0 << ICC_IGRPEN0_EL1_SHIFT) &
> +			ICC_IGRPEN0_EL1_MASK;
> +	}
> +
> +	return true;
> +}
> +
> +bool access_gic_grpen1_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			   unsigned long *reg)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +	if (is_write) {
> +		vmcr.grpen1 = (*reg & ICC_IGRPEN1_EL1_MASK) >>
> +			       ICC_IGRPEN1_EL1_SHIFT;
> +		vgic_set_vmcr(vcpu, &vmcr);
> +	} else {
> +		*reg = (vmcr.grpen1 << ICC_IGRPEN1_EL1_SHIFT) &
> +			ICC_IGRPEN1_EL1_MASK;
> +	}
> +
> +	return true;
> +}
> +
> +static void vgic_v3_access_apr_reg(struct kvm_vcpu *vcpu, bool is_write,
> +				   u8 apr, u8 idx, unsigned long *reg)
> +{
> +	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
> +	uint32_t *ap_reg;
> +
> +	if (apr)
> +		ap_reg = &vgicv3->vgic_ap1r[idx];
> +	else
> +		ap_reg = &vgicv3->vgic_ap0r[idx];
> +
> +	if (is_write)
> +		*ap_reg = *reg;
> +	else
> +		*reg = *ap_reg;
> +}
> +
> +static bool access_gic_aprn(struct kvm_vcpu *vcpu, bool is_write, u8 apr,
> +			    u8 idx, unsigned long *reg)
> +{
> +	struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
> +
> +	/* num_pri_bits are initialized with HW supported values.
> +	 * We can rely safely on num_pri_bits even if VM has not
> +	 * restored ICC_CTLR_EL1 before restoring APnR registers.
> +	 */

nit: commenting style

> +	switch (vgic_v3_cpu->num_pri_bits) {
> +	case 7:
> +		vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
> +		break;
> +	case 6:
> +		if (idx > 1)
> +			goto err;
> +		vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
> +		break;
> +	default:
> +		if (idx > 0)
> +			goto err;
> +		vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
> +	}

It looks to me like userspace can then program active priorities with
higher numbers than what it will program num_pri_bits to later.  Is that
not weird, or am I missing something?

> +
> +	return true;
> +err:
> +	if (!is_write)
> +		*reg = 0;
> +
> +	return false;
> +}
> +
> +bool access_gic_ap0r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
> +			 unsigned long *reg)
> +{
> +	return access_gic_aprn(vcpu, is_write, 0, idx, reg);
> +}
> +
> +bool access_gic_ap1r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
> +			 unsigned long *reg)
> +{
> +	return access_gic_aprn(vcpu, is_write, 1, idx, reg);
> +}
> +
> +bool access_gic_sre_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			unsigned long *reg)
> +{
> +	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
> +
> +	/* Validate SRE bit */
> +	if (is_write) {
> +		if (!(*reg & ICC_SRE_EL1_SRE))
> +			return false;
> +	} else {
> +		*reg = vgicv3->vgic_sre;
> +	}
> +
> +	return true;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-sys-reg-v3.c b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
> new file mode 100644
> index 0000000..82c2f02
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
> @@ -0,0 +1,142 @@
> +/*
> + * VGIC system registers handling functions
> + *
> + * 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.
> + */
> +
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <asm/kvm_emulate.h>
> +#include "vgic.h"
> +#include "sys_regs.h"
> +
> +#define ACCESS_SYS_REG(REG)						\
> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,		\
> +				    struct sys_reg_params *p,		\
> +				    const struct sys_reg_desc *r)	\
> +{									\
> +	unsigned long tmp;						\
> +	bool ret;							\
> +									\
> +	if (p->is_write)						\
> +		tmp = p->regval;					\
> +	ret = access_gic_##REG##_reg(vcpu, p->is_write, &tmp);		\
> +	if (!p->is_write)						\
> +		p->regval = tmp;					\
> +									\
> +	return ret;							\
> +}
> +
> +ACCESS_SYS_REG(ctlr)
> +ACCESS_SYS_REG(pmr)
> +ACCESS_SYS_REG(bpr0)
> +ACCESS_SYS_REG(bpr1)
> +ACCESS_SYS_REG(sre)
> +ACCESS_SYS_REG(grpen0)
> +ACCESS_SYS_REG(grpen1)
> +
> +#define ACCESS_APNR_SYS_REG(REG)					\
> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,		\
> +				    struct sys_reg_params *p,		\
> +				    const struct sys_reg_desc *r)	\
> +{									\
> +	unsigned long tmp;						\
> +	u8 idx = p->Op2 & 3;						\
> +	bool ret;							\
> +									\
> +	if (p->is_write)						\
> +		tmp = p->regval;					\
> +	ret = access_gic_##REG##_reg(vcpu, p->is_write, idx, &tmp);	\
> +	if (!p->is_write)						\
> +		p->regval = tmp;					\
> +									\
> +	return ret;							\
> +}
> +
> +ACCESS_APNR_SYS_REG(ap0r)
> +ACCESS_APNR_SYS_REG(ap1r)

I don't get these indirections.  Why can't you call the functions
directly?

> +
> +static const struct sys_reg_desc gic_v3_icc_reg_descs[] = {
> +	/* ICC_PMR_EL1 */
> +	{ Op0(3), Op1(0), CRn(4), CRm(6), Op2(0), access_gic_pmr_sys_reg },
> +	/* ICC_BPR0_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(3), access_gic_bpr0_sys_reg },
> +	/* ICC_AP0R0_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(4), access_gic_ap0r_sys_reg },
> +	/* ICC_AP0R1_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(5), access_gic_ap0r_sys_reg },
> +	/* ICC_AP0R2_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(6), access_gic_ap0r_sys_reg },
> +	/* ICC_AP0R3_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(7), access_gic_ap0r_sys_reg },
> +	/* ICC_AP1R0_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(0), access_gic_ap1r_sys_reg },
> +	/* ICC_AP1R1_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(1), access_gic_ap1r_sys_reg },
> +	/* ICC_AP1R2_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(2), access_gic_ap1r_sys_reg },
> +	/* ICC_AP1R3_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(3), access_gic_ap1r_sys_reg },
> +	/* ICC_BPR1_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(3), access_gic_bpr1_sys_reg },
> +	/* ICC_CTLR_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(4), access_gic_ctlr_sys_reg },
> +	/* ICC_SRE_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(5), access_gic_sre_sys_reg },
> +	/* ICC_IGRPEN0_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(6), access_gic_grpen0_sys_reg },
> +	/* ICC_GRPEN1_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(7), access_gic_grpen1_sys_reg },
> +};
> +
> +int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
> +				u64 *reg)
> +{
> +	struct sys_reg_params params;
> +	u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64;
> +
> +	params.regval = *reg;
> +	params.is_write = is_write;
> +	params.is_aarch32 = false;
> +	params.is_32bit = false;
> +
> +	if (find_reg_by_id(sysreg, &params, gic_v3_icc_reg_descs,
> +			      ARRAY_SIZE(gic_v3_icc_reg_descs)))
> +		return 0;
> +
> +	return -ENXIO;
> +}
> +
> +int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
> +				u64 *reg)
> +{
> +	struct sys_reg_params params;
> +	const struct sys_reg_desc *r;
> +	u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64;
> +
> +	if (is_write)
> +		params.regval = *reg;
> +	params.is_write = is_write;
> +	params.is_aarch32 = false;
> +	params.is_32bit = false;
> +
> +	r = find_reg_by_id(sysreg, &params, gic_v3_icc_reg_descs,
> +			   ARRAY_SIZE(gic_v3_icc_reg_descs));
> +	if (!r)
> +		return -ENXIO;
> +
> +	if (!r->access(vcpu, &params, r))
> +		return -EINVAL;
> +
> +	if (!is_write)
> +		*reg = params.regval;
> +
> +	return 0;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index a3ff04b..6e7400e 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -240,6 +240,13 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
>  		vgic_v3->vgic_sre = 0;
>  	}
>  
> +	vcpu->arch.vgic_cpu.num_id_bits = (kvm_vgic_global_state.ich_vtr_el2 &
> +					   ICH_VTR_ID_BITS_MASK) >>
> +					   ICH_VTR_ID_BITS_SHIFT;
> +	vcpu->arch.vgic_cpu.num_pri_bits = ((kvm_vgic_global_state.ich_vtr_el2 &
> +					    ICH_VTR_PRI_BITS_MASK) >>
> +					    ICH_VTR_PRI_BITS_SHIFT) + 1;
> +
>  	/* Get the show on the road... */
>  	vgic_v3->vgic_hcr = ICH_HCR_EN;
>  }
> @@ -340,6 +347,7 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
>  	 */
>  	kvm_vgic_global_state.nr_lr = (ich_vtr_el2 & 0xf) + 1;
>  	kvm_vgic_global_state.can_emulate_gicv2 = false;
> +	kvm_vgic_global_state.ich_vtr_el2 = ich_vtr_el2;
>  
>  	if (!info->vcpu.start) {
>  		kvm_info("GICv3: no GICV resource entry\n");
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 9232791..af23399 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -140,6 +140,28 @@ int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			 int offset, u32 *val);
>  int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			 int offset, u32 *val);
> +int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +			 u64 id, u64 *val);
> +int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
> +				u64 *reg);
> +bool access_gic_ctlr_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			 unsigned long *reg);
> +bool access_gic_pmr_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			unsigned long *reg);
> +bool access_gic_bpr0_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			 unsigned long *reg);
> +bool access_gic_bpr1_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			 unsigned long *reg);
> +bool access_gic_grpen0_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			   unsigned long *reg);
> +bool access_gic_grpen1_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			   unsigned long *reg);
> +bool access_gic_ap0r_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			 u8 idx, unsigned long *reg);
> +bool access_gic_ap1r_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			 u8 idx, unsigned long *reg);
> +bool access_gic_sre_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			unsigned long *reg);

nit: since all of this is exported, I would name them vgic_access_ctlr()
and so on. The _reg postfix is probably also unnecessary for all of
these.

>  int kvm_register_vgic_device(unsigned long type);
>  void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> -- 
> 1.9.1
> 

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 06/11] arm/arm64: vgic: Implement VGICv3 CPU interface access
@ 2016-11-28 19:39     ` Christoffer Dall
  0 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-28 19:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 23, 2016 at 06:31:53PM +0530, vijay.kilari at gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> 
> VGICv3 CPU interface registers are accessed using
> KVM_DEV_ARM_VGIC_CPU_SYSREGS ioctl. These registers are accessed
> as 64-bit. The cpu MPIDR value is passed along with register id.
> is used to identify the cpu for registers access.
> 
> The VM that supports SEIs expect it on destination machine to handle
> guest aborts and hence checked for ICC_CTLR_EL1.SEIS compatibility.
> Similarly, VM that supports Affinity Level 3 that is required for AArch64
> mode, is required to be supported on destination machine. Hence checked
> for ICC_CTLR_EL1.A3V compatibility.
> 
> The CPU system register handling is spitted into two files

spitted?  Did you mean 'split into' ?

> vgic-sys-reg-common.c and vgic-sys-reg-v3.c.
> The vgic-sys-reg-common.c handles read and write of VGIC CPU registers

So this is weird because everything in virt/kvm/arm/ is exactly supposed
to be common between arm and arm64 already.

I would rather that you had a copy of vgic-sys-reg-v3.c in arch/arm/kvm/
and in arch/arm64/kvm/ each taking care of its own architecture.

But note that I didn't actually require that you implemented support for
GICv3 migration on AArch32 hosts for these patches, I just didn't want
thigns to silently break.

If we cannot test the AArch32 implementation, we should potentially just
make sure that is not supported yet, return a proper error to userspace
and get the AArch64 host implementation correct.

I suggest you move your:
  virt/kvm/arm/vgic/vgic-sys-reg-v3.c to
  arch/arm64/kvm/vgic-sys-reg-v3.c
  
and rename
  virt/kvm/arm/vgic/vgic-sys-reg-common.c to
  virt/kvm/arm/vgic/vgic-sys-reg-v3.c

And then wait with the AArch32 host side for now, but just make sure it
compiles and returns an error as opposed to crashing the system if
someone tries to excercise this interface on an AArch32 host.

> for both AArch64 and AArch32 mode. The vgic-sys-reg-v3.c handles AArch64
> mode and is compiled only for AArch64 mode.
> 
> Updated arch/arm/include/uapi/asm/kvm.h with new definitions
> required to compile for AArch32.
> 
> The version of VGIC v3 specification is define here
> Documentation/virtual/kvm/devices/arm-vgic-v3.txt
> 
> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> ---
>  arch/arm/include/uapi/asm/kvm.h         |   2 +
>  arch/arm64/include/uapi/asm/kvm.h       |   3 +
>  arch/arm64/kvm/Makefile                 |   2 +
>  include/kvm/arm_vgic.h                  |   9 ++
>  virt/kvm/arm/vgic/vgic-kvm-device.c     |  28 ++++
>  virt/kvm/arm/vgic/vgic-mmio-v3.c        |  18 +++
>  virt/kvm/arm/vgic/vgic-sys-reg-common.c | 258 ++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-sys-reg-v3.c     | 142 ++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c             |   8 +
>  virt/kvm/arm/vgic/vgic.h                |  22 +++
>  10 files changed, 492 insertions(+)
> 
> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
> index 0ae6035..98658d9d 100644
> --- a/arch/arm/include/uapi/asm/kvm.h
> +++ b/arch/arm/include/uapi/asm/kvm.h
> @@ -186,9 +186,11 @@ struct kvm_arch_memory_slot {
>  			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
>  #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
>  #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
> +#define   KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK (0xffff)
>  #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
>  #define KVM_DEV_ARM_VGIC_GRP_CTRL       4
>  #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
> +#define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
>  
>  /* KVM_IRQ_LINE irq field index values */
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 56dc08d..91c7137 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -206,9 +206,12 @@ struct kvm_arch_memory_slot {
>  			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
>  #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
>  #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
> +#define   KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK (0xffff)
>  #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
>  #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
> +#define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
> +
>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
>  
>  /* Device Control API on vcpu fd */
> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
> index d50a82a..5c8580e 100644
> --- a/arch/arm64/kvm/Makefile
> +++ b/arch/arm64/kvm/Makefile
> @@ -32,5 +32,7 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-kvm-device.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-its.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/irqchip.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-sys-reg-common.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-sys-reg-v3.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_vgic.h b/include/kvm/arm_vgic.h
> index 002f092..730a18a 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -71,6 +71,9 @@ struct vgic_global {
>  
>  	/* GIC system register CPU interface */
>  	struct static_key_false gicv3_cpuif;
> +
> +	/* Cache ICH_VTR_EL2 reg value */
> +	u32			ich_vtr_el2;
>  };
>  
>  extern struct vgic_global kvm_vgic_global_state;
> @@ -269,6 +272,12 @@ struct vgic_cpu {
>  	u64 pendbaser;
>  
>  	bool lpis_enabled;
> +
> +	/* Cache guest priority bits */
> +	u32 num_pri_bits;
> +
> +	/* Cache guest interrupt ID bits */
> +	u32 num_id_bits;
>  };
>  
>  extern struct static_key_false vgic_v2_cpuif_trap;
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index bc7de95..b6266fe 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -16,6 +16,7 @@
>  #include <linux/kvm_host.h>
>  #include <kvm/arm_vgic.h>
>  #include <linux/uaccess.h>
> +#include <asm/kvm_emulate.h>
>  #include <asm/kvm_mmu.h>
>  #include "vgic.h"
>  
> @@ -501,6 +502,14 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
>  		if (!is_write)
>  			*reg = tmp32;
>  		break;
> +	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
> +		u64 regid;
> +
> +		regid = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK);
> +		ret = vgic_v3_cpu_sysregs_uaccess(vcpu, is_write,
> +						  regid, reg);
> +		break;
> +	}
>  	default:
>  		ret = -EINVAL;
>  		break;
> @@ -534,6 +543,15 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
>  		reg = tmp32;
>  		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
>  	}
> +	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
> +		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
> +		u64 reg;
> +
> +		if (get_user(reg, uaddr))
> +			return -EFAULT;
> +
> +		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
> +	}
>  	}
>  	return -ENXIO;
>  }
> @@ -560,6 +578,15 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
>  		tmp32 = reg;
>  		return put_user(tmp32, uaddr);
>  	}
> +	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
> +		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
> +		u64 reg;
> +
> +		ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
> +		if (ret)
> +			return ret;
> +		return put_user(reg, uaddr);
> +	}
>  	}
>  
>  	return -ENXIO;
> @@ -578,6 +605,7 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
>  		break;
>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>  	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
> +	case KVM_DEV_ARM_VGIC_CPU_SYSREGS:
>  		return vgic_v3_has_attr_regs(dev, attr);
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>  		return 0;
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index 2a7cd62..2f7b4ed 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -641,6 +641,24 @@ int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>  		nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
>  		break;
>  	}
> +	case KVM_DEV_ARM_VGIC_CPU_SYSREGS: {
> +		u64 reg, id;
> +		unsigned long vgic_mpidr, mpidr_reg;
> +		struct kvm_vcpu *vcpu;
> +
> +		vgic_mpidr = (attr->attr & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) >>
> +			      KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT;
> +
> +		/* Convert plain mpidr value to MPIDR reg format */
> +		mpidr_reg = VGIC_TO_MPIDR(vgic_mpidr);
> +
> +		vcpu = kvm_mpidr_to_vcpu(dev->kvm, mpidr_reg);
> +		if (!vcpu)
> +			return -EINVAL;
> +
> +		id = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK);
> +		return vgic_v3_has_cpu_sysregs_attr(vcpu, 0, id, &reg);
> +	}
>  	default:
>  		return -ENXIO;
>  	}
> diff --git a/virt/kvm/arm/vgic/vgic-sys-reg-common.c b/virt/kvm/arm/vgic/vgic-sys-reg-common.c
> new file mode 100644
> index 0000000..a1fc370c
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-sys-reg-common.c
> @@ -0,0 +1,258 @@
> +/*
> + * VGIC system registers handling functions
> + *
> + * 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.
> + */
> +
> +#include <linux/irqchip/arm-gic-v3.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <asm/kvm_emulate.h>
> +#include "vgic.h"
> +
> +bool access_gic_ctlr_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			 unsigned long *reg)
> +{
> +	struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_vmcr vmcr;
> +	u64 val;
> +	u32 valid_bits, seis, a3v;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +	if (is_write) {
> +		val = *reg;
> +
> +		/*
> +		 * Disallow restoring VM state if not supported by this
> +		 * hardware.
> +		 */
> +		valid_bits = ((val & ICC_CTLR_EL1_PRI_BITS_MASK) >>
> +				ICC_CTLR_EL1_PRI_BITS_SHIFT) + 1;
> +		if (valid_bits > vgic_v3_cpu->num_pri_bits)
> +			return false;
> +
> +		vgic_v3_cpu->num_pri_bits = valid_bits;
> +
> +		valid_bits = (val & ICC_CTLR_EL1_ID_BITS_MASK) >>
> +			       ICC_CTLR_EL1_ID_BITS_SHIFT;
> +		if (valid_bits > vgic_v3_cpu->num_id_bits)
> +			return false;
> +
> +		vgic_v3_cpu->num_id_bits = valid_bits;

nit: could you just define the variables your need instead of reusing
this valid_bits thing, that would make the code a lot more readable.


> +
> +		valid_bits = ((kvm_vgic_global_state.ich_vtr_el2 &
> +			ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT);

it's especially confusing that you now use valid_bits for the host's
values...

> +		seis = (val & ICC_CTLR_EL1_SEIS_MASK) >>
> +			ICC_CTLR_EL1_SEIS_SHIFT;
> +		if (valid_bits != seis)
> +			return false;



> +
> +		valid_bits = ((kvm_vgic_global_state.ich_vtr_el2 &
> +			ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT);
> +		a3v = (val & ICC_CTLR_EL1_A3V_MASK) >>
> +			ICC_CTLR_EL1_A3V_SHIFT;
> +		if (valid_bits != a3v)
> +			return false;
> +
> +		vmcr.ctlr = (val & ICC_CTLR_EL1_CBPR_MASK);
> +		vmcr.ctlr |= (val & ICC_CTLR_EL1_EOImode_MASK);
> +		vgic_set_vmcr(vcpu, &vmcr);
> +	} else {
> +		val = 0;
> +		val |= (vgic_v3_cpu->num_pri_bits - 1) <<
> +			ICC_CTLR_EL1_PRI_BITS_SHIFT;
> +		val |= vgic_v3_cpu->num_id_bits <<
> +			ICC_CTLR_EL1_ID_BITS_SHIFT;
> +		val |= ((kvm_vgic_global_state.ich_vtr_el2 &
> +			ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT) <<
> +			ICC_CTLR_EL1_SEIS_SHIFT;
> +		val |= ((kvm_vgic_global_state.ich_vtr_el2 &
> +			ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT) <<
> +			ICC_CTLR_EL1_A3V_SHIFT;
> +		val |= (vmcr.ctlr & ICC_CTLR_EL1_CBPR_MASK);
> +		val |= (vmcr.ctlr & ICC_CTLR_EL1_EOImode_MASK);
> +
> +		*reg = val;
> +	}
> +
> +	return true;
> +}
> +
> +bool access_gic_pmr_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			unsigned long *reg)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +	if (is_write) {
> +		vmcr.pmr = (*reg & ICC_PMR_EL1_MASK) >> ICC_PMR_EL1_SHIFT;
> +		vgic_set_vmcr(vcpu, &vmcr);
> +	} else {
> +		*reg = (vmcr.pmr << ICC_PMR_EL1_SHIFT) & ICC_PMR_EL1_MASK;
> +	}
> +
> +	return true;
> +}
> +
> +bool access_gic_bpr0_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			 unsigned long *reg)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +	if (is_write) {
> +		vmcr.bpr = (*reg & ICC_BPR0_EL1_MASK) >>
> +			    ICC_BPR0_EL1_SHIFT;
> +		vgic_set_vmcr(vcpu, &vmcr);
> +	} else {
> +		*reg = (vmcr.bpr << ICC_BPR0_EL1_SHIFT) & ICC_BPR0_EL1_MASK;
> +	}
> +
> +	return true;
> +}
> +
> +bool access_gic_bpr1_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			 unsigned long *reg)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	if (!is_write)
> +		*reg = 0;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +	if (!((vmcr.ctlr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT)) {
> +		if (is_write) {
> +			vmcr.abpr = (*reg & ICC_BPR1_EL1_MASK) >>
> +				     ICC_BPR1_EL1_SHIFT;
> +			vgic_set_vmcr(vcpu, &vmcr);
> +		} else {
> +			*reg = (vmcr.abpr << ICC_BPR1_EL1_SHIFT) &
> +				ICC_BPR1_EL1_MASK;
> +		}
> +	} else {
> +		if (!is_write)
> +			*reg = min((vmcr.bpr + 1), 7U);
> +	}
> +
> +	return true;
> +}
> +
> +bool access_gic_grpen0_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			   unsigned long *reg)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +	if (is_write) {
> +		vmcr.grpen0 = (*reg & ICC_IGRPEN0_EL1_MASK) >>
> +			       ICC_IGRPEN0_EL1_SHIFT;
> +		vgic_set_vmcr(vcpu, &vmcr);
> +	} else {
> +		*reg = (vmcr.grpen0 << ICC_IGRPEN0_EL1_SHIFT) &
> +			ICC_IGRPEN0_EL1_MASK;
> +	}
> +
> +	return true;
> +}
> +
> +bool access_gic_grpen1_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			   unsigned long *reg)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +	if (is_write) {
> +		vmcr.grpen1 = (*reg & ICC_IGRPEN1_EL1_MASK) >>
> +			       ICC_IGRPEN1_EL1_SHIFT;
> +		vgic_set_vmcr(vcpu, &vmcr);
> +	} else {
> +		*reg = (vmcr.grpen1 << ICC_IGRPEN1_EL1_SHIFT) &
> +			ICC_IGRPEN1_EL1_MASK;
> +	}
> +
> +	return true;
> +}
> +
> +static void vgic_v3_access_apr_reg(struct kvm_vcpu *vcpu, bool is_write,
> +				   u8 apr, u8 idx, unsigned long *reg)
> +{
> +	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
> +	uint32_t *ap_reg;
> +
> +	if (apr)
> +		ap_reg = &vgicv3->vgic_ap1r[idx];
> +	else
> +		ap_reg = &vgicv3->vgic_ap0r[idx];
> +
> +	if (is_write)
> +		*ap_reg = *reg;
> +	else
> +		*reg = *ap_reg;
> +}
> +
> +static bool access_gic_aprn(struct kvm_vcpu *vcpu, bool is_write, u8 apr,
> +			    u8 idx, unsigned long *reg)
> +{
> +	struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
> +
> +	/* num_pri_bits are initialized with HW supported values.
> +	 * We can rely safely on num_pri_bits even if VM has not
> +	 * restored ICC_CTLR_EL1 before restoring APnR registers.
> +	 */

nit: commenting style

> +	switch (vgic_v3_cpu->num_pri_bits) {
> +	case 7:
> +		vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
> +		break;
> +	case 6:
> +		if (idx > 1)
> +			goto err;
> +		vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
> +		break;
> +	default:
> +		if (idx > 0)
> +			goto err;
> +		vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
> +	}

It looks to me like userspace can then program active priorities with
higher numbers than what it will program num_pri_bits to later.  Is that
not weird, or am I missing something?

> +
> +	return true;
> +err:
> +	if (!is_write)
> +		*reg = 0;
> +
> +	return false;
> +}
> +
> +bool access_gic_ap0r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
> +			 unsigned long *reg)
> +{
> +	return access_gic_aprn(vcpu, is_write, 0, idx, reg);
> +}
> +
> +bool access_gic_ap1r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
> +			 unsigned long *reg)
> +{
> +	return access_gic_aprn(vcpu, is_write, 1, idx, reg);
> +}
> +
> +bool access_gic_sre_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			unsigned long *reg)
> +{
> +	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
> +
> +	/* Validate SRE bit */
> +	if (is_write) {
> +		if (!(*reg & ICC_SRE_EL1_SRE))
> +			return false;
> +	} else {
> +		*reg = vgicv3->vgic_sre;
> +	}
> +
> +	return true;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-sys-reg-v3.c b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
> new file mode 100644
> index 0000000..82c2f02
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
> @@ -0,0 +1,142 @@
> +/*
> + * VGIC system registers handling functions
> + *
> + * 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.
> + */
> +
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <asm/kvm_emulate.h>
> +#include "vgic.h"
> +#include "sys_regs.h"
> +
> +#define ACCESS_SYS_REG(REG)						\
> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,		\
> +				    struct sys_reg_params *p,		\
> +				    const struct sys_reg_desc *r)	\
> +{									\
> +	unsigned long tmp;						\
> +	bool ret;							\
> +									\
> +	if (p->is_write)						\
> +		tmp = p->regval;					\
> +	ret = access_gic_##REG##_reg(vcpu, p->is_write, &tmp);		\
> +	if (!p->is_write)						\
> +		p->regval = tmp;					\
> +									\
> +	return ret;							\
> +}
> +
> +ACCESS_SYS_REG(ctlr)
> +ACCESS_SYS_REG(pmr)
> +ACCESS_SYS_REG(bpr0)
> +ACCESS_SYS_REG(bpr1)
> +ACCESS_SYS_REG(sre)
> +ACCESS_SYS_REG(grpen0)
> +ACCESS_SYS_REG(grpen1)
> +
> +#define ACCESS_APNR_SYS_REG(REG)					\
> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,		\
> +				    struct sys_reg_params *p,		\
> +				    const struct sys_reg_desc *r)	\
> +{									\
> +	unsigned long tmp;						\
> +	u8 idx = p->Op2 & 3;						\
> +	bool ret;							\
> +									\
> +	if (p->is_write)						\
> +		tmp = p->regval;					\
> +	ret = access_gic_##REG##_reg(vcpu, p->is_write, idx, &tmp);	\
> +	if (!p->is_write)						\
> +		p->regval = tmp;					\
> +									\
> +	return ret;							\
> +}
> +
> +ACCESS_APNR_SYS_REG(ap0r)
> +ACCESS_APNR_SYS_REG(ap1r)

I don't get these indirections.  Why can't you call the functions
directly?

> +
> +static const struct sys_reg_desc gic_v3_icc_reg_descs[] = {
> +	/* ICC_PMR_EL1 */
> +	{ Op0(3), Op1(0), CRn(4), CRm(6), Op2(0), access_gic_pmr_sys_reg },
> +	/* ICC_BPR0_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(3), access_gic_bpr0_sys_reg },
> +	/* ICC_AP0R0_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(4), access_gic_ap0r_sys_reg },
> +	/* ICC_AP0R1_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(5), access_gic_ap0r_sys_reg },
> +	/* ICC_AP0R2_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(6), access_gic_ap0r_sys_reg },
> +	/* ICC_AP0R3_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(8), Op2(7), access_gic_ap0r_sys_reg },
> +	/* ICC_AP1R0_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(0), access_gic_ap1r_sys_reg },
> +	/* ICC_AP1R1_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(1), access_gic_ap1r_sys_reg },
> +	/* ICC_AP1R2_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(2), access_gic_ap1r_sys_reg },
> +	/* ICC_AP1R3_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(9), Op2(3), access_gic_ap1r_sys_reg },
> +	/* ICC_BPR1_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(3), access_gic_bpr1_sys_reg },
> +	/* ICC_CTLR_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(4), access_gic_ctlr_sys_reg },
> +	/* ICC_SRE_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(5), access_gic_sre_sys_reg },
> +	/* ICC_IGRPEN0_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(6), access_gic_grpen0_sys_reg },
> +	/* ICC_GRPEN1_EL1 */
> +	{ Op0(3), Op1(0), CRn(12), CRm(12), Op2(7), access_gic_grpen1_sys_reg },
> +};
> +
> +int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
> +				u64 *reg)
> +{
> +	struct sys_reg_params params;
> +	u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64;
> +
> +	params.regval = *reg;
> +	params.is_write = is_write;
> +	params.is_aarch32 = false;
> +	params.is_32bit = false;
> +
> +	if (find_reg_by_id(sysreg, &params, gic_v3_icc_reg_descs,
> +			      ARRAY_SIZE(gic_v3_icc_reg_descs)))
> +		return 0;
> +
> +	return -ENXIO;
> +}
> +
> +int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
> +				u64 *reg)
> +{
> +	struct sys_reg_params params;
> +	const struct sys_reg_desc *r;
> +	u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64;
> +
> +	if (is_write)
> +		params.regval = *reg;
> +	params.is_write = is_write;
> +	params.is_aarch32 = false;
> +	params.is_32bit = false;
> +
> +	r = find_reg_by_id(sysreg, &params, gic_v3_icc_reg_descs,
> +			   ARRAY_SIZE(gic_v3_icc_reg_descs));
> +	if (!r)
> +		return -ENXIO;
> +
> +	if (!r->access(vcpu, &params, r))
> +		return -EINVAL;
> +
> +	if (!is_write)
> +		*reg = params.regval;
> +
> +	return 0;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index a3ff04b..6e7400e 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -240,6 +240,13 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
>  		vgic_v3->vgic_sre = 0;
>  	}
>  
> +	vcpu->arch.vgic_cpu.num_id_bits = (kvm_vgic_global_state.ich_vtr_el2 &
> +					   ICH_VTR_ID_BITS_MASK) >>
> +					   ICH_VTR_ID_BITS_SHIFT;
> +	vcpu->arch.vgic_cpu.num_pri_bits = ((kvm_vgic_global_state.ich_vtr_el2 &
> +					    ICH_VTR_PRI_BITS_MASK) >>
> +					    ICH_VTR_PRI_BITS_SHIFT) + 1;
> +
>  	/* Get the show on the road... */
>  	vgic_v3->vgic_hcr = ICH_HCR_EN;
>  }
> @@ -340,6 +347,7 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
>  	 */
>  	kvm_vgic_global_state.nr_lr = (ich_vtr_el2 & 0xf) + 1;
>  	kvm_vgic_global_state.can_emulate_gicv2 = false;
> +	kvm_vgic_global_state.ich_vtr_el2 = ich_vtr_el2;
>  
>  	if (!info->vcpu.start) {
>  		kvm_info("GICv3: no GICV resource entry\n");
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 9232791..af23399 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -140,6 +140,28 @@ int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			 int offset, u32 *val);
>  int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			 int offset, u32 *val);
> +int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +			 u64 id, u64 *val);
> +int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
> +				u64 *reg);
> +bool access_gic_ctlr_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			 unsigned long *reg);
> +bool access_gic_pmr_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			unsigned long *reg);
> +bool access_gic_bpr0_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			 unsigned long *reg);
> +bool access_gic_bpr1_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			 unsigned long *reg);
> +bool access_gic_grpen0_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			   unsigned long *reg);
> +bool access_gic_grpen1_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			   unsigned long *reg);
> +bool access_gic_ap0r_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			 u8 idx, unsigned long *reg);
> +bool access_gic_ap1r_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			 u8 idx, unsigned long *reg);
> +bool access_gic_sre_reg(struct kvm_vcpu *vcpu, bool is_write,
> +			unsigned long *reg);

nit: since all of this is exported, I would name them vgic_access_ctlr()
and so on. The _reg postfix is probably also unnecessary for all of
these.

>  int kvm_register_vgic_device(unsigned long type);
>  void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> -- 
> 1.9.1
> 

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 07/11] arm/arm64: vgic: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl
  2016-11-23 13:01   ` vijay.kilari at gmail.com
@ 2016-11-28 19:50     ` Christoffer Dall
  -1 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-28 19:50 UTC (permalink / raw)
  To: vijay.kilari; +Cc: marc.zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

On Wed, Nov 23, 2016 at 06:31:54PM +0530, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> 
> Userspace requires to store and restore of line_level for
> level triggered interrupts using ioctl KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO.
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> ---
>  arch/arm/include/uapi/asm/kvm.h     |  7 ++++++
>  arch/arm64/include/uapi/asm/kvm.h   |  6 +++++
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 49 ++++++++++++++++++++++++++++++++++++-
>  virt/kvm/arm/vgic/vgic-mmio-v3.c    | 11 +++++++++
>  virt/kvm/arm/vgic/vgic-mmio.c       | 38 ++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h       |  5 ++++
>  virt/kvm/arm/vgic/vgic.h            |  2 ++
>  7 files changed, 117 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
> index 98658d9d..f347779 100644
> --- a/arch/arm/include/uapi/asm/kvm.h
> +++ b/arch/arm/include/uapi/asm/kvm.h
> @@ -191,6 +191,13 @@ struct kvm_arch_memory_slot {
>  #define KVM_DEV_ARM_VGIC_GRP_CTRL       4
>  #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
>  #define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
> +#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT	10
> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
> +			(0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK	0x3ff
> +#define VGIC_LEVEL_INFO_LINE_LEVEL	0
> +
>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
>  
>  /* KVM_IRQ_LINE irq field index values */
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 91c7137..4100f8c 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -211,6 +211,12 @@ struct kvm_arch_memory_slot {
>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
>  #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
>  #define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
> +#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT	10
> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
> +			(0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK	0x3ff
> +#define VGIC_LEVEL_INFO_LINE_LEVEL	0
>  
>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
>  
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index b6266fe..52ed00b 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -510,6 +510,25 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
>  						  regid, reg);
>  		break;
>  	}
> +	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
> +		unsigned int info, intid;
> +
> +		info = (attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
> +			KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT;
> +		if (info == VGIC_LEVEL_INFO_LINE_LEVEL) {
> +			if (is_write)
> +				tmp32 = *reg;
> +			intid = attr->attr &
> +				KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK;
> +			ret = vgic_v3_line_level_info_uaccess(vcpu, is_write,
> +							      intid, &tmp32);
> +			if (!is_write)
> +				*reg = tmp32;

I had a comment here about not having to use the tmp32 by modifying the
line_level_info function, that you seem to have missed.

Hint: The level info is not called from an MMIO path so you should be
able to just write it in a natural way.

> +		} else {
> +			ret = -EINVAL;
> +		}
> +		break;
> +	}
>  	default:
>  		ret = -EINVAL;
>  		break;
> @@ -552,6 +571,17 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
>  
>  		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
>  	}
> +	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
> +		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
> +		u64 reg;
> +		u32 tmp32;
> +
> +		if (get_user(tmp32, uaddr))
> +			return -EFAULT;
> +
> +		reg = tmp32;
> +		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
> +	}
>  	}
>  	return -ENXIO;
>  }
> @@ -587,8 +617,18 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
>  			return ret;
>  		return put_user(reg, uaddr);
>  	}
> -	}
> +	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
> +		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
> +		u64 reg;
> +		u32 tmp32;
>  
> +		ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
> +		if (ret)
> +			return ret;
> +		tmp32 = reg;
> +		return put_user(tmp32, uaddr);
> +	}
> +	}
>  	return -ENXIO;
>  }
>  
> @@ -609,6 +649,13 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
>  		return vgic_v3_has_attr_regs(dev, attr);
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>  		return 0;
> +	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
> +		if (((attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
> +		      KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) ==
> +		      VGIC_LEVEL_INFO_LINE_LEVEL)
> +			return 0;
> +		break;
> +	}
>  	case KVM_DEV_ARM_VGIC_GRP_CTRL:
>  		switch (attr->attr) {
>  		case KVM_DEV_ARM_VGIC_CTRL_INIT:
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index 2f7b4ed..4d7d93d 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -808,3 +808,14 @@ int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  		return vgic_uaccess(vcpu, &rd_dev, is_write,
>  				    offset, val);
>  }
> +
> +int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +				    u32 intid, u32 *val)
> +{
> +	if (is_write)
> +		vgic_write_irq_line_level_info(vcpu, intid, *val);
> +	else
> +		*val = vgic_read_irq_line_level_info(vcpu, intid);
> +
> +	return 0;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index f81e0e5..d602081 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -371,6 +371,44 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>  	}
>  }
>  
> +unsigned long vgic_read_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid)
> +{
> +	int i;
> +	unsigned long val = 0;
> +
> +	for (i = 0; i < 32; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (irq->line_level)
> +			val |= (1U << i);
> +
> +		vgic_put_irq(vcpu->kvm, irq);
> +	}
> +
> +	return val;
> +}
> +
> +void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid,
> +				    const unsigned long val)
> +{
> +	int i;
> +
> +	for (i = 0; i < 32; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		if (val & (1U << i)) {
> +			irq->line_level = true;
> +			vgic_queue_irq_unlock(vcpu->kvm, irq);
> +		} else {
> +			irq->line_level = false;
> +			spin_unlock(&irq->irq_lock);
> +		}

I think you also missed my comment about having to keep the pending
state in sync with the level state.

Which means you have to set the pending state when the line_level goes
up, and lower it when it goes down unless soft_pending is also set,
assuming it's configured as a level triggered interrupt.

If it's an edge-triggered interrupt, I think you only need to set the
pending state on a line being asserted and the rest should be adjusted
in case the user restores the configuration state to level triggered
later.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 07/11] arm/arm64: vgic: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl
@ 2016-11-28 19:50     ` Christoffer Dall
  0 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-28 19:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 23, 2016 at 06:31:54PM +0530, vijay.kilari at gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> 
> Userspace requires to store and restore of line_level for
> level triggered interrupts using ioctl KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO.
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> ---
>  arch/arm/include/uapi/asm/kvm.h     |  7 ++++++
>  arch/arm64/include/uapi/asm/kvm.h   |  6 +++++
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 49 ++++++++++++++++++++++++++++++++++++-
>  virt/kvm/arm/vgic/vgic-mmio-v3.c    | 11 +++++++++
>  virt/kvm/arm/vgic/vgic-mmio.c       | 38 ++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h       |  5 ++++
>  virt/kvm/arm/vgic/vgic.h            |  2 ++
>  7 files changed, 117 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
> index 98658d9d..f347779 100644
> --- a/arch/arm/include/uapi/asm/kvm.h
> +++ b/arch/arm/include/uapi/asm/kvm.h
> @@ -191,6 +191,13 @@ struct kvm_arch_memory_slot {
>  #define KVM_DEV_ARM_VGIC_GRP_CTRL       4
>  #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
>  #define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
> +#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT	10
> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
> +			(0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK	0x3ff
> +#define VGIC_LEVEL_INFO_LINE_LEVEL	0
> +
>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
>  
>  /* KVM_IRQ_LINE irq field index values */
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 91c7137..4100f8c 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -211,6 +211,12 @@ struct kvm_arch_memory_slot {
>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
>  #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
>  #define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
> +#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT	10
> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
> +			(0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK	0x3ff
> +#define VGIC_LEVEL_INFO_LINE_LEVEL	0
>  
>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
>  
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index b6266fe..52ed00b 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -510,6 +510,25 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
>  						  regid, reg);
>  		break;
>  	}
> +	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
> +		unsigned int info, intid;
> +
> +		info = (attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
> +			KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT;
> +		if (info == VGIC_LEVEL_INFO_LINE_LEVEL) {
> +			if (is_write)
> +				tmp32 = *reg;
> +			intid = attr->attr &
> +				KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK;
> +			ret = vgic_v3_line_level_info_uaccess(vcpu, is_write,
> +							      intid, &tmp32);
> +			if (!is_write)
> +				*reg = tmp32;

I had a comment here about not having to use the tmp32 by modifying the
line_level_info function, that you seem to have missed.

Hint: The level info is not called from an MMIO path so you should be
able to just write it in a natural way.

> +		} else {
> +			ret = -EINVAL;
> +		}
> +		break;
> +	}
>  	default:
>  		ret = -EINVAL;
>  		break;
> @@ -552,6 +571,17 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
>  
>  		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
>  	}
> +	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
> +		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
> +		u64 reg;
> +		u32 tmp32;
> +
> +		if (get_user(tmp32, uaddr))
> +			return -EFAULT;
> +
> +		reg = tmp32;
> +		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
> +	}
>  	}
>  	return -ENXIO;
>  }
> @@ -587,8 +617,18 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
>  			return ret;
>  		return put_user(reg, uaddr);
>  	}
> -	}
> +	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
> +		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
> +		u64 reg;
> +		u32 tmp32;
>  
> +		ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
> +		if (ret)
> +			return ret;
> +		tmp32 = reg;
> +		return put_user(tmp32, uaddr);
> +	}
> +	}
>  	return -ENXIO;
>  }
>  
> @@ -609,6 +649,13 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
>  		return vgic_v3_has_attr_regs(dev, attr);
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>  		return 0;
> +	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
> +		if (((attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
> +		      KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) ==
> +		      VGIC_LEVEL_INFO_LINE_LEVEL)
> +			return 0;
> +		break;
> +	}
>  	case KVM_DEV_ARM_VGIC_GRP_CTRL:
>  		switch (attr->attr) {
>  		case KVM_DEV_ARM_VGIC_CTRL_INIT:
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index 2f7b4ed..4d7d93d 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -808,3 +808,14 @@ int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  		return vgic_uaccess(vcpu, &rd_dev, is_write,
>  				    offset, val);
>  }
> +
> +int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +				    u32 intid, u32 *val)
> +{
> +	if (is_write)
> +		vgic_write_irq_line_level_info(vcpu, intid, *val);
> +	else
> +		*val = vgic_read_irq_line_level_info(vcpu, intid);
> +
> +	return 0;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index f81e0e5..d602081 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -371,6 +371,44 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>  	}
>  }
>  
> +unsigned long vgic_read_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid)
> +{
> +	int i;
> +	unsigned long val = 0;
> +
> +	for (i = 0; i < 32; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (irq->line_level)
> +			val |= (1U << i);
> +
> +		vgic_put_irq(vcpu->kvm, irq);
> +	}
> +
> +	return val;
> +}
> +
> +void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid,
> +				    const unsigned long val)
> +{
> +	int i;
> +
> +	for (i = 0; i < 32; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		if (val & (1U << i)) {
> +			irq->line_level = true;
> +			vgic_queue_irq_unlock(vcpu->kvm, irq);
> +		} else {
> +			irq->line_level = false;
> +			spin_unlock(&irq->irq_lock);
> +		}

I think you also missed my comment about having to keep the pending
state in sync with the level state.

Which means you have to set the pending state when the line_level goes
up, and lower it when it goes down unless soft_pending is also set,
assuming it's configured as a level triggered interrupt.

If it's an edge-triggered interrupt, I think you only need to set the
pending state on a line being asserted and the rest should be adjusted
in case the user restores the configuration state to level triggered
later.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 0/11] arm/arm64: vgic: Implement API for vGICv3 live migration
  2016-11-23 13:01 ` vijay.kilari at gmail.com
@ 2016-11-28 19:51   ` Christoffer Dall
  -1 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-28 19:51 UTC (permalink / raw)
  To: vijay.kilari; +Cc: marc.zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

Hi Vijaya,

On Wed, Nov 23, 2016 at 06:31:47PM +0530, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> 
> This patchset adds API for saving and restoring
> of VGICv3 registers to support live migration with new vgic feature.
> This API definition is as per version of VGICv3 specification
> Documentation/virtual/kvm/devices/arm-vgic-v3.txt
> 
> The patch 3 & 4 are picked from the Pavel's previous implementation.
> http://www.spinics.net/lists/kvm/msg122040.html
> 
> NOTE: Only compilation tested for AArch32. No hardware to test.

I did not review the 32-bit part, because if you cannot test it, I don't
think we should merge it.

I just want clarity on what happens if someone tries to use this on
32-bit, and I want to make sure it fails gracefully.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 0/11] arm/arm64: vgic: Implement API for vGICv3 live migration
@ 2016-11-28 19:51   ` Christoffer Dall
  0 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-28 19:51 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Vijaya,

On Wed, Nov 23, 2016 at 06:31:47PM +0530, vijay.kilari at gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> 
> This patchset adds API for saving and restoring
> of VGICv3 registers to support live migration with new vgic feature.
> This API definition is as per version of VGICv3 specification
> Documentation/virtual/kvm/devices/arm-vgic-v3.txt
> 
> The patch 3 & 4 are picked from the Pavel's previous implementation.
> http://www.spinics.net/lists/kvm/msg122040.html
> 
> NOTE: Only compilation tested for AArch32. No hardware to test.

I did not review the 32-bit part, because if you cannot test it, I don't
think we should merge it.

I just want clarity on what happens if someone tries to use this on
32-bit, and I want to make sure it fails gracefully.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 06/11] arm/arm64: vgic: Implement VGICv3 CPU interface access
  2016-11-28 19:39     ` Christoffer Dall
@ 2016-11-29  7:38       ` Vijay Kilari
  -1 siblings, 0 replies; 78+ messages in thread
From: Vijay Kilari @ 2016-11-29  7:38 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

On Tue, Nov 29, 2016 at 1:09 AM, Christoffer Dall
<christoffer.dall@linaro.org> wrote:
> On Wed, Nov 23, 2016 at 06:31:53PM +0530, vijay.kilari@gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>
>> VGICv3 CPU interface registers are accessed using
>> KVM_DEV_ARM_VGIC_CPU_SYSREGS ioctl. These registers are accessed
>> as 64-bit. The cpu MPIDR value is passed along with register id.
>> is used to identify the cpu for registers access.
>>
>> The VM that supports SEIs expect it on destination machine to handle
>> guest aborts and hence checked for ICC_CTLR_EL1.SEIS compatibility.
>> Similarly, VM that supports Affinity Level 3 that is required for AArch64
>> mode, is required to be supported on destination machine. Hence checked
>> for ICC_CTLR_EL1.A3V compatibility.
>>
>> The CPU system register handling is spitted into two files
>
> spitted?  Did you mean 'split into' ?
>
>> vgic-sys-reg-common.c and vgic-sys-reg-v3.c.
>> The vgic-sys-reg-common.c handles read and write of VGIC CPU registers
>
> So this is weird because everything in virt/kvm/arm/ is exactly supposed
> to be common between arm and arm64 already.
>
> I would rather that you had a copy of vgic-sys-reg-v3.c in arch/arm/kvm/
> and in arch/arm64/kvm/ each taking care of its own architecture.
>
> But note that I didn't actually require that you implemented support for
> GICv3 migration on AArch32 hosts for these patches, I just didn't want
> thigns to silently break.
>
> If we cannot test the AArch32 implementation, we should potentially just
> make sure that is not supported yet, return a proper error to userspace
> and get the AArch64 host implementation correct.
>
> I suggest you move your:
>   virt/kvm/arm/vgic/vgic-sys-reg-v3.c to
>   arch/arm64/kvm/vgic-sys-reg-v3.c
>
> and rename
>   virt/kvm/arm/vgic/vgic-sys-reg-common.c to
>   virt/kvm/arm/vgic/vgic-sys-reg-v3.c
>
> And then wait with the AArch32 host side for now, but just make sure it
> compiles and returns an error as opposed to crashing the system if
> someone tries to excercise this interface on an AArch32 host.

I will add arch/arm/kvm/vgic-coproc-v3.c (pls check if file name is ok or not?)
and return -ENXIO as shown below and update document accordingly.

int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
                               u64 *reg)
{
       /*
        * TODO: Implement for AArch32
        */
       return -ENXIO;
}

int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
                               u64 *reg)
{
       /*
        * TODO: Implement for AArch32
        */
       return -ENXIO;
}

>
>> for both AArch64 and AArch32 mode. The vgic-sys-reg-v3.c handles AArch64
>> mode and is compiled only for AArch64 mode.
>>
>> Updated arch/arm/include/uapi/asm/kvm.h with new definitions
>> required to compile for AArch32.
>>
>> The version of VGIC v3 specification is define here
>> Documentation/virtual/kvm/devices/arm-vgic-v3.txt
>>
>> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>> ---
[...]
>> +static bool access_gic_aprn(struct kvm_vcpu *vcpu, bool is_write, u8 apr,
>> +                         u8 idx, unsigned long *reg)
>> +{
>> +     struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
>> +
>> +     /* num_pri_bits are initialized with HW supported values.
>> +      * We can rely safely on num_pri_bits even if VM has not
>> +      * restored ICC_CTLR_EL1 before restoring APnR registers.
>> +      */
>
> nit: commenting style
ok
>
>> +     switch (vgic_v3_cpu->num_pri_bits) {
>> +     case 7:
>> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
>> +             break;
>> +     case 6:
>> +             if (idx > 1)
>> +                     goto err;
>> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
>> +             break;
>> +     default:
>> +             if (idx > 0)
>> +                     goto err;
>> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
>> +     }
>
> It looks to me like userspace can then program active priorities with
> higher numbers than what it will program num_pri_bits to later.  Is that
> not weird, or am I missing something?

As long as it is within HW supported priorities it is safe.
>
>> +
>> +     return true;
>> +err:
>> +     if (!is_write)
>> +             *reg = 0;
>> +
>> +     return false;
>> +}
>> +
>> +bool access_gic_ap0r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
>> +                      unsigned long *reg)
>> +{
>> +     return access_gic_aprn(vcpu, is_write, 0, idx, reg);
>> +}
>> +
>> +bool access_gic_ap1r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
>> +                      unsigned long *reg)
>> +{
>> +     return access_gic_aprn(vcpu, is_write, 1, idx, reg);
>> +}
>> +
>> +bool access_gic_sre_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                     unsigned long *reg)
>> +{
>> +     struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
>> +
>> +     /* Validate SRE bit */
>> +     if (is_write) {
>> +             if (!(*reg & ICC_SRE_EL1_SRE))
>> +                     return false;
>> +     } else {
>> +             *reg = vgicv3->vgic_sre;
>> +     }
>> +
>> +     return true;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic-sys-reg-v3.c b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
>> new file mode 100644
>> index 0000000..82c2f02
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
>> @@ -0,0 +1,142 @@
>> +/*
>> + * VGIC system registers handling functions
>> + *
>> + * 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.
>> + */
>> +
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +#include <asm/kvm_emulate.h>
>> +#include "vgic.h"
>> +#include "sys_regs.h"
>> +
>> +#define ACCESS_SYS_REG(REG)                                          \
>> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,                \
>> +                                 struct sys_reg_params *p,           \
>> +                                 const struct sys_reg_desc *r)       \
>> +{                                                                    \
>> +     unsigned long tmp;                                              \
>> +     bool ret;                                                       \
>> +                                                                     \
>> +     if (p->is_write)                                                \
>> +             tmp = p->regval;                                        \
>> +     ret = access_gic_##REG##_reg(vcpu, p->is_write, &tmp);          \
>> +     if (!p->is_write)                                               \
>> +             p->regval = tmp;                                        \
>> +                                                                     \
>> +     return ret;                                                     \
>> +}
>> +
>> +ACCESS_SYS_REG(ctlr)
>> +ACCESS_SYS_REG(pmr)
>> +ACCESS_SYS_REG(bpr0)
>> +ACCESS_SYS_REG(bpr1)
>> +ACCESS_SYS_REG(sre)
>> +ACCESS_SYS_REG(grpen0)
>> +ACCESS_SYS_REG(grpen1)
>> +
>> +#define ACCESS_APNR_SYS_REG(REG)                                     \
>> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,                \
>> +                                 struct sys_reg_params *p,           \
>> +                                 const struct sys_reg_desc *r)       \
>> +{                                                                    \
>> +     unsigned long tmp;                                              \
>> +     u8 idx = p->Op2 & 3;                                            \
>> +     bool ret;                                                       \
>> +                                                                     \
>> +     if (p->is_write)                                                \
>> +             tmp = p->regval;                                        \
>> +     ret = access_gic_##REG##_reg(vcpu, p->is_write, idx, &tmp);     \
>> +     if (!p->is_write)                                               \
>> +             p->regval = tmp;                                        \
>> +                                                                     \
>> +     return ret;                                                     \
>> +}
>> +
>> +ACCESS_APNR_SYS_REG(ap0r)
>> +ACCESS_APNR_SYS_REG(ap1r)
>
> I don't get these indirections.  Why can't you call the functions
> directly?

The code is same for accessing the registers hence added this indirection.

>
>> +
>> +static const struct sys_reg_desc gic_v3_icc_reg_descs[] = {
>> +     /* ICC_PMR_EL1 */
>> +     { Op0(3), Op1(0), CRn(4), CRm(6), Op2(0), access_gic_pmr_sys_reg },
>> +     /* ICC_BPR0_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(8), Op2(3), access_gic_bpr0_sys_reg },
>> +     /* ICC_AP0R0_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(8), Op2(4), access_gic_ap0r_sys_reg },
>> +     /* ICC_AP0R1_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(8), Op2(5), access_gic_ap0r_sys_reg },
>> +     /* ICC_AP0R2_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(8), Op2(6), access_gic_ap0r_sys_reg },
>> +     /* ICC_AP0R3_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(8), Op2(7), access_gic_ap0r_sys_reg },
>> +     /* ICC_AP1R0_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(9), Op2(0), access_gic_ap1r_sys_reg },
>> +     /* ICC_AP1R1_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(9), Op2(1), access_gic_ap1r_sys_reg },
>> +     /* ICC_AP1R2_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(9), Op2(2), access_gic_ap1r_sys_reg },
>> +     /* ICC_AP1R3_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(9), Op2(3), access_gic_ap1r_sys_reg },
>> +     /* ICC_BPR1_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(12), Op2(3), access_gic_bpr1_sys_reg },
>> +     /* ICC_CTLR_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(12), Op2(4), access_gic_ctlr_sys_reg },
>> +     /* ICC_SRE_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(12), Op2(5), access_gic_sre_sys_reg },
>> +     /* ICC_IGRPEN0_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(12), Op2(6), access_gic_grpen0_sys_reg },
>> +     /* ICC_GRPEN1_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(12), Op2(7), access_gic_grpen1_sys_reg },
>> +};
>> +
>> +int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
>> +                             u64 *reg)
>> +{
>> +     struct sys_reg_params params;
>> +     u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64;
>> +
>> +     params.regval = *reg;
>> +     params.is_write = is_write;
>> +     params.is_aarch32 = false;
>> +     params.is_32bit = false;
>> +
>> +     if (find_reg_by_id(sysreg, &params, gic_v3_icc_reg_descs,
>> +                           ARRAY_SIZE(gic_v3_icc_reg_descs)))
>> +             return 0;
>> +
>> +     return -ENXIO;
>> +}
>> +
>> +int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
>> +                             u64 *reg)
>> +{
>> +     struct sys_reg_params params;
>> +     const struct sys_reg_desc *r;
>> +     u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64;
>> +
>> +     if (is_write)
>> +             params.regval = *reg;
>> +     params.is_write = is_write;
>> +     params.is_aarch32 = false;
>> +     params.is_32bit = false;
>> +
>> +     r = find_reg_by_id(sysreg, &params, gic_v3_icc_reg_descs,
>> +                        ARRAY_SIZE(gic_v3_icc_reg_descs));
>> +     if (!r)
>> +             return -ENXIO;
>> +
>> +     if (!r->access(vcpu, &params, r))
>> +             return -EINVAL;
>> +
>> +     if (!is_write)
>> +             *reg = params.regval;
>> +
>> +     return 0;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>> index a3ff04b..6e7400e 100644
>> --- a/virt/kvm/arm/vgic/vgic-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>> @@ -240,6 +240,13 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
>>               vgic_v3->vgic_sre = 0;
>>       }
>>
>> +     vcpu->arch.vgic_cpu.num_id_bits = (kvm_vgic_global_state.ich_vtr_el2 &
>> +                                        ICH_VTR_ID_BITS_MASK) >>
>> +                                        ICH_VTR_ID_BITS_SHIFT;
>> +     vcpu->arch.vgic_cpu.num_pri_bits = ((kvm_vgic_global_state.ich_vtr_el2 &
>> +                                         ICH_VTR_PRI_BITS_MASK) >>
>> +                                         ICH_VTR_PRI_BITS_SHIFT) + 1;
>> +
>>       /* Get the show on the road... */
>>       vgic_v3->vgic_hcr = ICH_HCR_EN;
>>  }
>> @@ -340,6 +347,7 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
>>        */
>>       kvm_vgic_global_state.nr_lr = (ich_vtr_el2 & 0xf) + 1;
>>       kvm_vgic_global_state.can_emulate_gicv2 = false;
>> +     kvm_vgic_global_state.ich_vtr_el2 = ich_vtr_el2;
>>
>>       if (!info->vcpu.start) {
>>               kvm_info("GICv3: no GICV resource entry\n");
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 9232791..af23399 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -140,6 +140,28 @@ int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>                        int offset, u32 *val);
>>  int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>                        int offset, u32 *val);
>> +int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>> +                      u64 id, u64 *val);
>> +int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
>> +                             u64 *reg);
>> +bool access_gic_ctlr_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                      unsigned long *reg);
>> +bool access_gic_pmr_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                     unsigned long *reg);
>> +bool access_gic_bpr0_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                      unsigned long *reg);
>> +bool access_gic_bpr1_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                      unsigned long *reg);
>> +bool access_gic_grpen0_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                        unsigned long *reg);
>> +bool access_gic_grpen1_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                        unsigned long *reg);
>> +bool access_gic_ap0r_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                      u8 idx, unsigned long *reg);
>> +bool access_gic_ap1r_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                      u8 idx, unsigned long *reg);
>> +bool access_gic_sre_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                     unsigned long *reg);
>
> nit: since all of this is exported, I would name them vgic_access_ctlr()
> and so on. The _reg postfix is probably also unnecessary for all of
> these.

OK
>
>>  int kvm_register_vgic_device(unsigned long type);
>>  void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>>  void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>> --
>> 1.9.1
>>
>
> Thanks,
> -Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 06/11] arm/arm64: vgic: Implement VGICv3 CPU interface access
@ 2016-11-29  7:38       ` Vijay Kilari
  0 siblings, 0 replies; 78+ messages in thread
From: Vijay Kilari @ 2016-11-29  7:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Nov 29, 2016 at 1:09 AM, Christoffer Dall
<christoffer.dall@linaro.org> wrote:
> On Wed, Nov 23, 2016 at 06:31:53PM +0530, vijay.kilari at gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>
>> VGICv3 CPU interface registers are accessed using
>> KVM_DEV_ARM_VGIC_CPU_SYSREGS ioctl. These registers are accessed
>> as 64-bit. The cpu MPIDR value is passed along with register id.
>> is used to identify the cpu for registers access.
>>
>> The VM that supports SEIs expect it on destination machine to handle
>> guest aborts and hence checked for ICC_CTLR_EL1.SEIS compatibility.
>> Similarly, VM that supports Affinity Level 3 that is required for AArch64
>> mode, is required to be supported on destination machine. Hence checked
>> for ICC_CTLR_EL1.A3V compatibility.
>>
>> The CPU system register handling is spitted into two files
>
> spitted?  Did you mean 'split into' ?
>
>> vgic-sys-reg-common.c and vgic-sys-reg-v3.c.
>> The vgic-sys-reg-common.c handles read and write of VGIC CPU registers
>
> So this is weird because everything in virt/kvm/arm/ is exactly supposed
> to be common between arm and arm64 already.
>
> I would rather that you had a copy of vgic-sys-reg-v3.c in arch/arm/kvm/
> and in arch/arm64/kvm/ each taking care of its own architecture.
>
> But note that I didn't actually require that you implemented support for
> GICv3 migration on AArch32 hosts for these patches, I just didn't want
> thigns to silently break.
>
> If we cannot test the AArch32 implementation, we should potentially just
> make sure that is not supported yet, return a proper error to userspace
> and get the AArch64 host implementation correct.
>
> I suggest you move your:
>   virt/kvm/arm/vgic/vgic-sys-reg-v3.c to
>   arch/arm64/kvm/vgic-sys-reg-v3.c
>
> and rename
>   virt/kvm/arm/vgic/vgic-sys-reg-common.c to
>   virt/kvm/arm/vgic/vgic-sys-reg-v3.c
>
> And then wait with the AArch32 host side for now, but just make sure it
> compiles and returns an error as opposed to crashing the system if
> someone tries to excercise this interface on an AArch32 host.

I will add arch/arm/kvm/vgic-coproc-v3.c (pls check if file name is ok or not?)
and return -ENXIO as shown below and update document accordingly.

int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
                               u64 *reg)
{
       /*
        * TODO: Implement for AArch32
        */
       return -ENXIO;
}

int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
                               u64 *reg)
{
       /*
        * TODO: Implement for AArch32
        */
       return -ENXIO;
}

>
>> for both AArch64 and AArch32 mode. The vgic-sys-reg-v3.c handles AArch64
>> mode and is compiled only for AArch64 mode.
>>
>> Updated arch/arm/include/uapi/asm/kvm.h with new definitions
>> required to compile for AArch32.
>>
>> The version of VGIC v3 specification is define here
>> Documentation/virtual/kvm/devices/arm-vgic-v3.txt
>>
>> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>> ---
[...]
>> +static bool access_gic_aprn(struct kvm_vcpu *vcpu, bool is_write, u8 apr,
>> +                         u8 idx, unsigned long *reg)
>> +{
>> +     struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
>> +
>> +     /* num_pri_bits are initialized with HW supported values.
>> +      * We can rely safely on num_pri_bits even if VM has not
>> +      * restored ICC_CTLR_EL1 before restoring APnR registers.
>> +      */
>
> nit: commenting style
ok
>
>> +     switch (vgic_v3_cpu->num_pri_bits) {
>> +     case 7:
>> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
>> +             break;
>> +     case 6:
>> +             if (idx > 1)
>> +                     goto err;
>> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
>> +             break;
>> +     default:
>> +             if (idx > 0)
>> +                     goto err;
>> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
>> +     }
>
> It looks to me like userspace can then program active priorities with
> higher numbers than what it will program num_pri_bits to later.  Is that
> not weird, or am I missing something?

As long as it is within HW supported priorities it is safe.
>
>> +
>> +     return true;
>> +err:
>> +     if (!is_write)
>> +             *reg = 0;
>> +
>> +     return false;
>> +}
>> +
>> +bool access_gic_ap0r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
>> +                      unsigned long *reg)
>> +{
>> +     return access_gic_aprn(vcpu, is_write, 0, idx, reg);
>> +}
>> +
>> +bool access_gic_ap1r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
>> +                      unsigned long *reg)
>> +{
>> +     return access_gic_aprn(vcpu, is_write, 1, idx, reg);
>> +}
>> +
>> +bool access_gic_sre_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                     unsigned long *reg)
>> +{
>> +     struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
>> +
>> +     /* Validate SRE bit */
>> +     if (is_write) {
>> +             if (!(*reg & ICC_SRE_EL1_SRE))
>> +                     return false;
>> +     } else {
>> +             *reg = vgicv3->vgic_sre;
>> +     }
>> +
>> +     return true;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic-sys-reg-v3.c b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
>> new file mode 100644
>> index 0000000..82c2f02
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
>> @@ -0,0 +1,142 @@
>> +/*
>> + * VGIC system registers handling functions
>> + *
>> + * 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.
>> + */
>> +
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +#include <asm/kvm_emulate.h>
>> +#include "vgic.h"
>> +#include "sys_regs.h"
>> +
>> +#define ACCESS_SYS_REG(REG)                                          \
>> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,                \
>> +                                 struct sys_reg_params *p,           \
>> +                                 const struct sys_reg_desc *r)       \
>> +{                                                                    \
>> +     unsigned long tmp;                                              \
>> +     bool ret;                                                       \
>> +                                                                     \
>> +     if (p->is_write)                                                \
>> +             tmp = p->regval;                                        \
>> +     ret = access_gic_##REG##_reg(vcpu, p->is_write, &tmp);          \
>> +     if (!p->is_write)                                               \
>> +             p->regval = tmp;                                        \
>> +                                                                     \
>> +     return ret;                                                     \
>> +}
>> +
>> +ACCESS_SYS_REG(ctlr)
>> +ACCESS_SYS_REG(pmr)
>> +ACCESS_SYS_REG(bpr0)
>> +ACCESS_SYS_REG(bpr1)
>> +ACCESS_SYS_REG(sre)
>> +ACCESS_SYS_REG(grpen0)
>> +ACCESS_SYS_REG(grpen1)
>> +
>> +#define ACCESS_APNR_SYS_REG(REG)                                     \
>> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,                \
>> +                                 struct sys_reg_params *p,           \
>> +                                 const struct sys_reg_desc *r)       \
>> +{                                                                    \
>> +     unsigned long tmp;                                              \
>> +     u8 idx = p->Op2 & 3;                                            \
>> +     bool ret;                                                       \
>> +                                                                     \
>> +     if (p->is_write)                                                \
>> +             tmp = p->regval;                                        \
>> +     ret = access_gic_##REG##_reg(vcpu, p->is_write, idx, &tmp);     \
>> +     if (!p->is_write)                                               \
>> +             p->regval = tmp;                                        \
>> +                                                                     \
>> +     return ret;                                                     \
>> +}
>> +
>> +ACCESS_APNR_SYS_REG(ap0r)
>> +ACCESS_APNR_SYS_REG(ap1r)
>
> I don't get these indirections.  Why can't you call the functions
> directly?

The code is same for accessing the registers hence added this indirection.

>
>> +
>> +static const struct sys_reg_desc gic_v3_icc_reg_descs[] = {
>> +     /* ICC_PMR_EL1 */
>> +     { Op0(3), Op1(0), CRn(4), CRm(6), Op2(0), access_gic_pmr_sys_reg },
>> +     /* ICC_BPR0_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(8), Op2(3), access_gic_bpr0_sys_reg },
>> +     /* ICC_AP0R0_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(8), Op2(4), access_gic_ap0r_sys_reg },
>> +     /* ICC_AP0R1_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(8), Op2(5), access_gic_ap0r_sys_reg },
>> +     /* ICC_AP0R2_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(8), Op2(6), access_gic_ap0r_sys_reg },
>> +     /* ICC_AP0R3_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(8), Op2(7), access_gic_ap0r_sys_reg },
>> +     /* ICC_AP1R0_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(9), Op2(0), access_gic_ap1r_sys_reg },
>> +     /* ICC_AP1R1_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(9), Op2(1), access_gic_ap1r_sys_reg },
>> +     /* ICC_AP1R2_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(9), Op2(2), access_gic_ap1r_sys_reg },
>> +     /* ICC_AP1R3_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(9), Op2(3), access_gic_ap1r_sys_reg },
>> +     /* ICC_BPR1_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(12), Op2(3), access_gic_bpr1_sys_reg },
>> +     /* ICC_CTLR_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(12), Op2(4), access_gic_ctlr_sys_reg },
>> +     /* ICC_SRE_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(12), Op2(5), access_gic_sre_sys_reg },
>> +     /* ICC_IGRPEN0_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(12), Op2(6), access_gic_grpen0_sys_reg },
>> +     /* ICC_GRPEN1_EL1 */
>> +     { Op0(3), Op1(0), CRn(12), CRm(12), Op2(7), access_gic_grpen1_sys_reg },
>> +};
>> +
>> +int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
>> +                             u64 *reg)
>> +{
>> +     struct sys_reg_params params;
>> +     u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64;
>> +
>> +     params.regval = *reg;
>> +     params.is_write = is_write;
>> +     params.is_aarch32 = false;
>> +     params.is_32bit = false;
>> +
>> +     if (find_reg_by_id(sysreg, &params, gic_v3_icc_reg_descs,
>> +                           ARRAY_SIZE(gic_v3_icc_reg_descs)))
>> +             return 0;
>> +
>> +     return -ENXIO;
>> +}
>> +
>> +int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
>> +                             u64 *reg)
>> +{
>> +     struct sys_reg_params params;
>> +     const struct sys_reg_desc *r;
>> +     u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64;
>> +
>> +     if (is_write)
>> +             params.regval = *reg;
>> +     params.is_write = is_write;
>> +     params.is_aarch32 = false;
>> +     params.is_32bit = false;
>> +
>> +     r = find_reg_by_id(sysreg, &params, gic_v3_icc_reg_descs,
>> +                        ARRAY_SIZE(gic_v3_icc_reg_descs));
>> +     if (!r)
>> +             return -ENXIO;
>> +
>> +     if (!r->access(vcpu, &params, r))
>> +             return -EINVAL;
>> +
>> +     if (!is_write)
>> +             *reg = params.regval;
>> +
>> +     return 0;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>> index a3ff04b..6e7400e 100644
>> --- a/virt/kvm/arm/vgic/vgic-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>> @@ -240,6 +240,13 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
>>               vgic_v3->vgic_sre = 0;
>>       }
>>
>> +     vcpu->arch.vgic_cpu.num_id_bits = (kvm_vgic_global_state.ich_vtr_el2 &
>> +                                        ICH_VTR_ID_BITS_MASK) >>
>> +                                        ICH_VTR_ID_BITS_SHIFT;
>> +     vcpu->arch.vgic_cpu.num_pri_bits = ((kvm_vgic_global_state.ich_vtr_el2 &
>> +                                         ICH_VTR_PRI_BITS_MASK) >>
>> +                                         ICH_VTR_PRI_BITS_SHIFT) + 1;
>> +
>>       /* Get the show on the road... */
>>       vgic_v3->vgic_hcr = ICH_HCR_EN;
>>  }
>> @@ -340,6 +347,7 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
>>        */
>>       kvm_vgic_global_state.nr_lr = (ich_vtr_el2 & 0xf) + 1;
>>       kvm_vgic_global_state.can_emulate_gicv2 = false;
>> +     kvm_vgic_global_state.ich_vtr_el2 = ich_vtr_el2;
>>
>>       if (!info->vcpu.start) {
>>               kvm_info("GICv3: no GICV resource entry\n");
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 9232791..af23399 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -140,6 +140,28 @@ int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>                        int offset, u32 *val);
>>  int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>                        int offset, u32 *val);
>> +int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>> +                      u64 id, u64 *val);
>> +int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
>> +                             u64 *reg);
>> +bool access_gic_ctlr_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                      unsigned long *reg);
>> +bool access_gic_pmr_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                     unsigned long *reg);
>> +bool access_gic_bpr0_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                      unsigned long *reg);
>> +bool access_gic_bpr1_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                      unsigned long *reg);
>> +bool access_gic_grpen0_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                        unsigned long *reg);
>> +bool access_gic_grpen1_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                        unsigned long *reg);
>> +bool access_gic_ap0r_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                      u8 idx, unsigned long *reg);
>> +bool access_gic_ap1r_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                      u8 idx, unsigned long *reg);
>> +bool access_gic_sre_reg(struct kvm_vcpu *vcpu, bool is_write,
>> +                     unsigned long *reg);
>
> nit: since all of this is exported, I would name them vgic_access_ctlr()
> and so on. The _reg postfix is probably also unnecessary for all of
> these.

OK
>
>>  int kvm_register_vgic_device(unsigned long type);
>>  void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>>  void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>> --
>> 1.9.1
>>
>
> Thanks,
> -Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 06/11] arm/arm64: vgic: Implement VGICv3 CPU interface access
  2016-11-29  7:38       ` Vijay Kilari
@ 2016-11-29  8:37         ` Christoffer Dall
  -1 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-29  8:37 UTC (permalink / raw)
  To: Vijay Kilari; +Cc: Marc Zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

On Tue, Nov 29, 2016 at 01:08:26PM +0530, Vijay Kilari wrote:
> On Tue, Nov 29, 2016 at 1:09 AM, Christoffer Dall
> <christoffer.dall@linaro.org> wrote:
> > On Wed, Nov 23, 2016 at 06:31:53PM +0530, vijay.kilari@gmail.com wrote:
> >> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >>
> >> VGICv3 CPU interface registers are accessed using
> >> KVM_DEV_ARM_VGIC_CPU_SYSREGS ioctl. These registers are accessed
> >> as 64-bit. The cpu MPIDR value is passed along with register id.
> >> is used to identify the cpu for registers access.
> >>
> >> The VM that supports SEIs expect it on destination machine to handle
> >> guest aborts and hence checked for ICC_CTLR_EL1.SEIS compatibility.
> >> Similarly, VM that supports Affinity Level 3 that is required for AArch64
> >> mode, is required to be supported on destination machine. Hence checked
> >> for ICC_CTLR_EL1.A3V compatibility.
> >>
> >> The CPU system register handling is spitted into two files
> >
> > spitted?  Did you mean 'split into' ?
> >
> >> vgic-sys-reg-common.c and vgic-sys-reg-v3.c.
> >> The vgic-sys-reg-common.c handles read and write of VGIC CPU registers
> >
> > So this is weird because everything in virt/kvm/arm/ is exactly supposed
> > to be common between arm and arm64 already.
> >
> > I would rather that you had a copy of vgic-sys-reg-v3.c in arch/arm/kvm/
> > and in arch/arm64/kvm/ each taking care of its own architecture.
> >
> > But note that I didn't actually require that you implemented support for
> > GICv3 migration on AArch32 hosts for these patches, I just didn't want
> > thigns to silently break.
> >
> > If we cannot test the AArch32 implementation, we should potentially just
> > make sure that is not supported yet, return a proper error to userspace
> > and get the AArch64 host implementation correct.
> >
> > I suggest you move your:
> >   virt/kvm/arm/vgic/vgic-sys-reg-v3.c to
> >   arch/arm64/kvm/vgic-sys-reg-v3.c
> >
> > and rename
> >   virt/kvm/arm/vgic/vgic-sys-reg-common.c to
> >   virt/kvm/arm/vgic/vgic-sys-reg-v3.c
> >
> > And then wait with the AArch32 host side for now, but just make sure it
> > compiles and returns an error as opposed to crashing the system if
> > someone tries to excercise this interface on an AArch32 host.
> 
> I will add arch/arm/kvm/vgic-coproc-v3.c (pls check if file name is ok or not?)

I would call it vgic-v3-coproc.c

> and return -ENXIO as shown below and update document accordingly.
> 
> int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
>                                u64 *reg)
> {
>        /*
>         * TODO: Implement for AArch32
>         */
>        return -ENXIO;
> }
> 
> int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
>                                u64 *reg)
> {
>        /*
>         * TODO: Implement for AArch32
>         */
>        return -ENXIO;
> }


> 
> >
> >> for both AArch64 and AArch32 mode. The vgic-sys-reg-v3.c handles AArch64
> >> mode and is compiled only for AArch64 mode.
> >>
> >> Updated arch/arm/include/uapi/asm/kvm.h with new definitions
> >> required to compile for AArch32.
> >>
> >> The version of VGIC v3 specification is define here
> >> Documentation/virtual/kvm/devices/arm-vgic-v3.txt
> >>
> >> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
> >> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >> ---
> [...]
> >> +static bool access_gic_aprn(struct kvm_vcpu *vcpu, bool is_write, u8 apr,
> >> +                         u8 idx, unsigned long *reg)
> >> +{
> >> +     struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
> >> +
> >> +     /* num_pri_bits are initialized with HW supported values.
> >> +      * We can rely safely on num_pri_bits even if VM has not
> >> +      * restored ICC_CTLR_EL1 before restoring APnR registers.
> >> +      */
> >
> > nit: commenting style
> ok
> >
> >> +     switch (vgic_v3_cpu->num_pri_bits) {
> >> +     case 7:
> >> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
> >> +             break;
> >> +     case 6:
> >> +             if (idx > 1)
> >> +                     goto err;
> >> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
> >> +             break;
> >> +     default:
> >> +             if (idx > 0)
> >> +                     goto err;
> >> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
> >> +     }
> >
> > It looks to me like userspace can then program active priorities with
> > higher numbers than what it will program num_pri_bits to later.  Is that
> > not weird, or am I missing something?
> 
> As long as it is within HW supported priorities it is safe.

I know that it is safe on the hardware, but it is weird to define a VM
with some max priority and still be able to set a higher active priority
is it not?

On the other hand, if we cannot enforce this at runtime, it may not
matter?

Hint: I'd like for you to actually think about these constraints and
make sure the sematics of the emulated VM environment remain intact
across migrations.

> >
> >> +
> >> +     return true;
> >> +err:
> >> +     if (!is_write)
> >> +             *reg = 0;
> >> +
> >> +     return false;
> >> +}
> >> +
> >> +bool access_gic_ap0r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
> >> +                      unsigned long *reg)
> >> +{
> >> +     return access_gic_aprn(vcpu, is_write, 0, idx, reg);
> >> +}
> >> +
> >> +bool access_gic_ap1r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
> >> +                      unsigned long *reg)
> >> +{
> >> +     return access_gic_aprn(vcpu, is_write, 1, idx, reg);
> >> +}
> >> +
> >> +bool access_gic_sre_reg(struct kvm_vcpu *vcpu, bool is_write,
> >> +                     unsigned long *reg)
> >> +{
> >> +     struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
> >> +
> >> +     /* Validate SRE bit */
> >> +     if (is_write) {
> >> +             if (!(*reg & ICC_SRE_EL1_SRE))
> >> +                     return false;
> >> +     } else {
> >> +             *reg = vgicv3->vgic_sre;
> >> +     }
> >> +
> >> +     return true;
> >> +}
> >> diff --git a/virt/kvm/arm/vgic/vgic-sys-reg-v3.c b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
> >> new file mode 100644
> >> index 0000000..82c2f02
> >> --- /dev/null
> >> +++ b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
> >> @@ -0,0 +1,142 @@
> >> +/*
> >> + * VGIC system registers handling functions
> >> + *
> >> + * 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.
> >> + */
> >> +
> >> +#include <linux/kvm.h>
> >> +#include <linux/kvm_host.h>
> >> +#include <asm/kvm_emulate.h>
> >> +#include "vgic.h"
> >> +#include "sys_regs.h"
> >> +
> >> +#define ACCESS_SYS_REG(REG)                                          \
> >> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,                \
> >> +                                 struct sys_reg_params *p,           \
> >> +                                 const struct sys_reg_desc *r)       \
> >> +{                                                                    \
> >> +     unsigned long tmp;                                              \
> >> +     bool ret;                                                       \
> >> +                                                                     \
> >> +     if (p->is_write)                                                \
> >> +             tmp = p->regval;                                        \
> >> +     ret = access_gic_##REG##_reg(vcpu, p->is_write, &tmp);          \
> >> +     if (!p->is_write)                                               \
> >> +             p->regval = tmp;                                        \
> >> +                                                                     \
> >> +     return ret;                                                     \
> >> +}
> >> +
> >> +ACCESS_SYS_REG(ctlr)
> >> +ACCESS_SYS_REG(pmr)
> >> +ACCESS_SYS_REG(bpr0)
> >> +ACCESS_SYS_REG(bpr1)
> >> +ACCESS_SYS_REG(sre)
> >> +ACCESS_SYS_REG(grpen0)
> >> +ACCESS_SYS_REG(grpen1)
> >> +
> >> +#define ACCESS_APNR_SYS_REG(REG)                                     \
> >> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,                \
> >> +                                 struct sys_reg_params *p,           \
> >> +                                 const struct sys_reg_desc *r)       \
> >> +{                                                                    \
> >> +     unsigned long tmp;                                              \
> >> +     u8 idx = p->Op2 & 3;                                            \
> >> +     bool ret;                                                       \
> >> +                                                                     \
> >> +     if (p->is_write)                                                \
> >> +             tmp = p->regval;                                        \
> >> +     ret = access_gic_##REG##_reg(vcpu, p->is_write, idx, &tmp);     \
> >> +     if (!p->is_write)                                               \
> >> +             p->regval = tmp;                                        \
> >> +                                                                     \
> >> +     return ret;                                                     \
> >> +}
> >> +
> >> +ACCESS_APNR_SYS_REG(ap0r)
> >> +ACCESS_APNR_SYS_REG(ap1r)
> >
> > I don't get these indirections.  Why can't you call the functions
> > directly?
> 
> The code is same for accessing the registers hence added this indirection.
> 

That's not answering my question.

What is the benefit of adding this indirection as opposed to having the
functions called directly?

To make my point clear:  I hate this kind of preprocessor macro fun, and
I think it should only ever be used when there's a huge benefit in terms
of code reuse or simplicity of some sort.  I don't see anything like
that in this case.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 06/11] arm/arm64: vgic: Implement VGICv3 CPU interface access
@ 2016-11-29  8:37         ` Christoffer Dall
  0 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-29  8:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Nov 29, 2016 at 01:08:26PM +0530, Vijay Kilari wrote:
> On Tue, Nov 29, 2016 at 1:09 AM, Christoffer Dall
> <christoffer.dall@linaro.org> wrote:
> > On Wed, Nov 23, 2016 at 06:31:53PM +0530, vijay.kilari at gmail.com wrote:
> >> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >>
> >> VGICv3 CPU interface registers are accessed using
> >> KVM_DEV_ARM_VGIC_CPU_SYSREGS ioctl. These registers are accessed
> >> as 64-bit. The cpu MPIDR value is passed along with register id.
> >> is used to identify the cpu for registers access.
> >>
> >> The VM that supports SEIs expect it on destination machine to handle
> >> guest aborts and hence checked for ICC_CTLR_EL1.SEIS compatibility.
> >> Similarly, VM that supports Affinity Level 3 that is required for AArch64
> >> mode, is required to be supported on destination machine. Hence checked
> >> for ICC_CTLR_EL1.A3V compatibility.
> >>
> >> The CPU system register handling is spitted into two files
> >
> > spitted?  Did you mean 'split into' ?
> >
> >> vgic-sys-reg-common.c and vgic-sys-reg-v3.c.
> >> The vgic-sys-reg-common.c handles read and write of VGIC CPU registers
> >
> > So this is weird because everything in virt/kvm/arm/ is exactly supposed
> > to be common between arm and arm64 already.
> >
> > I would rather that you had a copy of vgic-sys-reg-v3.c in arch/arm/kvm/
> > and in arch/arm64/kvm/ each taking care of its own architecture.
> >
> > But note that I didn't actually require that you implemented support for
> > GICv3 migration on AArch32 hosts for these patches, I just didn't want
> > thigns to silently break.
> >
> > If we cannot test the AArch32 implementation, we should potentially just
> > make sure that is not supported yet, return a proper error to userspace
> > and get the AArch64 host implementation correct.
> >
> > I suggest you move your:
> >   virt/kvm/arm/vgic/vgic-sys-reg-v3.c to
> >   arch/arm64/kvm/vgic-sys-reg-v3.c
> >
> > and rename
> >   virt/kvm/arm/vgic/vgic-sys-reg-common.c to
> >   virt/kvm/arm/vgic/vgic-sys-reg-v3.c
> >
> > And then wait with the AArch32 host side for now, but just make sure it
> > compiles and returns an error as opposed to crashing the system if
> > someone tries to excercise this interface on an AArch32 host.
> 
> I will add arch/arm/kvm/vgic-coproc-v3.c (pls check if file name is ok or not?)

I would call it vgic-v3-coproc.c

> and return -ENXIO as shown below and update document accordingly.
> 
> int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
>                                u64 *reg)
> {
>        /*
>         * TODO: Implement for AArch32
>         */
>        return -ENXIO;
> }
> 
> int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
>                                u64 *reg)
> {
>        /*
>         * TODO: Implement for AArch32
>         */
>        return -ENXIO;
> }


> 
> >
> >> for both AArch64 and AArch32 mode. The vgic-sys-reg-v3.c handles AArch64
> >> mode and is compiled only for AArch64 mode.
> >>
> >> Updated arch/arm/include/uapi/asm/kvm.h with new definitions
> >> required to compile for AArch32.
> >>
> >> The version of VGIC v3 specification is define here
> >> Documentation/virtual/kvm/devices/arm-vgic-v3.txt
> >>
> >> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
> >> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >> ---
> [...]
> >> +static bool access_gic_aprn(struct kvm_vcpu *vcpu, bool is_write, u8 apr,
> >> +                         u8 idx, unsigned long *reg)
> >> +{
> >> +     struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
> >> +
> >> +     /* num_pri_bits are initialized with HW supported values.
> >> +      * We can rely safely on num_pri_bits even if VM has not
> >> +      * restored ICC_CTLR_EL1 before restoring APnR registers.
> >> +      */
> >
> > nit: commenting style
> ok
> >
> >> +     switch (vgic_v3_cpu->num_pri_bits) {
> >> +     case 7:
> >> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
> >> +             break;
> >> +     case 6:
> >> +             if (idx > 1)
> >> +                     goto err;
> >> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
> >> +             break;
> >> +     default:
> >> +             if (idx > 0)
> >> +                     goto err;
> >> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
> >> +     }
> >
> > It looks to me like userspace can then program active priorities with
> > higher numbers than what it will program num_pri_bits to later.  Is that
> > not weird, or am I missing something?
> 
> As long as it is within HW supported priorities it is safe.

I know that it is safe on the hardware, but it is weird to define a VM
with some max priority and still be able to set a higher active priority
is it not?

On the other hand, if we cannot enforce this at runtime, it may not
matter?

Hint: I'd like for you to actually think about these constraints and
make sure the sematics of the emulated VM environment remain intact
across migrations.

> >
> >> +
> >> +     return true;
> >> +err:
> >> +     if (!is_write)
> >> +             *reg = 0;
> >> +
> >> +     return false;
> >> +}
> >> +
> >> +bool access_gic_ap0r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
> >> +                      unsigned long *reg)
> >> +{
> >> +     return access_gic_aprn(vcpu, is_write, 0, idx, reg);
> >> +}
> >> +
> >> +bool access_gic_ap1r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
> >> +                      unsigned long *reg)
> >> +{
> >> +     return access_gic_aprn(vcpu, is_write, 1, idx, reg);
> >> +}
> >> +
> >> +bool access_gic_sre_reg(struct kvm_vcpu *vcpu, bool is_write,
> >> +                     unsigned long *reg)
> >> +{
> >> +     struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
> >> +
> >> +     /* Validate SRE bit */
> >> +     if (is_write) {
> >> +             if (!(*reg & ICC_SRE_EL1_SRE))
> >> +                     return false;
> >> +     } else {
> >> +             *reg = vgicv3->vgic_sre;
> >> +     }
> >> +
> >> +     return true;
> >> +}
> >> diff --git a/virt/kvm/arm/vgic/vgic-sys-reg-v3.c b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
> >> new file mode 100644
> >> index 0000000..82c2f02
> >> --- /dev/null
> >> +++ b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
> >> @@ -0,0 +1,142 @@
> >> +/*
> >> + * VGIC system registers handling functions
> >> + *
> >> + * 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.
> >> + */
> >> +
> >> +#include <linux/kvm.h>
> >> +#include <linux/kvm_host.h>
> >> +#include <asm/kvm_emulate.h>
> >> +#include "vgic.h"
> >> +#include "sys_regs.h"
> >> +
> >> +#define ACCESS_SYS_REG(REG)                                          \
> >> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,                \
> >> +                                 struct sys_reg_params *p,           \
> >> +                                 const struct sys_reg_desc *r)       \
> >> +{                                                                    \
> >> +     unsigned long tmp;                                              \
> >> +     bool ret;                                                       \
> >> +                                                                     \
> >> +     if (p->is_write)                                                \
> >> +             tmp = p->regval;                                        \
> >> +     ret = access_gic_##REG##_reg(vcpu, p->is_write, &tmp);          \
> >> +     if (!p->is_write)                                               \
> >> +             p->regval = tmp;                                        \
> >> +                                                                     \
> >> +     return ret;                                                     \
> >> +}
> >> +
> >> +ACCESS_SYS_REG(ctlr)
> >> +ACCESS_SYS_REG(pmr)
> >> +ACCESS_SYS_REG(bpr0)
> >> +ACCESS_SYS_REG(bpr1)
> >> +ACCESS_SYS_REG(sre)
> >> +ACCESS_SYS_REG(grpen0)
> >> +ACCESS_SYS_REG(grpen1)
> >> +
> >> +#define ACCESS_APNR_SYS_REG(REG)                                     \
> >> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,                \
> >> +                                 struct sys_reg_params *p,           \
> >> +                                 const struct sys_reg_desc *r)       \
> >> +{                                                                    \
> >> +     unsigned long tmp;                                              \
> >> +     u8 idx = p->Op2 & 3;                                            \
> >> +     bool ret;                                                       \
> >> +                                                                     \
> >> +     if (p->is_write)                                                \
> >> +             tmp = p->regval;                                        \
> >> +     ret = access_gic_##REG##_reg(vcpu, p->is_write, idx, &tmp);     \
> >> +     if (!p->is_write)                                               \
> >> +             p->regval = tmp;                                        \
> >> +                                                                     \
> >> +     return ret;                                                     \
> >> +}
> >> +
> >> +ACCESS_APNR_SYS_REG(ap0r)
> >> +ACCESS_APNR_SYS_REG(ap1r)
> >
> > I don't get these indirections.  Why can't you call the functions
> > directly?
> 
> The code is same for accessing the registers hence added this indirection.
> 

That's not answering my question.

What is the benefit of adding this indirection as opposed to having the
functions called directly?

To make my point clear:  I hate this kind of preprocessor macro fun, and
I think it should only ever be used when there's a huge benefit in terms
of code reuse or simplicity of some sort.  I don't see anything like
that in this case.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 06/11] arm/arm64: vgic: Implement VGICv3 CPU interface access
  2016-11-29  8:37         ` Christoffer Dall
@ 2016-11-29 10:01           ` Vijay Kilari
  -1 siblings, 0 replies; 78+ messages in thread
From: Vijay Kilari @ 2016-11-29 10:01 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

On Tue, Nov 29, 2016 at 2:07 PM, Christoffer Dall
<christoffer.dall@linaro.org> wrote:
> On Tue, Nov 29, 2016 at 01:08:26PM +0530, Vijay Kilari wrote:
>> On Tue, Nov 29, 2016 at 1:09 AM, Christoffer Dall
>> <christoffer.dall@linaro.org> wrote:
>> > On Wed, Nov 23, 2016 at 06:31:53PM +0530, vijay.kilari@gmail.com wrote:
>> >> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>> >>
>> >> VGICv3 CPU interface registers are accessed using
>> >> KVM_DEV_ARM_VGIC_CPU_SYSREGS ioctl. These registers are accessed
>> >> as 64-bit. The cpu MPIDR value is passed along with register id.
>> >> is used to identify the cpu for registers access.
>> >>
>> >> The VM that supports SEIs expect it on destination machine to handle
>> >> guest aborts and hence checked for ICC_CTLR_EL1.SEIS compatibility.
>> >> Similarly, VM that supports Affinity Level 3 that is required for AArch64
>> >> mode, is required to be supported on destination machine. Hence checked
>> >> for ICC_CTLR_EL1.A3V compatibility.
>> >>
>> >> The CPU system register handling is spitted into two files
>> >
>> > spitted?  Did you mean 'split into' ?
>> >
>> >> vgic-sys-reg-common.c and vgic-sys-reg-v3.c.
>> >> The vgic-sys-reg-common.c handles read and write of VGIC CPU registers
>> >
>> > So this is weird because everything in virt/kvm/arm/ is exactly supposed
>> > to be common between arm and arm64 already.
>> >
>> > I would rather that you had a copy of vgic-sys-reg-v3.c in arch/arm/kvm/
>> > and in arch/arm64/kvm/ each taking care of its own architecture.
>> >
>> > But note that I didn't actually require that you implemented support for
>> > GICv3 migration on AArch32 hosts for these patches, I just didn't want
>> > thigns to silently break.
>> >
>> > If we cannot test the AArch32 implementation, we should potentially just
>> > make sure that is not supported yet, return a proper error to userspace
>> > and get the AArch64 host implementation correct.
>> >
>> > I suggest you move your:
>> >   virt/kvm/arm/vgic/vgic-sys-reg-v3.c to
>> >   arch/arm64/kvm/vgic-sys-reg-v3.c
>> >
>> > and rename
>> >   virt/kvm/arm/vgic/vgic-sys-reg-common.c to
>> >   virt/kvm/arm/vgic/vgic-sys-reg-v3.c
>> >
>> > And then wait with the AArch32 host side for now, but just make sure it
>> > compiles and returns an error as opposed to crashing the system if
>> > someone tries to excercise this interface on an AArch32 host.
>>
>> I will add arch/arm/kvm/vgic-coproc-v3.c (pls check if file name is ok or not?)
>
> I would call it vgic-v3-coproc.c
>
>> and return -ENXIO as shown below and update document accordingly.
>>
>> int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
>>                                u64 *reg)
>> {
>>        /*
>>         * TODO: Implement for AArch32
>>         */
>>        return -ENXIO;
>> }
>>
>> int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
>>                                u64 *reg)
>> {
>>        /*
>>         * TODO: Implement for AArch32
>>         */
>>        return -ENXIO;
>> }
>
>
>>
>> >
>> >> for both AArch64 and AArch32 mode. The vgic-sys-reg-v3.c handles AArch64
>> >> mode and is compiled only for AArch64 mode.
>> >>
>> >> Updated arch/arm/include/uapi/asm/kvm.h with new definitions
>> >> required to compile for AArch32.
>> >>
>> >> The version of VGIC v3 specification is define here
>> >> Documentation/virtual/kvm/devices/arm-vgic-v3.txt
>> >>
>> >> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
>> >> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>> >> ---
>> [...]
>> >> +static bool access_gic_aprn(struct kvm_vcpu *vcpu, bool is_write, u8 apr,
>> >> +                         u8 idx, unsigned long *reg)
>> >> +{
>> >> +     struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
>> >> +
>> >> +     /* num_pri_bits are initialized with HW supported values.
>> >> +      * We can rely safely on num_pri_bits even if VM has not
>> >> +      * restored ICC_CTLR_EL1 before restoring APnR registers.
>> >> +      */
>> >
>> > nit: commenting style
>> ok
>> >
>> >> +     switch (vgic_v3_cpu->num_pri_bits) {
>> >> +     case 7:
>> >> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
>> >> +             break;
>> >> +     case 6:
>> >> +             if (idx > 1)
>> >> +                     goto err;
>> >> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
>> >> +             break;
>> >> +     default:
>> >> +             if (idx > 0)
>> >> +                     goto err;
>> >> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
>> >> +     }
>> >
>> > It looks to me like userspace can then program active priorities with
>> > higher numbers than what it will program num_pri_bits to later.  Is that
>> > not weird, or am I missing something?
>>
>> As long as it is within HW supported priorities it is safe.
>
> I know that it is safe on the hardware, but it is weird to define a VM
> with some max priority and still be able to set a higher active priority
> is it not?

In that case, we need to cache the highest active priorities updated
by a VM in a variable
when APnR is restored and later check against num_pri_bits when
ICC_CTLR_EL1 is updated.
If the value cached is greater than num_pri_bits restored then reject
ICC_CTLR_EL1 restore.

This variable should be initialized with value 5 ( min priority)

>
> On the other hand, if we cannot enforce this at runtime, it may not
> matter?

At VM runtime irrespective of VM's num_pri_bits all the APnR registers that
HW supports are saved and restored.

>
> Hint: I'd like for you to actually think about these constraints and
> make sure the sematics of the emulated VM environment remain intact
> across migrations.
>
>> >
>> >> +
>> >> +     return true;
>> >> +err:
>> >> +     if (!is_write)
>> >> +             *reg = 0;
>> >> +
>> >> +     return false;
>> >> +}
>> >> +
>> >> +bool access_gic_ap0r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
>> >> +                      unsigned long *reg)
>> >> +{
>> >> +     return access_gic_aprn(vcpu, is_write, 0, idx, reg);
>> >> +}
>> >> +
>> >> +bool access_gic_ap1r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
>> >> +                      unsigned long *reg)
>> >> +{
>> >> +     return access_gic_aprn(vcpu, is_write, 1, idx, reg);
>> >> +}
>> >> +
>> >> +bool access_gic_sre_reg(struct kvm_vcpu *vcpu, bool is_write,
>> >> +                     unsigned long *reg)
>> >> +{
>> >> +     struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
>> >> +
>> >> +     /* Validate SRE bit */
>> >> +     if (is_write) {
>> >> +             if (!(*reg & ICC_SRE_EL1_SRE))
>> >> +                     return false;
>> >> +     } else {
>> >> +             *reg = vgicv3->vgic_sre;
>> >> +     }
>> >> +
>> >> +     return true;
>> >> +}
>> >> diff --git a/virt/kvm/arm/vgic/vgic-sys-reg-v3.c b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
>> >> new file mode 100644
>> >> index 0000000..82c2f02
>> >> --- /dev/null
>> >> +++ b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
>> >> @@ -0,0 +1,142 @@
>> >> +/*
>> >> + * VGIC system registers handling functions
>> >> + *
>> >> + * 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.
>> >> + */
>> >> +
>> >> +#include <linux/kvm.h>
>> >> +#include <linux/kvm_host.h>
>> >> +#include <asm/kvm_emulate.h>
>> >> +#include "vgic.h"
>> >> +#include "sys_regs.h"
>> >> +
>> >> +#define ACCESS_SYS_REG(REG)                                          \
>> >> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,                \
>> >> +                                 struct sys_reg_params *p,           \
>> >> +                                 const struct sys_reg_desc *r)       \
>> >> +{                                                                    \
>> >> +     unsigned long tmp;                                              \
>> >> +     bool ret;                                                       \
>> >> +                                                                     \
>> >> +     if (p->is_write)                                                \
>> >> +             tmp = p->regval;                                        \
>> >> +     ret = access_gic_##REG##_reg(vcpu, p->is_write, &tmp);          \
>> >> +     if (!p->is_write)                                               \
>> >> +             p->regval = tmp;                                        \
>> >> +                                                                     \
>> >> +     return ret;                                                     \
>> >> +}
>> >> +
>> >> +ACCESS_SYS_REG(ctlr)
>> >> +ACCESS_SYS_REG(pmr)
>> >> +ACCESS_SYS_REG(bpr0)
>> >> +ACCESS_SYS_REG(bpr1)
>> >> +ACCESS_SYS_REG(sre)
>> >> +ACCESS_SYS_REG(grpen0)
>> >> +ACCESS_SYS_REG(grpen1)
>> >> +
>> >> +#define ACCESS_APNR_SYS_REG(REG)                                     \
>> >> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,                \
>> >> +                                 struct sys_reg_params *p,           \
>> >> +                                 const struct sys_reg_desc *r)       \
>> >> +{                                                                    \
>> >> +     unsigned long tmp;                                              \
>> >> +     u8 idx = p->Op2 & 3;                                            \
>> >> +     bool ret;                                                       \
>> >> +                                                                     \
>> >> +     if (p->is_write)                                                \
>> >> +             tmp = p->regval;                                        \
>> >> +     ret = access_gic_##REG##_reg(vcpu, p->is_write, idx, &tmp);     \
>> >> +     if (!p->is_write)                                               \
>> >> +             p->regval = tmp;                                        \
>> >> +                                                                     \
>> >> +     return ret;                                                     \
>> >> +}
>> >> +
>> >> +ACCESS_APNR_SYS_REG(ap0r)
>> >> +ACCESS_APNR_SYS_REG(ap1r)
>> >
>> > I don't get these indirections.  Why can't you call the functions
>> > directly?
>>
>> The code is same for accessing the registers hence added this indirection.
>>
>
> That's not answering my question.
>
> What is the benefit of adding this indirection as opposed to having the
> functions called directly?

In sys_reg_desc the access function is of type

        bool (*access)(struct kvm_vcpu *,
                       struct sys_reg_params *,
                       const struct sys_reg_desc *);

Where as the each register access function is of type below to support
access to AArch32(later if not now).

bool access_gic_xxx(struct kvm_vcpu *vcpu, bool is_write, unsigned long *reg);

I can drop this macro and make function calls for each reg access.

>
> To make my point clear:  I hate this kind of preprocessor macro fun, and
> I think it should only ever be used when there's a huge benefit in terms
> of code reuse or simplicity of some sort.  I don't see anything like
> that in this case.
>
> Thanks,
> -Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 06/11] arm/arm64: vgic: Implement VGICv3 CPU interface access
@ 2016-11-29 10:01           ` Vijay Kilari
  0 siblings, 0 replies; 78+ messages in thread
From: Vijay Kilari @ 2016-11-29 10:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Nov 29, 2016 at 2:07 PM, Christoffer Dall
<christoffer.dall@linaro.org> wrote:
> On Tue, Nov 29, 2016 at 01:08:26PM +0530, Vijay Kilari wrote:
>> On Tue, Nov 29, 2016 at 1:09 AM, Christoffer Dall
>> <christoffer.dall@linaro.org> wrote:
>> > On Wed, Nov 23, 2016 at 06:31:53PM +0530, vijay.kilari at gmail.com wrote:
>> >> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>> >>
>> >> VGICv3 CPU interface registers are accessed using
>> >> KVM_DEV_ARM_VGIC_CPU_SYSREGS ioctl. These registers are accessed
>> >> as 64-bit. The cpu MPIDR value is passed along with register id.
>> >> is used to identify the cpu for registers access.
>> >>
>> >> The VM that supports SEIs expect it on destination machine to handle
>> >> guest aborts and hence checked for ICC_CTLR_EL1.SEIS compatibility.
>> >> Similarly, VM that supports Affinity Level 3 that is required for AArch64
>> >> mode, is required to be supported on destination machine. Hence checked
>> >> for ICC_CTLR_EL1.A3V compatibility.
>> >>
>> >> The CPU system register handling is spitted into two files
>> >
>> > spitted?  Did you mean 'split into' ?
>> >
>> >> vgic-sys-reg-common.c and vgic-sys-reg-v3.c.
>> >> The vgic-sys-reg-common.c handles read and write of VGIC CPU registers
>> >
>> > So this is weird because everything in virt/kvm/arm/ is exactly supposed
>> > to be common between arm and arm64 already.
>> >
>> > I would rather that you had a copy of vgic-sys-reg-v3.c in arch/arm/kvm/
>> > and in arch/arm64/kvm/ each taking care of its own architecture.
>> >
>> > But note that I didn't actually require that you implemented support for
>> > GICv3 migration on AArch32 hosts for these patches, I just didn't want
>> > thigns to silently break.
>> >
>> > If we cannot test the AArch32 implementation, we should potentially just
>> > make sure that is not supported yet, return a proper error to userspace
>> > and get the AArch64 host implementation correct.
>> >
>> > I suggest you move your:
>> >   virt/kvm/arm/vgic/vgic-sys-reg-v3.c to
>> >   arch/arm64/kvm/vgic-sys-reg-v3.c
>> >
>> > and rename
>> >   virt/kvm/arm/vgic/vgic-sys-reg-common.c to
>> >   virt/kvm/arm/vgic/vgic-sys-reg-v3.c
>> >
>> > And then wait with the AArch32 host side for now, but just make sure it
>> > compiles and returns an error as opposed to crashing the system if
>> > someone tries to excercise this interface on an AArch32 host.
>>
>> I will add arch/arm/kvm/vgic-coproc-v3.c (pls check if file name is ok or not?)
>
> I would call it vgic-v3-coproc.c
>
>> and return -ENXIO as shown below and update document accordingly.
>>
>> int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
>>                                u64 *reg)
>> {
>>        /*
>>         * TODO: Implement for AArch32
>>         */
>>        return -ENXIO;
>> }
>>
>> int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
>>                                u64 *reg)
>> {
>>        /*
>>         * TODO: Implement for AArch32
>>         */
>>        return -ENXIO;
>> }
>
>
>>
>> >
>> >> for both AArch64 and AArch32 mode. The vgic-sys-reg-v3.c handles AArch64
>> >> mode and is compiled only for AArch64 mode.
>> >>
>> >> Updated arch/arm/include/uapi/asm/kvm.h with new definitions
>> >> required to compile for AArch32.
>> >>
>> >> The version of VGIC v3 specification is define here
>> >> Documentation/virtual/kvm/devices/arm-vgic-v3.txt
>> >>
>> >> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
>> >> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>> >> ---
>> [...]
>> >> +static bool access_gic_aprn(struct kvm_vcpu *vcpu, bool is_write, u8 apr,
>> >> +                         u8 idx, unsigned long *reg)
>> >> +{
>> >> +     struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
>> >> +
>> >> +     /* num_pri_bits are initialized with HW supported values.
>> >> +      * We can rely safely on num_pri_bits even if VM has not
>> >> +      * restored ICC_CTLR_EL1 before restoring APnR registers.
>> >> +      */
>> >
>> > nit: commenting style
>> ok
>> >
>> >> +     switch (vgic_v3_cpu->num_pri_bits) {
>> >> +     case 7:
>> >> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
>> >> +             break;
>> >> +     case 6:
>> >> +             if (idx > 1)
>> >> +                     goto err;
>> >> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
>> >> +             break;
>> >> +     default:
>> >> +             if (idx > 0)
>> >> +                     goto err;
>> >> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
>> >> +     }
>> >
>> > It looks to me like userspace can then program active priorities with
>> > higher numbers than what it will program num_pri_bits to later.  Is that
>> > not weird, or am I missing something?
>>
>> As long as it is within HW supported priorities it is safe.
>
> I know that it is safe on the hardware, but it is weird to define a VM
> with some max priority and still be able to set a higher active priority
> is it not?

In that case, we need to cache the highest active priorities updated
by a VM in a variable
when APnR is restored and later check against num_pri_bits when
ICC_CTLR_EL1 is updated.
If the value cached is greater than num_pri_bits restored then reject
ICC_CTLR_EL1 restore.

This variable should be initialized with value 5 ( min priority)

>
> On the other hand, if we cannot enforce this at runtime, it may not
> matter?

At VM runtime irrespective of VM's num_pri_bits all the APnR registers that
HW supports are saved and restored.

>
> Hint: I'd like for you to actually think about these constraints and
> make sure the sematics of the emulated VM environment remain intact
> across migrations.
>
>> >
>> >> +
>> >> +     return true;
>> >> +err:
>> >> +     if (!is_write)
>> >> +             *reg = 0;
>> >> +
>> >> +     return false;
>> >> +}
>> >> +
>> >> +bool access_gic_ap0r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
>> >> +                      unsigned long *reg)
>> >> +{
>> >> +     return access_gic_aprn(vcpu, is_write, 0, idx, reg);
>> >> +}
>> >> +
>> >> +bool access_gic_ap1r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
>> >> +                      unsigned long *reg)
>> >> +{
>> >> +     return access_gic_aprn(vcpu, is_write, 1, idx, reg);
>> >> +}
>> >> +
>> >> +bool access_gic_sre_reg(struct kvm_vcpu *vcpu, bool is_write,
>> >> +                     unsigned long *reg)
>> >> +{
>> >> +     struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
>> >> +
>> >> +     /* Validate SRE bit */
>> >> +     if (is_write) {
>> >> +             if (!(*reg & ICC_SRE_EL1_SRE))
>> >> +                     return false;
>> >> +     } else {
>> >> +             *reg = vgicv3->vgic_sre;
>> >> +     }
>> >> +
>> >> +     return true;
>> >> +}
>> >> diff --git a/virt/kvm/arm/vgic/vgic-sys-reg-v3.c b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
>> >> new file mode 100644
>> >> index 0000000..82c2f02
>> >> --- /dev/null
>> >> +++ b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
>> >> @@ -0,0 +1,142 @@
>> >> +/*
>> >> + * VGIC system registers handling functions
>> >> + *
>> >> + * 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.
>> >> + */
>> >> +
>> >> +#include <linux/kvm.h>
>> >> +#include <linux/kvm_host.h>
>> >> +#include <asm/kvm_emulate.h>
>> >> +#include "vgic.h"
>> >> +#include "sys_regs.h"
>> >> +
>> >> +#define ACCESS_SYS_REG(REG)                                          \
>> >> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,                \
>> >> +                                 struct sys_reg_params *p,           \
>> >> +                                 const struct sys_reg_desc *r)       \
>> >> +{                                                                    \
>> >> +     unsigned long tmp;                                              \
>> >> +     bool ret;                                                       \
>> >> +                                                                     \
>> >> +     if (p->is_write)                                                \
>> >> +             tmp = p->regval;                                        \
>> >> +     ret = access_gic_##REG##_reg(vcpu, p->is_write, &tmp);          \
>> >> +     if (!p->is_write)                                               \
>> >> +             p->regval = tmp;                                        \
>> >> +                                                                     \
>> >> +     return ret;                                                     \
>> >> +}
>> >> +
>> >> +ACCESS_SYS_REG(ctlr)
>> >> +ACCESS_SYS_REG(pmr)
>> >> +ACCESS_SYS_REG(bpr0)
>> >> +ACCESS_SYS_REG(bpr1)
>> >> +ACCESS_SYS_REG(sre)
>> >> +ACCESS_SYS_REG(grpen0)
>> >> +ACCESS_SYS_REG(grpen1)
>> >> +
>> >> +#define ACCESS_APNR_SYS_REG(REG)                                     \
>> >> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,                \
>> >> +                                 struct sys_reg_params *p,           \
>> >> +                                 const struct sys_reg_desc *r)       \
>> >> +{                                                                    \
>> >> +     unsigned long tmp;                                              \
>> >> +     u8 idx = p->Op2 & 3;                                            \
>> >> +     bool ret;                                                       \
>> >> +                                                                     \
>> >> +     if (p->is_write)                                                \
>> >> +             tmp = p->regval;                                        \
>> >> +     ret = access_gic_##REG##_reg(vcpu, p->is_write, idx, &tmp);     \
>> >> +     if (!p->is_write)                                               \
>> >> +             p->regval = tmp;                                        \
>> >> +                                                                     \
>> >> +     return ret;                                                     \
>> >> +}
>> >> +
>> >> +ACCESS_APNR_SYS_REG(ap0r)
>> >> +ACCESS_APNR_SYS_REG(ap1r)
>> >
>> > I don't get these indirections.  Why can't you call the functions
>> > directly?
>>
>> The code is same for accessing the registers hence added this indirection.
>>
>
> That's not answering my question.
>
> What is the benefit of adding this indirection as opposed to having the
> functions called directly?

In sys_reg_desc the access function is of type

        bool (*access)(struct kvm_vcpu *,
                       struct sys_reg_params *,
                       const struct sys_reg_desc *);

Where as the each register access function is of type below to support
access to AArch32(later if not now).

bool access_gic_xxx(struct kvm_vcpu *vcpu, bool is_write, unsigned long *reg);

I can drop this macro and make function calls for each reg access.

>
> To make my point clear:  I hate this kind of preprocessor macro fun, and
> I think it should only ever be used when there's a huge benefit in terms
> of code reuse or simplicity of some sort.  I don't see anything like
> that in this case.
>
> Thanks,
> -Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 06/11] arm/arm64: vgic: Implement VGICv3 CPU interface access
  2016-11-29 10:01           ` Vijay Kilari
@ 2016-11-29 10:51             ` Christoffer Dall
  -1 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-29 10:51 UTC (permalink / raw)
  To: Vijay Kilari; +Cc: Marc Zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

On Tue, Nov 29, 2016 at 03:31:44PM +0530, Vijay Kilari wrote:
> On Tue, Nov 29, 2016 at 2:07 PM, Christoffer Dall
> <christoffer.dall@linaro.org> wrote:
> > On Tue, Nov 29, 2016 at 01:08:26PM +0530, Vijay Kilari wrote:
> >> On Tue, Nov 29, 2016 at 1:09 AM, Christoffer Dall
> >> <christoffer.dall@linaro.org> wrote:
> >> > On Wed, Nov 23, 2016 at 06:31:53PM +0530, vijay.kilari@gmail.com wrote:
> >> >> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >> >>
> >> >> VGICv3 CPU interface registers are accessed using
> >> >> KVM_DEV_ARM_VGIC_CPU_SYSREGS ioctl. These registers are accessed
> >> >> as 64-bit. The cpu MPIDR value is passed along with register id.
> >> >> is used to identify the cpu for registers access.
> >> >>
> >> >> The VM that supports SEIs expect it on destination machine to handle
> >> >> guest aborts and hence checked for ICC_CTLR_EL1.SEIS compatibility.
> >> >> Similarly, VM that supports Affinity Level 3 that is required for AArch64
> >> >> mode, is required to be supported on destination machine. Hence checked
> >> >> for ICC_CTLR_EL1.A3V compatibility.
> >> >>
> >> >> The CPU system register handling is spitted into two files
> >> >
> >> > spitted?  Did you mean 'split into' ?
> >> >
> >> >> vgic-sys-reg-common.c and vgic-sys-reg-v3.c.
> >> >> The vgic-sys-reg-common.c handles read and write of VGIC CPU registers
> >> >
> >> > So this is weird because everything in virt/kvm/arm/ is exactly supposed
> >> > to be common between arm and arm64 already.
> >> >
> >> > I would rather that you had a copy of vgic-sys-reg-v3.c in arch/arm/kvm/
> >> > and in arch/arm64/kvm/ each taking care of its own architecture.
> >> >
> >> > But note that I didn't actually require that you implemented support for
> >> > GICv3 migration on AArch32 hosts for these patches, I just didn't want
> >> > thigns to silently break.
> >> >
> >> > If we cannot test the AArch32 implementation, we should potentially just
> >> > make sure that is not supported yet, return a proper error to userspace
> >> > and get the AArch64 host implementation correct.
> >> >
> >> > I suggest you move your:
> >> >   virt/kvm/arm/vgic/vgic-sys-reg-v3.c to
> >> >   arch/arm64/kvm/vgic-sys-reg-v3.c
> >> >
> >> > and rename
> >> >   virt/kvm/arm/vgic/vgic-sys-reg-common.c to
> >> >   virt/kvm/arm/vgic/vgic-sys-reg-v3.c
> >> >
> >> > And then wait with the AArch32 host side for now, but just make sure it
> >> > compiles and returns an error as opposed to crashing the system if
> >> > someone tries to excercise this interface on an AArch32 host.
> >>
> >> I will add arch/arm/kvm/vgic-coproc-v3.c (pls check if file name is ok or not?)
> >
> > I would call it vgic-v3-coproc.c
> >
> >> and return -ENXIO as shown below and update document accordingly.
> >>
> >> int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
> >>                                u64 *reg)
> >> {
> >>        /*
> >>         * TODO: Implement for AArch32
> >>         */
> >>        return -ENXIO;
> >> }
> >>
> >> int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
> >>                                u64 *reg)
> >> {
> >>        /*
> >>         * TODO: Implement for AArch32
> >>         */
> >>        return -ENXIO;
> >> }
> >
> >
> >>
> >> >
> >> >> for both AArch64 and AArch32 mode. The vgic-sys-reg-v3.c handles AArch64
> >> >> mode and is compiled only for AArch64 mode.
> >> >>
> >> >> Updated arch/arm/include/uapi/asm/kvm.h with new definitions
> >> >> required to compile for AArch32.
> >> >>
> >> >> The version of VGIC v3 specification is define here
> >> >> Documentation/virtual/kvm/devices/arm-vgic-v3.txt
> >> >>
> >> >> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
> >> >> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >> >> ---
> >> [...]
> >> >> +static bool access_gic_aprn(struct kvm_vcpu *vcpu, bool is_write, u8 apr,
> >> >> +                         u8 idx, unsigned long *reg)
> >> >> +{
> >> >> +     struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
> >> >> +
> >> >> +     /* num_pri_bits are initialized with HW supported values.
> >> >> +      * We can rely safely on num_pri_bits even if VM has not
> >> >> +      * restored ICC_CTLR_EL1 before restoring APnR registers.
> >> >> +      */
> >> >
> >> > nit: commenting style
> >> ok
> >> >
> >> >> +     switch (vgic_v3_cpu->num_pri_bits) {
> >> >> +     case 7:
> >> >> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
> >> >> +             break;
> >> >> +     case 6:
> >> >> +             if (idx > 1)
> >> >> +                     goto err;
> >> >> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
> >> >> +             break;
> >> >> +     default:
> >> >> +             if (idx > 0)
> >> >> +                     goto err;
> >> >> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
> >> >> +     }
> >> >
> >> > It looks to me like userspace can then program active priorities with
> >> > higher numbers than what it will program num_pri_bits to later.  Is that
> >> > not weird, or am I missing something?
> >>
> >> As long as it is within HW supported priorities it is safe.
> >
> > I know that it is safe on the hardware, but it is weird to define a VM
> > with some max priority and still be able to set a higher active priority
> > is it not?
> 
> In that case, we need to cache the highest active priorities updated
> by a VM in a variable
> when APnR is restored and later check against num_pri_bits when
> ICC_CTLR_EL1 is updated.
> If the value cached is greater than num_pri_bits restored then reject
> ICC_CTLR_EL1 restore.
> 
> This variable should be initialized with value 5 ( min priority)
> 
> >
> > On the other hand, if we cannot enforce this at runtime, it may not
> > matter?
> 
> At VM runtime irrespective of VM's num_pri_bits all the APnR registers that
> HW supports are saved and restored.
> 

Yes, never mind my comment.  Since we cannot enforce this constraint
once the VM runs, I don't think there's any concern here.

> >> >
> >> >> +
> >> >> +     return true;
> >> >> +err:
> >> >> +     if (!is_write)
> >> >> +             *reg = 0;
> >> >> +
> >> >> +     return false;
> >> >> +}
> >> >> +
> >> >> +bool access_gic_ap0r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
> >> >> +                      unsigned long *reg)
> >> >> +{
> >> >> +     return access_gic_aprn(vcpu, is_write, 0, idx, reg);
> >> >> +}
> >> >> +
> >> >> +bool access_gic_ap1r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
> >> >> +                      unsigned long *reg)
> >> >> +{
> >> >> +     return access_gic_aprn(vcpu, is_write, 1, idx, reg);
> >> >> +}
> >> >> +
> >> >> +bool access_gic_sre_reg(struct kvm_vcpu *vcpu, bool is_write,
> >> >> +                     unsigned long *reg)
> >> >> +{
> >> >> +     struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
> >> >> +
> >> >> +     /* Validate SRE bit */
> >> >> +     if (is_write) {
> >> >> +             if (!(*reg & ICC_SRE_EL1_SRE))
> >> >> +                     return false;
> >> >> +     } else {
> >> >> +             *reg = vgicv3->vgic_sre;
> >> >> +     }
> >> >> +
> >> >> +     return true;
> >> >> +}
> >> >> diff --git a/virt/kvm/arm/vgic/vgic-sys-reg-v3.c b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
> >> >> new file mode 100644
> >> >> index 0000000..82c2f02
> >> >> --- /dev/null
> >> >> +++ b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
> >> >> @@ -0,0 +1,142 @@
> >> >> +/*
> >> >> + * VGIC system registers handling functions
> >> >> + *
> >> >> + * 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.
> >> >> + */
> >> >> +
> >> >> +#include <linux/kvm.h>
> >> >> +#include <linux/kvm_host.h>
> >> >> +#include <asm/kvm_emulate.h>
> >> >> +#include "vgic.h"
> >> >> +#include "sys_regs.h"
> >> >> +
> >> >> +#define ACCESS_SYS_REG(REG)                                          \
> >> >> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,                \
> >> >> +                                 struct sys_reg_params *p,           \
> >> >> +                                 const struct sys_reg_desc *r)       \
> >> >> +{                                                                    \
> >> >> +     unsigned long tmp;                                              \
> >> >> +     bool ret;                                                       \
> >> >> +                                                                     \
> >> >> +     if (p->is_write)                                                \
> >> >> +             tmp = p->regval;                                        \
> >> >> +     ret = access_gic_##REG##_reg(vcpu, p->is_write, &tmp);          \
> >> >> +     if (!p->is_write)                                               \
> >> >> +             p->regval = tmp;                                        \
> >> >> +                                                                     \
> >> >> +     return ret;                                                     \
> >> >> +}
> >> >> +
> >> >> +ACCESS_SYS_REG(ctlr)
> >> >> +ACCESS_SYS_REG(pmr)
> >> >> +ACCESS_SYS_REG(bpr0)
> >> >> +ACCESS_SYS_REG(bpr1)
> >> >> +ACCESS_SYS_REG(sre)
> >> >> +ACCESS_SYS_REG(grpen0)
> >> >> +ACCESS_SYS_REG(grpen1)
> >> >> +
> >> >> +#define ACCESS_APNR_SYS_REG(REG)                                     \
> >> >> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,                \
> >> >> +                                 struct sys_reg_params *p,           \
> >> >> +                                 const struct sys_reg_desc *r)       \
> >> >> +{                                                                    \
> >> >> +     unsigned long tmp;                                              \
> >> >> +     u8 idx = p->Op2 & 3;                                            \
> >> >> +     bool ret;                                                       \
> >> >> +                                                                     \
> >> >> +     if (p->is_write)                                                \
> >> >> +             tmp = p->regval;                                        \
> >> >> +     ret = access_gic_##REG##_reg(vcpu, p->is_write, idx, &tmp);     \
> >> >> +     if (!p->is_write)                                               \
> >> >> +             p->regval = tmp;                                        \
> >> >> +                                                                     \
> >> >> +     return ret;                                                     \
> >> >> +}
> >> >> +
> >> >> +ACCESS_APNR_SYS_REG(ap0r)
> >> >> +ACCESS_APNR_SYS_REG(ap1r)
> >> >
> >> > I don't get these indirections.  Why can't you call the functions
> >> > directly?
> >>
> >> The code is same for accessing the registers hence added this indirection.
> >>
> >
> > That's not answering my question.
> >
> > What is the benefit of adding this indirection as opposed to having the
> > functions called directly?
> 
> In sys_reg_desc the access function is of type
> 
>         bool (*access)(struct kvm_vcpu *,
>                        struct sys_reg_params *,
>                        const struct sys_reg_desc *);
> 
> Where as the each register access function is of type below to support
> access to AArch32(later if not now).
> 
> bool access_gic_xxx(struct kvm_vcpu *vcpu, bool is_write, unsigned long *reg);
> 
> I can drop this macro and make function calls for each reg access.
> 

Please don't worry about the 32-bit side until we actually implement
that.  And once we do, we can move things around in patches to support
the 32-bit side so that it makes sense to the reader.

So, for now, just have this one file, moved to arch/arm64/kvm/ where all
the access functions are static in this file and called directly from
the single dispatch function.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 06/11] arm/arm64: vgic: Implement VGICv3 CPU interface access
@ 2016-11-29 10:51             ` Christoffer Dall
  0 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-29 10:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Nov 29, 2016 at 03:31:44PM +0530, Vijay Kilari wrote:
> On Tue, Nov 29, 2016 at 2:07 PM, Christoffer Dall
> <christoffer.dall@linaro.org> wrote:
> > On Tue, Nov 29, 2016 at 01:08:26PM +0530, Vijay Kilari wrote:
> >> On Tue, Nov 29, 2016 at 1:09 AM, Christoffer Dall
> >> <christoffer.dall@linaro.org> wrote:
> >> > On Wed, Nov 23, 2016 at 06:31:53PM +0530, vijay.kilari at gmail.com wrote:
> >> >> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >> >>
> >> >> VGICv3 CPU interface registers are accessed using
> >> >> KVM_DEV_ARM_VGIC_CPU_SYSREGS ioctl. These registers are accessed
> >> >> as 64-bit. The cpu MPIDR value is passed along with register id.
> >> >> is used to identify the cpu for registers access.
> >> >>
> >> >> The VM that supports SEIs expect it on destination machine to handle
> >> >> guest aborts and hence checked for ICC_CTLR_EL1.SEIS compatibility.
> >> >> Similarly, VM that supports Affinity Level 3 that is required for AArch64
> >> >> mode, is required to be supported on destination machine. Hence checked
> >> >> for ICC_CTLR_EL1.A3V compatibility.
> >> >>
> >> >> The CPU system register handling is spitted into two files
> >> >
> >> > spitted?  Did you mean 'split into' ?
> >> >
> >> >> vgic-sys-reg-common.c and vgic-sys-reg-v3.c.
> >> >> The vgic-sys-reg-common.c handles read and write of VGIC CPU registers
> >> >
> >> > So this is weird because everything in virt/kvm/arm/ is exactly supposed
> >> > to be common between arm and arm64 already.
> >> >
> >> > I would rather that you had a copy of vgic-sys-reg-v3.c in arch/arm/kvm/
> >> > and in arch/arm64/kvm/ each taking care of its own architecture.
> >> >
> >> > But note that I didn't actually require that you implemented support for
> >> > GICv3 migration on AArch32 hosts for these patches, I just didn't want
> >> > thigns to silently break.
> >> >
> >> > If we cannot test the AArch32 implementation, we should potentially just
> >> > make sure that is not supported yet, return a proper error to userspace
> >> > and get the AArch64 host implementation correct.
> >> >
> >> > I suggest you move your:
> >> >   virt/kvm/arm/vgic/vgic-sys-reg-v3.c to
> >> >   arch/arm64/kvm/vgic-sys-reg-v3.c
> >> >
> >> > and rename
> >> >   virt/kvm/arm/vgic/vgic-sys-reg-common.c to
> >> >   virt/kvm/arm/vgic/vgic-sys-reg-v3.c
> >> >
> >> > And then wait with the AArch32 host side for now, but just make sure it
> >> > compiles and returns an error as opposed to crashing the system if
> >> > someone tries to excercise this interface on an AArch32 host.
> >>
> >> I will add arch/arm/kvm/vgic-coproc-v3.c (pls check if file name is ok or not?)
> >
> > I would call it vgic-v3-coproc.c
> >
> >> and return -ENXIO as shown below and update document accordingly.
> >>
> >> int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
> >>                                u64 *reg)
> >> {
> >>        /*
> >>         * TODO: Implement for AArch32
> >>         */
> >>        return -ENXIO;
> >> }
> >>
> >> int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
> >>                                u64 *reg)
> >> {
> >>        /*
> >>         * TODO: Implement for AArch32
> >>         */
> >>        return -ENXIO;
> >> }
> >
> >
> >>
> >> >
> >> >> for both AArch64 and AArch32 mode. The vgic-sys-reg-v3.c handles AArch64
> >> >> mode and is compiled only for AArch64 mode.
> >> >>
> >> >> Updated arch/arm/include/uapi/asm/kvm.h with new definitions
> >> >> required to compile for AArch32.
> >> >>
> >> >> The version of VGIC v3 specification is define here
> >> >> Documentation/virtual/kvm/devices/arm-vgic-v3.txt
> >> >>
> >> >> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
> >> >> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >> >> ---
> >> [...]
> >> >> +static bool access_gic_aprn(struct kvm_vcpu *vcpu, bool is_write, u8 apr,
> >> >> +                         u8 idx, unsigned long *reg)
> >> >> +{
> >> >> +     struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
> >> >> +
> >> >> +     /* num_pri_bits are initialized with HW supported values.
> >> >> +      * We can rely safely on num_pri_bits even if VM has not
> >> >> +      * restored ICC_CTLR_EL1 before restoring APnR registers.
> >> >> +      */
> >> >
> >> > nit: commenting style
> >> ok
> >> >
> >> >> +     switch (vgic_v3_cpu->num_pri_bits) {
> >> >> +     case 7:
> >> >> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
> >> >> +             break;
> >> >> +     case 6:
> >> >> +             if (idx > 1)
> >> >> +                     goto err;
> >> >> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
> >> >> +             break;
> >> >> +     default:
> >> >> +             if (idx > 0)
> >> >> +                     goto err;
> >> >> +             vgic_v3_access_apr_reg(vcpu, is_write, apr, idx, reg);
> >> >> +     }
> >> >
> >> > It looks to me like userspace can then program active priorities with
> >> > higher numbers than what it will program num_pri_bits to later.  Is that
> >> > not weird, or am I missing something?
> >>
> >> As long as it is within HW supported priorities it is safe.
> >
> > I know that it is safe on the hardware, but it is weird to define a VM
> > with some max priority and still be able to set a higher active priority
> > is it not?
> 
> In that case, we need to cache the highest active priorities updated
> by a VM in a variable
> when APnR is restored and later check against num_pri_bits when
> ICC_CTLR_EL1 is updated.
> If the value cached is greater than num_pri_bits restored then reject
> ICC_CTLR_EL1 restore.
> 
> This variable should be initialized with value 5 ( min priority)
> 
> >
> > On the other hand, if we cannot enforce this at runtime, it may not
> > matter?
> 
> At VM runtime irrespective of VM's num_pri_bits all the APnR registers that
> HW supports are saved and restored.
> 

Yes, never mind my comment.  Since we cannot enforce this constraint
once the VM runs, I don't think there's any concern here.

> >> >
> >> >> +
> >> >> +     return true;
> >> >> +err:
> >> >> +     if (!is_write)
> >> >> +             *reg = 0;
> >> >> +
> >> >> +     return false;
> >> >> +}
> >> >> +
> >> >> +bool access_gic_ap0r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
> >> >> +                      unsigned long *reg)
> >> >> +{
> >> >> +     return access_gic_aprn(vcpu, is_write, 0, idx, reg);
> >> >> +}
> >> >> +
> >> >> +bool access_gic_ap1r_reg(struct kvm_vcpu *vcpu, bool is_write, u8 idx,
> >> >> +                      unsigned long *reg)
> >> >> +{
> >> >> +     return access_gic_aprn(vcpu, is_write, 1, idx, reg);
> >> >> +}
> >> >> +
> >> >> +bool access_gic_sre_reg(struct kvm_vcpu *vcpu, bool is_write,
> >> >> +                     unsigned long *reg)
> >> >> +{
> >> >> +     struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
> >> >> +
> >> >> +     /* Validate SRE bit */
> >> >> +     if (is_write) {
> >> >> +             if (!(*reg & ICC_SRE_EL1_SRE))
> >> >> +                     return false;
> >> >> +     } else {
> >> >> +             *reg = vgicv3->vgic_sre;
> >> >> +     }
> >> >> +
> >> >> +     return true;
> >> >> +}
> >> >> diff --git a/virt/kvm/arm/vgic/vgic-sys-reg-v3.c b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
> >> >> new file mode 100644
> >> >> index 0000000..82c2f02
> >> >> --- /dev/null
> >> >> +++ b/virt/kvm/arm/vgic/vgic-sys-reg-v3.c
> >> >> @@ -0,0 +1,142 @@
> >> >> +/*
> >> >> + * VGIC system registers handling functions
> >> >> + *
> >> >> + * 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.
> >> >> + */
> >> >> +
> >> >> +#include <linux/kvm.h>
> >> >> +#include <linux/kvm_host.h>
> >> >> +#include <asm/kvm_emulate.h>
> >> >> +#include "vgic.h"
> >> >> +#include "sys_regs.h"
> >> >> +
> >> >> +#define ACCESS_SYS_REG(REG)                                          \
> >> >> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,                \
> >> >> +                                 struct sys_reg_params *p,           \
> >> >> +                                 const struct sys_reg_desc *r)       \
> >> >> +{                                                                    \
> >> >> +     unsigned long tmp;                                              \
> >> >> +     bool ret;                                                       \
> >> >> +                                                                     \
> >> >> +     if (p->is_write)                                                \
> >> >> +             tmp = p->regval;                                        \
> >> >> +     ret = access_gic_##REG##_reg(vcpu, p->is_write, &tmp);          \
> >> >> +     if (!p->is_write)                                               \
> >> >> +             p->regval = tmp;                                        \
> >> >> +                                                                     \
> >> >> +     return ret;                                                     \
> >> >> +}
> >> >> +
> >> >> +ACCESS_SYS_REG(ctlr)
> >> >> +ACCESS_SYS_REG(pmr)
> >> >> +ACCESS_SYS_REG(bpr0)
> >> >> +ACCESS_SYS_REG(bpr1)
> >> >> +ACCESS_SYS_REG(sre)
> >> >> +ACCESS_SYS_REG(grpen0)
> >> >> +ACCESS_SYS_REG(grpen1)
> >> >> +
> >> >> +#define ACCESS_APNR_SYS_REG(REG)                                     \
> >> >> +static bool access_gic_##REG##_sys_reg(struct kvm_vcpu *vcpu,                \
> >> >> +                                 struct sys_reg_params *p,           \
> >> >> +                                 const struct sys_reg_desc *r)       \
> >> >> +{                                                                    \
> >> >> +     unsigned long tmp;                                              \
> >> >> +     u8 idx = p->Op2 & 3;                                            \
> >> >> +     bool ret;                                                       \
> >> >> +                                                                     \
> >> >> +     if (p->is_write)                                                \
> >> >> +             tmp = p->regval;                                        \
> >> >> +     ret = access_gic_##REG##_reg(vcpu, p->is_write, idx, &tmp);     \
> >> >> +     if (!p->is_write)                                               \
> >> >> +             p->regval = tmp;                                        \
> >> >> +                                                                     \
> >> >> +     return ret;                                                     \
> >> >> +}
> >> >> +
> >> >> +ACCESS_APNR_SYS_REG(ap0r)
> >> >> +ACCESS_APNR_SYS_REG(ap1r)
> >> >
> >> > I don't get these indirections.  Why can't you call the functions
> >> > directly?
> >>
> >> The code is same for accessing the registers hence added this indirection.
> >>
> >
> > That's not answering my question.
> >
> > What is the benefit of adding this indirection as opposed to having the
> > functions called directly?
> 
> In sys_reg_desc the access function is of type
> 
>         bool (*access)(struct kvm_vcpu *,
>                        struct sys_reg_params *,
>                        const struct sys_reg_desc *);
> 
> Where as the each register access function is of type below to support
> access to AArch32(later if not now).
> 
> bool access_gic_xxx(struct kvm_vcpu *vcpu, bool is_write, unsigned long *reg);
> 
> I can drop this macro and make function calls for each reg access.
> 

Please don't worry about the 32-bit side until we actually implement
that.  And once we do, we can move things around in patches to support
the 32-bit side so that it makes sense to the reader.

So, for now, just have this one file, moved to arch/arm64/kvm/ where all
the access functions are static in this file and called directly from
the single dispatch function.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 07/11] arm/arm64: vgic: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl
  2016-11-28 19:50     ` Christoffer Dall
@ 2016-11-29 16:36       ` Vijay Kilari
  -1 siblings, 0 replies; 78+ messages in thread
From: Vijay Kilari @ 2016-11-29 16:36 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

On Tue, Nov 29, 2016 at 1:20 AM, Christoffer Dall
<christoffer.dall@linaro.org> wrote:
> On Wed, Nov 23, 2016 at 06:31:54PM +0530, vijay.kilari@gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>
>> Userspace requires to store and restore of line_level for
>> level triggered interrupts using ioctl KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO.
>>
>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>> ---
>>  arch/arm/include/uapi/asm/kvm.h     |  7 ++++++
>>  arch/arm64/include/uapi/asm/kvm.h   |  6 +++++
>>  virt/kvm/arm/vgic/vgic-kvm-device.c | 49 ++++++++++++++++++++++++++++++++++++-
>>  virt/kvm/arm/vgic/vgic-mmio-v3.c    | 11 +++++++++
>>  virt/kvm/arm/vgic/vgic-mmio.c       | 38 ++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-mmio.h       |  5 ++++
>>  virt/kvm/arm/vgic/vgic.h            |  2 ++
>>  7 files changed, 117 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
>> index 98658d9d..f347779 100644
>> --- a/arch/arm/include/uapi/asm/kvm.h
>> +++ b/arch/arm/include/uapi/asm/kvm.h
>> @@ -191,6 +191,13 @@ struct kvm_arch_memory_slot {
>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL       4
>>  #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
>>  #define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
>> +#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
>> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT       10
>> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
>> +                     (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
>> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK       0x3ff
>> +#define VGIC_LEVEL_INFO_LINE_LEVEL   0
>> +
>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
>>
>>  /* KVM_IRQ_LINE irq field index values */
>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>> index 91c7137..4100f8c 100644
>> --- a/arch/arm64/include/uapi/asm/kvm.h
>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>> @@ -211,6 +211,12 @@ struct kvm_arch_memory_slot {
>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL    4
>>  #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
>>  #define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
>> +#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
>> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT       10
>> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
>> +                     (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
>> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK       0x3ff
>> +#define VGIC_LEVEL_INFO_LINE_LEVEL   0
>>
>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT 0
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> index b6266fe..52ed00b 100644
>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> @@ -510,6 +510,25 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
>>                                                 regid, reg);
>>               break;
>>       }
>> +     case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
>> +             unsigned int info, intid;
>> +
>> +             info = (attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
>> +                     KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT;
>> +             if (info == VGIC_LEVEL_INFO_LINE_LEVEL) {
>> +                     if (is_write)
>> +                             tmp32 = *reg;
>> +                     intid = attr->attr &
>> +                             KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK;
>> +                     ret = vgic_v3_line_level_info_uaccess(vcpu, is_write,
>> +                                                           intid, &tmp32);
>> +                     if (!is_write)
>> +                             *reg = tmp32;
>
> I had a comment here about not having to use the tmp32 by modifying the
> line_level_info function, that you seem to have missed.
>
> Hint: The level info is not called from an MMIO path so you should be
> able to just write it in a natural way.

Ok. Changed the prototype of vgic_v3_line_level_info_uaccess() to take
u64 reg instead of tmp32

>
>> +             } else {
>> +                     ret = -EINVAL;
>> +             }
>> +             break;
>> +     }
>>       default:
>>               ret = -EINVAL;
>>               break;
>> @@ -552,6 +571,17 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
>>
>>               return vgic_v3_attr_regs_access(dev, attr, &reg, true);
>>       }
>> +     case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
>> +             u32 __user *uaddr = (u32 __user *)(long)attr->addr;
>> +             u64 reg;
>> +             u32 tmp32;
>> +
>> +             if (get_user(tmp32, uaddr))
>> +                     return -EFAULT;
>> +
>> +             reg = tmp32;
>> +             return vgic_v3_attr_regs_access(dev, attr, &reg, true);
>> +     }
>>       }
>>       return -ENXIO;
>>  }
>> @@ -587,8 +617,18 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
>>                       return ret;
>>               return put_user(reg, uaddr);
>>       }
>> -     }
>> +     case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
>> +             u32 __user *uaddr = (u32 __user *)(long)attr->addr;
>> +             u64 reg;
>> +             u32 tmp32;
>>
>> +             ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
>> +             if (ret)
>> +                     return ret;
>> +             tmp32 = reg;
>> +             return put_user(tmp32, uaddr);
>> +     }
>> +     }
>>       return -ENXIO;
>>  }
>>
>> @@ -609,6 +649,13 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
>>               return vgic_v3_has_attr_regs(dev, attr);
>>       case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>>               return 0;
>> +     case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
>> +             if (((attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
>> +                   KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) ==
>> +                   VGIC_LEVEL_INFO_LINE_LEVEL)
>> +                     return 0;
>> +             break;
>> +     }
>>       case KVM_DEV_ARM_VGIC_GRP_CTRL:
>>               switch (attr->attr) {
>>               case KVM_DEV_ARM_VGIC_CTRL_INIT:
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> index 2f7b4ed..4d7d93d 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> @@ -808,3 +808,14 @@ int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>               return vgic_uaccess(vcpu, &rd_dev, is_write,
>>                                   offset, val);
>>  }
>> +
>> +int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>> +                                 u32 intid, u32 *val)
>> +{
>> +     if (is_write)
>> +             vgic_write_irq_line_level_info(vcpu, intid, *val);
>> +     else
>> +             *val = vgic_read_irq_line_level_info(vcpu, intid);
>> +
>> +     return 0;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>> index f81e0e5..d602081 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>> @@ -371,6 +371,44 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>>       }
>>  }
>>
>> +unsigned long vgic_read_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid)
>> +{
>> +     int i;
>> +     unsigned long val = 0;
>> +
>> +     for (i = 0; i < 32; i++) {
>> +             struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +             if (irq->line_level)
>> +                     val |= (1U << i);
>> +
>> +             vgic_put_irq(vcpu->kvm, irq);
>> +     }
>> +
>> +     return val;
>> +}
>> +
>> +void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid,
>> +                                 const unsigned long val)
>> +{
>> +     int i;
>> +
>> +     for (i = 0; i < 32; i++) {
>> +             struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +             spin_lock(&irq->irq_lock);
>> +             if (val & (1U << i)) {
>> +                     irq->line_level = true;
>> +                     vgic_queue_irq_unlock(vcpu->kvm, irq);
>> +             } else {
>> +                     irq->line_level = false;
>> +                     spin_unlock(&irq->irq_lock);
>> +             }
>
> I think you also missed my comment about having to keep the pending
> state in sync with the level state.
>
> Which means you have to set the pending state when the line_level goes
> up, and lower it when it goes down unless soft_pending is also set,
> assuming it's configured as a level triggered interrupt.
>
> If it's an edge-triggered interrupt, I think you only need to set the
> pending state on a line being asserted and the rest should be adjusted
> in case the user restores the configuration state to level triggered
> later.

Is this ok?

void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid,
                                    const u64 val)
{
        int i;

        for (i = 0; i < 32; i++) {
                struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);

                spin_lock(&irq->irq_lock);
                if (val & (1U << i)) {
                        irq->line_level = true;
                        irq->pending = true;
                        vgic_queue_irq_unlock(vcpu->kvm, irq);
                } else {
                        if (irq->config == VGIC_CONFIG_EDGE ||
                            (irq->config == VGIC_CONFIG_LEVEL &&
                            !irq->soft_pending))
                                irq->line_level = false;
                        spin_unlock(&irq->irq_lock);
                }

                vgic_put_irq(vcpu->kvm, irq);
        }
}


>
> Thanks,
> -Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 07/11] arm/arm64: vgic: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl
@ 2016-11-29 16:36       ` Vijay Kilari
  0 siblings, 0 replies; 78+ messages in thread
From: Vijay Kilari @ 2016-11-29 16:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Nov 29, 2016 at 1:20 AM, Christoffer Dall
<christoffer.dall@linaro.org> wrote:
> On Wed, Nov 23, 2016 at 06:31:54PM +0530, vijay.kilari at gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>
>> Userspace requires to store and restore of line_level for
>> level triggered interrupts using ioctl KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO.
>>
>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>> ---
>>  arch/arm/include/uapi/asm/kvm.h     |  7 ++++++
>>  arch/arm64/include/uapi/asm/kvm.h   |  6 +++++
>>  virt/kvm/arm/vgic/vgic-kvm-device.c | 49 ++++++++++++++++++++++++++++++++++++-
>>  virt/kvm/arm/vgic/vgic-mmio-v3.c    | 11 +++++++++
>>  virt/kvm/arm/vgic/vgic-mmio.c       | 38 ++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-mmio.h       |  5 ++++
>>  virt/kvm/arm/vgic/vgic.h            |  2 ++
>>  7 files changed, 117 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
>> index 98658d9d..f347779 100644
>> --- a/arch/arm/include/uapi/asm/kvm.h
>> +++ b/arch/arm/include/uapi/asm/kvm.h
>> @@ -191,6 +191,13 @@ struct kvm_arch_memory_slot {
>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL       4
>>  #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
>>  #define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
>> +#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
>> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT       10
>> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
>> +                     (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
>> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK       0x3ff
>> +#define VGIC_LEVEL_INFO_LINE_LEVEL   0
>> +
>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
>>
>>  /* KVM_IRQ_LINE irq field index values */
>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>> index 91c7137..4100f8c 100644
>> --- a/arch/arm64/include/uapi/asm/kvm.h
>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>> @@ -211,6 +211,12 @@ struct kvm_arch_memory_slot {
>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL    4
>>  #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
>>  #define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
>> +#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
>> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT       10
>> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
>> +                     (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
>> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK       0x3ff
>> +#define VGIC_LEVEL_INFO_LINE_LEVEL   0
>>
>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT 0
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> index b6266fe..52ed00b 100644
>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> @@ -510,6 +510,25 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
>>                                                 regid, reg);
>>               break;
>>       }
>> +     case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
>> +             unsigned int info, intid;
>> +
>> +             info = (attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
>> +                     KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT;
>> +             if (info == VGIC_LEVEL_INFO_LINE_LEVEL) {
>> +                     if (is_write)
>> +                             tmp32 = *reg;
>> +                     intid = attr->attr &
>> +                             KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK;
>> +                     ret = vgic_v3_line_level_info_uaccess(vcpu, is_write,
>> +                                                           intid, &tmp32);
>> +                     if (!is_write)
>> +                             *reg = tmp32;
>
> I had a comment here about not having to use the tmp32 by modifying the
> line_level_info function, that you seem to have missed.
>
> Hint: The level info is not called from an MMIO path so you should be
> able to just write it in a natural way.

Ok. Changed the prototype of vgic_v3_line_level_info_uaccess() to take
u64 reg instead of tmp32

>
>> +             } else {
>> +                     ret = -EINVAL;
>> +             }
>> +             break;
>> +     }
>>       default:
>>               ret = -EINVAL;
>>               break;
>> @@ -552,6 +571,17 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
>>
>>               return vgic_v3_attr_regs_access(dev, attr, &reg, true);
>>       }
>> +     case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
>> +             u32 __user *uaddr = (u32 __user *)(long)attr->addr;
>> +             u64 reg;
>> +             u32 tmp32;
>> +
>> +             if (get_user(tmp32, uaddr))
>> +                     return -EFAULT;
>> +
>> +             reg = tmp32;
>> +             return vgic_v3_attr_regs_access(dev, attr, &reg, true);
>> +     }
>>       }
>>       return -ENXIO;
>>  }
>> @@ -587,8 +617,18 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
>>                       return ret;
>>               return put_user(reg, uaddr);
>>       }
>> -     }
>> +     case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
>> +             u32 __user *uaddr = (u32 __user *)(long)attr->addr;
>> +             u64 reg;
>> +             u32 tmp32;
>>
>> +             ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
>> +             if (ret)
>> +                     return ret;
>> +             tmp32 = reg;
>> +             return put_user(tmp32, uaddr);
>> +     }
>> +     }
>>       return -ENXIO;
>>  }
>>
>> @@ -609,6 +649,13 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
>>               return vgic_v3_has_attr_regs(dev, attr);
>>       case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>>               return 0;
>> +     case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
>> +             if (((attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
>> +                   KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) ==
>> +                   VGIC_LEVEL_INFO_LINE_LEVEL)
>> +                     return 0;
>> +             break;
>> +     }
>>       case KVM_DEV_ARM_VGIC_GRP_CTRL:
>>               switch (attr->attr) {
>>               case KVM_DEV_ARM_VGIC_CTRL_INIT:
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> index 2f7b4ed..4d7d93d 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> @@ -808,3 +808,14 @@ int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>               return vgic_uaccess(vcpu, &rd_dev, is_write,
>>                                   offset, val);
>>  }
>> +
>> +int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>> +                                 u32 intid, u32 *val)
>> +{
>> +     if (is_write)
>> +             vgic_write_irq_line_level_info(vcpu, intid, *val);
>> +     else
>> +             *val = vgic_read_irq_line_level_info(vcpu, intid);
>> +
>> +     return 0;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>> index f81e0e5..d602081 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>> @@ -371,6 +371,44 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>>       }
>>  }
>>
>> +unsigned long vgic_read_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid)
>> +{
>> +     int i;
>> +     unsigned long val = 0;
>> +
>> +     for (i = 0; i < 32; i++) {
>> +             struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +             if (irq->line_level)
>> +                     val |= (1U << i);
>> +
>> +             vgic_put_irq(vcpu->kvm, irq);
>> +     }
>> +
>> +     return val;
>> +}
>> +
>> +void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid,
>> +                                 const unsigned long val)
>> +{
>> +     int i;
>> +
>> +     for (i = 0; i < 32; i++) {
>> +             struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +             spin_lock(&irq->irq_lock);
>> +             if (val & (1U << i)) {
>> +                     irq->line_level = true;
>> +                     vgic_queue_irq_unlock(vcpu->kvm, irq);
>> +             } else {
>> +                     irq->line_level = false;
>> +                     spin_unlock(&irq->irq_lock);
>> +             }
>
> I think you also missed my comment about having to keep the pending
> state in sync with the level state.
>
> Which means you have to set the pending state when the line_level goes
> up, and lower it when it goes down unless soft_pending is also set,
> assuming it's configured as a level triggered interrupt.
>
> If it's an edge-triggered interrupt, I think you only need to set the
> pending state on a line being asserted and the rest should be adjusted
> in case the user restores the configuration state to level triggered
> later.

Is this ok?

void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid,
                                    const u64 val)
{
        int i;

        for (i = 0; i < 32; i++) {
                struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);

                spin_lock(&irq->irq_lock);
                if (val & (1U << i)) {
                        irq->line_level = true;
                        irq->pending = true;
                        vgic_queue_irq_unlock(vcpu->kvm, irq);
                } else {
                        if (irq->config == VGIC_CONFIG_EDGE ||
                            (irq->config == VGIC_CONFIG_LEVEL &&
                            !irq->soft_pending))
                                irq->line_level = false;
                        spin_unlock(&irq->irq_lock);
                }

                vgic_put_irq(vcpu->kvm, irq);
        }
}


>
> Thanks,
> -Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 07/11] arm/arm64: vgic: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl
  2016-11-29 16:36       ` Vijay Kilari
@ 2016-11-29 21:09         ` Christoffer Dall
  -1 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-29 21:09 UTC (permalink / raw)
  To: Vijay Kilari; +Cc: Marc Zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

On Tue, Nov 29, 2016 at 10:06:27PM +0530, Vijay Kilari wrote:
> On Tue, Nov 29, 2016 at 1:20 AM, Christoffer Dall
> <christoffer.dall@linaro.org> wrote:
> > On Wed, Nov 23, 2016 at 06:31:54PM +0530, vijay.kilari@gmail.com wrote:
> >> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >>
> >> Userspace requires to store and restore of line_level for
> >> level triggered interrupts using ioctl KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO.
> >>
> >> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >> ---
> >>  arch/arm/include/uapi/asm/kvm.h     |  7 ++++++
> >>  arch/arm64/include/uapi/asm/kvm.h   |  6 +++++
> >>  virt/kvm/arm/vgic/vgic-kvm-device.c | 49 ++++++++++++++++++++++++++++++++++++-
> >>  virt/kvm/arm/vgic/vgic-mmio-v3.c    | 11 +++++++++
> >>  virt/kvm/arm/vgic/vgic-mmio.c       | 38 ++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic-mmio.h       |  5 ++++
> >>  virt/kvm/arm/vgic/vgic.h            |  2 ++
> >>  7 files changed, 117 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
> >> index 98658d9d..f347779 100644
> >> --- a/arch/arm/include/uapi/asm/kvm.h
> >> +++ b/arch/arm/include/uapi/asm/kvm.h
> >> @@ -191,6 +191,13 @@ struct kvm_arch_memory_slot {
> >>  #define KVM_DEV_ARM_VGIC_GRP_CTRL       4
> >>  #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
> >>  #define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
> >> +#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
> >> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT       10
> >> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
> >> +                     (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
> >> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK       0x3ff
> >> +#define VGIC_LEVEL_INFO_LINE_LEVEL   0
> >> +
> >>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
> >>
> >>  /* KVM_IRQ_LINE irq field index values */
> >> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> >> index 91c7137..4100f8c 100644
> >> --- a/arch/arm64/include/uapi/asm/kvm.h
> >> +++ b/arch/arm64/include/uapi/asm/kvm.h
> >> @@ -211,6 +211,12 @@ struct kvm_arch_memory_slot {
> >>  #define KVM_DEV_ARM_VGIC_GRP_CTRL    4
> >>  #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
> >>  #define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
> >> +#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
> >> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT       10
> >> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
> >> +                     (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
> >> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK       0x3ff
> >> +#define VGIC_LEVEL_INFO_LINE_LEVEL   0
> >>
> >>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT 0
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >> index b6266fe..52ed00b 100644
> >> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> >> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >> @@ -510,6 +510,25 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
> >>                                                 regid, reg);
> >>               break;
> >>       }
> >> +     case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
> >> +             unsigned int info, intid;
> >> +
> >> +             info = (attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
> >> +                     KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT;
> >> +             if (info == VGIC_LEVEL_INFO_LINE_LEVEL) {
> >> +                     if (is_write)
> >> +                             tmp32 = *reg;
> >> +                     intid = attr->attr &
> >> +                             KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK;
> >> +                     ret = vgic_v3_line_level_info_uaccess(vcpu, is_write,
> >> +                                                           intid, &tmp32);
> >> +                     if (!is_write)
> >> +                             *reg = tmp32;
> >
> > I had a comment here about not having to use the tmp32 by modifying the
> > line_level_info function, that you seem to have missed.
> >
> > Hint: The level info is not called from an MMIO path so you should be
> > able to just write it in a natural way.
> 
> Ok. Changed the prototype of vgic_v3_line_level_info_uaccess() to take
> u64 reg instead of tmp32
> 
> >
> >> +             } else {
> >> +                     ret = -EINVAL;
> >> +             }
> >> +             break;
> >> +     }
> >>       default:
> >>               ret = -EINVAL;
> >>               break;
> >> @@ -552,6 +571,17 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
> >>
> >>               return vgic_v3_attr_regs_access(dev, attr, &reg, true);
> >>       }
> >> +     case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
> >> +             u32 __user *uaddr = (u32 __user *)(long)attr->addr;
> >> +             u64 reg;
> >> +             u32 tmp32;
> >> +
> >> +             if (get_user(tmp32, uaddr))
> >> +                     return -EFAULT;
> >> +
> >> +             reg = tmp32;
> >> +             return vgic_v3_attr_regs_access(dev, attr, &reg, true);
> >> +     }
> >>       }
> >>       return -ENXIO;
> >>  }
> >> @@ -587,8 +617,18 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
> >>                       return ret;
> >>               return put_user(reg, uaddr);
> >>       }
> >> -     }
> >> +     case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
> >> +             u32 __user *uaddr = (u32 __user *)(long)attr->addr;
> >> +             u64 reg;
> >> +             u32 tmp32;
> >>
> >> +             ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
> >> +             if (ret)
> >> +                     return ret;
> >> +             tmp32 = reg;
> >> +             return put_user(tmp32, uaddr);
> >> +     }
> >> +     }
> >>       return -ENXIO;
> >>  }
> >>
> >> @@ -609,6 +649,13 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
> >>               return vgic_v3_has_attr_regs(dev, attr);
> >>       case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
> >>               return 0;
> >> +     case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
> >> +             if (((attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
> >> +                   KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) ==
> >> +                   VGIC_LEVEL_INFO_LINE_LEVEL)
> >> +                     return 0;
> >> +             break;
> >> +     }
> >>       case KVM_DEV_ARM_VGIC_GRP_CTRL:
> >>               switch (attr->attr) {
> >>               case KVM_DEV_ARM_VGIC_CTRL_INIT:
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> >> index 2f7b4ed..4d7d93d 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> >> @@ -808,3 +808,14 @@ int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> >>               return vgic_uaccess(vcpu, &rd_dev, is_write,
> >>                                   offset, val);
> >>  }
> >> +
> >> +int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> >> +                                 u32 intid, u32 *val)
> >> +{
> >> +     if (is_write)
> >> +             vgic_write_irq_line_level_info(vcpu, intid, *val);
> >> +     else
> >> +             *val = vgic_read_irq_line_level_info(vcpu, intid);
> >> +
> >> +     return 0;
> >> +}
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> >> index f81e0e5..d602081 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> >> @@ -371,6 +371,44 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
> >>       }
> >>  }
> >>
> >> +unsigned long vgic_read_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid)
> >> +{
> >> +     int i;
> >> +     unsigned long val = 0;
> >> +
> >> +     for (i = 0; i < 32; i++) {
> >> +             struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +             if (irq->line_level)
> >> +                     val |= (1U << i);
> >> +
> >> +             vgic_put_irq(vcpu->kvm, irq);
> >> +     }
> >> +
> >> +     return val;
> >> +}
> >> +
> >> +void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid,
> >> +                                 const unsigned long val)
> >> +{
> >> +     int i;
> >> +
> >> +     for (i = 0; i < 32; i++) {
> >> +             struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +             spin_lock(&irq->irq_lock);
> >> +             if (val & (1U << i)) {
> >> +                     irq->line_level = true;
> >> +                     vgic_queue_irq_unlock(vcpu->kvm, irq);
> >> +             } else {
> >> +                     irq->line_level = false;
> >> +                     spin_unlock(&irq->irq_lock);
> >> +             }
> >
> > I think you also missed my comment about having to keep the pending
> > state in sync with the level state.
> >
> > Which means you have to set the pending state when the line_level goes
> > up, and lower it when it goes down unless soft_pending is also set,
> > assuming it's configured as a level triggered interrupt.
> >
> > If it's an edge-triggered interrupt, I think you only need to set the
> > pending state on a line being asserted and the rest should be adjusted
> > in case the user restores the configuration state to level triggered
> > later.
> 
> Is this ok?
> 
> void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid,
>                                     const u64 val)
> {
>         int i;
> 
>         for (i = 0; i < 32; i++) {
>                 struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> 
>                 spin_lock(&irq->irq_lock);
>                 if (val & (1U << i)) {
>                         irq->line_level = true;
>                         irq->pending = true;
>                         vgic_queue_irq_unlock(vcpu->kvm, irq);

Actually, I'm not sure what the semantics of the line level ioctl should
be for edge-triggered interrupts?  My inclination is that it shouldn't
have any effect at this point, but that would mean that at this point we
should only set the pending variable and try to queue the interrupt if
the config is level.  But that also means that when we set the config
later, we need to try to queue the interrupt, which we don't do
currently, because we rely on the guest not fiddling with the config of
an enabled interrupt.

Could it be considered an error if user space tries to set the level for
an edge-triggered interrupt and therefore something we can just ignore
and assume that the corresponing interrupt will be configured as a
level-triggered one later?

Marc/Peter, thoughts on this one?

In any case we probably need to clarify the ABI in terms of this
particular KVM_DEV_AR_VGIC_GRP_LEVEL_INFO group and how it relates to
the config of edge vs. level of interrupts and ordering on restore...


Thanks,
-Christoffer

>                 } else {
>                         if (irq->config == VGIC_CONFIG_EDGE ||
>                             (irq->config == VGIC_CONFIG_LEVEL &&
>                             !irq->soft_pending))
>                                 irq->line_level = false;
>                         spin_unlock(&irq->irq_lock);
>                 }
> 
>                 vgic_put_irq(vcpu->kvm, irq);
>         }
> }

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 07/11] arm/arm64: vgic: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl
@ 2016-11-29 21:09         ` Christoffer Dall
  0 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-29 21:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Nov 29, 2016 at 10:06:27PM +0530, Vijay Kilari wrote:
> On Tue, Nov 29, 2016 at 1:20 AM, Christoffer Dall
> <christoffer.dall@linaro.org> wrote:
> > On Wed, Nov 23, 2016 at 06:31:54PM +0530, vijay.kilari at gmail.com wrote:
> >> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >>
> >> Userspace requires to store and restore of line_level for
> >> level triggered interrupts using ioctl KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO.
> >>
> >> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >> ---
> >>  arch/arm/include/uapi/asm/kvm.h     |  7 ++++++
> >>  arch/arm64/include/uapi/asm/kvm.h   |  6 +++++
> >>  virt/kvm/arm/vgic/vgic-kvm-device.c | 49 ++++++++++++++++++++++++++++++++++++-
> >>  virt/kvm/arm/vgic/vgic-mmio-v3.c    | 11 +++++++++
> >>  virt/kvm/arm/vgic/vgic-mmio.c       | 38 ++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic-mmio.h       |  5 ++++
> >>  virt/kvm/arm/vgic/vgic.h            |  2 ++
> >>  7 files changed, 117 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
> >> index 98658d9d..f347779 100644
> >> --- a/arch/arm/include/uapi/asm/kvm.h
> >> +++ b/arch/arm/include/uapi/asm/kvm.h
> >> @@ -191,6 +191,13 @@ struct kvm_arch_memory_slot {
> >>  #define KVM_DEV_ARM_VGIC_GRP_CTRL       4
> >>  #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
> >>  #define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
> >> +#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
> >> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT       10
> >> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
> >> +                     (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
> >> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK       0x3ff
> >> +#define VGIC_LEVEL_INFO_LINE_LEVEL   0
> >> +
> >>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
> >>
> >>  /* KVM_IRQ_LINE irq field index values */
> >> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> >> index 91c7137..4100f8c 100644
> >> --- a/arch/arm64/include/uapi/asm/kvm.h
> >> +++ b/arch/arm64/include/uapi/asm/kvm.h
> >> @@ -211,6 +211,12 @@ struct kvm_arch_memory_slot {
> >>  #define KVM_DEV_ARM_VGIC_GRP_CTRL    4
> >>  #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
> >>  #define KVM_DEV_ARM_VGIC_CPU_SYSREGS    6
> >> +#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
> >> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT       10
> >> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
> >> +                     (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
> >> +#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK       0x3ff
> >> +#define VGIC_LEVEL_INFO_LINE_LEVEL   0
> >>
> >>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT 0
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >> index b6266fe..52ed00b 100644
> >> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> >> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >> @@ -510,6 +510,25 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
> >>                                                 regid, reg);
> >>               break;
> >>       }
> >> +     case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
> >> +             unsigned int info, intid;
> >> +
> >> +             info = (attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
> >> +                     KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT;
> >> +             if (info == VGIC_LEVEL_INFO_LINE_LEVEL) {
> >> +                     if (is_write)
> >> +                             tmp32 = *reg;
> >> +                     intid = attr->attr &
> >> +                             KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK;
> >> +                     ret = vgic_v3_line_level_info_uaccess(vcpu, is_write,
> >> +                                                           intid, &tmp32);
> >> +                     if (!is_write)
> >> +                             *reg = tmp32;
> >
> > I had a comment here about not having to use the tmp32 by modifying the
> > line_level_info function, that you seem to have missed.
> >
> > Hint: The level info is not called from an MMIO path so you should be
> > able to just write it in a natural way.
> 
> Ok. Changed the prototype of vgic_v3_line_level_info_uaccess() to take
> u64 reg instead of tmp32
> 
> >
> >> +             } else {
> >> +                     ret = -EINVAL;
> >> +             }
> >> +             break;
> >> +     }
> >>       default:
> >>               ret = -EINVAL;
> >>               break;
> >> @@ -552,6 +571,17 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
> >>
> >>               return vgic_v3_attr_regs_access(dev, attr, &reg, true);
> >>       }
> >> +     case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
> >> +             u32 __user *uaddr = (u32 __user *)(long)attr->addr;
> >> +             u64 reg;
> >> +             u32 tmp32;
> >> +
> >> +             if (get_user(tmp32, uaddr))
> >> +                     return -EFAULT;
> >> +
> >> +             reg = tmp32;
> >> +             return vgic_v3_attr_regs_access(dev, attr, &reg, true);
> >> +     }
> >>       }
> >>       return -ENXIO;
> >>  }
> >> @@ -587,8 +617,18 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
> >>                       return ret;
> >>               return put_user(reg, uaddr);
> >>       }
> >> -     }
> >> +     case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
> >> +             u32 __user *uaddr = (u32 __user *)(long)attr->addr;
> >> +             u64 reg;
> >> +             u32 tmp32;
> >>
> >> +             ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
> >> +             if (ret)
> >> +                     return ret;
> >> +             tmp32 = reg;
> >> +             return put_user(tmp32, uaddr);
> >> +     }
> >> +     }
> >>       return -ENXIO;
> >>  }
> >>
> >> @@ -609,6 +649,13 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
> >>               return vgic_v3_has_attr_regs(dev, attr);
> >>       case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
> >>               return 0;
> >> +     case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
> >> +             if (((attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
> >> +                   KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) ==
> >> +                   VGIC_LEVEL_INFO_LINE_LEVEL)
> >> +                     return 0;
> >> +             break;
> >> +     }
> >>       case KVM_DEV_ARM_VGIC_GRP_CTRL:
> >>               switch (attr->attr) {
> >>               case KVM_DEV_ARM_VGIC_CTRL_INIT:
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> >> index 2f7b4ed..4d7d93d 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> >> @@ -808,3 +808,14 @@ int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> >>               return vgic_uaccess(vcpu, &rd_dev, is_write,
> >>                                   offset, val);
> >>  }
> >> +
> >> +int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> >> +                                 u32 intid, u32 *val)
> >> +{
> >> +     if (is_write)
> >> +             vgic_write_irq_line_level_info(vcpu, intid, *val);
> >> +     else
> >> +             *val = vgic_read_irq_line_level_info(vcpu, intid);
> >> +
> >> +     return 0;
> >> +}
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> >> index f81e0e5..d602081 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> >> @@ -371,6 +371,44 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
> >>       }
> >>  }
> >>
> >> +unsigned long vgic_read_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid)
> >> +{
> >> +     int i;
> >> +     unsigned long val = 0;
> >> +
> >> +     for (i = 0; i < 32; i++) {
> >> +             struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +             if (irq->line_level)
> >> +                     val |= (1U << i);
> >> +
> >> +             vgic_put_irq(vcpu->kvm, irq);
> >> +     }
> >> +
> >> +     return val;
> >> +}
> >> +
> >> +void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid,
> >> +                                 const unsigned long val)
> >> +{
> >> +     int i;
> >> +
> >> +     for (i = 0; i < 32; i++) {
> >> +             struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +             spin_lock(&irq->irq_lock);
> >> +             if (val & (1U << i)) {
> >> +                     irq->line_level = true;
> >> +                     vgic_queue_irq_unlock(vcpu->kvm, irq);
> >> +             } else {
> >> +                     irq->line_level = false;
> >> +                     spin_unlock(&irq->irq_lock);
> >> +             }
> >
> > I think you also missed my comment about having to keep the pending
> > state in sync with the level state.
> >
> > Which means you have to set the pending state when the line_level goes
> > up, and lower it when it goes down unless soft_pending is also set,
> > assuming it's configured as a level triggered interrupt.
> >
> > If it's an edge-triggered interrupt, I think you only need to set the
> > pending state on a line being asserted and the rest should be adjusted
> > in case the user restores the configuration state to level triggered
> > later.
> 
> Is this ok?
> 
> void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid,
>                                     const u64 val)
> {
>         int i;
> 
>         for (i = 0; i < 32; i++) {
>                 struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> 
>                 spin_lock(&irq->irq_lock);
>                 if (val & (1U << i)) {
>                         irq->line_level = true;
>                         irq->pending = true;
>                         vgic_queue_irq_unlock(vcpu->kvm, irq);

Actually, I'm not sure what the semantics of the line level ioctl should
be for edge-triggered interrupts?  My inclination is that it shouldn't
have any effect at this point, but that would mean that at this point we
should only set the pending variable and try to queue the interrupt if
the config is level.  But that also means that when we set the config
later, we need to try to queue the interrupt, which we don't do
currently, because we rely on the guest not fiddling with the config of
an enabled interrupt.

Could it be considered an error if user space tries to set the level for
an edge-triggered interrupt and therefore something we can just ignore
and assume that the corresponing interrupt will be configured as a
level-triggered one later?

Marc/Peter, thoughts on this one?

In any case we probably need to clarify the ABI in terms of this
particular KVM_DEV_AR_VGIC_GRP_LEVEL_INFO group and how it relates to
the config of edge vs. level of interrupts and ordering on restore...


Thanks,
-Christoffer

>                 } else {
>                         if (irq->config == VGIC_CONFIG_EDGE ||
>                             (irq->config == VGIC_CONFIG_LEVEL &&
>                             !irq->soft_pending))
>                                 irq->line_level = false;
>                         spin_unlock(&irq->irq_lock);
>                 }
> 
>                 vgic_put_irq(vcpu->kvm, irq);
>         }
> }

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 07/11] arm/arm64: vgic: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl
  2016-11-29 21:09         ` Christoffer Dall
@ 2016-11-30  7:10           ` Peter Maydell
  -1 siblings, 0 replies; 78+ messages in thread
From: Peter Maydell @ 2016-11-30  7:10 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Vijay Kilari, Marc Zyngier, Pavel Fedin, Vijaya Kumar K, kvmarm,
	linux-arm-kernel

On 29 November 2016 at 21:09, Christoffer Dall
<christoffer.dall@linaro.org> wrote:
> Actually, I'm not sure what the semantics of the line level ioctl should
> be for edge-triggered interrupts?  My inclination is that it shouldn't
> have any effect at this point, but that would mean that at this point we
> should only set the pending variable and try to queue the interrupt if
> the config is level.  But that also means that when we set the config
> later, we need to try to queue the interrupt, which we don't do
> currently, because we rely on the guest not fiddling with the config of
> an enabled interrupt.
>
> Could it be considered an error if user space tries to set the level for
> an edge-triggered interrupt and therefore something we can just ignore
> and assume that the corresponing interrupt will be configured as a
> level-triggered one later?

Userspace will always read the line-level values out and write
them back for migration, and I'd rather not make it have to
do cross-checks against whether the interrupt is edge or level
triggered to see whether it should write the level values into
the kernel. Telling the kernel the level for an edge-triggered
interrupt should be a no-op because it doesn't have any effect
on pending status.

> In any case we probably need to clarify the ABI in terms of this
> particular KVM_DEV_AR_VGIC_GRP_LEVEL_INFO group and how it relates to
> the config of edge vs. level of interrupts and ordering on restore...

IIRC the QEMU code restores the config first. (There's a similar
ordering thing for GICv2 where we have to restore GICD_ICFGRn before
GICD_ISPENDRn.)

thanks
-- PMM

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 07/11] arm/arm64: vgic: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl
@ 2016-11-30  7:10           ` Peter Maydell
  0 siblings, 0 replies; 78+ messages in thread
From: Peter Maydell @ 2016-11-30  7:10 UTC (permalink / raw)
  To: linux-arm-kernel

On 29 November 2016 at 21:09, Christoffer Dall
<christoffer.dall@linaro.org> wrote:
> Actually, I'm not sure what the semantics of the line level ioctl should
> be for edge-triggered interrupts?  My inclination is that it shouldn't
> have any effect at this point, but that would mean that at this point we
> should only set the pending variable and try to queue the interrupt if
> the config is level.  But that also means that when we set the config
> later, we need to try to queue the interrupt, which we don't do
> currently, because we rely on the guest not fiddling with the config of
> an enabled interrupt.
>
> Could it be considered an error if user space tries to set the level for
> an edge-triggered interrupt and therefore something we can just ignore
> and assume that the corresponing interrupt will be configured as a
> level-triggered one later?

Userspace will always read the line-level values out and write
them back for migration, and I'd rather not make it have to
do cross-checks against whether the interrupt is edge or level
triggered to see whether it should write the level values into
the kernel. Telling the kernel the level for an edge-triggered
interrupt should be a no-op because it doesn't have any effect
on pending status.

> In any case we probably need to clarify the ABI in terms of this
> particular KVM_DEV_AR_VGIC_GRP_LEVEL_INFO group and how it relates to
> the config of edge vs. level of interrupts and ordering on restore...

IIRC the QEMU code restores the config first. (There's a similar
ordering thing for GICv2 where we have to restore GICD_ICFGRn before
GICD_ISPENDRn.)

thanks
-- PMM

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 07/11] arm/arm64: vgic: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl
  2016-11-30  7:10           ` Peter Maydell
@ 2016-11-30  8:24             ` Christoffer Dall
  -1 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-30  8:24 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Marc Zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

On Wed, Nov 30, 2016 at 07:10:51AM +0000, Peter Maydell wrote:
> On 29 November 2016 at 21:09, Christoffer Dall
> <christoffer.dall@linaro.org> wrote:
> > Actually, I'm not sure what the semantics of the line level ioctl should
> > be for edge-triggered interrupts?  My inclination is that it shouldn't
> > have any effect at this point, but that would mean that at this point we
> > should only set the pending variable and try to queue the interrupt if
> > the config is level.  But that also means that when we set the config
> > later, we need to try to queue the interrupt, which we don't do
> > currently, because we rely on the guest not fiddling with the config of
> > an enabled interrupt.
> >
> > Could it be considered an error if user space tries to set the level for
> > an edge-triggered interrupt and therefore something we can just ignore
> > and assume that the corresponing interrupt will be configured as a
> > level-triggered one later?
> 
> Userspace will always read the line-level values out and write
> them back for migration, and I'd rather not make it have to
> do cross-checks against whether the interrupt is edge or level
> triggered to see whether it should write the level values into
> the kernel. Telling the kernel the level for an edge-triggered
> interrupt should be a no-op because it doesn't have any effect
> on pending status.
> 
> > In any case we probably need to clarify the ABI in terms of this
> > particular KVM_DEV_AR_VGIC_GRP_LEVEL_INFO group and how it relates to
> > the config of edge vs. level of interrupts and ordering on restore...
> 
> IIRC the QEMU code restores the config first. (There's a similar
> ordering thing for GICv2 where we have to restore GICD_ICFGRn before
> GICD_ISPENDRn.)
> 

So it sounds to me that we should add a note in the Documentation like
this:

diff --git a/Documentation/virtual/kvm/devices/arm-vgic-v3.txt b/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
index 9348b3c..7bac20a 100644
--- a/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
+++ b/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
@@ -193,6 +193,11 @@ Groups:
 
 	Bit[n] indicates the status for interrupt vINTID + n.
 
+	Getting or setting the level info for an edge-triggered interrupt is
+	not guaranteed to work.  To restore the complete state of the VGIC, the
+	configuration (edge/level) of interrupts must be restored before
+	restoring the level.
+
     SGIs and any interrupt with a higher ID than the number of interrupts
     supported, will be RAZ/WI.  LPIs are always edge-triggered and are
     therefore not supported by this interface.

Vijay, this means that the first block in your if-statement should only
set pending and queue the interrupt if the interrupt is a level
triggered one.

(Peter, I thought you once argued that it was important for user space
to be able to save/restore the state without any ordering requirements,
but I may have misunderstood.  It is still the option to add something
like the above to the docs but also do our best to allow any ordering of
level/config, but it becomes slightly more invasive.)

Thanks,
-Christoffer

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* [PATCH v9 07/11] arm/arm64: vgic: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl
@ 2016-11-30  8:24             ` Christoffer Dall
  0 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-11-30  8:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 30, 2016 at 07:10:51AM +0000, Peter Maydell wrote:
> On 29 November 2016 at 21:09, Christoffer Dall
> <christoffer.dall@linaro.org> wrote:
> > Actually, I'm not sure what the semantics of the line level ioctl should
> > be for edge-triggered interrupts?  My inclination is that it shouldn't
> > have any effect at this point, but that would mean that at this point we
> > should only set the pending variable and try to queue the interrupt if
> > the config is level.  But that also means that when we set the config
> > later, we need to try to queue the interrupt, which we don't do
> > currently, because we rely on the guest not fiddling with the config of
> > an enabled interrupt.
> >
> > Could it be considered an error if user space tries to set the level for
> > an edge-triggered interrupt and therefore something we can just ignore
> > and assume that the corresponing interrupt will be configured as a
> > level-triggered one later?
> 
> Userspace will always read the line-level values out and write
> them back for migration, and I'd rather not make it have to
> do cross-checks against whether the interrupt is edge or level
> triggered to see whether it should write the level values into
> the kernel. Telling the kernel the level for an edge-triggered
> interrupt should be a no-op because it doesn't have any effect
> on pending status.
> 
> > In any case we probably need to clarify the ABI in terms of this
> > particular KVM_DEV_AR_VGIC_GRP_LEVEL_INFO group and how it relates to
> > the config of edge vs. level of interrupts and ordering on restore...
> 
> IIRC the QEMU code restores the config first. (There's a similar
> ordering thing for GICv2 where we have to restore GICD_ICFGRn before
> GICD_ISPENDRn.)
> 

So it sounds to me that we should add a note in the Documentation like
this:

diff --git a/Documentation/virtual/kvm/devices/arm-vgic-v3.txt b/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
index 9348b3c..7bac20a 100644
--- a/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
+++ b/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
@@ -193,6 +193,11 @@ Groups:
 
 	Bit[n] indicates the status for interrupt vINTID + n.
 
+	Getting or setting the level info for an edge-triggered interrupt is
+	not guaranteed to work.  To restore the complete state of the VGIC, the
+	configuration (edge/level) of interrupts must be restored before
+	restoring the level.
+
     SGIs and any interrupt with a higher ID than the number of interrupts
     supported, will be RAZ/WI.  LPIs are always edge-triggered and are
     therefore not supported by this interface.

Vijay, this means that the first block in your if-statement should only
set pending and queue the interrupt if the interrupt is a level
triggered one.

(Peter, I thought you once argued that it was important for user space
to be able to save/restore the state without any ordering requirements,
but I may have misunderstood.  It is still the option to add something
like the above to the docs but also do our best to allow any ordering of
level/config, but it becomes slightly more invasive.)

Thanks,
-Christoffer

^ permalink raw reply related	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 07/11] arm/arm64: vgic: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl
  2016-11-30  8:24             ` Christoffer Dall
@ 2016-11-30  8:29               ` Peter Maydell
  -1 siblings, 0 replies; 78+ messages in thread
From: Peter Maydell @ 2016-11-30  8:29 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

On 30 November 2016 at 08:24, Christoffer Dall
<christoffer.dall@linaro.org> wrote:
> (Peter, I thought you once argued that it was important for user space
> to be able to save/restore the state without any ordering requirements,
> but I may have misunderstood.  It is still the option to add something
> like the above to the docs but also do our best to allow any ordering of
> level/config, but it becomes slightly more invasive.)

Hmm; perhaps I should think about this a bit more.

-- PMM

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 07/11] arm/arm64: vgic: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl
@ 2016-11-30  8:29               ` Peter Maydell
  0 siblings, 0 replies; 78+ messages in thread
From: Peter Maydell @ 2016-11-30  8:29 UTC (permalink / raw)
  To: linux-arm-kernel

On 30 November 2016 at 08:24, Christoffer Dall
<christoffer.dall@linaro.org> wrote:
> (Peter, I thought you once argued that it was important for user space
> to be able to save/restore the state without any ordering requirements,
> but I may have misunderstood.  It is still the option to add something
> like the above to the docs but also do our best to allow any ordering of
> level/config, but it becomes slightly more invasive.)

Hmm; perhaps I should think about this a bit more.

-- PMM

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 01/11] arm/arm64: vgic: Implement support for userspace access
  2016-11-28 13:05     ` Christoffer Dall
@ 2016-12-06 11:42       ` Auger Eric
  -1 siblings, 0 replies; 78+ messages in thread
From: Auger Eric @ 2016-12-06 11:42 UTC (permalink / raw)
  To: Christoffer Dall, vijay.kilari
  Cc: marc.zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

Hi,

On 28/11/2016 14:05, Christoffer Dall wrote:
> On Wed, Nov 23, 2016 at 06:31:48PM +0530, vijay.kilari@gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>
>> Read and write of some registers like ISPENDR and ICPENDR
>> from userspace requires special handling when compared to
>> guest access for these registers.
>>
>> Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
>> for handling of ISPENDR, ICPENDR registers handling.
>>
>> Add infrastructure to support guest and userspace read
>> and write for the required registers
>> Also moved vgic_uaccess from vgic-mmio-v2.c to vgic-mmio.c
>>
>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>> ---
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  25 ----------
>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 102 ++++++++++++++++++++++++++++++++-------
>>  virt/kvm/arm/vgic/vgic-mmio.c    |  78 +++++++++++++++++++++++++++---
>>  virt/kvm/arm/vgic/vgic-mmio.h    |  19 ++++++++
>>  4 files changed, 175 insertions(+), 49 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index b44b359..0b32f40 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -406,31 +406,6 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>>  	return -ENXIO;
>>  }
>>  
>> -/*
>> - * When userland tries to access the VGIC register handlers, we need to
>> - * create a usable struct vgic_io_device to be passed to the handlers and we
>> - * have to set up a buffer similar to what would have happened if a guest MMIO
>> - * access occurred, including doing endian conversions on BE systems.
>> - */
>> -static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>> -			bool is_write, int offset, u32 *val)
>> -{
>> -	unsigned int len = 4;
>> -	u8 buf[4];
>> -	int ret;
>> -
>> -	if (is_write) {
>> -		vgic_data_host_to_mmio_bus(buf, len, *val);
>> -		ret = kvm_io_gic_ops.write(vcpu, &dev->dev, offset, len, buf);
>> -	} else {
>> -		ret = kvm_io_gic_ops.read(vcpu, &dev->dev, offset, len, buf);
>> -		if (!ret)
>> -			*val = vgic_data_mmio_bus_to_host(buf, len);
>> -	}
>> -
>> -	return ret;
>> -}
>> -
>>  int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>  			  int offset, u32 *val)
>>  {
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> index 50f42f0..8e76d04 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> @@ -207,6 +207,66 @@ static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
>>  	return 0;
>>  }
>>  
>> +static unsigned long vgic_v3_uaccess_read_pending(struct kvm_vcpu *vcpu,
>> +						  gpa_t addr, unsigned int len)
>> +{
>> +	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
>> +	u32 value = 0;
>> +	int i;
>> +
>> +	/*
>> +	 * A level triggerred interrupt pending state is latched in both
>> +	 * "soft_pending" and "line_level" variables. Userspace will save
>> +	 * and restore soft_pending and line_level separately.
>> +	 * Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
>> +	 * handling of ISPENDR and ICPENDR.
>> +	 */
>> +	for (i = 0; i < len * 8; i++) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		if (irq->config == VGIC_CONFIG_LEVEL && irq->soft_pending)
>> +			value |= (1U << i);
>> +		if (irq->config == VGIC_CONFIG_EDGE && irq->pending)
>> +			value |= (1U << i);
>> +
>> +		vgic_put_irq(vcpu->kvm, irq);
>> +	}
>> +
>> +	return value;
>> +}
>> +
>> +static void vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu,
>> +					  gpa_t addr, unsigned int len,
>> +					  unsigned long val)
>> +{
>> +	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
>> +	int i;
>> +
>> +	for (i = 0; i < len * 8; i++) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +		if (test_bit(i, &val)) {
>> +			/* soft_pending is set irrespective of irq type
>> +			 * (level or edge) to avoid dependency that VM should
>> +			 * restore irq config before pending info.
>> +			 */
> 
> nit: kernel commenting style
> 
>> +			irq->pending = true;
>> +			irq->soft_pending = true;
>> +			vgic_queue_irq_unlock(vcpu->kvm, irq);
>> +		} else {
>> +			irq->soft_pending = false;
>> +			if (irq->config == VGIC_CONFIG_EDGE ||
>> +			    (irq->config == VGIC_CONFIG_LEVEL &&
>> +			    !irq->line_level))
>> +				irq->pending = false;
I am confused by the comment above. Since we test the irq config here
don't we assume the config was restored before the pending state?
>> +			spin_unlock(&irq->irq_lock);
>> +		}
>> +
>> +		vgic_put_irq(vcpu->kvm, irq);
>> +	}
>> +}
>> +
>>  /* We want to avoid outer shareable. */
>>  u64 vgic_sanitise_shareability(u64 field)
>>  {
>> @@ -356,7 +416,7 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>   * We take some special care here to fix the calculation of the register
>>   * offset.
>>   */
>> -#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, bpi, acc)	\
>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, ur, uw, bpi, acc) \
>>  	{								\
>>  		.reg_offset = off,					\
>>  		.bits_per_irq = bpi,					\
>> @@ -371,6 +431,8 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>  		.access_flags = acc,					\
>>  		.read = rd,						\
>>  		.write = wr,						\
>> +		.uaccess_read = ur,					\
>> +		.uaccess_write = uw,					\
>>  	}
>>  
>>  static const struct vgic_register_region vgic_v3_dist_registers[] = {
>> @@ -378,40 +440,42 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>  		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>> -		vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
>> +		vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
>> -		vgic_mmio_read_enable, vgic_mmio_write_senable, 1,
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, NULL, NULL, 1,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
>> -		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, NULL, NULL, 1,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
>> -		vgic_mmio_read_pending, vgic_mmio_write_spending, 1,
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending,
>> +		vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 1,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
>> -		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1,
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
>> -		vgic_mmio_read_active, vgic_mmio_write_sactive, 1,
>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, NULL, NULL, 1,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
>> -		vgic_mmio_read_active, vgic_mmio_write_cactive, 1,
>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, NULL, NULL, 1,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
>> -		vgic_mmio_read_priority, vgic_mmio_write_priority, 8,
>> -		VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, NULL, NULL,
>> +		8, VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 8,
>>  		VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
>> -		vgic_mmio_read_config, vgic_mmio_write_config, 2,
>> +		vgic_mmio_read_config, vgic_mmio_write_config, NULL, NULL, 2,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
>> -		vgic_mmio_read_irouter, vgic_mmio_write_irouter, 64,
>> +		vgic_mmio_read_irouter, vgic_mmio_write_irouter, NULL, NULL, 64,
>>  		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>>  		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48,
>> @@ -449,11 +513,13 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>  	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
>>  		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4,
>>  		VGIC_ACCESS_32bit),
>> -	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
>> -		vgic_mmio_read_pending, vgic_mmio_write_spending, 4,
>> +	REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ISPENDR0,
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending,
>> +		vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 4,
>>  		VGIC_ACCESS_32bit),
>> -	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
>> -		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4,
>> +	REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ICPENDR0,
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
>>  		vgic_mmio_read_active, vgic_mmio_write_sactive, 4,
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>> index ebe1b9f..d5f3ee2 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>> @@ -484,6 +484,74 @@ static bool check_region(const struct kvm *kvm,
>>  	return false;
>>  }
>>  
>> +static const struct vgic_register_region *
>> +vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev,
>> +		     gpa_t addr, int len)
>> +{
>> +	const struct vgic_register_region *region;
>> +
>> +	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
>> +				       addr - iodev->base_addr);
>> +	if (!region || !check_region(vcpu->kvm, region, addr, len))
>> +		return NULL;
>> +
>> +	return region;
>> +}
>> +
>> +static int vgic_uaccess_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>> +			     gpa_t addr, u32 *val)
>> +{
>> +	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
>> +	const struct vgic_register_region *region;
>> +	struct kvm_vcpu *r_vcpu;
>> +
>> +	region = vgic_get_mmio_region(vcpu, iodev, addr, sizeof(u32));
>> +	if (!region) {
>> +		*val = 0;
>> +		return 0;
do we really want to return 0 here? -ENXIO?
I see that dispatch_mmio_read/write return 0 in that case but I don't
see any reason either? Other kvm_io_device_ops seem to return
-EOPNOTSUPP in such a case.

Thanks

Eric
>> +	}
>> +
>> +	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
>> +	if (region->uaccess_read)
>> +		*val = region->uaccess_read(r_vcpu, addr, sizeof(u32));
>> +	else
>> +		*val = region->read(r_vcpu, addr, sizeof(u32));
>> +
>> +	return 0;
>> +}
>> +
>> +static int vgic_uaccess_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>> +			      gpa_t addr, const u32 *val)
>> +{
>> +	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
>> +	const struct vgic_register_region *region;
>> +	struct kvm_vcpu *r_vcpu;
>> +
>> +	region = vgic_get_mmio_region(vcpu, iodev, addr, sizeof(u32));
>> +	if (!region)
>> +		return 0;
same?
>> +
>> +	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
>> +	if (region->uaccess_write)
>> +		region->uaccess_write(r_vcpu, addr, sizeof(u32), *val);
>> +	else
>> +		region->write(r_vcpu, addr, sizeof(u32), *val);
>> +
>> +	return 0;
>> +}
>> +
>> +/*
>> + * Userland access to VGIC registers.
>> + */
>> +int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>> +		 bool is_write, int offset, u32 *val)
>> +{
>> +	if (is_write)
>> +		return vgic_uaccess_write(vcpu, &dev->dev, offset, val);
>> +	else
>> +		return vgic_uaccess_read(vcpu, &dev->dev, offset, val);
>> +}
>> +
>>  static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>>  			      gpa_t addr, int len, void *val)
>>  {
>> @@ -491,9 +559,8 @@ static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>>  	const struct vgic_register_region *region;
>>  	unsigned long data = 0;
>>  
>> -	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
>> -				       addr - iodev->base_addr);
>> -	if (!region || !check_region(vcpu->kvm, region, addr, len)) {
>> +	region = vgic_get_mmio_region(vcpu, iodev, addr, len);
>> +	if (!region) {
>>  		memset(val, 0, len);
>>  		return 0;
>>  	}
>> @@ -524,9 +591,8 @@ static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>>  	const struct vgic_register_region *region;
>>  	unsigned long data = vgic_data_mmio_bus_to_host(val, len);
>>  
>> -	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
>> -				       addr - iodev->base_addr);
>> -	if (!region || !check_region(vcpu->kvm, region, addr, len))
>> +	region = vgic_get_mmio_region(vcpu, iodev, addr, len);
>> +	if (!region)
>>  		return 0;
>>  
>>  	switch (iodev->iodev_type) {
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
>> index 84961b4..7b30296 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.h
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
>> @@ -34,6 +34,10 @@ struct vgic_register_region {
>>  				  gpa_t addr, unsigned int len,
>>  				  unsigned long val);
>>  	};
>> +	unsigned long (*uaccess_read)(struct kvm_vcpu *vcpu, gpa_t addr,
>> +				      unsigned int len);
>> +	void (*uaccess_write)(struct kvm_vcpu *vcpu, gpa_t addr,
>> +			      unsigned int len, unsigned long val);
>>  };
>>  
>>  extern struct kvm_io_device_ops kvm_io_gic_ops;
>> @@ -86,6 +90,18 @@ struct vgic_register_region {
>>  		.write = wr,						\
>>  	}
>>  
>> +#define REGISTER_DESC_WITH_LENGTH_UACCESS(off, rd, wr, urd, uwr, length, acc) \
>> +	{								\
>> +		.reg_offset = off,					\
>> +		.bits_per_irq = 0,					\
>> +		.len = length,						\
>> +		.access_flags = acc,					\
>> +		.read = rd,						\
>> +		.write = wr,						\
>> +		.uaccess_read = urd,					\
>> +		.uaccess_write = uwr,					\
>> +	}
>> +
>>  int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  				  struct vgic_register_region *reg_desc,
>>  				  struct vgic_io_device *region,
>> @@ -158,6 +174,9 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>>  			    gpa_t addr, unsigned int len,
>>  			    unsigned long val);
>>  
>> +int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>> +		 bool is_write, int offset, u32 *val);
>> +
>>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>>  
>>  unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
>> -- 
>> 1.9.1
>>
> 
> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 01/11] arm/arm64: vgic: Implement support for userspace access
@ 2016-12-06 11:42       ` Auger Eric
  0 siblings, 0 replies; 78+ messages in thread
From: Auger Eric @ 2016-12-06 11:42 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 28/11/2016 14:05, Christoffer Dall wrote:
> On Wed, Nov 23, 2016 at 06:31:48PM +0530, vijay.kilari at gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>
>> Read and write of some registers like ISPENDR and ICPENDR
>> from userspace requires special handling when compared to
>> guest access for these registers.
>>
>> Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
>> for handling of ISPENDR, ICPENDR registers handling.
>>
>> Add infrastructure to support guest and userspace read
>> and write for the required registers
>> Also moved vgic_uaccess from vgic-mmio-v2.c to vgic-mmio.c
>>
>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>> ---
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  25 ----------
>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 102 ++++++++++++++++++++++++++++++++-------
>>  virt/kvm/arm/vgic/vgic-mmio.c    |  78 +++++++++++++++++++++++++++---
>>  virt/kvm/arm/vgic/vgic-mmio.h    |  19 ++++++++
>>  4 files changed, 175 insertions(+), 49 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index b44b359..0b32f40 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -406,31 +406,6 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>>  	return -ENXIO;
>>  }
>>  
>> -/*
>> - * When userland tries to access the VGIC register handlers, we need to
>> - * create a usable struct vgic_io_device to be passed to the handlers and we
>> - * have to set up a buffer similar to what would have happened if a guest MMIO
>> - * access occurred, including doing endian conversions on BE systems.
>> - */
>> -static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>> -			bool is_write, int offset, u32 *val)
>> -{
>> -	unsigned int len = 4;
>> -	u8 buf[4];
>> -	int ret;
>> -
>> -	if (is_write) {
>> -		vgic_data_host_to_mmio_bus(buf, len, *val);
>> -		ret = kvm_io_gic_ops.write(vcpu, &dev->dev, offset, len, buf);
>> -	} else {
>> -		ret = kvm_io_gic_ops.read(vcpu, &dev->dev, offset, len, buf);
>> -		if (!ret)
>> -			*val = vgic_data_mmio_bus_to_host(buf, len);
>> -	}
>> -
>> -	return ret;
>> -}
>> -
>>  int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>  			  int offset, u32 *val)
>>  {
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> index 50f42f0..8e76d04 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> @@ -207,6 +207,66 @@ static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
>>  	return 0;
>>  }
>>  
>> +static unsigned long vgic_v3_uaccess_read_pending(struct kvm_vcpu *vcpu,
>> +						  gpa_t addr, unsigned int len)
>> +{
>> +	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
>> +	u32 value = 0;
>> +	int i;
>> +
>> +	/*
>> +	 * A level triggerred interrupt pending state is latched in both
>> +	 * "soft_pending" and "line_level" variables. Userspace will save
>> +	 * and restore soft_pending and line_level separately.
>> +	 * Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
>> +	 * handling of ISPENDR and ICPENDR.
>> +	 */
>> +	for (i = 0; i < len * 8; i++) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		if (irq->config == VGIC_CONFIG_LEVEL && irq->soft_pending)
>> +			value |= (1U << i);
>> +		if (irq->config == VGIC_CONFIG_EDGE && irq->pending)
>> +			value |= (1U << i);
>> +
>> +		vgic_put_irq(vcpu->kvm, irq);
>> +	}
>> +
>> +	return value;
>> +}
>> +
>> +static void vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu,
>> +					  gpa_t addr, unsigned int len,
>> +					  unsigned long val)
>> +{
>> +	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
>> +	int i;
>> +
>> +	for (i = 0; i < len * 8; i++) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +		if (test_bit(i, &val)) {
>> +			/* soft_pending is set irrespective of irq type
>> +			 * (level or edge) to avoid dependency that VM should
>> +			 * restore irq config before pending info.
>> +			 */
> 
> nit: kernel commenting style
> 
>> +			irq->pending = true;
>> +			irq->soft_pending = true;
>> +			vgic_queue_irq_unlock(vcpu->kvm, irq);
>> +		} else {
>> +			irq->soft_pending = false;
>> +			if (irq->config == VGIC_CONFIG_EDGE ||
>> +			    (irq->config == VGIC_CONFIG_LEVEL &&
>> +			    !irq->line_level))
>> +				irq->pending = false;
I am confused by the comment above. Since we test the irq config here
don't we assume the config was restored before the pending state?
>> +			spin_unlock(&irq->irq_lock);
>> +		}
>> +
>> +		vgic_put_irq(vcpu->kvm, irq);
>> +	}
>> +}
>> +
>>  /* We want to avoid outer shareable. */
>>  u64 vgic_sanitise_shareability(u64 field)
>>  {
>> @@ -356,7 +416,7 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>   * We take some special care here to fix the calculation of the register
>>   * offset.
>>   */
>> -#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, bpi, acc)	\
>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, ur, uw, bpi, acc) \
>>  	{								\
>>  		.reg_offset = off,					\
>>  		.bits_per_irq = bpi,					\
>> @@ -371,6 +431,8 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>  		.access_flags = acc,					\
>>  		.read = rd,						\
>>  		.write = wr,						\
>> +		.uaccess_read = ur,					\
>> +		.uaccess_write = uw,					\
>>  	}
>>  
>>  static const struct vgic_register_region vgic_v3_dist_registers[] = {
>> @@ -378,40 +440,42 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>  		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>> -		vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
>> +		vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
>> -		vgic_mmio_read_enable, vgic_mmio_write_senable, 1,
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, NULL, NULL, 1,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
>> -		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, NULL, NULL, 1,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
>> -		vgic_mmio_read_pending, vgic_mmio_write_spending, 1,
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending,
>> +		vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 1,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
>> -		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1,
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
>> -		vgic_mmio_read_active, vgic_mmio_write_sactive, 1,
>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, NULL, NULL, 1,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
>> -		vgic_mmio_read_active, vgic_mmio_write_cactive, 1,
>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, NULL, NULL, 1,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
>> -		vgic_mmio_read_priority, vgic_mmio_write_priority, 8,
>> -		VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, NULL, NULL,
>> +		8, VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 8,
>>  		VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
>> -		vgic_mmio_read_config, vgic_mmio_write_config, 2,
>> +		vgic_mmio_read_config, vgic_mmio_write_config, NULL, NULL, 2,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
>> -		vgic_mmio_read_irouter, vgic_mmio_write_irouter, 64,
>> +		vgic_mmio_read_irouter, vgic_mmio_write_irouter, NULL, NULL, 64,
>>  		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>>  		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48,
>> @@ -449,11 +513,13 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>  	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
>>  		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4,
>>  		VGIC_ACCESS_32bit),
>> -	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
>> -		vgic_mmio_read_pending, vgic_mmio_write_spending, 4,
>> +	REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ISPENDR0,
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending,
>> +		vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 4,
>>  		VGIC_ACCESS_32bit),
>> -	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
>> -		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4,
>> +	REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ICPENDR0,
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
>>  		vgic_mmio_read_active, vgic_mmio_write_sactive, 4,
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>> index ebe1b9f..d5f3ee2 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>> @@ -484,6 +484,74 @@ static bool check_region(const struct kvm *kvm,
>>  	return false;
>>  }
>>  
>> +static const struct vgic_register_region *
>> +vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev,
>> +		     gpa_t addr, int len)
>> +{
>> +	const struct vgic_register_region *region;
>> +
>> +	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
>> +				       addr - iodev->base_addr);
>> +	if (!region || !check_region(vcpu->kvm, region, addr, len))
>> +		return NULL;
>> +
>> +	return region;
>> +}
>> +
>> +static int vgic_uaccess_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>> +			     gpa_t addr, u32 *val)
>> +{
>> +	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
>> +	const struct vgic_register_region *region;
>> +	struct kvm_vcpu *r_vcpu;
>> +
>> +	region = vgic_get_mmio_region(vcpu, iodev, addr, sizeof(u32));
>> +	if (!region) {
>> +		*val = 0;
>> +		return 0;
do we really want to return 0 here? -ENXIO?
I see that dispatch_mmio_read/write return 0 in that case but I don't
see any reason either? Other kvm_io_device_ops seem to return
-EOPNOTSUPP in such a case.

Thanks

Eric
>> +	}
>> +
>> +	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
>> +	if (region->uaccess_read)
>> +		*val = region->uaccess_read(r_vcpu, addr, sizeof(u32));
>> +	else
>> +		*val = region->read(r_vcpu, addr, sizeof(u32));
>> +
>> +	return 0;
>> +}
>> +
>> +static int vgic_uaccess_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>> +			      gpa_t addr, const u32 *val)
>> +{
>> +	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
>> +	const struct vgic_register_region *region;
>> +	struct kvm_vcpu *r_vcpu;
>> +
>> +	region = vgic_get_mmio_region(vcpu, iodev, addr, sizeof(u32));
>> +	if (!region)
>> +		return 0;
same?
>> +
>> +	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
>> +	if (region->uaccess_write)
>> +		region->uaccess_write(r_vcpu, addr, sizeof(u32), *val);
>> +	else
>> +		region->write(r_vcpu, addr, sizeof(u32), *val);
>> +
>> +	return 0;
>> +}
>> +
>> +/*
>> + * Userland access to VGIC registers.
>> + */
>> +int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>> +		 bool is_write, int offset, u32 *val)
>> +{
>> +	if (is_write)
>> +		return vgic_uaccess_write(vcpu, &dev->dev, offset, val);
>> +	else
>> +		return vgic_uaccess_read(vcpu, &dev->dev, offset, val);
>> +}
>> +
>>  static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>>  			      gpa_t addr, int len, void *val)
>>  {
>> @@ -491,9 +559,8 @@ static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>>  	const struct vgic_register_region *region;
>>  	unsigned long data = 0;
>>  
>> -	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
>> -				       addr - iodev->base_addr);
>> -	if (!region || !check_region(vcpu->kvm, region, addr, len)) {
>> +	region = vgic_get_mmio_region(vcpu, iodev, addr, len);
>> +	if (!region) {
>>  		memset(val, 0, len);
>>  		return 0;
>>  	}
>> @@ -524,9 +591,8 @@ static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>>  	const struct vgic_register_region *region;
>>  	unsigned long data = vgic_data_mmio_bus_to_host(val, len);
>>  
>> -	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
>> -				       addr - iodev->base_addr);
>> -	if (!region || !check_region(vcpu->kvm, region, addr, len))
>> +	region = vgic_get_mmio_region(vcpu, iodev, addr, len);
>> +	if (!region)
>>  		return 0;
>>  
>>  	switch (iodev->iodev_type) {
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
>> index 84961b4..7b30296 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.h
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
>> @@ -34,6 +34,10 @@ struct vgic_register_region {
>>  				  gpa_t addr, unsigned int len,
>>  				  unsigned long val);
>>  	};
>> +	unsigned long (*uaccess_read)(struct kvm_vcpu *vcpu, gpa_t addr,
>> +				      unsigned int len);
>> +	void (*uaccess_write)(struct kvm_vcpu *vcpu, gpa_t addr,
>> +			      unsigned int len, unsigned long val);
>>  };
>>  
>>  extern struct kvm_io_device_ops kvm_io_gic_ops;
>> @@ -86,6 +90,18 @@ struct vgic_register_region {
>>  		.write = wr,						\
>>  	}
>>  
>> +#define REGISTER_DESC_WITH_LENGTH_UACCESS(off, rd, wr, urd, uwr, length, acc) \
>> +	{								\
>> +		.reg_offset = off,					\
>> +		.bits_per_irq = 0,					\
>> +		.len = length,						\
>> +		.access_flags = acc,					\
>> +		.read = rd,						\
>> +		.write = wr,						\
>> +		.uaccess_read = urd,					\
>> +		.uaccess_write = uwr,					\
>> +	}
>> +
>>  int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  				  struct vgic_register_region *reg_desc,
>>  				  struct vgic_io_device *region,
>> @@ -158,6 +174,9 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>>  			    gpa_t addr, unsigned int len,
>>  			    unsigned long val);
>>  
>> +int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>> +		 bool is_write, int offset, u32 *val);
>> +
>>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>>  
>>  unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
>> -- 
>> 1.9.1
>>
> 
> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 02/11] arm/arm64: vgic: Add distributor and redistributor access
  2016-11-28 13:08     ` Christoffer Dall
@ 2016-12-06 13:18       ` Auger Eric
  -1 siblings, 0 replies; 78+ messages in thread
From: Auger Eric @ 2016-12-06 13:18 UTC (permalink / raw)
  To: Christoffer Dall, vijay.kilari
  Cc: marc.zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

Hi,

On 28/11/2016 14:08, Christoffer Dall wrote:
> On Wed, Nov 23, 2016 at 06:31:49PM +0530, vijay.kilari@gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>
>> VGICv3 Distributor and Redistributor registers are accessed using
>> KVM_DEV_ARM_VGIC_GRP_DIST_REGS and KVM_DEV_ARM_VGIC_GRP_REDIST_REGS
>> with KVM_SET_DEVICE_ATTR and KVM_GET_DEVICE_ATTR ioctls.
>> These registers are accessed as 32-bit and cpu mpidr
>> value passed along with register offset is used to identify the
>> cpu for redistributor registers access.
>>
>> The version of VGIC v3 specification is define here
s/define/defined
>> Documentation/virtual/kvm/devices/arm-vgic-v3.txt
>>
>> Also update arch/arm/include/uapi/asm/kvm.h to compile for
>> AArch32 mode.
>>
>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>> ---
>>  arch/arm/include/uapi/asm/kvm.h     |   4 +
>>  arch/arm64/include/uapi/asm/kvm.h   |   4 +
>>  virt/kvm/arm/vgic/vgic-kvm-device.c | 144 ++++++++++++++++++++++++++++++++++--
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c    |  16 +---
>>  virt/kvm/arm/vgic/vgic-mmio-v3.c    |  72 ++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-mmio.c       |  22 ++++++
>>  virt/kvm/arm/vgic/vgic-mmio.h       |   4 +
>>  virt/kvm/arm/vgic/vgic.h            |  49 +++++++++++-
>>  8 files changed, 292 insertions(+), 23 deletions(-)
>>
>> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
>> index af05f8e..0ae6035 100644
>> --- a/arch/arm/include/uapi/asm/kvm.h
>> +++ b/arch/arm/include/uapi/asm/kvm.h
>> @@ -181,10 +181,14 @@ struct kvm_arch_memory_slot {
>>  #define KVM_DEV_ARM_VGIC_GRP_CPU_REGS	2
>>  #define   KVM_DEV_ARM_VGIC_CPUID_SHIFT	32
>>  #define   KVM_DEV_ARM_VGIC_CPUID_MASK	(0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
>> +#define   KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32
>> +#define   KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \
>> +			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
>>  #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
>>  #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
>>  #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL       4
>> +#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
>>  
>>  /* KVM_IRQ_LINE irq field index values */
>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>> index 3051f86..56dc08d 100644
>> --- a/arch/arm64/include/uapi/asm/kvm.h
>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>> @@ -201,10 +201,14 @@ struct kvm_arch_memory_slot {
>>  #define KVM_DEV_ARM_VGIC_GRP_CPU_REGS	2
>>  #define   KVM_DEV_ARM_VGIC_CPUID_SHIFT	32
>>  #define   KVM_DEV_ARM_VGIC_CPUID_MASK	(0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
>> +#define   KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32
>> +#define   KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \
>> +			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
>>  #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
>>  #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
>>  #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
>> +#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
>>  
>>  /* Device Control API on vcpu fd */
>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> index fbe87a6..bc7de95 100644
>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> @@ -235,7 +235,7 @@ struct vgic_reg_attr {
>>  	gpa_t addr;
>>  };
>>  
>> -static int parse_vgic_v2_attr(struct kvm_device *dev,
>> +static int vgic_v2_parse_attr(struct kvm_device *dev,
>>  			      struct kvm_device_attr *attr,
>>  			      struct vgic_reg_attr *reg_attr)
>>  {
>> @@ -292,14 +292,14 @@ static bool lock_all_vcpus(struct kvm *kvm)
>>  }
>>  
>>  /**
>> - * vgic_attr_regs_access_v2 - allows user space to access VGIC v2 state
>> + * vgic_v2_attr_regs_access - allows user space to access VGIC v2 state
>>   *
>>   * @dev:      kvm device handle
>>   * @attr:     kvm device attribute
>>   * @reg:      address the value is read or written
>>   * @is_write: true if userspace is writing a register
>>   */
>> -static int vgic_attr_regs_access_v2(struct kvm_device *dev,
>> +static int vgic_v2_attr_regs_access(struct kvm_device *dev,
>>  				    struct kvm_device_attr *attr,
>>  				    u32 *reg, bool is_write)
>>  {
>> @@ -308,7 +308,7 @@ static int vgic_attr_regs_access_v2(struct kvm_device *dev,
>>  	struct kvm_vcpu *vcpu;
>>  	int ret;
>>  
>> -	ret = parse_vgic_v2_attr(dev, attr, &reg_attr);
>> +	ret = vgic_v2_parse_attr(dev, attr, &reg_attr);
>>  	if (ret)
>>  		return ret;
>>  
>> @@ -362,7 +362,7 @@ static int vgic_v2_set_attr(struct kvm_device *dev,
>>  		if (get_user(reg, uaddr))
>>  			return -EFAULT;
>>  
>> -		return vgic_attr_regs_access_v2(dev, attr, &reg, true);
>> +		return vgic_v2_attr_regs_access(dev, attr, &reg, true);
>>  	}
>>  	}
>>  
>> @@ -384,7 +384,7 @@ static int vgic_v2_get_attr(struct kvm_device *dev,
>>  		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
>>  		u32 reg = 0;
>>  
>> -		ret = vgic_attr_regs_access_v2(dev, attr, &reg, false);
>> +		ret = vgic_v2_attr_regs_access(dev, attr, &reg, false);
>>  		if (ret)
>>  			return ret;
>>  		return put_user(reg, uaddr);
>> @@ -428,16 +428,141 @@ struct kvm_device_ops kvm_arm_vgic_v2_ops = {
>>  	.has_attr = vgic_v2_has_attr,
>>  };
>>  
>> +static int vgic_v3_parse_attr(struct kvm_device *dev,
>> +			      struct kvm_device_attr *attr,
>> +			      struct vgic_reg_attr *reg_attr)
>> +{
>> +	unsigned long vgic_mpidr, mpidr_reg;
>> +
>> +	vgic_mpidr = (attr->attr & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) >>
>> +		      KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT;
>> +
>> +	mpidr_reg = VGIC_TO_MPIDR(vgic_mpidr);
>> +	reg_attr->vcpu = kvm_mpidr_to_vcpu(dev->kvm, mpidr_reg);
>> +	if (!reg_attr->vcpu)
>> +		return -EINVAL;
>> +
>> +	reg_attr->addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
>> +
>> +	return 0;
>> +}
>> +
>> +/*
>> + * vgic_v3_attr_regs_access - allows user space to access VGIC v3 state
>> + *
>> + * @dev:      kvm device handle
>> + * @attr:     kvm device attribute
>> + * @reg:      address the value is read or written
>> + * @is_write: true if userspace is writing a register
>> + */
>> +static int vgic_v3_attr_regs_access(struct kvm_device *dev,
>> +				    struct kvm_device_attr *attr,
>> +				    u64 *reg, bool is_write)
>> +{
>> +	struct vgic_reg_attr reg_attr;
>> +	gpa_t addr;
>> +	struct kvm_vcpu *vcpu;
>> +	int ret;
>> +	u32 tmp32;
>> +
>> +	ret = vgic_v3_parse_attr(dev, attr, &reg_attr);
>> +	if (ret)
>> +		return ret;
>> +
>> +	vcpu = reg_attr.vcpu;
>> +	addr = reg_attr.addr;
>> +
>> +	mutex_lock(&dev->kvm->lock);
>> +
>> +	if (unlikely(!vgic_initialized(dev->kvm))) {
>> +		ret = -EBUSY;
>> +		goto out;
>> +	}
>> +
>> +	if (!lock_all_vcpus(dev->kvm)) {
>> +		ret = -EBUSY;
>> +		goto out;
>> +	}
>> +
>> +	switch (attr->group) {
>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>> +		if (is_write)
>> +			tmp32 = *reg;
>> +
>> +		ret = vgic_v3_dist_uaccess(vcpu, is_write, addr, &tmp32);
>> +		if (!is_write)
>> +			*reg = tmp32;
>> +		break;
>> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
>> +		if (is_write)
>> +			tmp32 = *reg;
>> +
>> +		ret = vgic_v3_redist_uaccess(vcpu, is_write, addr, &tmp32);
>> +		if (!is_write)
>> +			*reg = tmp32;
>> +		break;
>> +	default:
>> +		ret = -EINVAL;
>> +		break;
>> +	}
>> +
>> +	unlock_all_vcpus(dev->kvm);
>> +out:
>> +	mutex_unlock(&dev->kvm->lock);
>> +	return ret;
>> +}
>> +
>>  static int vgic_v3_set_attr(struct kvm_device *dev,
>>  			    struct kvm_device_attr *attr)
>>  {
>> -	return vgic_set_common_attr(dev, attr);
>> +	int ret;
>> +
>> +	ret = vgic_set_common_attr(dev, attr);
>> +	if (ret != -ENXIO)
>> +		return ret;
>> +
>> +	switch (attr->group) {
>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: {
>> +		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
>> +		u32 tmp32;
>> +		u64 reg;
>> +
>> +		if (get_user(tmp32, uaddr))
>> +			return -EFAULT;
>> +
>> +		reg = tmp32;
>> +		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
>> +	}
>> +	}
>> +	return -ENXIO;
>>  }
>>  
>>  static int vgic_v3_get_attr(struct kvm_device *dev,
>>  			    struct kvm_device_attr *attr)
>>  {
>> -	return vgic_get_common_attr(dev, attr);
>> +	int ret;
>> +
>> +	ret = vgic_get_common_attr(dev, attr);
>> +	if (ret != -ENXIO)
>> +		return ret;
>> +
>> +	switch (attr->group) {
>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: {
>> +		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
>> +		u64 reg;
>> +		u32 tmp32;
>> +
>> +		ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
>> +		if (ret)
>> +			return ret;
>> +		tmp32 = reg;
>> +		return put_user(tmp32, uaddr);
>> +	}
>> +	}
>> +
>> +	return -ENXIO;
>>  }
>>  
>>  static int vgic_v3_has_attr(struct kvm_device *dev,
>> @@ -451,6 +576,9 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
>>  			return 0;
>>  		}
>>  		break;
>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
>> +		return vgic_v3_has_attr_regs(dev, attr);
>>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>>  		return 0;
>>  	case KVM_DEV_ARM_VGIC_GRP_CTRL:
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index 0b32f40..2cb04b7 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -368,10 +368,9 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
>>  
>>  int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>>  {
>> -	int nr_irqs = dev->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>>  	const struct vgic_register_region *regions;
>>  	gpa_t addr;
>> -	int nr_regions, i, len;
>> +	int nr_regions;
>>  
>>  	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
>>  
>> @@ -392,18 +391,7 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>>  	if (addr & 3)
>>  		return -ENXIO;
>>  
>> -	for (i = 0; i < nr_regions; i++) {
>> -		if (regions[i].bits_per_irq)
>> -			len = (regions[i].bits_per_irq * nr_irqs) / 8;
>> -		else
>> -			len = regions[i].len;
>> -
>> -		if (regions[i].reg_offset <= addr &&
>> -		    regions[i].reg_offset + len > addr)
>> -			return 0;
>> -	}
>> -
>> -	return -ENXIO;
>> +	return vgic_validate_mmio_region_addr(dev, regions, nr_regions, addr);
>>  }
>>  
>>  int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> index 8e76d04..2a7cd62 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> @@ -18,6 +18,8 @@
>>  #include <kvm/arm_vgic.h>
>>  
>>  #include <asm/kvm_emulate.h>
>> +#include <asm/kvm_arm.h>
>> +#include <asm/kvm_mmu.h>
>>  
>>  #include "vgic.h"
>>  #include "vgic-mmio.h"
>> @@ -439,6 +441,9 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>  	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>>  		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16,
>>  		VGIC_ACCESS_32bit),
>> +	REGISTER_DESC_WITH_LENGTH(GICD_STATUSR,
>> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 4,
>> +		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
>>  		VGIC_ACCESS_32bit),
>> @@ -486,12 +491,18 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>  	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
>>  		vgic_mmio_read_v3r_ctlr, vgic_mmio_write_v3r_ctlr, 4,
>>  		VGIC_ACCESS_32bit),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_STATUSR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
>> +		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
>>  		vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
>>  		vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8,
>>  		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_WAKER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
4 ? WAKER is a 32b reg
>> +		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
>>  		vgic_mmio_read_propbase, vgic_mmio_write_propbase, 8,
>>  		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
>> @@ -612,6 +623,34 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
>>  	return ret;
>>  }
>>  
>> +int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>> +{
>> +	const struct vgic_register_region *regions;
>> +	gpa_t addr;
>> +	int nr_regions;
>> +
>> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
>> +
>> +	switch (attr->group) {
>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>> +		regions = vgic_v3_dist_registers;
>> +		nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
Couldn't you set
	struct vgic_io_device dev = {
		.regions = vgic_v3_dist_registers,
		.nr_regions = ARRAY_SIZE(vgic_v3_dist_registers),
	};

and reuse:
vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device
*iodev, gpa_t addr, int len)?

In such a case is vgic_validate_mmio_region_addr() still mandated?
>> +		break;
>> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:{
>> +		regions = vgic_v3_rdbase_registers;
>> +		nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
>> +		break;
>> +	}
>> +	default:
>> +		return -ENXIO;
>> +	}
>> +
>> +	/* We only support aligned 32-bit accesses. */
>> +	if (addr & 3)
>> +		return -ENXIO;
>> +
>> +	return vgic_validate_mmio_region_addr(dev, regions, nr_regions, addr);
>> +}
>>  /*
>>   * Compare a given affinity (level 1-3 and a level 0 mask, from the SGI
>>   * generation register ICC_SGI1R_EL1) with a given VCPU.
>> @@ -718,3 +757,36 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
>>  		vgic_put_irq(vcpu->kvm, irq);
>>  	}
>>  }
>> +
>> +int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>> +			 int offset, u32 *val)
>> +{
>> +	struct vgic_io_device dev = {
>> +		.regions = vgic_v3_dist_registers,
>> +		.nr_regions = ARRAY_SIZE(vgic_v3_dist_registers),
>> +	};
>> +
>> +	return vgic_uaccess(vcpu, &dev, is_write, offset, val);
>> +}
>> +
>> +int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>> +			   int offset, u32 *val)
>> +{
>> +	struct vgic_io_device rd_dev = {
>> +		.regions = vgic_v3_rdbase_registers,
>> +		.nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers),
>> +	};
>> +
>> +	struct vgic_io_device sgi_dev = {
>> +		.regions = vgic_v3_sgibase_registers,
>> +		.nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers),
>> +	};
>> +
>> +	/* SGI_base is the next 64K frame after RD_base */
>> +	if (offset >= SZ_64K)
>> +		return vgic_uaccess(vcpu, &sgi_dev, is_write,
>> +				    offset - SZ_64K, val);
>> +	else
>> +		return vgic_uaccess(vcpu, &rd_dev, is_write,
>> +				    offset, val);
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>> index d5f3ee2..0d1bc98 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>> @@ -394,6 +394,28 @@ static int match_region(const void *key, const void *elt)
>>  		       sizeof(region[0]), match_region);
>>  }
>>  
>> +/* Check if address falls within the region */
>> +int vgic_validate_mmio_region_addr(struct kvm_device *dev,
>> +				   const struct vgic_register_region *regions,
>> +				   int nr_regions, gpa_t addr)
>> +{
>> +	int i, len;
>> +	int nr_irqs = dev->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +
>> +	for (i = 0; i < nr_regions; i++) {
>> +		if (regions[i].bits_per_irq)
>> +			len = (regions[i].bits_per_irq * nr_irqs) / 8;
>> +		else
>> +			len = regions[i].len;
>> +
>> +		if (regions[i].reg_offset <= addr &&
>> +		    regions[i].reg_offset + len > addr)
>> +			return 0;
>> +	}
>> +
>> +	return -ENXIO;
>> +}
>> +
>>  /*
>>   * kvm_mmio_read_buf() returns a value in a format where it can be converted
>>   * to a byte array and be directly observed as the guest wanted it to appear
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
>> index 7b30296..1cc7faf 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.h
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
>> @@ -177,6 +177,10 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>>  int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>>  		 bool is_write, int offset, u32 *val);
>>  
>> +int vgic_validate_mmio_region_addr(struct kvm_device *dev,
>> +				   const struct vgic_register_region *regions,
>> +				   int nr_regions, gpa_t addr);
>> +
>>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>>  
>>  unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 859f65c..91f58b2 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -30,6 +30,49 @@
>>  
>>  #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
>>  
>> +#define VGIC_AFFINITY_0_SHIFT 0
>> +#define VGIC_AFFINITY_0_MASK (0xffUL << VGIC_AFFINITY_0_SHIFT)
>> +#define VGIC_AFFINITY_1_SHIFT 8
>> +#define VGIC_AFFINITY_1_MASK (0xffUL << VGIC_AFFINITY_1_SHIFT)
>> +#define VGIC_AFFINITY_2_SHIFT 16
>> +#define VGIC_AFFINITY_2_MASK (0xffUL << VGIC_AFFINITY_2_SHIFT)
>> +#define VGIC_AFFINITY_3_SHIFT 24
>> +#define VGIC_AFFINITY_3_MASK (0xffUL << VGIC_AFFINITY_3_SHIFT)
>> +
>> +#define VGIC_AFFINITY_LEVEL(reg, level) \
>> +	((((reg) & VGIC_AFFINITY_## level ##_MASK) \
>> +	>> VGIC_AFFINITY_## level ##_SHIFT) << MPIDR_LEVEL_SHIFT(level))
>> +
>> +/*
>> + * The Userspace encodes the affinity differently from the MPIDR,
>> + * Below macro converts vgic userspace format to MPIDR reg format.
>> + */
>> +#define VGIC_TO_MPIDR(val) (VGIC_AFFINITY_LEVEL(val, 0) | \
>> +			    VGIC_AFFINITY_LEVEL(val, 1) | \
>> +			    VGIC_AFFINITY_LEVEL(val, 2) | \
>> +			    VGIC_AFFINITY_LEVEL(val, 3))
>> +
>> +/*
>> + * As per Documentation/virtual/kvm/devices/arm-vgic-v3.txt,
>> + * below macros are defined for CPUREG encoding.
>> + */
>> +#define KVM_REG_ARM_VGIC_SYSREG_OP0_MASK   0x000000000000c000
>> +#define KVM_REG_ARM_VGIC_SYSREG_OP0_SHIFT  14
>> +#define KVM_REG_ARM_VGIC_SYSREG_OP1_MASK   0x0000000000003800
>> +#define KVM_REG_ARM_VGIC_SYSREG_OP1_SHIFT  11
>> +#define KVM_REG_ARM_VGIC_SYSREG_CRN_MASK   0x0000000000000780
>> +#define KVM_REG_ARM_VGIC_SYSREG_CRN_SHIFT  7
>> +#define KVM_REG_ARM_VGIC_SYSREG_CRM_MASK   0x0000000000000078
>> +#define KVM_REG_ARM_VGIC_SYSREG_CRM_SHIFT  3
>> +#define KVM_REG_ARM_VGIC_SYSREG_OP2_MASK   0x0000000000000007
>> +#define KVM_REG_ARM_VGIC_SYSREG_OP2_SHIFT  0
>> +
>> +#define KVM_DEV_ARM_VGIC_SYSREG_MASK (KVM_REG_ARM_VGIC_SYSREG_OP0_MASK | \
>> +				      KVM_REG_ARM_VGIC_SYSREG_OP1_MASK | \
>> +				      KVM_REG_ARM_VGIC_SYSREG_CRN_MASK | \
>> +				      KVM_REG_ARM_VGIC_SYSREG_CRM_MASK | \
>> +				      KVM_REG_ARM_VGIC_SYSREG_OP2_MASK)
nit: do those SYSREG defines relate to this patch?

Thanks

Eric
>> +
>>  struct vgic_vmcr {
>>  	u32	ctlr;
>>  	u32	abpr;
>> @@ -89,7 +132,11 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq)
>>  int kvm_vgic_register_its_device(void);
>>  void vgic_enable_lpis(struct kvm_vcpu *vcpu);
>>  int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi);
>> -
>> +int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
>> +int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>> +			 int offset, u32 *val);
>> +int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>> +			 int offset, u32 *val);
>>  int kvm_register_vgic_device(unsigned long type);
>>  int vgic_lazy_init(struct kvm *kvm);
>>  int vgic_init(struct kvm *kvm);
>> -- 
>> 1.9.1
>>
> 
> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 02/11] arm/arm64: vgic: Add distributor and redistributor access
@ 2016-12-06 13:18       ` Auger Eric
  0 siblings, 0 replies; 78+ messages in thread
From: Auger Eric @ 2016-12-06 13:18 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 28/11/2016 14:08, Christoffer Dall wrote:
> On Wed, Nov 23, 2016 at 06:31:49PM +0530, vijay.kilari at gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>
>> VGICv3 Distributor and Redistributor registers are accessed using
>> KVM_DEV_ARM_VGIC_GRP_DIST_REGS and KVM_DEV_ARM_VGIC_GRP_REDIST_REGS
>> with KVM_SET_DEVICE_ATTR and KVM_GET_DEVICE_ATTR ioctls.
>> These registers are accessed as 32-bit and cpu mpidr
>> value passed along with register offset is used to identify the
>> cpu for redistributor registers access.
>>
>> The version of VGIC v3 specification is define here
s/define/defined
>> Documentation/virtual/kvm/devices/arm-vgic-v3.txt
>>
>> Also update arch/arm/include/uapi/asm/kvm.h to compile for
>> AArch32 mode.
>>
>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>> ---
>>  arch/arm/include/uapi/asm/kvm.h     |   4 +
>>  arch/arm64/include/uapi/asm/kvm.h   |   4 +
>>  virt/kvm/arm/vgic/vgic-kvm-device.c | 144 ++++++++++++++++++++++++++++++++++--
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c    |  16 +---
>>  virt/kvm/arm/vgic/vgic-mmio-v3.c    |  72 ++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-mmio.c       |  22 ++++++
>>  virt/kvm/arm/vgic/vgic-mmio.h       |   4 +
>>  virt/kvm/arm/vgic/vgic.h            |  49 +++++++++++-
>>  8 files changed, 292 insertions(+), 23 deletions(-)
>>
>> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
>> index af05f8e..0ae6035 100644
>> --- a/arch/arm/include/uapi/asm/kvm.h
>> +++ b/arch/arm/include/uapi/asm/kvm.h
>> @@ -181,10 +181,14 @@ struct kvm_arch_memory_slot {
>>  #define KVM_DEV_ARM_VGIC_GRP_CPU_REGS	2
>>  #define   KVM_DEV_ARM_VGIC_CPUID_SHIFT	32
>>  #define   KVM_DEV_ARM_VGIC_CPUID_MASK	(0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
>> +#define   KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32
>> +#define   KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \
>> +			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
>>  #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
>>  #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
>>  #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL       4
>> +#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
>>  
>>  /* KVM_IRQ_LINE irq field index values */
>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>> index 3051f86..56dc08d 100644
>> --- a/arch/arm64/include/uapi/asm/kvm.h
>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>> @@ -201,10 +201,14 @@ struct kvm_arch_memory_slot {
>>  #define KVM_DEV_ARM_VGIC_GRP_CPU_REGS	2
>>  #define   KVM_DEV_ARM_VGIC_CPUID_SHIFT	32
>>  #define   KVM_DEV_ARM_VGIC_CPUID_MASK	(0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
>> +#define   KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32
>> +#define   KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \
>> +			(0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
>>  #define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT	0
>>  #define   KVM_DEV_ARM_VGIC_OFFSET_MASK	(0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
>>  #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
>> +#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
>>  
>>  /* Device Control API on vcpu fd */
>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> index fbe87a6..bc7de95 100644
>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> @@ -235,7 +235,7 @@ struct vgic_reg_attr {
>>  	gpa_t addr;
>>  };
>>  
>> -static int parse_vgic_v2_attr(struct kvm_device *dev,
>> +static int vgic_v2_parse_attr(struct kvm_device *dev,
>>  			      struct kvm_device_attr *attr,
>>  			      struct vgic_reg_attr *reg_attr)
>>  {
>> @@ -292,14 +292,14 @@ static bool lock_all_vcpus(struct kvm *kvm)
>>  }
>>  
>>  /**
>> - * vgic_attr_regs_access_v2 - allows user space to access VGIC v2 state
>> + * vgic_v2_attr_regs_access - allows user space to access VGIC v2 state
>>   *
>>   * @dev:      kvm device handle
>>   * @attr:     kvm device attribute
>>   * @reg:      address the value is read or written
>>   * @is_write: true if userspace is writing a register
>>   */
>> -static int vgic_attr_regs_access_v2(struct kvm_device *dev,
>> +static int vgic_v2_attr_regs_access(struct kvm_device *dev,
>>  				    struct kvm_device_attr *attr,
>>  				    u32 *reg, bool is_write)
>>  {
>> @@ -308,7 +308,7 @@ static int vgic_attr_regs_access_v2(struct kvm_device *dev,
>>  	struct kvm_vcpu *vcpu;
>>  	int ret;
>>  
>> -	ret = parse_vgic_v2_attr(dev, attr, &reg_attr);
>> +	ret = vgic_v2_parse_attr(dev, attr, &reg_attr);
>>  	if (ret)
>>  		return ret;
>>  
>> @@ -362,7 +362,7 @@ static int vgic_v2_set_attr(struct kvm_device *dev,
>>  		if (get_user(reg, uaddr))
>>  			return -EFAULT;
>>  
>> -		return vgic_attr_regs_access_v2(dev, attr, &reg, true);
>> +		return vgic_v2_attr_regs_access(dev, attr, &reg, true);
>>  	}
>>  	}
>>  
>> @@ -384,7 +384,7 @@ static int vgic_v2_get_attr(struct kvm_device *dev,
>>  		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
>>  		u32 reg = 0;
>>  
>> -		ret = vgic_attr_regs_access_v2(dev, attr, &reg, false);
>> +		ret = vgic_v2_attr_regs_access(dev, attr, &reg, false);
>>  		if (ret)
>>  			return ret;
>>  		return put_user(reg, uaddr);
>> @@ -428,16 +428,141 @@ struct kvm_device_ops kvm_arm_vgic_v2_ops = {
>>  	.has_attr = vgic_v2_has_attr,
>>  };
>>  
>> +static int vgic_v3_parse_attr(struct kvm_device *dev,
>> +			      struct kvm_device_attr *attr,
>> +			      struct vgic_reg_attr *reg_attr)
>> +{
>> +	unsigned long vgic_mpidr, mpidr_reg;
>> +
>> +	vgic_mpidr = (attr->attr & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) >>
>> +		      KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT;
>> +
>> +	mpidr_reg = VGIC_TO_MPIDR(vgic_mpidr);
>> +	reg_attr->vcpu = kvm_mpidr_to_vcpu(dev->kvm, mpidr_reg);
>> +	if (!reg_attr->vcpu)
>> +		return -EINVAL;
>> +
>> +	reg_attr->addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
>> +
>> +	return 0;
>> +}
>> +
>> +/*
>> + * vgic_v3_attr_regs_access - allows user space to access VGIC v3 state
>> + *
>> + * @dev:      kvm device handle
>> + * @attr:     kvm device attribute
>> + * @reg:      address the value is read or written
>> + * @is_write: true if userspace is writing a register
>> + */
>> +static int vgic_v3_attr_regs_access(struct kvm_device *dev,
>> +				    struct kvm_device_attr *attr,
>> +				    u64 *reg, bool is_write)
>> +{
>> +	struct vgic_reg_attr reg_attr;
>> +	gpa_t addr;
>> +	struct kvm_vcpu *vcpu;
>> +	int ret;
>> +	u32 tmp32;
>> +
>> +	ret = vgic_v3_parse_attr(dev, attr, &reg_attr);
>> +	if (ret)
>> +		return ret;
>> +
>> +	vcpu = reg_attr.vcpu;
>> +	addr = reg_attr.addr;
>> +
>> +	mutex_lock(&dev->kvm->lock);
>> +
>> +	if (unlikely(!vgic_initialized(dev->kvm))) {
>> +		ret = -EBUSY;
>> +		goto out;
>> +	}
>> +
>> +	if (!lock_all_vcpus(dev->kvm)) {
>> +		ret = -EBUSY;
>> +		goto out;
>> +	}
>> +
>> +	switch (attr->group) {
>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>> +		if (is_write)
>> +			tmp32 = *reg;
>> +
>> +		ret = vgic_v3_dist_uaccess(vcpu, is_write, addr, &tmp32);
>> +		if (!is_write)
>> +			*reg = tmp32;
>> +		break;
>> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
>> +		if (is_write)
>> +			tmp32 = *reg;
>> +
>> +		ret = vgic_v3_redist_uaccess(vcpu, is_write, addr, &tmp32);
>> +		if (!is_write)
>> +			*reg = tmp32;
>> +		break;
>> +	default:
>> +		ret = -EINVAL;
>> +		break;
>> +	}
>> +
>> +	unlock_all_vcpus(dev->kvm);
>> +out:
>> +	mutex_unlock(&dev->kvm->lock);
>> +	return ret;
>> +}
>> +
>>  static int vgic_v3_set_attr(struct kvm_device *dev,
>>  			    struct kvm_device_attr *attr)
>>  {
>> -	return vgic_set_common_attr(dev, attr);
>> +	int ret;
>> +
>> +	ret = vgic_set_common_attr(dev, attr);
>> +	if (ret != -ENXIO)
>> +		return ret;
>> +
>> +	switch (attr->group) {
>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: {
>> +		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
>> +		u32 tmp32;
>> +		u64 reg;
>> +
>> +		if (get_user(tmp32, uaddr))
>> +			return -EFAULT;
>> +
>> +		reg = tmp32;
>> +		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
>> +	}
>> +	}
>> +	return -ENXIO;
>>  }
>>  
>>  static int vgic_v3_get_attr(struct kvm_device *dev,
>>  			    struct kvm_device_attr *attr)
>>  {
>> -	return vgic_get_common_attr(dev, attr);
>> +	int ret;
>> +
>> +	ret = vgic_get_common_attr(dev, attr);
>> +	if (ret != -ENXIO)
>> +		return ret;
>> +
>> +	switch (attr->group) {
>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: {
>> +		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
>> +		u64 reg;
>> +		u32 tmp32;
>> +
>> +		ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
>> +		if (ret)
>> +			return ret;
>> +		tmp32 = reg;
>> +		return put_user(tmp32, uaddr);
>> +	}
>> +	}
>> +
>> +	return -ENXIO;
>>  }
>>  
>>  static int vgic_v3_has_attr(struct kvm_device *dev,
>> @@ -451,6 +576,9 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
>>  			return 0;
>>  		}
>>  		break;
>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
>> +		return vgic_v3_has_attr_regs(dev, attr);
>>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>>  		return 0;
>>  	case KVM_DEV_ARM_VGIC_GRP_CTRL:
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index 0b32f40..2cb04b7 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -368,10 +368,9 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
>>  
>>  int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>>  {
>> -	int nr_irqs = dev->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>>  	const struct vgic_register_region *regions;
>>  	gpa_t addr;
>> -	int nr_regions, i, len;
>> +	int nr_regions;
>>  
>>  	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
>>  
>> @@ -392,18 +391,7 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>>  	if (addr & 3)
>>  		return -ENXIO;
>>  
>> -	for (i = 0; i < nr_regions; i++) {
>> -		if (regions[i].bits_per_irq)
>> -			len = (regions[i].bits_per_irq * nr_irqs) / 8;
>> -		else
>> -			len = regions[i].len;
>> -
>> -		if (regions[i].reg_offset <= addr &&
>> -		    regions[i].reg_offset + len > addr)
>> -			return 0;
>> -	}
>> -
>> -	return -ENXIO;
>> +	return vgic_validate_mmio_region_addr(dev, regions, nr_regions, addr);
>>  }
>>  
>>  int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> index 8e76d04..2a7cd62 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> @@ -18,6 +18,8 @@
>>  #include <kvm/arm_vgic.h>
>>  
>>  #include <asm/kvm_emulate.h>
>> +#include <asm/kvm_arm.h>
>> +#include <asm/kvm_mmu.h>
>>  
>>  #include "vgic.h"
>>  #include "vgic-mmio.h"
>> @@ -439,6 +441,9 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>  	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>>  		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16,
>>  		VGIC_ACCESS_32bit),
>> +	REGISTER_DESC_WITH_LENGTH(GICD_STATUSR,
>> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 4,
>> +		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
>>  		VGIC_ACCESS_32bit),
>> @@ -486,12 +491,18 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>  	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
>>  		vgic_mmio_read_v3r_ctlr, vgic_mmio_write_v3r_ctlr, 4,
>>  		VGIC_ACCESS_32bit),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_STATUSR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
>> +		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
>>  		vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4,
>>  		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
>>  		vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8,
>>  		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_WAKER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
4 ? WAKER is a 32b reg
>> +		VGIC_ACCESS_32bit),
>>  	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
>>  		vgic_mmio_read_propbase, vgic_mmio_write_propbase, 8,
>>  		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
>> @@ -612,6 +623,34 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
>>  	return ret;
>>  }
>>  
>> +int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>> +{
>> +	const struct vgic_register_region *regions;
>> +	gpa_t addr;
>> +	int nr_regions;
>> +
>> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
>> +
>> +	switch (attr->group) {
>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>> +		regions = vgic_v3_dist_registers;
>> +		nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
Couldn't you set
	struct vgic_io_device dev = {
		.regions = vgic_v3_dist_registers,
		.nr_regions = ARRAY_SIZE(vgic_v3_dist_registers),
	};

and reuse:
vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device
*iodev, gpa_t addr, int len)?

In such a case is vgic_validate_mmio_region_addr() still mandated?
>> +		break;
>> +	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:{
>> +		regions = vgic_v3_rdbase_registers;
>> +		nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
>> +		break;
>> +	}
>> +	default:
>> +		return -ENXIO;
>> +	}
>> +
>> +	/* We only support aligned 32-bit accesses. */
>> +	if (addr & 3)
>> +		return -ENXIO;
>> +
>> +	return vgic_validate_mmio_region_addr(dev, regions, nr_regions, addr);
>> +}
>>  /*
>>   * Compare a given affinity (level 1-3 and a level 0 mask, from the SGI
>>   * generation register ICC_SGI1R_EL1) with a given VCPU.
>> @@ -718,3 +757,36 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
>>  		vgic_put_irq(vcpu->kvm, irq);
>>  	}
>>  }
>> +
>> +int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>> +			 int offset, u32 *val)
>> +{
>> +	struct vgic_io_device dev = {
>> +		.regions = vgic_v3_dist_registers,
>> +		.nr_regions = ARRAY_SIZE(vgic_v3_dist_registers),
>> +	};
>> +
>> +	return vgic_uaccess(vcpu, &dev, is_write, offset, val);
>> +}
>> +
>> +int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>> +			   int offset, u32 *val)
>> +{
>> +	struct vgic_io_device rd_dev = {
>> +		.regions = vgic_v3_rdbase_registers,
>> +		.nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers),
>> +	};
>> +
>> +	struct vgic_io_device sgi_dev = {
>> +		.regions = vgic_v3_sgibase_registers,
>> +		.nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers),
>> +	};
>> +
>> +	/* SGI_base is the next 64K frame after RD_base */
>> +	if (offset >= SZ_64K)
>> +		return vgic_uaccess(vcpu, &sgi_dev, is_write,
>> +				    offset - SZ_64K, val);
>> +	else
>> +		return vgic_uaccess(vcpu, &rd_dev, is_write,
>> +				    offset, val);
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>> index d5f3ee2..0d1bc98 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>> @@ -394,6 +394,28 @@ static int match_region(const void *key, const void *elt)
>>  		       sizeof(region[0]), match_region);
>>  }
>>  
>> +/* Check if address falls within the region */
>> +int vgic_validate_mmio_region_addr(struct kvm_device *dev,
>> +				   const struct vgic_register_region *regions,
>> +				   int nr_regions, gpa_t addr)
>> +{
>> +	int i, len;
>> +	int nr_irqs = dev->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +
>> +	for (i = 0; i < nr_regions; i++) {
>> +		if (regions[i].bits_per_irq)
>> +			len = (regions[i].bits_per_irq * nr_irqs) / 8;
>> +		else
>> +			len = regions[i].len;
>> +
>> +		if (regions[i].reg_offset <= addr &&
>> +		    regions[i].reg_offset + len > addr)
>> +			return 0;
>> +	}
>> +
>> +	return -ENXIO;
>> +}
>> +
>>  /*
>>   * kvm_mmio_read_buf() returns a value in a format where it can be converted
>>   * to a byte array and be directly observed as the guest wanted it to appear
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
>> index 7b30296..1cc7faf 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.h
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
>> @@ -177,6 +177,10 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>>  int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>>  		 bool is_write, int offset, u32 *val);
>>  
>> +int vgic_validate_mmio_region_addr(struct kvm_device *dev,
>> +				   const struct vgic_register_region *regions,
>> +				   int nr_regions, gpa_t addr);
>> +
>>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>>  
>>  unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 859f65c..91f58b2 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -30,6 +30,49 @@
>>  
>>  #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
>>  
>> +#define VGIC_AFFINITY_0_SHIFT 0
>> +#define VGIC_AFFINITY_0_MASK (0xffUL << VGIC_AFFINITY_0_SHIFT)
>> +#define VGIC_AFFINITY_1_SHIFT 8
>> +#define VGIC_AFFINITY_1_MASK (0xffUL << VGIC_AFFINITY_1_SHIFT)
>> +#define VGIC_AFFINITY_2_SHIFT 16
>> +#define VGIC_AFFINITY_2_MASK (0xffUL << VGIC_AFFINITY_2_SHIFT)
>> +#define VGIC_AFFINITY_3_SHIFT 24
>> +#define VGIC_AFFINITY_3_MASK (0xffUL << VGIC_AFFINITY_3_SHIFT)
>> +
>> +#define VGIC_AFFINITY_LEVEL(reg, level) \
>> +	((((reg) & VGIC_AFFINITY_## level ##_MASK) \
>> +	>> VGIC_AFFINITY_## level ##_SHIFT) << MPIDR_LEVEL_SHIFT(level))
>> +
>> +/*
>> + * The Userspace encodes the affinity differently from the MPIDR,
>> + * Below macro converts vgic userspace format to MPIDR reg format.
>> + */
>> +#define VGIC_TO_MPIDR(val) (VGIC_AFFINITY_LEVEL(val, 0) | \
>> +			    VGIC_AFFINITY_LEVEL(val, 1) | \
>> +			    VGIC_AFFINITY_LEVEL(val, 2) | \
>> +			    VGIC_AFFINITY_LEVEL(val, 3))
>> +
>> +/*
>> + * As per Documentation/virtual/kvm/devices/arm-vgic-v3.txt,
>> + * below macros are defined for CPUREG encoding.
>> + */
>> +#define KVM_REG_ARM_VGIC_SYSREG_OP0_MASK   0x000000000000c000
>> +#define KVM_REG_ARM_VGIC_SYSREG_OP0_SHIFT  14
>> +#define KVM_REG_ARM_VGIC_SYSREG_OP1_MASK   0x0000000000003800
>> +#define KVM_REG_ARM_VGIC_SYSREG_OP1_SHIFT  11
>> +#define KVM_REG_ARM_VGIC_SYSREG_CRN_MASK   0x0000000000000780
>> +#define KVM_REG_ARM_VGIC_SYSREG_CRN_SHIFT  7
>> +#define KVM_REG_ARM_VGIC_SYSREG_CRM_MASK   0x0000000000000078
>> +#define KVM_REG_ARM_VGIC_SYSREG_CRM_SHIFT  3
>> +#define KVM_REG_ARM_VGIC_SYSREG_OP2_MASK   0x0000000000000007
>> +#define KVM_REG_ARM_VGIC_SYSREG_OP2_SHIFT  0
>> +
>> +#define KVM_DEV_ARM_VGIC_SYSREG_MASK (KVM_REG_ARM_VGIC_SYSREG_OP0_MASK | \
>> +				      KVM_REG_ARM_VGIC_SYSREG_OP1_MASK | \
>> +				      KVM_REG_ARM_VGIC_SYSREG_CRN_MASK | \
>> +				      KVM_REG_ARM_VGIC_SYSREG_CRM_MASK | \
>> +				      KVM_REG_ARM_VGIC_SYSREG_OP2_MASK)
nit: do those SYSREG defines relate to this patch?

Thanks

Eric
>> +
>>  struct vgic_vmcr {
>>  	u32	ctlr;
>>  	u32	abpr;
>> @@ -89,7 +132,11 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq)
>>  int kvm_vgic_register_its_device(void);
>>  void vgic_enable_lpis(struct kvm_vcpu *vcpu);
>>  int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi);
>> -
>> +int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
>> +int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>> +			 int offset, u32 *val);
>> +int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>> +			 int offset, u32 *val);
>>  int kvm_register_vgic_device(unsigned long type);
>>  int vgic_lazy_init(struct kvm *kvm);
>>  int vgic_init(struct kvm *kvm);
>> -- 
>> 1.9.1
>>
> 
> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 03/11] arm/arm64: vgic: Introduce find_reg_by_id()
  2016-11-23 13:01   ` vijay.kilari at gmail.com
@ 2016-12-06 13:27     ` Auger Eric
  -1 siblings, 0 replies; 78+ messages in thread
From: Auger Eric @ 2016-12-06 13:27 UTC (permalink / raw)
  To: vijay.kilari, marc.zyngier, christoffer.dall, peter.maydell
  Cc: kvmarm, linux-arm-kernel, Vijaya Kumar K

Hi Vijay,
On 23/11/2016 14:01, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> 
> In order to implement vGICv3 CPU interface access, we will need to perform
> table lookup of system registers. We would need both index_to_params() and
> find_reg() exported for that purpose, but instead we export a single
> function which combines them both.
> 
> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> Reviewed-by: Andre Przywara <andre.przywara@arm.com>
> Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 22 +++++++++++++++-------
>  arch/arm64/kvm/sys_regs.h |  4 ++++
>  2 files changed, 19 insertions(+), 7 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index f302fdb..1330d4c 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -1789,6 +1789,17 @@ static bool index_to_params(u64 id, struct sys_reg_params *params)
>  	}
>  }
>  
> +const struct sys_reg_desc *find_reg_by_id(u64 id,
> +					  struct sys_reg_params *params,
> +					  const struct sys_reg_desc table[],
> +					  unsigned int num)
> +{
> +	if (!index_to_params(id, params))
> +		return NULL;
> +
> +	return find_reg(params, table, num);
> +}
> +
Can't you use find_reg_by_id in index_to_sys_reg_desc too?

Besides Reviewed-by: Eric Auger <eric.auger@redhat.com>

Thanks

Eric
>  /* Decode an index value, and find the sys_reg_desc entry. */
>  static const struct sys_reg_desc *index_to_sys_reg_desc(struct kvm_vcpu *vcpu,
>  						    u64 id)
> @@ -1912,10 +1923,8 @@ static int get_invariant_sys_reg(u64 id, void __user *uaddr)
>  	struct sys_reg_params params;
>  	const struct sys_reg_desc *r;
>  
> -	if (!index_to_params(id, &params))
> -		return -ENOENT;
> -
> -	r = find_reg(&params, invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs));
> +	r = find_reg_by_id(id, &params, invariant_sys_regs,
> +			   ARRAY_SIZE(invariant_sys_regs));
>  	if (!r)
>  		return -ENOENT;
>  
> @@ -1929,9 +1938,8 @@ static int set_invariant_sys_reg(u64 id, void __user *uaddr)
>  	int err;
>  	u64 val = 0; /* Make sure high bits are 0 for 32-bit regs */
>  
> -	if (!index_to_params(id, &params))
> -		return -ENOENT;
> -	r = find_reg(&params, invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs));
> +	r = find_reg_by_id(id, &params, invariant_sys_regs,
> +			   ARRAY_SIZE(invariant_sys_regs));
>  	if (!r)
>  		return -ENOENT;
>  
> diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
> index dbbb01c..9c6ffd0 100644
> --- a/arch/arm64/kvm/sys_regs.h
> +++ b/arch/arm64/kvm/sys_regs.h
> @@ -136,6 +136,10 @@ static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
>  	return i1->Op2 - i2->Op2;
>  }
>  
> +const struct sys_reg_desc *find_reg_by_id(u64 id,
> +					  struct sys_reg_params *params,
> +					  const struct sys_reg_desc table[],
> +					  unsigned int num);
>  
>  #define Op0(_x) 	.Op0 = _x
>  #define Op1(_x) 	.Op1 = _x
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 03/11] arm/arm64: vgic: Introduce find_reg_by_id()
@ 2016-12-06 13:27     ` Auger Eric
  0 siblings, 0 replies; 78+ messages in thread
From: Auger Eric @ 2016-12-06 13:27 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Vijay,
On 23/11/2016 14:01, vijay.kilari at gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> 
> In order to implement vGICv3 CPU interface access, we will need to perform
> table lookup of system registers. We would need both index_to_params() and
> find_reg() exported for that purpose, but instead we export a single
> function which combines them both.
> 
> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> Reviewed-by: Andre Przywara <andre.przywara@arm.com>
> Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 22 +++++++++++++++-------
>  arch/arm64/kvm/sys_regs.h |  4 ++++
>  2 files changed, 19 insertions(+), 7 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index f302fdb..1330d4c 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -1789,6 +1789,17 @@ static bool index_to_params(u64 id, struct sys_reg_params *params)
>  	}
>  }
>  
> +const struct sys_reg_desc *find_reg_by_id(u64 id,
> +					  struct sys_reg_params *params,
> +					  const struct sys_reg_desc table[],
> +					  unsigned int num)
> +{
> +	if (!index_to_params(id, params))
> +		return NULL;
> +
> +	return find_reg(params, table, num);
> +}
> +
Can't you use find_reg_by_id in index_to_sys_reg_desc too?

Besides Reviewed-by: Eric Auger <eric.auger@redhat.com>

Thanks

Eric
>  /* Decode an index value, and find the sys_reg_desc entry. */
>  static const struct sys_reg_desc *index_to_sys_reg_desc(struct kvm_vcpu *vcpu,
>  						    u64 id)
> @@ -1912,10 +1923,8 @@ static int get_invariant_sys_reg(u64 id, void __user *uaddr)
>  	struct sys_reg_params params;
>  	const struct sys_reg_desc *r;
>  
> -	if (!index_to_params(id, &params))
> -		return -ENOENT;
> -
> -	r = find_reg(&params, invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs));
> +	r = find_reg_by_id(id, &params, invariant_sys_regs,
> +			   ARRAY_SIZE(invariant_sys_regs));
>  	if (!r)
>  		return -ENOENT;
>  
> @@ -1929,9 +1938,8 @@ static int set_invariant_sys_reg(u64 id, void __user *uaddr)
>  	int err;
>  	u64 val = 0; /* Make sure high bits are 0 for 32-bit regs */
>  
> -	if (!index_to_params(id, &params))
> -		return -ENOENT;
> -	r = find_reg(&params, invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs));
> +	r = find_reg_by_id(id, &params, invariant_sys_regs,
> +			   ARRAY_SIZE(invariant_sys_regs));
>  	if (!r)
>  		return -ENOENT;
>  
> diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
> index dbbb01c..9c6ffd0 100644
> --- a/arch/arm64/kvm/sys_regs.h
> +++ b/arch/arm64/kvm/sys_regs.h
> @@ -136,6 +136,10 @@ static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
>  	return i1->Op2 - i2->Op2;
>  }
>  
> +const struct sys_reg_desc *find_reg_by_id(u64 id,
> +					  struct sys_reg_params *params,
> +					  const struct sys_reg_desc table[],
> +					  unsigned int num);
>  
>  #define Op0(_x) 	.Op0 = _x
>  #define Op1(_x) 	.Op1 = _x
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 04/11] irqchip/gic-v3: Add missing system register definitions
  2016-11-23 13:01   ` vijay.kilari at gmail.com
@ 2016-12-06 13:53     ` Auger Eric
  -1 siblings, 0 replies; 78+ messages in thread
From: Auger Eric @ 2016-12-06 13:53 UTC (permalink / raw)
  To: vijay.kilari, marc.zyngier, christoffer.dall, peter.maydell
  Cc: kvmarm, linux-arm-kernel, Vijaya Kumar K

Hi,
On 23/11/2016 14:01, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> 
> Define register definitions for ICH_VMCR_EL2, ICC_CTLR_EL1 and
> ICH_VTR_EL2, ICC_BPR0_EL1, ICC_BPR1_EL1 registers.
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

> ---
>  include/linux/irqchip/arm-gic-v3.h | 43 ++++++++++++++++++++++++++++++++++++--
>  1 file changed, 41 insertions(+), 2 deletions(-)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 0deea34..b4f8287 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -352,8 +352,30 @@
>  /*
>   * CPU interface registers
>   */
> -#define ICC_CTLR_EL1_EOImode_drop_dir	(0U << 1)
> -#define ICC_CTLR_EL1_EOImode_drop	(1U << 1)
> +#define ICC_CTLR_EL1_EOImode_SHIFT	(1)
> +#define ICC_CTLR_EL1_EOImode_drop_dir	(0U << ICC_CTLR_EL1_EOImode_SHIFT)
> +#define ICC_CTLR_EL1_EOImode_drop	(1U << ICC_CTLR_EL1_EOImode_SHIFT)
> +#define ICC_CTLR_EL1_EOImode_MASK	(1 << ICC_CTLR_EL1_EOImode_SHIFT)
> +#define ICC_CTLR_EL1_CBPR_SHIFT		0
> +#define ICC_CTLR_EL1_CBPR_MASK		(1 << ICC_CTLR_EL1_CBPR_SHIFT)
> +#define ICC_CTLR_EL1_PRI_BITS_SHIFT	8
> +#define ICC_CTLR_EL1_PRI_BITS_MASK	(0x7 << ICC_CTLR_EL1_PRI_BITS_SHIFT)
> +#define ICC_CTLR_EL1_ID_BITS_SHIFT	11
> +#define ICC_CTLR_EL1_ID_BITS_MASK	(0x7 << ICC_CTLR_EL1_ID_BITS_SHIFT)
> +#define ICC_CTLR_EL1_SEIS_SHIFT		14
> +#define ICC_CTLR_EL1_SEIS_MASK		(0x1 << ICC_CTLR_EL1_SEIS_SHIFT)
> +#define ICC_CTLR_EL1_A3V_SHIFT		15
> +#define ICC_CTLR_EL1_A3V_MASK		(0x1 << ICC_CTLR_EL1_A3V_SHIFT)
> +#define ICC_PMR_EL1_SHIFT		0
> +#define ICC_PMR_EL1_MASK		(0xff << ICC_PMR_EL1_SHIFT)
> +#define ICC_BPR0_EL1_SHIFT		0
> +#define ICC_BPR0_EL1_MASK		(0x7 << ICC_BPR0_EL1_SHIFT)
> +#define ICC_BPR1_EL1_SHIFT		0
> +#define ICC_BPR1_EL1_MASK		(0x7 << ICC_BPR1_EL1_SHIFT)
> +#define ICC_IGRPEN0_EL1_SHIFT		0
> +#define ICC_IGRPEN0_EL1_MASK		(1 << ICC_IGRPEN0_EL1_SHIFT)
> +#define ICC_IGRPEN1_EL1_SHIFT		0
> +#define ICC_IGRPEN1_EL1_MASK		(1 << ICC_IGRPEN1_EL1_SHIFT)
>  #define ICC_SRE_EL1_SRE			(1U << 0)
>  
>  /*
> @@ -384,12 +406,29 @@
>  
>  #define ICH_VMCR_CTLR_SHIFT		0
>  #define ICH_VMCR_CTLR_MASK		(0x21f << ICH_VMCR_CTLR_SHIFT)
> +#define ICH_VMCR_CBPR_SHIFT		4
> +#define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
> +#define ICH_VMCR_EOIM_SHIFT		9
> +#define ICH_VMCR_EOIM_MASK		(1 << ICH_VMCR_EOIM_SHIFT)
>  #define ICH_VMCR_BPR1_SHIFT		18
>  #define ICH_VMCR_BPR1_MASK		(7 << ICH_VMCR_BPR1_SHIFT)
>  #define ICH_VMCR_BPR0_SHIFT		21
>  #define ICH_VMCR_BPR0_MASK		(7 << ICH_VMCR_BPR0_SHIFT)
>  #define ICH_VMCR_PMR_SHIFT		24
>  #define ICH_VMCR_PMR_MASK		(0xffUL << ICH_VMCR_PMR_SHIFT)
> +#define ICH_VMCR_ENG0_SHIFT		0
> +#define ICH_VMCR_ENG0_MASK		(1 << ICH_VMCR_ENG0_SHIFT)
> +#define ICH_VMCR_ENG1_SHIFT		1
> +#define ICH_VMCR_ENG1_MASK		(1 << ICH_VMCR_ENG1_SHIFT)
Besides the fact the V* was omitted (for instance VENG0) this looks good
to me.
> +
> +#define ICH_VTR_PRI_BITS_SHIFT		29
> +#define ICH_VTR_PRI_BITS_MASK		(7 << ICH_VTR_PRI_BITS_SHIFT)
> +#define ICH_VTR_ID_BITS_SHIFT		23
> +#define ICH_VTR_ID_BITS_MASK		(7 << ICH_VTR_ID_BITS_SHIFT)
> +#define ICH_VTR_SEIS_SHIFT		22
> +#define ICH_VTR_SEIS_MASK		(1 << ICH_VTR_SEIS_SHIFT)
> +#define ICH_VTR_A3V_SHIFT		21
> +#define ICH_VTR_A3V_MASK		(1 << ICH_VTR_A3V_SHIFT)
Some fields are omitted but I guess they are not used.

Reviewed-by: Eric Auger <eric.auger@redhat.com>

Eric

>  
>  #define ICC_IAR1_EL1_SPURIOUS		0x3ff
>  
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 04/11] irqchip/gic-v3: Add missing system register definitions
@ 2016-12-06 13:53     ` Auger Eric
  0 siblings, 0 replies; 78+ messages in thread
From: Auger Eric @ 2016-12-06 13:53 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,
On 23/11/2016 14:01, vijay.kilari at gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> 
> Define register definitions for ICH_VMCR_EL2, ICC_CTLR_EL1 and
> ICH_VTR_EL2, ICC_BPR0_EL1, ICC_BPR1_EL1 registers.
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>

> ---
>  include/linux/irqchip/arm-gic-v3.h | 43 ++++++++++++++++++++++++++++++++++++--
>  1 file changed, 41 insertions(+), 2 deletions(-)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 0deea34..b4f8287 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -352,8 +352,30 @@
>  /*
>   * CPU interface registers
>   */
> -#define ICC_CTLR_EL1_EOImode_drop_dir	(0U << 1)
> -#define ICC_CTLR_EL1_EOImode_drop	(1U << 1)
> +#define ICC_CTLR_EL1_EOImode_SHIFT	(1)
> +#define ICC_CTLR_EL1_EOImode_drop_dir	(0U << ICC_CTLR_EL1_EOImode_SHIFT)
> +#define ICC_CTLR_EL1_EOImode_drop	(1U << ICC_CTLR_EL1_EOImode_SHIFT)
> +#define ICC_CTLR_EL1_EOImode_MASK	(1 << ICC_CTLR_EL1_EOImode_SHIFT)
> +#define ICC_CTLR_EL1_CBPR_SHIFT		0
> +#define ICC_CTLR_EL1_CBPR_MASK		(1 << ICC_CTLR_EL1_CBPR_SHIFT)
> +#define ICC_CTLR_EL1_PRI_BITS_SHIFT	8
> +#define ICC_CTLR_EL1_PRI_BITS_MASK	(0x7 << ICC_CTLR_EL1_PRI_BITS_SHIFT)
> +#define ICC_CTLR_EL1_ID_BITS_SHIFT	11
> +#define ICC_CTLR_EL1_ID_BITS_MASK	(0x7 << ICC_CTLR_EL1_ID_BITS_SHIFT)
> +#define ICC_CTLR_EL1_SEIS_SHIFT		14
> +#define ICC_CTLR_EL1_SEIS_MASK		(0x1 << ICC_CTLR_EL1_SEIS_SHIFT)
> +#define ICC_CTLR_EL1_A3V_SHIFT		15
> +#define ICC_CTLR_EL1_A3V_MASK		(0x1 << ICC_CTLR_EL1_A3V_SHIFT)
> +#define ICC_PMR_EL1_SHIFT		0
> +#define ICC_PMR_EL1_MASK		(0xff << ICC_PMR_EL1_SHIFT)
> +#define ICC_BPR0_EL1_SHIFT		0
> +#define ICC_BPR0_EL1_MASK		(0x7 << ICC_BPR0_EL1_SHIFT)
> +#define ICC_BPR1_EL1_SHIFT		0
> +#define ICC_BPR1_EL1_MASK		(0x7 << ICC_BPR1_EL1_SHIFT)
> +#define ICC_IGRPEN0_EL1_SHIFT		0
> +#define ICC_IGRPEN0_EL1_MASK		(1 << ICC_IGRPEN0_EL1_SHIFT)
> +#define ICC_IGRPEN1_EL1_SHIFT		0
> +#define ICC_IGRPEN1_EL1_MASK		(1 << ICC_IGRPEN1_EL1_SHIFT)
>  #define ICC_SRE_EL1_SRE			(1U << 0)
>  
>  /*
> @@ -384,12 +406,29 @@
>  
>  #define ICH_VMCR_CTLR_SHIFT		0
>  #define ICH_VMCR_CTLR_MASK		(0x21f << ICH_VMCR_CTLR_SHIFT)
> +#define ICH_VMCR_CBPR_SHIFT		4
> +#define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
> +#define ICH_VMCR_EOIM_SHIFT		9
> +#define ICH_VMCR_EOIM_MASK		(1 << ICH_VMCR_EOIM_SHIFT)
>  #define ICH_VMCR_BPR1_SHIFT		18
>  #define ICH_VMCR_BPR1_MASK		(7 << ICH_VMCR_BPR1_SHIFT)
>  #define ICH_VMCR_BPR0_SHIFT		21
>  #define ICH_VMCR_BPR0_MASK		(7 << ICH_VMCR_BPR0_SHIFT)
>  #define ICH_VMCR_PMR_SHIFT		24
>  #define ICH_VMCR_PMR_MASK		(0xffUL << ICH_VMCR_PMR_SHIFT)
> +#define ICH_VMCR_ENG0_SHIFT		0
> +#define ICH_VMCR_ENG0_MASK		(1 << ICH_VMCR_ENG0_SHIFT)
> +#define ICH_VMCR_ENG1_SHIFT		1
> +#define ICH_VMCR_ENG1_MASK		(1 << ICH_VMCR_ENG1_SHIFT)
Besides the fact the V* was omitted (for instance VENG0) this looks good
to me.
> +
> +#define ICH_VTR_PRI_BITS_SHIFT		29
> +#define ICH_VTR_PRI_BITS_MASK		(7 << ICH_VTR_PRI_BITS_SHIFT)
> +#define ICH_VTR_ID_BITS_SHIFT		23
> +#define ICH_VTR_ID_BITS_MASK		(7 << ICH_VTR_ID_BITS_SHIFT)
> +#define ICH_VTR_SEIS_SHIFT		22
> +#define ICH_VTR_SEIS_MASK		(1 << ICH_VTR_SEIS_SHIFT)
> +#define ICH_VTR_A3V_SHIFT		21
> +#define ICH_VTR_A3V_MASK		(1 << ICH_VTR_A3V_SHIFT)
Some fields are omitted but I guess they are not used.

Reviewed-by: Eric Auger <eric.auger@redhat.com>

Eric

>  
>  #define ICC_IAR1_EL1_SPURIOUS		0x3ff
>  
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 01/11] arm/arm64: vgic: Implement support for userspace access
  2016-12-06 11:42       ` Auger Eric
@ 2016-12-06 14:30         ` Christoffer Dall
  -1 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-12-06 14:30 UTC (permalink / raw)
  To: Auger Eric; +Cc: marc.zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

On Tue, Dec 06, 2016 at 12:42:09PM +0100, Auger Eric wrote:
> Hi,
> 
> On 28/11/2016 14:05, Christoffer Dall wrote:
> > On Wed, Nov 23, 2016 at 06:31:48PM +0530, vijay.kilari@gmail.com wrote:
> >> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >>
> >> Read and write of some registers like ISPENDR and ICPENDR
> >> from userspace requires special handling when compared to
> >> guest access for these registers.
> >>
> >> Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
> >> for handling of ISPENDR, ICPENDR registers handling.
> >>
> >> Add infrastructure to support guest and userspace read
> >> and write for the required registers
> >> Also moved vgic_uaccess from vgic-mmio-v2.c to vgic-mmio.c
> >>
> >> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >> ---
> >>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  25 ----------
> >>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 102 ++++++++++++++++++++++++++++++++-------
> >>  virt/kvm/arm/vgic/vgic-mmio.c    |  78 +++++++++++++++++++++++++++---
> >>  virt/kvm/arm/vgic/vgic-mmio.h    |  19 ++++++++
> >>  4 files changed, 175 insertions(+), 49 deletions(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> index b44b359..0b32f40 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> @@ -406,31 +406,6 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
> >>  	return -ENXIO;
> >>  }
> >>  
> >> -/*
> >> - * When userland tries to access the VGIC register handlers, we need to
> >> - * create a usable struct vgic_io_device to be passed to the handlers and we
> >> - * have to set up a buffer similar to what would have happened if a guest MMIO
> >> - * access occurred, including doing endian conversions on BE systems.
> >> - */
> >> -static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
> >> -			bool is_write, int offset, u32 *val)
> >> -{
> >> -	unsigned int len = 4;
> >> -	u8 buf[4];
> >> -	int ret;
> >> -
> >> -	if (is_write) {
> >> -		vgic_data_host_to_mmio_bus(buf, len, *val);
> >> -		ret = kvm_io_gic_ops.write(vcpu, &dev->dev, offset, len, buf);
> >> -	} else {
> >> -		ret = kvm_io_gic_ops.read(vcpu, &dev->dev, offset, len, buf);
> >> -		if (!ret)
> >> -			*val = vgic_data_mmio_bus_to_host(buf, len);
> >> -	}
> >> -
> >> -	return ret;
> >> -}
> >> -
> >>  int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> >>  			  int offset, u32 *val)
> >>  {
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> >> index 50f42f0..8e76d04 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> >> @@ -207,6 +207,66 @@ static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
> >>  	return 0;
> >>  }
> >>  
> >> +static unsigned long vgic_v3_uaccess_read_pending(struct kvm_vcpu *vcpu,
> >> +						  gpa_t addr, unsigned int len)
> >> +{
> >> +	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
> >> +	u32 value = 0;
> >> +	int i;
> >> +
> >> +	/*
> >> +	 * A level triggerred interrupt pending state is latched in both
> >> +	 * "soft_pending" and "line_level" variables. Userspace will save
> >> +	 * and restore soft_pending and line_level separately.
> >> +	 * Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
> >> +	 * handling of ISPENDR and ICPENDR.
> >> +	 */
> >> +	for (i = 0; i < len * 8; i++) {
> >> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +		if (irq->config == VGIC_CONFIG_LEVEL && irq->soft_pending)
> >> +			value |= (1U << i);
> >> +		if (irq->config == VGIC_CONFIG_EDGE && irq->pending)
> >> +			value |= (1U << i);
> >> +
> >> +		vgic_put_irq(vcpu->kvm, irq);
> >> +	}
> >> +
> >> +	return value;
> >> +}
> >> +
> >> +static void vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu,
> >> +					  gpa_t addr, unsigned int len,
> >> +					  unsigned long val)
> >> +{
> >> +	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
> >> +	int i;
> >> +
> >> +	for (i = 0; i < len * 8; i++) {
> >> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +		spin_lock(&irq->irq_lock);
> >> +		if (test_bit(i, &val)) {
> >> +			/* soft_pending is set irrespective of irq type
> >> +			 * (level or edge) to avoid dependency that VM should
> >> +			 * restore irq config before pending info.
> >> +			 */
> > 
> > nit: kernel commenting style
> > 
> >> +			irq->pending = true;
> >> +			irq->soft_pending = true;
> >> +			vgic_queue_irq_unlock(vcpu->kvm, irq);
> >> +		} else {
> >> +			irq->soft_pending = false;
> >> +			if (irq->config == VGIC_CONFIG_EDGE ||
> >> +			    (irq->config == VGIC_CONFIG_LEVEL &&
> >> +			    !irq->line_level))
> >> +				irq->pending = false;
> I am confused by the comment above. Since we test the irq config here
> don't we assume the config was restored before the pending state?

THe idea here was that if you're setting the value, then if you later
set the config to level, then the soft_pending state has already been
set properly, and if the irq stays an edge, then it doesn't matter what
that field is.

If you read the value, the assumption is that you're reading a
consistently configured GIC, if not, then all bets are off anyhow.

Does that make sense?

Perhaps only the comment should be adjusted or do you think the logic is
flawed?

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 01/11] arm/arm64: vgic: Implement support for userspace access
@ 2016-12-06 14:30         ` Christoffer Dall
  0 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-12-06 14:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 06, 2016 at 12:42:09PM +0100, Auger Eric wrote:
> Hi,
> 
> On 28/11/2016 14:05, Christoffer Dall wrote:
> > On Wed, Nov 23, 2016 at 06:31:48PM +0530, vijay.kilari at gmail.com wrote:
> >> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >>
> >> Read and write of some registers like ISPENDR and ICPENDR
> >> from userspace requires special handling when compared to
> >> guest access for these registers.
> >>
> >> Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
> >> for handling of ISPENDR, ICPENDR registers handling.
> >>
> >> Add infrastructure to support guest and userspace read
> >> and write for the required registers
> >> Also moved vgic_uaccess from vgic-mmio-v2.c to vgic-mmio.c
> >>
> >> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >> ---
> >>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  25 ----------
> >>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 102 ++++++++++++++++++++++++++++++++-------
> >>  virt/kvm/arm/vgic/vgic-mmio.c    |  78 +++++++++++++++++++++++++++---
> >>  virt/kvm/arm/vgic/vgic-mmio.h    |  19 ++++++++
> >>  4 files changed, 175 insertions(+), 49 deletions(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> index b44b359..0b32f40 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> @@ -406,31 +406,6 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
> >>  	return -ENXIO;
> >>  }
> >>  
> >> -/*
> >> - * When userland tries to access the VGIC register handlers, we need to
> >> - * create a usable struct vgic_io_device to be passed to the handlers and we
> >> - * have to set up a buffer similar to what would have happened if a guest MMIO
> >> - * access occurred, including doing endian conversions on BE systems.
> >> - */
> >> -static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
> >> -			bool is_write, int offset, u32 *val)
> >> -{
> >> -	unsigned int len = 4;
> >> -	u8 buf[4];
> >> -	int ret;
> >> -
> >> -	if (is_write) {
> >> -		vgic_data_host_to_mmio_bus(buf, len, *val);
> >> -		ret = kvm_io_gic_ops.write(vcpu, &dev->dev, offset, len, buf);
> >> -	} else {
> >> -		ret = kvm_io_gic_ops.read(vcpu, &dev->dev, offset, len, buf);
> >> -		if (!ret)
> >> -			*val = vgic_data_mmio_bus_to_host(buf, len);
> >> -	}
> >> -
> >> -	return ret;
> >> -}
> >> -
> >>  int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> >>  			  int offset, u32 *val)
> >>  {
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> >> index 50f42f0..8e76d04 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> >> @@ -207,6 +207,66 @@ static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
> >>  	return 0;
> >>  }
> >>  
> >> +static unsigned long vgic_v3_uaccess_read_pending(struct kvm_vcpu *vcpu,
> >> +						  gpa_t addr, unsigned int len)
> >> +{
> >> +	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
> >> +	u32 value = 0;
> >> +	int i;
> >> +
> >> +	/*
> >> +	 * A level triggerred interrupt pending state is latched in both
> >> +	 * "soft_pending" and "line_level" variables. Userspace will save
> >> +	 * and restore soft_pending and line_level separately.
> >> +	 * Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
> >> +	 * handling of ISPENDR and ICPENDR.
> >> +	 */
> >> +	for (i = 0; i < len * 8; i++) {
> >> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +		if (irq->config == VGIC_CONFIG_LEVEL && irq->soft_pending)
> >> +			value |= (1U << i);
> >> +		if (irq->config == VGIC_CONFIG_EDGE && irq->pending)
> >> +			value |= (1U << i);
> >> +
> >> +		vgic_put_irq(vcpu->kvm, irq);
> >> +	}
> >> +
> >> +	return value;
> >> +}
> >> +
> >> +static void vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu,
> >> +					  gpa_t addr, unsigned int len,
> >> +					  unsigned long val)
> >> +{
> >> +	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
> >> +	int i;
> >> +
> >> +	for (i = 0; i < len * 8; i++) {
> >> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +		spin_lock(&irq->irq_lock);
> >> +		if (test_bit(i, &val)) {
> >> +			/* soft_pending is set irrespective of irq type
> >> +			 * (level or edge) to avoid dependency that VM should
> >> +			 * restore irq config before pending info.
> >> +			 */
> > 
> > nit: kernel commenting style
> > 
> >> +			irq->pending = true;
> >> +			irq->soft_pending = true;
> >> +			vgic_queue_irq_unlock(vcpu->kvm, irq);
> >> +		} else {
> >> +			irq->soft_pending = false;
> >> +			if (irq->config == VGIC_CONFIG_EDGE ||
> >> +			    (irq->config == VGIC_CONFIG_LEVEL &&
> >> +			    !irq->line_level))
> >> +				irq->pending = false;
> I am confused by the comment above. Since we test the irq config here
> don't we assume the config was restored before the pending state?

THe idea here was that if you're setting the value, then if you later
set the config to level, then the soft_pending state has already been
set properly, and if the irq stays an edge, then it doesn't matter what
that field is.

If you read the value, the assumption is that you're reading a
consistently configured GIC, if not, then all bets are off anyhow.

Does that make sense?

Perhaps only the comment should be adjusted or do you think the logic is
flawed?

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 05/11] arm/arm64: vgic: Introduce VENG0 and VENG1 fields to vmcr struct
  2016-11-28 14:28     ` Christoffer Dall
@ 2016-12-08 11:52       ` Auger Eric
  -1 siblings, 0 replies; 78+ messages in thread
From: Auger Eric @ 2016-12-08 11:52 UTC (permalink / raw)
  To: Christoffer Dall, vijay.kilari
  Cc: marc.zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

Hi Vijay,

On 28/11/2016 15:28, Christoffer Dall wrote:
> On Wed, Nov 23, 2016 at 06:31:52PM +0530, vijay.kilari@gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>
>> ICC_VMCR_EL2 supports virtual access to ICC_IGRPEN1_EL1.Enable
>> and ICC_IGRPEN0_EL1.Enable fields. Add grpen0 and grpen1 member
>> variables to struct vmcr to support read and write of these fields.
>>
>> Also refactor vgic_set_vmcr and vgic_get_vmcr() code.
>> Drop ICH_VMCR_CTLR_SHIFT and ICH_VMCR_CTLR_MASK macros and instead
>> use ICH_VMCR_EOI* and ICH_VMCR_CBPR* macros
>> .
>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>> ---
>>  include/linux/irqchip/arm-gic-v3.h |  2 --
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c   | 16 ----------------
>>  virt/kvm/arm/vgic/vgic-mmio.c      | 16 ++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-v3.c        | 22 ++++++++++++++++++++--
>>  virt/kvm/arm/vgic/vgic.h           |  5 +++++
>>  5 files changed, 41 insertions(+), 20 deletions(-)
>>
>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
>> index b4f8287..406fc3e 100644
>> --- a/include/linux/irqchip/arm-gic-v3.h
>> +++ b/include/linux/irqchip/arm-gic-v3.h
>> @@ -404,8 +404,6 @@
>>  #define ICH_HCR_EN			(1 << 0)
>>  #define ICH_HCR_UIE			(1 << 1)
>>  
>> -#define ICH_VMCR_CTLR_SHIFT		0
>> -#define ICH_VMCR_CTLR_MASK		(0x21f << ICH_VMCR_CTLR_SHIFT)
>>  #define ICH_VMCR_CBPR_SHIFT		4
>>  #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
>>  #define ICH_VMCR_EOIM_SHIFT		9
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index 2cb04b7..ad353b5 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -212,22 +212,6 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
>>  	}
>>  }
>>  
>> -static void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>> -{
>> -	if (kvm_vgic_global_state.type == VGIC_V2)
>> -		vgic_v2_set_vmcr(vcpu, vmcr);
>> -	else
>> -		vgic_v3_set_vmcr(vcpu, vmcr);
>> -}
>> -
>> -static void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>> -{
>> -	if (kvm_vgic_global_state.type == VGIC_V2)
>> -		vgic_v2_get_vmcr(vcpu, vmcr);
>> -	else
>> -		vgic_v3_get_vmcr(vcpu, vmcr);
>> -}
>> -
>>  #define GICC_ARCH_VERSION_V2	0x2
>>  
>>  /* These are for userland accesses only, there is no guest-facing emulation. */
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>> index 0d1bc98..f81e0e5 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>> @@ -416,6 +416,22 @@ int vgic_validate_mmio_region_addr(struct kvm_device *dev,
>>  	return -ENXIO;
>>  }
>>  
>> +void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_set_vmcr(vcpu, vmcr);
>> +	else
>> +		vgic_v3_set_vmcr(vcpu, vmcr);
>> +}
>> +
>> +void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_get_vmcr(vcpu, vmcr);
>> +	else
>> +		vgic_v3_get_vmcr(vcpu, vmcr);
>> +}
>> +
>>  /*
>>   * kvm_mmio_read_buf() returns a value in a format where it can be converted
>>   * to a byte array and be directly observed as the guest wanted it to appear
>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>> index 9f0dae3..a3ff04b 100644
>> --- a/virt/kvm/arm/vgic/vgic-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>> @@ -175,10 +175,19 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>>  {
>>  	u32 vmcr;
>>  
>> -	vmcr  = (vmcrp->ctlr << ICH_VMCR_CTLR_SHIFT) & ICH_VMCR_CTLR_MASK;
>> +	/*
>> +	 * Ignore the FIQen bit, because GIC emulation always implies
>> +	 * SRE=1 which means the vFIQEn bit is also RES1.
>> +	 */
>> +	vmcr = (vmcrp->ctlr & ICC_CTLR_EL1_EOImode_MASK) >>
>> +		ICC_CTLR_EL1_EOImode_SHIFT;
>> +	vmcr = (vmcr << ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;
I am not able to understand why we use ICC_CTLR _*macros here? Please
could you explain it to me? Besides if we want to ignore the FIQen bit
can't we change the ICH_VMCR_CTLR_MASK value?

Thanks

Eric
> 
> Nit: I think this can be written more nicely as:
> 	vmcr = ((vmcrp->ctlr >> ICC_CTLR_EL1_EOImode_SHIFT)
> 		<< ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;
> 
>> +	vmcr |= (vmcrp->ctlr << ICH_VMCR_CBPR_SHIFT) & ICH_VMCR_CBPR_MASK;
>>  	vmcr |= (vmcrp->abpr << ICH_VMCR_BPR1_SHIFT) & ICH_VMCR_BPR1_MASK;
>>  	vmcr |= (vmcrp->bpr << ICH_VMCR_BPR0_SHIFT) & ICH_VMCR_BPR0_MASK;
>>  	vmcr |= (vmcrp->pmr << ICH_VMCR_PMR_SHIFT) & ICH_VMCR_PMR_MASK;
>> +	vmcr |= (vmcrp->grpen0 << ICH_VMCR_ENG0_SHIFT) & ICH_VMCR_ENG0_MASK;
>> +	vmcr |= (vmcrp->grpen1 << ICH_VMCR_ENG1_SHIFT) & ICH_VMCR_ENG1_MASK;
>>  
>>  	vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
>>  }
>> @@ -187,10 +196,19 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>>  {
>>  	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr;
>>  
>> -	vmcrp->ctlr = (vmcr & ICH_VMCR_CTLR_MASK) >> ICH_VMCR_CTLR_SHIFT;
>> +	/*
>> +	 * Ignore the FIQen bit, because GIC emulation always implies
>> +	 * SRE=1 which means the vFIQEn bit is also RES1.
>> +	 */
>> +	vmcrp->ctlr = (vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT;
>> +	vmcrp->ctlr = (vmcrp->ctlr << ICC_CTLR_EL1_EOImode_SHIFT) &
>> +		       ICC_CTLR_EL1_EOImode_MASK;
> 
> similarly, this could be written as:
> 	vmcrp->ctlr = ((vmcr >> ICH_VMCR_EOIM_SHIFT) <<
> 			ICC_CTLR_EL1_EOImode_SHIFT) & ICC_CTLR_EL1_EOImode_MASK;
> 
>> +	vmcrp->ctlr |= (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT;
>>  	vmcrp->abpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
>>  	vmcrp->bpr  = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
>>  	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
>> +	vmcrp->grpen0 = (vmcr & ICH_VMCR_ENG0_MASK) >> ICH_VMCR_ENG0_SHIFT;
>> +	vmcrp->grpen1 = (vmcr & ICH_VMCR_ENG1_MASK) >> ICH_VMCR_ENG1_SHIFT;
>>  }
>>  
>>  #define INITIAL_PENDBASER_VALUE						  \
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 91f58b2..9232791 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -78,6 +78,9 @@ struct vgic_vmcr {
>>  	u32	abpr;
>>  	u32	bpr;
>>  	u32	pmr;
>> +	/* Below member variable are valid only for GICv3 */
>> +	u32	grpen0;
>> +	u32	grpen1;
>>  };
>>  
>>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> @@ -138,6 +141,8 @@ int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>  int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>  			 int offset, u32 *val);
>>  int kvm_register_vgic_device(unsigned long type);
>> +void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>> +void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>>  int vgic_lazy_init(struct kvm *kvm);
>>  int vgic_init(struct kvm *kvm);
>>  
>> -- 
>> 1.9.1
>>
> My comments on style above notwithstanding:
> 
> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 05/11] arm/arm64: vgic: Introduce VENG0 and VENG1 fields to vmcr struct
@ 2016-12-08 11:52       ` Auger Eric
  0 siblings, 0 replies; 78+ messages in thread
From: Auger Eric @ 2016-12-08 11:52 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Vijay,

On 28/11/2016 15:28, Christoffer Dall wrote:
> On Wed, Nov 23, 2016 at 06:31:52PM +0530, vijay.kilari at gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>
>> ICC_VMCR_EL2 supports virtual access to ICC_IGRPEN1_EL1.Enable
>> and ICC_IGRPEN0_EL1.Enable fields. Add grpen0 and grpen1 member
>> variables to struct vmcr to support read and write of these fields.
>>
>> Also refactor vgic_set_vmcr and vgic_get_vmcr() code.
>> Drop ICH_VMCR_CTLR_SHIFT and ICH_VMCR_CTLR_MASK macros and instead
>> use ICH_VMCR_EOI* and ICH_VMCR_CBPR* macros
>> .
>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>> ---
>>  include/linux/irqchip/arm-gic-v3.h |  2 --
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c   | 16 ----------------
>>  virt/kvm/arm/vgic/vgic-mmio.c      | 16 ++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-v3.c        | 22 ++++++++++++++++++++--
>>  virt/kvm/arm/vgic/vgic.h           |  5 +++++
>>  5 files changed, 41 insertions(+), 20 deletions(-)
>>
>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
>> index b4f8287..406fc3e 100644
>> --- a/include/linux/irqchip/arm-gic-v3.h
>> +++ b/include/linux/irqchip/arm-gic-v3.h
>> @@ -404,8 +404,6 @@
>>  #define ICH_HCR_EN			(1 << 0)
>>  #define ICH_HCR_UIE			(1 << 1)
>>  
>> -#define ICH_VMCR_CTLR_SHIFT		0
>> -#define ICH_VMCR_CTLR_MASK		(0x21f << ICH_VMCR_CTLR_SHIFT)
>>  #define ICH_VMCR_CBPR_SHIFT		4
>>  #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
>>  #define ICH_VMCR_EOIM_SHIFT		9
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index 2cb04b7..ad353b5 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -212,22 +212,6 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
>>  	}
>>  }
>>  
>> -static void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>> -{
>> -	if (kvm_vgic_global_state.type == VGIC_V2)
>> -		vgic_v2_set_vmcr(vcpu, vmcr);
>> -	else
>> -		vgic_v3_set_vmcr(vcpu, vmcr);
>> -}
>> -
>> -static void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>> -{
>> -	if (kvm_vgic_global_state.type == VGIC_V2)
>> -		vgic_v2_get_vmcr(vcpu, vmcr);
>> -	else
>> -		vgic_v3_get_vmcr(vcpu, vmcr);
>> -}
>> -
>>  #define GICC_ARCH_VERSION_V2	0x2
>>  
>>  /* These are for userland accesses only, there is no guest-facing emulation. */
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>> index 0d1bc98..f81e0e5 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>> @@ -416,6 +416,22 @@ int vgic_validate_mmio_region_addr(struct kvm_device *dev,
>>  	return -ENXIO;
>>  }
>>  
>> +void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_set_vmcr(vcpu, vmcr);
>> +	else
>> +		vgic_v3_set_vmcr(vcpu, vmcr);
>> +}
>> +
>> +void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>> +{
>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>> +		vgic_v2_get_vmcr(vcpu, vmcr);
>> +	else
>> +		vgic_v3_get_vmcr(vcpu, vmcr);
>> +}
>> +
>>  /*
>>   * kvm_mmio_read_buf() returns a value in a format where it can be converted
>>   * to a byte array and be directly observed as the guest wanted it to appear
>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>> index 9f0dae3..a3ff04b 100644
>> --- a/virt/kvm/arm/vgic/vgic-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>> @@ -175,10 +175,19 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>>  {
>>  	u32 vmcr;
>>  
>> -	vmcr  = (vmcrp->ctlr << ICH_VMCR_CTLR_SHIFT) & ICH_VMCR_CTLR_MASK;
>> +	/*
>> +	 * Ignore the FIQen bit, because GIC emulation always implies
>> +	 * SRE=1 which means the vFIQEn bit is also RES1.
>> +	 */
>> +	vmcr = (vmcrp->ctlr & ICC_CTLR_EL1_EOImode_MASK) >>
>> +		ICC_CTLR_EL1_EOImode_SHIFT;
>> +	vmcr = (vmcr << ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;
I am not able to understand why we use ICC_CTLR _*macros here? Please
could you explain it to me? Besides if we want to ignore the FIQen bit
can't we change the ICH_VMCR_CTLR_MASK value?

Thanks

Eric
> 
> Nit: I think this can be written more nicely as:
> 	vmcr = ((vmcrp->ctlr >> ICC_CTLR_EL1_EOImode_SHIFT)
> 		<< ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;
> 
>> +	vmcr |= (vmcrp->ctlr << ICH_VMCR_CBPR_SHIFT) & ICH_VMCR_CBPR_MASK;
>>  	vmcr |= (vmcrp->abpr << ICH_VMCR_BPR1_SHIFT) & ICH_VMCR_BPR1_MASK;
>>  	vmcr |= (vmcrp->bpr << ICH_VMCR_BPR0_SHIFT) & ICH_VMCR_BPR0_MASK;
>>  	vmcr |= (vmcrp->pmr << ICH_VMCR_PMR_SHIFT) & ICH_VMCR_PMR_MASK;
>> +	vmcr |= (vmcrp->grpen0 << ICH_VMCR_ENG0_SHIFT) & ICH_VMCR_ENG0_MASK;
>> +	vmcr |= (vmcrp->grpen1 << ICH_VMCR_ENG1_SHIFT) & ICH_VMCR_ENG1_MASK;
>>  
>>  	vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
>>  }
>> @@ -187,10 +196,19 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>>  {
>>  	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr;
>>  
>> -	vmcrp->ctlr = (vmcr & ICH_VMCR_CTLR_MASK) >> ICH_VMCR_CTLR_SHIFT;
>> +	/*
>> +	 * Ignore the FIQen bit, because GIC emulation always implies
>> +	 * SRE=1 which means the vFIQEn bit is also RES1.
>> +	 */
>> +	vmcrp->ctlr = (vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT;
>> +	vmcrp->ctlr = (vmcrp->ctlr << ICC_CTLR_EL1_EOImode_SHIFT) &
>> +		       ICC_CTLR_EL1_EOImode_MASK;
> 
> similarly, this could be written as:
> 	vmcrp->ctlr = ((vmcr >> ICH_VMCR_EOIM_SHIFT) <<
> 			ICC_CTLR_EL1_EOImode_SHIFT) & ICC_CTLR_EL1_EOImode_MASK;
> 
>> +	vmcrp->ctlr |= (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT;
>>  	vmcrp->abpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
>>  	vmcrp->bpr  = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
>>  	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
>> +	vmcrp->grpen0 = (vmcr & ICH_VMCR_ENG0_MASK) >> ICH_VMCR_ENG0_SHIFT;
>> +	vmcrp->grpen1 = (vmcr & ICH_VMCR_ENG1_MASK) >> ICH_VMCR_ENG1_SHIFT;
>>  }
>>  
>>  #define INITIAL_PENDBASER_VALUE						  \
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 91f58b2..9232791 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -78,6 +78,9 @@ struct vgic_vmcr {
>>  	u32	abpr;
>>  	u32	bpr;
>>  	u32	pmr;
>> +	/* Below member variable are valid only for GICv3 */
>> +	u32	grpen0;
>> +	u32	grpen1;
>>  };
>>  
>>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> @@ -138,6 +141,8 @@ int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>  int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>  			 int offset, u32 *val);
>>  int kvm_register_vgic_device(unsigned long type);
>> +void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>> +void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>>  int vgic_lazy_init(struct kvm *kvm);
>>  int vgic_init(struct kvm *kvm);
>>  
>> -- 
>> 1.9.1
>>
> My comments on style above notwithstanding:
> 
> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 05/11] arm/arm64: vgic: Introduce VENG0 and VENG1 fields to vmcr struct
  2016-12-08 11:52       ` Auger Eric
@ 2016-12-08 12:21         ` Christoffer Dall
  -1 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-12-08 12:21 UTC (permalink / raw)
  To: Auger Eric; +Cc: marc.zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

On Thu, Dec 08, 2016 at 12:52:39PM +0100, Auger Eric wrote:
> Hi Vijay,
> 
> On 28/11/2016 15:28, Christoffer Dall wrote:
> > On Wed, Nov 23, 2016 at 06:31:52PM +0530, vijay.kilari@gmail.com wrote:
> >> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >>
> >> ICC_VMCR_EL2 supports virtual access to ICC_IGRPEN1_EL1.Enable
> >> and ICC_IGRPEN0_EL1.Enable fields. Add grpen0 and grpen1 member
> >> variables to struct vmcr to support read and write of these fields.
> >>
> >> Also refactor vgic_set_vmcr and vgic_get_vmcr() code.
> >> Drop ICH_VMCR_CTLR_SHIFT and ICH_VMCR_CTLR_MASK macros and instead
> >> use ICH_VMCR_EOI* and ICH_VMCR_CBPR* macros
> >> .
> >> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >> ---
> >>  include/linux/irqchip/arm-gic-v3.h |  2 --
> >>  virt/kvm/arm/vgic/vgic-mmio-v2.c   | 16 ----------------
> >>  virt/kvm/arm/vgic/vgic-mmio.c      | 16 ++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic-v3.c        | 22 ++++++++++++++++++++--
> >>  virt/kvm/arm/vgic/vgic.h           |  5 +++++
> >>  5 files changed, 41 insertions(+), 20 deletions(-)
> >>
> >> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> >> index b4f8287..406fc3e 100644
> >> --- a/include/linux/irqchip/arm-gic-v3.h
> >> +++ b/include/linux/irqchip/arm-gic-v3.h
> >> @@ -404,8 +404,6 @@
> >>  #define ICH_HCR_EN			(1 << 0)
> >>  #define ICH_HCR_UIE			(1 << 1)
> >>  
> >> -#define ICH_VMCR_CTLR_SHIFT		0
> >> -#define ICH_VMCR_CTLR_MASK		(0x21f << ICH_VMCR_CTLR_SHIFT)
> >>  #define ICH_VMCR_CBPR_SHIFT		4
> >>  #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
> >>  #define ICH_VMCR_EOIM_SHIFT		9
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> index 2cb04b7..ad353b5 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> @@ -212,22 +212,6 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
> >>  	}
> >>  }
> >>  
> >> -static void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> >> -{
> >> -	if (kvm_vgic_global_state.type == VGIC_V2)
> >> -		vgic_v2_set_vmcr(vcpu, vmcr);
> >> -	else
> >> -		vgic_v3_set_vmcr(vcpu, vmcr);
> >> -}
> >> -
> >> -static void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> >> -{
> >> -	if (kvm_vgic_global_state.type == VGIC_V2)
> >> -		vgic_v2_get_vmcr(vcpu, vmcr);
> >> -	else
> >> -		vgic_v3_get_vmcr(vcpu, vmcr);
> >> -}
> >> -
> >>  #define GICC_ARCH_VERSION_V2	0x2
> >>  
> >>  /* These are for userland accesses only, there is no guest-facing emulation. */
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> >> index 0d1bc98..f81e0e5 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> >> @@ -416,6 +416,22 @@ int vgic_validate_mmio_region_addr(struct kvm_device *dev,
> >>  	return -ENXIO;
> >>  }
> >>  
> >> +void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> >> +{
> >> +	if (kvm_vgic_global_state.type == VGIC_V2)
> >> +		vgic_v2_set_vmcr(vcpu, vmcr);
> >> +	else
> >> +		vgic_v3_set_vmcr(vcpu, vmcr);
> >> +}
> >> +
> >> +void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> >> +{
> >> +	if (kvm_vgic_global_state.type == VGIC_V2)
> >> +		vgic_v2_get_vmcr(vcpu, vmcr);
> >> +	else
> >> +		vgic_v3_get_vmcr(vcpu, vmcr);
> >> +}
> >> +
> >>  /*
> >>   * kvm_mmio_read_buf() returns a value in a format where it can be converted
> >>   * to a byte array and be directly observed as the guest wanted it to appear
> >> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> >> index 9f0dae3..a3ff04b 100644
> >> --- a/virt/kvm/arm/vgic/vgic-v3.c
> >> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> >> @@ -175,10 +175,19 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
> >>  {
> >>  	u32 vmcr;
> >>  
> >> -	vmcr  = (vmcrp->ctlr << ICH_VMCR_CTLR_SHIFT) & ICH_VMCR_CTLR_MASK;
> >> +	/*
> >> +	 * Ignore the FIQen bit, because GIC emulation always implies
> >> +	 * SRE=1 which means the vFIQEn bit is also RES1.
> >> +	 */
> >> +	vmcr = (vmcrp->ctlr & ICC_CTLR_EL1_EOImode_MASK) >>
> >> +		ICC_CTLR_EL1_EOImode_SHIFT;
> >> +	vmcr = (vmcr << ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;

> I am not able to understand why we use ICC_CTLR _*macros here? Please
> could you explain it to me? Besides if we want to ignore the FIQen bit
> can't we change the ICH_VMCR_CTLR_MASK value?
> 
This first statement is setting the vmcr to the ctlr's bit[1], but
placed in bit[0], and then the next statement is moving that bit value
to the corresponding place in the vmcr.  I think this is correct
(although a little opaque).

There's also a newer series on the list, just so you know.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 05/11] arm/arm64: vgic: Introduce VENG0 and VENG1 fields to vmcr struct
@ 2016-12-08 12:21         ` Christoffer Dall
  0 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-12-08 12:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Dec 08, 2016 at 12:52:39PM +0100, Auger Eric wrote:
> Hi Vijay,
> 
> On 28/11/2016 15:28, Christoffer Dall wrote:
> > On Wed, Nov 23, 2016 at 06:31:52PM +0530, vijay.kilari at gmail.com wrote:
> >> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >>
> >> ICC_VMCR_EL2 supports virtual access to ICC_IGRPEN1_EL1.Enable
> >> and ICC_IGRPEN0_EL1.Enable fields. Add grpen0 and grpen1 member
> >> variables to struct vmcr to support read and write of these fields.
> >>
> >> Also refactor vgic_set_vmcr and vgic_get_vmcr() code.
> >> Drop ICH_VMCR_CTLR_SHIFT and ICH_VMCR_CTLR_MASK macros and instead
> >> use ICH_VMCR_EOI* and ICH_VMCR_CBPR* macros
> >> .
> >> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >> ---
> >>  include/linux/irqchip/arm-gic-v3.h |  2 --
> >>  virt/kvm/arm/vgic/vgic-mmio-v2.c   | 16 ----------------
> >>  virt/kvm/arm/vgic/vgic-mmio.c      | 16 ++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic-v3.c        | 22 ++++++++++++++++++++--
> >>  virt/kvm/arm/vgic/vgic.h           |  5 +++++
> >>  5 files changed, 41 insertions(+), 20 deletions(-)
> >>
> >> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> >> index b4f8287..406fc3e 100644
> >> --- a/include/linux/irqchip/arm-gic-v3.h
> >> +++ b/include/linux/irqchip/arm-gic-v3.h
> >> @@ -404,8 +404,6 @@
> >>  #define ICH_HCR_EN			(1 << 0)
> >>  #define ICH_HCR_UIE			(1 << 1)
> >>  
> >> -#define ICH_VMCR_CTLR_SHIFT		0
> >> -#define ICH_VMCR_CTLR_MASK		(0x21f << ICH_VMCR_CTLR_SHIFT)
> >>  #define ICH_VMCR_CBPR_SHIFT		4
> >>  #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
> >>  #define ICH_VMCR_EOIM_SHIFT		9
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> index 2cb04b7..ad353b5 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> @@ -212,22 +212,6 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
> >>  	}
> >>  }
> >>  
> >> -static void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> >> -{
> >> -	if (kvm_vgic_global_state.type == VGIC_V2)
> >> -		vgic_v2_set_vmcr(vcpu, vmcr);
> >> -	else
> >> -		vgic_v3_set_vmcr(vcpu, vmcr);
> >> -}
> >> -
> >> -static void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> >> -{
> >> -	if (kvm_vgic_global_state.type == VGIC_V2)
> >> -		vgic_v2_get_vmcr(vcpu, vmcr);
> >> -	else
> >> -		vgic_v3_get_vmcr(vcpu, vmcr);
> >> -}
> >> -
> >>  #define GICC_ARCH_VERSION_V2	0x2
> >>  
> >>  /* These are for userland accesses only, there is no guest-facing emulation. */
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> >> index 0d1bc98..f81e0e5 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> >> @@ -416,6 +416,22 @@ int vgic_validate_mmio_region_addr(struct kvm_device *dev,
> >>  	return -ENXIO;
> >>  }
> >>  
> >> +void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> >> +{
> >> +	if (kvm_vgic_global_state.type == VGIC_V2)
> >> +		vgic_v2_set_vmcr(vcpu, vmcr);
> >> +	else
> >> +		vgic_v3_set_vmcr(vcpu, vmcr);
> >> +}
> >> +
> >> +void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> >> +{
> >> +	if (kvm_vgic_global_state.type == VGIC_V2)
> >> +		vgic_v2_get_vmcr(vcpu, vmcr);
> >> +	else
> >> +		vgic_v3_get_vmcr(vcpu, vmcr);
> >> +}
> >> +
> >>  /*
> >>   * kvm_mmio_read_buf() returns a value in a format where it can be converted
> >>   * to a byte array and be directly observed as the guest wanted it to appear
> >> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> >> index 9f0dae3..a3ff04b 100644
> >> --- a/virt/kvm/arm/vgic/vgic-v3.c
> >> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> >> @@ -175,10 +175,19 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
> >>  {
> >>  	u32 vmcr;
> >>  
> >> -	vmcr  = (vmcrp->ctlr << ICH_VMCR_CTLR_SHIFT) & ICH_VMCR_CTLR_MASK;
> >> +	/*
> >> +	 * Ignore the FIQen bit, because GIC emulation always implies
> >> +	 * SRE=1 which means the vFIQEn bit is also RES1.
> >> +	 */
> >> +	vmcr = (vmcrp->ctlr & ICC_CTLR_EL1_EOImode_MASK) >>
> >> +		ICC_CTLR_EL1_EOImode_SHIFT;
> >> +	vmcr = (vmcr << ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;

> I am not able to understand why we use ICC_CTLR _*macros here? Please
> could you explain it to me? Besides if we want to ignore the FIQen bit
> can't we change the ICH_VMCR_CTLR_MASK value?
> 
This first statement is setting the vmcr to the ctlr's bit[1], but
placed in bit[0], and then the next statement is moving that bit value
to the corresponding place in the vmcr.  I think this is correct
(although a little opaque).

There's also a newer series on the list, just so you know.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 05/11] arm/arm64: vgic: Introduce VENG0 and VENG1 fields to vmcr struct
  2016-12-08 12:21         ` Christoffer Dall
@ 2016-12-08 12:50           ` Auger Eric
  -1 siblings, 0 replies; 78+ messages in thread
From: Auger Eric @ 2016-12-08 12:50 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: marc.zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

Hi Christoffer,

On 08/12/2016 13:21, Christoffer Dall wrote:
> On Thu, Dec 08, 2016 at 12:52:39PM +0100, Auger Eric wrote:
>> Hi Vijay,
>>
>> On 28/11/2016 15:28, Christoffer Dall wrote:
>>> On Wed, Nov 23, 2016 at 06:31:52PM +0530, vijay.kilari@gmail.com wrote:
>>>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>>>
>>>> ICC_VMCR_EL2 supports virtual access to ICC_IGRPEN1_EL1.Enable
>>>> and ICC_IGRPEN0_EL1.Enable fields. Add grpen0 and grpen1 member
>>>> variables to struct vmcr to support read and write of these fields.
>>>>
>>>> Also refactor vgic_set_vmcr and vgic_get_vmcr() code.
>>>> Drop ICH_VMCR_CTLR_SHIFT and ICH_VMCR_CTLR_MASK macros and instead
>>>> use ICH_VMCR_EOI* and ICH_VMCR_CBPR* macros
>>>> .
>>>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>>> ---
>>>>  include/linux/irqchip/arm-gic-v3.h |  2 --
>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c   | 16 ----------------
>>>>  virt/kvm/arm/vgic/vgic-mmio.c      | 16 ++++++++++++++++
>>>>  virt/kvm/arm/vgic/vgic-v3.c        | 22 ++++++++++++++++++++--
>>>>  virt/kvm/arm/vgic/vgic.h           |  5 +++++
>>>>  5 files changed, 41 insertions(+), 20 deletions(-)
>>>>
>>>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
>>>> index b4f8287..406fc3e 100644
>>>> --- a/include/linux/irqchip/arm-gic-v3.h
>>>> +++ b/include/linux/irqchip/arm-gic-v3.h
>>>> @@ -404,8 +404,6 @@
>>>>  #define ICH_HCR_EN			(1 << 0)
>>>>  #define ICH_HCR_UIE			(1 << 1)
>>>>  
>>>> -#define ICH_VMCR_CTLR_SHIFT		0
>>>> -#define ICH_VMCR_CTLR_MASK		(0x21f << ICH_VMCR_CTLR_SHIFT)
>>>>  #define ICH_VMCR_CBPR_SHIFT		4
>>>>  #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
>>>>  #define ICH_VMCR_EOIM_SHIFT		9
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> index 2cb04b7..ad353b5 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> @@ -212,22 +212,6 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
>>>>  	}
>>>>  }
>>>>  
>>>> -static void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>>>> -{
>>>> -	if (kvm_vgic_global_state.type == VGIC_V2)
>>>> -		vgic_v2_set_vmcr(vcpu, vmcr);
>>>> -	else
>>>> -		vgic_v3_set_vmcr(vcpu, vmcr);
>>>> -}
>>>> -
>>>> -static void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>>>> -{
>>>> -	if (kvm_vgic_global_state.type == VGIC_V2)
>>>> -		vgic_v2_get_vmcr(vcpu, vmcr);
>>>> -	else
>>>> -		vgic_v3_get_vmcr(vcpu, vmcr);
>>>> -}
>>>> -
>>>>  #define GICC_ARCH_VERSION_V2	0x2
>>>>  
>>>>  /* These are for userland accesses only, there is no guest-facing emulation. */
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>>>> index 0d1bc98..f81e0e5 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>>>> @@ -416,6 +416,22 @@ int vgic_validate_mmio_region_addr(struct kvm_device *dev,
>>>>  	return -ENXIO;
>>>>  }
>>>>  
>>>> +void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>>>> +{
>>>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>>>> +		vgic_v2_set_vmcr(vcpu, vmcr);
>>>> +	else
>>>> +		vgic_v3_set_vmcr(vcpu, vmcr);
>>>> +}
>>>> +
>>>> +void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>>>> +{
>>>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>>>> +		vgic_v2_get_vmcr(vcpu, vmcr);
>>>> +	else
>>>> +		vgic_v3_get_vmcr(vcpu, vmcr);
>>>> +}
>>>> +
>>>>  /*
>>>>   * kvm_mmio_read_buf() returns a value in a format where it can be converted
>>>>   * to a byte array and be directly observed as the guest wanted it to appear
>>>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>>>> index 9f0dae3..a3ff04b 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-v3.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>>>> @@ -175,10 +175,19 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>>>>  {
>>>>  	u32 vmcr;
>>>>  
>>>> -	vmcr  = (vmcrp->ctlr << ICH_VMCR_CTLR_SHIFT) & ICH_VMCR_CTLR_MASK;
>>>> +	/*
>>>> +	 * Ignore the FIQen bit, because GIC emulation always implies
>>>> +	 * SRE=1 which means the vFIQEn bit is also RES1.
>>>> +	 */
>>>> +	vmcr = (vmcrp->ctlr & ICC_CTLR_EL1_EOImode_MASK) >>
>>>> +		ICC_CTLR_EL1_EOImode_SHIFT;
>>>> +	vmcr = (vmcr << ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;
> 
>> I am not able to understand why we use ICC_CTLR _*macros here? Please
>> could you explain it to me? Besides if we want to ignore the FIQen bit
>> can't we change the ICH_VMCR_CTLR_MASK value?
>>
> This first statement is setting the vmcr to the ctlr's bit[1], but
> placed in bit[0], and then the next statement is moving that bit value
> to the corresponding place in the vmcr.  I think this is correct
> (although a little opaque).
Yes the question was more about the semantic of the vmcrp->ctlr field. I
thought it was supposed to store ICH_VMCR_EL2 ctrl bits as they are and
not with a different layout.
> 
> There's also a newer series on the list, just so you know.

Argh OK I missed it. I will check the diffs in the AArch64 related patches.

Thanks

Eric
> 
> Thanks,
> -Christoffer
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 05/11] arm/arm64: vgic: Introduce VENG0 and VENG1 fields to vmcr struct
@ 2016-12-08 12:50           ` Auger Eric
  0 siblings, 0 replies; 78+ messages in thread
From: Auger Eric @ 2016-12-08 12:50 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoffer,

On 08/12/2016 13:21, Christoffer Dall wrote:
> On Thu, Dec 08, 2016 at 12:52:39PM +0100, Auger Eric wrote:
>> Hi Vijay,
>>
>> On 28/11/2016 15:28, Christoffer Dall wrote:
>>> On Wed, Nov 23, 2016 at 06:31:52PM +0530, vijay.kilari at gmail.com wrote:
>>>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>>>
>>>> ICC_VMCR_EL2 supports virtual access to ICC_IGRPEN1_EL1.Enable
>>>> and ICC_IGRPEN0_EL1.Enable fields. Add grpen0 and grpen1 member
>>>> variables to struct vmcr to support read and write of these fields.
>>>>
>>>> Also refactor vgic_set_vmcr and vgic_get_vmcr() code.
>>>> Drop ICH_VMCR_CTLR_SHIFT and ICH_VMCR_CTLR_MASK macros and instead
>>>> use ICH_VMCR_EOI* and ICH_VMCR_CBPR* macros
>>>> .
>>>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>>> ---
>>>>  include/linux/irqchip/arm-gic-v3.h |  2 --
>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c   | 16 ----------------
>>>>  virt/kvm/arm/vgic/vgic-mmio.c      | 16 ++++++++++++++++
>>>>  virt/kvm/arm/vgic/vgic-v3.c        | 22 ++++++++++++++++++++--
>>>>  virt/kvm/arm/vgic/vgic.h           |  5 +++++
>>>>  5 files changed, 41 insertions(+), 20 deletions(-)
>>>>
>>>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
>>>> index b4f8287..406fc3e 100644
>>>> --- a/include/linux/irqchip/arm-gic-v3.h
>>>> +++ b/include/linux/irqchip/arm-gic-v3.h
>>>> @@ -404,8 +404,6 @@
>>>>  #define ICH_HCR_EN			(1 << 0)
>>>>  #define ICH_HCR_UIE			(1 << 1)
>>>>  
>>>> -#define ICH_VMCR_CTLR_SHIFT		0
>>>> -#define ICH_VMCR_CTLR_MASK		(0x21f << ICH_VMCR_CTLR_SHIFT)
>>>>  #define ICH_VMCR_CBPR_SHIFT		4
>>>>  #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
>>>>  #define ICH_VMCR_EOIM_SHIFT		9
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> index 2cb04b7..ad353b5 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> @@ -212,22 +212,6 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
>>>>  	}
>>>>  }
>>>>  
>>>> -static void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>>>> -{
>>>> -	if (kvm_vgic_global_state.type == VGIC_V2)
>>>> -		vgic_v2_set_vmcr(vcpu, vmcr);
>>>> -	else
>>>> -		vgic_v3_set_vmcr(vcpu, vmcr);
>>>> -}
>>>> -
>>>> -static void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>>>> -{
>>>> -	if (kvm_vgic_global_state.type == VGIC_V2)
>>>> -		vgic_v2_get_vmcr(vcpu, vmcr);
>>>> -	else
>>>> -		vgic_v3_get_vmcr(vcpu, vmcr);
>>>> -}
>>>> -
>>>>  #define GICC_ARCH_VERSION_V2	0x2
>>>>  
>>>>  /* These are for userland accesses only, there is no guest-facing emulation. */
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>>>> index 0d1bc98..f81e0e5 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>>>> @@ -416,6 +416,22 @@ int vgic_validate_mmio_region_addr(struct kvm_device *dev,
>>>>  	return -ENXIO;
>>>>  }
>>>>  
>>>> +void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>>>> +{
>>>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>>>> +		vgic_v2_set_vmcr(vcpu, vmcr);
>>>> +	else
>>>> +		vgic_v3_set_vmcr(vcpu, vmcr);
>>>> +}
>>>> +
>>>> +void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>>>> +{
>>>> +	if (kvm_vgic_global_state.type == VGIC_V2)
>>>> +		vgic_v2_get_vmcr(vcpu, vmcr);
>>>> +	else
>>>> +		vgic_v3_get_vmcr(vcpu, vmcr);
>>>> +}
>>>> +
>>>>  /*
>>>>   * kvm_mmio_read_buf() returns a value in a format where it can be converted
>>>>   * to a byte array and be directly observed as the guest wanted it to appear
>>>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>>>> index 9f0dae3..a3ff04b 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-v3.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>>>> @@ -175,10 +175,19 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>>>>  {
>>>>  	u32 vmcr;
>>>>  
>>>> -	vmcr  = (vmcrp->ctlr << ICH_VMCR_CTLR_SHIFT) & ICH_VMCR_CTLR_MASK;
>>>> +	/*
>>>> +	 * Ignore the FIQen bit, because GIC emulation always implies
>>>> +	 * SRE=1 which means the vFIQEn bit is also RES1.
>>>> +	 */
>>>> +	vmcr = (vmcrp->ctlr & ICC_CTLR_EL1_EOImode_MASK) >>
>>>> +		ICC_CTLR_EL1_EOImode_SHIFT;
>>>> +	vmcr = (vmcr << ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;
> 
>> I am not able to understand why we use ICC_CTLR _*macros here? Please
>> could you explain it to me? Besides if we want to ignore the FIQen bit
>> can't we change the ICH_VMCR_CTLR_MASK value?
>>
> This first statement is setting the vmcr to the ctlr's bit[1], but
> placed in bit[0], and then the next statement is moving that bit value
> to the corresponding place in the vmcr.  I think this is correct
> (although a little opaque).
Yes the question was more about the semantic of the vmcrp->ctlr field. I
thought it was supposed to store ICH_VMCR_EL2 ctrl bits as they are and
not with a different layout.
> 
> There's also a newer series on the list, just so you know.

Argh OK I missed it. I will check the diffs in the AArch64 related patches.

Thanks

Eric
> 
> Thanks,
> -Christoffer
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 05/11] arm/arm64: vgic: Introduce VENG0 and VENG1 fields to vmcr struct
  2016-12-08 12:50           ` Auger Eric
@ 2016-12-11 16:38             ` Christoffer Dall
  -1 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-12-11 16:38 UTC (permalink / raw)
  To: Auger Eric; +Cc: marc.zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

On Thu, Dec 08, 2016 at 01:50:43PM +0100, Auger Eric wrote:
> Hi Christoffer,
> 
> On 08/12/2016 13:21, Christoffer Dall wrote:
> > On Thu, Dec 08, 2016 at 12:52:39PM +0100, Auger Eric wrote:
> >> Hi Vijay,
> >>
> >> On 28/11/2016 15:28, Christoffer Dall wrote:
> >>> On Wed, Nov 23, 2016 at 06:31:52PM +0530, vijay.kilari@gmail.com wrote:
> >>>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >>>>
> >>>> ICC_VMCR_EL2 supports virtual access to ICC_IGRPEN1_EL1.Enable
> >>>> and ICC_IGRPEN0_EL1.Enable fields. Add grpen0 and grpen1 member
> >>>> variables to struct vmcr to support read and write of these fields.
> >>>>
> >>>> Also refactor vgic_set_vmcr and vgic_get_vmcr() code.
> >>>> Drop ICH_VMCR_CTLR_SHIFT and ICH_VMCR_CTLR_MASK macros and instead
> >>>> use ICH_VMCR_EOI* and ICH_VMCR_CBPR* macros
> >>>> .
> >>>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >>>> ---
> >>>>  include/linux/irqchip/arm-gic-v3.h |  2 --
> >>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c   | 16 ----------------
> >>>>  virt/kvm/arm/vgic/vgic-mmio.c      | 16 ++++++++++++++++
> >>>>  virt/kvm/arm/vgic/vgic-v3.c        | 22 ++++++++++++++++++++--
> >>>>  virt/kvm/arm/vgic/vgic.h           |  5 +++++
> >>>>  5 files changed, 41 insertions(+), 20 deletions(-)
> >>>>
> >>>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> >>>> index b4f8287..406fc3e 100644
> >>>> --- a/include/linux/irqchip/arm-gic-v3.h
> >>>> +++ b/include/linux/irqchip/arm-gic-v3.h
> >>>> @@ -404,8 +404,6 @@
> >>>>  #define ICH_HCR_EN			(1 << 0)
> >>>>  #define ICH_HCR_UIE			(1 << 1)
> >>>>  
> >>>> -#define ICH_VMCR_CTLR_SHIFT		0
> >>>> -#define ICH_VMCR_CTLR_MASK		(0x21f << ICH_VMCR_CTLR_SHIFT)
> >>>>  #define ICH_VMCR_CBPR_SHIFT		4
> >>>>  #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
> >>>>  #define ICH_VMCR_EOIM_SHIFT		9
> >>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> index 2cb04b7..ad353b5 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> @@ -212,22 +212,6 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
> >>>>  	}
> >>>>  }
> >>>>  
> >>>> -static void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> >>>> -{
> >>>> -	if (kvm_vgic_global_state.type == VGIC_V2)
> >>>> -		vgic_v2_set_vmcr(vcpu, vmcr);
> >>>> -	else
> >>>> -		vgic_v3_set_vmcr(vcpu, vmcr);
> >>>> -}
> >>>> -
> >>>> -static void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> >>>> -{
> >>>> -	if (kvm_vgic_global_state.type == VGIC_V2)
> >>>> -		vgic_v2_get_vmcr(vcpu, vmcr);
> >>>> -	else
> >>>> -		vgic_v3_get_vmcr(vcpu, vmcr);
> >>>> -}
> >>>> -
> >>>>  #define GICC_ARCH_VERSION_V2	0x2
> >>>>  
> >>>>  /* These are for userland accesses only, there is no guest-facing emulation. */
> >>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> >>>> index 0d1bc98..f81e0e5 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> >>>> @@ -416,6 +416,22 @@ int vgic_validate_mmio_region_addr(struct kvm_device *dev,
> >>>>  	return -ENXIO;
> >>>>  }
> >>>>  
> >>>> +void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> >>>> +{
> >>>> +	if (kvm_vgic_global_state.type == VGIC_V2)
> >>>> +		vgic_v2_set_vmcr(vcpu, vmcr);
> >>>> +	else
> >>>> +		vgic_v3_set_vmcr(vcpu, vmcr);
> >>>> +}
> >>>> +
> >>>> +void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> >>>> +{
> >>>> +	if (kvm_vgic_global_state.type == VGIC_V2)
> >>>> +		vgic_v2_get_vmcr(vcpu, vmcr);
> >>>> +	else
> >>>> +		vgic_v3_get_vmcr(vcpu, vmcr);
> >>>> +}
> >>>> +
> >>>>  /*
> >>>>   * kvm_mmio_read_buf() returns a value in a format where it can be converted
> >>>>   * to a byte array and be directly observed as the guest wanted it to appear
> >>>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> >>>> index 9f0dae3..a3ff04b 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic-v3.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> >>>> @@ -175,10 +175,19 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
> >>>>  {
> >>>>  	u32 vmcr;
> >>>>  
> >>>> -	vmcr  = (vmcrp->ctlr << ICH_VMCR_CTLR_SHIFT) & ICH_VMCR_CTLR_MASK;
> >>>> +	/*
> >>>> +	 * Ignore the FIQen bit, because GIC emulation always implies
> >>>> +	 * SRE=1 which means the vFIQEn bit is also RES1.
> >>>> +	 */
> >>>> +	vmcr = (vmcrp->ctlr & ICC_CTLR_EL1_EOImode_MASK) >>
> >>>> +		ICC_CTLR_EL1_EOImode_SHIFT;
> >>>> +	vmcr = (vmcr << ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;
> > 
> >> I am not able to understand why we use ICC_CTLR _*macros here? Please
> >> could you explain it to me? Besides if we want to ignore the FIQen bit
> >> can't we change the ICH_VMCR_CTLR_MASK value?
> >>
> > This first statement is setting the vmcr to the ctlr's bit[1], but
> > placed in bit[0], and then the next statement is moving that bit value
> > to the corresponding place in the vmcr.  I think this is correct
> > (although a little opaque).
> Yes the question was more about the semantic of the vmcrp->ctlr field. I
> thought it was supposed to store ICH_VMCR_EL2 ctrl bits as they are and
> not with a different layout.

my understanding is that vmcrp->ctlr is a representation of the
GICC_CTLR field and its bit layout (based on the existin v2 code, unless
I misread it) and the vmcr is the vmcr field.

I don't care much either way, as long as it's clear what the semantics
are.  One problem with storing parts of the VMCR in the vmcrp->ctlr
field is that I don't think there's an architectural definition of the
concept 'ICH_VMCR_EL2 ctrl bits'.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 05/11] arm/arm64: vgic: Introduce VENG0 and VENG1 fields to vmcr struct
@ 2016-12-11 16:38             ` Christoffer Dall
  0 siblings, 0 replies; 78+ messages in thread
From: Christoffer Dall @ 2016-12-11 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Dec 08, 2016 at 01:50:43PM +0100, Auger Eric wrote:
> Hi Christoffer,
> 
> On 08/12/2016 13:21, Christoffer Dall wrote:
> > On Thu, Dec 08, 2016 at 12:52:39PM +0100, Auger Eric wrote:
> >> Hi Vijay,
> >>
> >> On 28/11/2016 15:28, Christoffer Dall wrote:
> >>> On Wed, Nov 23, 2016 at 06:31:52PM +0530, vijay.kilari at gmail.com wrote:
> >>>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >>>>
> >>>> ICC_VMCR_EL2 supports virtual access to ICC_IGRPEN1_EL1.Enable
> >>>> and ICC_IGRPEN0_EL1.Enable fields. Add grpen0 and grpen1 member
> >>>> variables to struct vmcr to support read and write of these fields.
> >>>>
> >>>> Also refactor vgic_set_vmcr and vgic_get_vmcr() code.
> >>>> Drop ICH_VMCR_CTLR_SHIFT and ICH_VMCR_CTLR_MASK macros and instead
> >>>> use ICH_VMCR_EOI* and ICH_VMCR_CBPR* macros
> >>>> .
> >>>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
> >>>> ---
> >>>>  include/linux/irqchip/arm-gic-v3.h |  2 --
> >>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c   | 16 ----------------
> >>>>  virt/kvm/arm/vgic/vgic-mmio.c      | 16 ++++++++++++++++
> >>>>  virt/kvm/arm/vgic/vgic-v3.c        | 22 ++++++++++++++++++++--
> >>>>  virt/kvm/arm/vgic/vgic.h           |  5 +++++
> >>>>  5 files changed, 41 insertions(+), 20 deletions(-)
> >>>>
> >>>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> >>>> index b4f8287..406fc3e 100644
> >>>> --- a/include/linux/irqchip/arm-gic-v3.h
> >>>> +++ b/include/linux/irqchip/arm-gic-v3.h
> >>>> @@ -404,8 +404,6 @@
> >>>>  #define ICH_HCR_EN			(1 << 0)
> >>>>  #define ICH_HCR_UIE			(1 << 1)
> >>>>  
> >>>> -#define ICH_VMCR_CTLR_SHIFT		0
> >>>> -#define ICH_VMCR_CTLR_MASK		(0x21f << ICH_VMCR_CTLR_SHIFT)
> >>>>  #define ICH_VMCR_CBPR_SHIFT		4
> >>>>  #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
> >>>>  #define ICH_VMCR_EOIM_SHIFT		9
> >>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> index 2cb04b7..ad353b5 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> @@ -212,22 +212,6 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
> >>>>  	}
> >>>>  }
> >>>>  
> >>>> -static void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> >>>> -{
> >>>> -	if (kvm_vgic_global_state.type == VGIC_V2)
> >>>> -		vgic_v2_set_vmcr(vcpu, vmcr);
> >>>> -	else
> >>>> -		vgic_v3_set_vmcr(vcpu, vmcr);
> >>>> -}
> >>>> -
> >>>> -static void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> >>>> -{
> >>>> -	if (kvm_vgic_global_state.type == VGIC_V2)
> >>>> -		vgic_v2_get_vmcr(vcpu, vmcr);
> >>>> -	else
> >>>> -		vgic_v3_get_vmcr(vcpu, vmcr);
> >>>> -}
> >>>> -
> >>>>  #define GICC_ARCH_VERSION_V2	0x2
> >>>>  
> >>>>  /* These are for userland accesses only, there is no guest-facing emulation. */
> >>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> >>>> index 0d1bc98..f81e0e5 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> >>>> @@ -416,6 +416,22 @@ int vgic_validate_mmio_region_addr(struct kvm_device *dev,
> >>>>  	return -ENXIO;
> >>>>  }
> >>>>  
> >>>> +void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> >>>> +{
> >>>> +	if (kvm_vgic_global_state.type == VGIC_V2)
> >>>> +		vgic_v2_set_vmcr(vcpu, vmcr);
> >>>> +	else
> >>>> +		vgic_v3_set_vmcr(vcpu, vmcr);
> >>>> +}
> >>>> +
> >>>> +void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> >>>> +{
> >>>> +	if (kvm_vgic_global_state.type == VGIC_V2)
> >>>> +		vgic_v2_get_vmcr(vcpu, vmcr);
> >>>> +	else
> >>>> +		vgic_v3_get_vmcr(vcpu, vmcr);
> >>>> +}
> >>>> +
> >>>>  /*
> >>>>   * kvm_mmio_read_buf() returns a value in a format where it can be converted
> >>>>   * to a byte array and be directly observed as the guest wanted it to appear
> >>>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> >>>> index 9f0dae3..a3ff04b 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic-v3.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> >>>> @@ -175,10 +175,19 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
> >>>>  {
> >>>>  	u32 vmcr;
> >>>>  
> >>>> -	vmcr  = (vmcrp->ctlr << ICH_VMCR_CTLR_SHIFT) & ICH_VMCR_CTLR_MASK;
> >>>> +	/*
> >>>> +	 * Ignore the FIQen bit, because GIC emulation always implies
> >>>> +	 * SRE=1 which means the vFIQEn bit is also RES1.
> >>>> +	 */
> >>>> +	vmcr = (vmcrp->ctlr & ICC_CTLR_EL1_EOImode_MASK) >>
> >>>> +		ICC_CTLR_EL1_EOImode_SHIFT;
> >>>> +	vmcr = (vmcr << ICH_VMCR_EOIM_SHIFT) & ICH_VMCR_EOIM_MASK;
> > 
> >> I am not able to understand why we use ICC_CTLR _*macros here? Please
> >> could you explain it to me? Besides if we want to ignore the FIQen bit
> >> can't we change the ICH_VMCR_CTLR_MASK value?
> >>
> > This first statement is setting the vmcr to the ctlr's bit[1], but
> > placed in bit[0], and then the next statement is moving that bit value
> > to the corresponding place in the vmcr.  I think this is correct
> > (although a little opaque).
> Yes the question was more about the semantic of the vmcrp->ctlr field. I
> thought it was supposed to store ICH_VMCR_EL2 ctrl bits as they are and
> not with a different layout.

my understanding is that vmcrp->ctlr is a representation of the
GICC_CTLR field and its bit layout (based on the existin v2 code, unless
I misread it) and the vmcr is the vmcr field.

I don't care much either way, as long as it's clear what the semantics
are.  One problem with storing parts of the VMCR in the vmcrp->ctlr
field is that I don't think there's an architectural definition of the
concept 'ICH_VMCR_EL2 ctrl bits'.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 01/11] arm/arm64: vgic: Implement support for userspace access
  2016-12-06 11:42       ` Auger Eric
@ 2016-12-15  7:36         ` Vijay Kilari
  -1 siblings, 0 replies; 78+ messages in thread
From: Vijay Kilari @ 2016-12-15  7:36 UTC (permalink / raw)
  To: Auger Eric; +Cc: Marc Zyngier, Vijaya Kumar K, linux-arm-kernel, kvmarm

On Tue, Dec 6, 2016 at 5:12 PM, Auger Eric <eric.auger@redhat.com> wrote:
> Hi,
>
> On 28/11/2016 14:05, Christoffer Dall wrote:
>> On Wed, Nov 23, 2016 at 06:31:48PM +0530, vijay.kilari@gmail.com wrote:
>>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>>
>>> Read and write of some registers like ISPENDR and ICPENDR
>>> from userspace requires special handling when compared to
>>> guest access for these registers.
>>>
>>> Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
>>> for handling of ISPENDR, ICPENDR registers handling.
>>>
>>> Add infrastructure to support guest and userspace read
>>> and write for the required registers
>>> Also moved vgic_uaccess from vgic-mmio-v2.c to vgic-mmio.c
>>>
>>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>> ---
>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  25 ----------
>>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 102 ++++++++++++++++++++++++++++++++-------
>>>  virt/kvm/arm/vgic/vgic-mmio.c    |  78 +++++++++++++++++++++++++++---
>>>  virt/kvm/arm/vgic/vgic-mmio.h    |  19 ++++++++
>>>  4 files changed, 175 insertions(+), 49 deletions(-)
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> index b44b359..0b32f40 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> @@ -406,31 +406,6 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>>>      return -ENXIO;
>>>  }
>>>
>>> -/*
>>> - * When userland tries to access the VGIC register handlers, we need to
>>> - * create a usable struct vgic_io_device to be passed to the handlers and we
>>> - * have to set up a buffer similar to what would have happened if a guest MMIO
>>> - * access occurred, including doing endian conversions on BE systems.
>>> - */
>>> -static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>>> -                    bool is_write, int offset, u32 *val)
>>> -{
>>> -    unsigned int len = 4;
>>> -    u8 buf[4];
>>> -    int ret;
>>> -
>>> -    if (is_write) {
>>> -            vgic_data_host_to_mmio_bus(buf, len, *val);
>>> -            ret = kvm_io_gic_ops.write(vcpu, &dev->dev, offset, len, buf);
>>> -    } else {
>>> -            ret = kvm_io_gic_ops.read(vcpu, &dev->dev, offset, len, buf);
>>> -            if (!ret)
>>> -                    *val = vgic_data_mmio_bus_to_host(buf, len);
>>> -    }
>>> -
>>> -    return ret;
>>> -}
>>> -
>>>  int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>>                        int offset, u32 *val)
>>>  {
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>> index 50f42f0..8e76d04 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>> @@ -207,6 +207,66 @@ static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
>>>      return 0;
>>>  }
>>>
>>> +static unsigned long vgic_v3_uaccess_read_pending(struct kvm_vcpu *vcpu,
>>> +                                              gpa_t addr, unsigned int len)
>>> +{
>>> +    u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
>>> +    u32 value = 0;
>>> +    int i;
>>> +
>>> +    /*
>>> +     * A level triggerred interrupt pending state is latched in both
>>> +     * "soft_pending" and "line_level" variables. Userspace will save
>>> +     * and restore soft_pending and line_level separately.
>>> +     * Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
>>> +     * handling of ISPENDR and ICPENDR.
>>> +     */
>>> +    for (i = 0; i < len * 8; i++) {
>>> +            struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>>> +
>>> +            if (irq->config == VGIC_CONFIG_LEVEL && irq->soft_pending)
>>> +                    value |= (1U << i);
>>> +            if (irq->config == VGIC_CONFIG_EDGE && irq->pending)
>>> +                    value |= (1U << i);
>>> +
>>> +            vgic_put_irq(vcpu->kvm, irq);
>>> +    }
>>> +
>>> +    return value;
>>> +}
>>> +
>>> +static void vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu,
>>> +                                      gpa_t addr, unsigned int len,
>>> +                                      unsigned long val)
>>> +{
>>> +    u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
>>> +    int i;
>>> +
>>> +    for (i = 0; i < len * 8; i++) {
>>> +            struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>>> +
>>> +            spin_lock(&irq->irq_lock);
>>> +            if (test_bit(i, &val)) {
>>> +                    /* soft_pending is set irrespective of irq type
>>> +                     * (level or edge) to avoid dependency that VM should
>>> +                     * restore irq config before pending info.
>>> +                     */
>>
>> nit: kernel commenting style
>>
>>> +                    irq->pending = true;
>>> +                    irq->soft_pending = true;
>>> +                    vgic_queue_irq_unlock(vcpu->kvm, irq);
>>> +            } else {
>>> +                    irq->soft_pending = false;
>>> +                    if (irq->config == VGIC_CONFIG_EDGE ||
>>> +                        (irq->config == VGIC_CONFIG_LEVEL &&
>>> +                        !irq->line_level))
>>> +                            irq->pending = false;
> I am confused by the comment above. Since we test the irq config here
> don't we assume the config was restored before the pending state?
>>> +                    spin_unlock(&irq->irq_lock);
>>> +            }
>>> +
>>> +            vgic_put_irq(vcpu->kvm, irq);
>>> +    }
>>> +}
>>> +
>>>  /* We want to avoid outer shareable. */
>>>  u64 vgic_sanitise_shareability(u64 field)
>>>  {
>>> @@ -356,7 +416,7 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>>   * We take some special care here to fix the calculation of the register
>>>   * offset.
>>>   */
>>> -#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, bpi, acc)       \
>>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, ur, uw, bpi, acc) \
>>>      {                                                               \
>>>              .reg_offset = off,                                      \
>>>              .bits_per_irq = bpi,                                    \
>>> @@ -371,6 +431,8 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>>              .access_flags = acc,                                    \
>>>              .read = rd,                                             \
>>>              .write = wr,                                            \
>>> +            .uaccess_read = ur,                                     \
>>> +            .uaccess_write = uw,                                    \
>>>      }
>>>
>>>  static const struct vgic_register_region vgic_v3_dist_registers[] = {
>>> @@ -378,40 +440,42 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>>              vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>>> -            vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
>>> +            vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
>>> -            vgic_mmio_read_enable, vgic_mmio_write_senable, 1,
>>> +            vgic_mmio_read_enable, vgic_mmio_write_senable, NULL, NULL, 1,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
>>> -            vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
>>> +            vgic_mmio_read_enable, vgic_mmio_write_cenable, NULL, NULL, 1,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
>>> -            vgic_mmio_read_pending, vgic_mmio_write_spending, 1,
>>> +            vgic_mmio_read_pending, vgic_mmio_write_spending,
>>> +            vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 1,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
>>> -            vgic_mmio_read_pending, vgic_mmio_write_cpending, 1,
>>> +            vgic_mmio_read_pending, vgic_mmio_write_cpending,
>>> +            vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
>>> -            vgic_mmio_read_active, vgic_mmio_write_sactive, 1,
>>> +            vgic_mmio_read_active, vgic_mmio_write_sactive, NULL, NULL, 1,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
>>> -            vgic_mmio_read_active, vgic_mmio_write_cactive, 1,
>>> +            vgic_mmio_read_active, vgic_mmio_write_cactive, NULL, NULL, 1,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
>>> -            vgic_mmio_read_priority, vgic_mmio_write_priority, 8,
>>> -            VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>>> +            vgic_mmio_read_priority, vgic_mmio_write_priority, NULL, NULL,
>>> +            8, VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
>>> -            vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
>>> +            vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 8,
>>>              VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
>>> -            vgic_mmio_read_config, vgic_mmio_write_config, 2,
>>> +            vgic_mmio_read_config, vgic_mmio_write_config, NULL, NULL, 2,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
>>> -            vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>>> +            vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
>>> -            vgic_mmio_read_irouter, vgic_mmio_write_irouter, 64,
>>> +            vgic_mmio_read_irouter, vgic_mmio_write_irouter, NULL, NULL, 64,
>>>              VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>>>              vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48,
>>> @@ -449,11 +513,13 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>>      REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
>>>              vgic_mmio_read_enable, vgic_mmio_write_cenable, 4,
>>>              VGIC_ACCESS_32bit),
>>> -    REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
>>> -            vgic_mmio_read_pending, vgic_mmio_write_spending, 4,
>>> +    REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ISPENDR0,
>>> +            vgic_mmio_read_pending, vgic_mmio_write_spending,
>>> +            vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 4,
>>>              VGIC_ACCESS_32bit),
>>> -    REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
>>> -            vgic_mmio_read_pending, vgic_mmio_write_cpending, 4,
>>> +    REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ICPENDR0,
>>> +            vgic_mmio_read_pending, vgic_mmio_write_cpending,
>>> +            vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
>>>              vgic_mmio_read_active, vgic_mmio_write_sactive, 4,
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>>> index ebe1b9f..d5f3ee2 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>>> @@ -484,6 +484,74 @@ static bool check_region(const struct kvm *kvm,
>>>      return false;
>>>  }
>>>
>>> +static const struct vgic_register_region *
>>> +vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev,
>>> +                 gpa_t addr, int len)
>>> +{
>>> +    const struct vgic_register_region *region;
>>> +
>>> +    region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
>>> +                                   addr - iodev->base_addr);
>>> +    if (!region || !check_region(vcpu->kvm, region, addr, len))
>>> +            return NULL;
>>> +
>>> +    return region;
>>> +}
>>> +
>>> +static int vgic_uaccess_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>>> +                         gpa_t addr, u32 *val)
>>> +{
>>> +    struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
>>> +    const struct vgic_register_region *region;
>>> +    struct kvm_vcpu *r_vcpu;
>>> +
>>> +    region = vgic_get_mmio_region(vcpu, iodev, addr, sizeof(u32));
>>> +    if (!region) {
>>> +            *val = 0;
>>> +            return 0;
> do we really want to return 0 here? -ENXIO?
> I see that dispatch_mmio_read/write return 0 in that case but I don't
> see any reason either? Other kvm_io_device_ops seem to return
> -EOPNOTSUPP in such a case.

Yes, This was discussed and decided to fix it outside of this series.

https://www.spinics.net/lists/arm-kernel/msg533695.html

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 01/11] arm/arm64: vgic: Implement support for userspace access
@ 2016-12-15  7:36         ` Vijay Kilari
  0 siblings, 0 replies; 78+ messages in thread
From: Vijay Kilari @ 2016-12-15  7:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 6, 2016 at 5:12 PM, Auger Eric <eric.auger@redhat.com> wrote:
> Hi,
>
> On 28/11/2016 14:05, Christoffer Dall wrote:
>> On Wed, Nov 23, 2016 at 06:31:48PM +0530, vijay.kilari at gmail.com wrote:
>>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>>
>>> Read and write of some registers like ISPENDR and ICPENDR
>>> from userspace requires special handling when compared to
>>> guest access for these registers.
>>>
>>> Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
>>> for handling of ISPENDR, ICPENDR registers handling.
>>>
>>> Add infrastructure to support guest and userspace read
>>> and write for the required registers
>>> Also moved vgic_uaccess from vgic-mmio-v2.c to vgic-mmio.c
>>>
>>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>> ---
>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  25 ----------
>>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 102 ++++++++++++++++++++++++++++++++-------
>>>  virt/kvm/arm/vgic/vgic-mmio.c    |  78 +++++++++++++++++++++++++++---
>>>  virt/kvm/arm/vgic/vgic-mmio.h    |  19 ++++++++
>>>  4 files changed, 175 insertions(+), 49 deletions(-)
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> index b44b359..0b32f40 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> @@ -406,31 +406,6 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>>>      return -ENXIO;
>>>  }
>>>
>>> -/*
>>> - * When userland tries to access the VGIC register handlers, we need to
>>> - * create a usable struct vgic_io_device to be passed to the handlers and we
>>> - * have to set up a buffer similar to what would have happened if a guest MMIO
>>> - * access occurred, including doing endian conversions on BE systems.
>>> - */
>>> -static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>>> -                    bool is_write, int offset, u32 *val)
>>> -{
>>> -    unsigned int len = 4;
>>> -    u8 buf[4];
>>> -    int ret;
>>> -
>>> -    if (is_write) {
>>> -            vgic_data_host_to_mmio_bus(buf, len, *val);
>>> -            ret = kvm_io_gic_ops.write(vcpu, &dev->dev, offset, len, buf);
>>> -    } else {
>>> -            ret = kvm_io_gic_ops.read(vcpu, &dev->dev, offset, len, buf);
>>> -            if (!ret)
>>> -                    *val = vgic_data_mmio_bus_to_host(buf, len);
>>> -    }
>>> -
>>> -    return ret;
>>> -}
>>> -
>>>  int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>>                        int offset, u32 *val)
>>>  {
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>> index 50f42f0..8e76d04 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>> @@ -207,6 +207,66 @@ static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
>>>      return 0;
>>>  }
>>>
>>> +static unsigned long vgic_v3_uaccess_read_pending(struct kvm_vcpu *vcpu,
>>> +                                              gpa_t addr, unsigned int len)
>>> +{
>>> +    u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
>>> +    u32 value = 0;
>>> +    int i;
>>> +
>>> +    /*
>>> +     * A level triggerred interrupt pending state is latched in both
>>> +     * "soft_pending" and "line_level" variables. Userspace will save
>>> +     * and restore soft_pending and line_level separately.
>>> +     * Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
>>> +     * handling of ISPENDR and ICPENDR.
>>> +     */
>>> +    for (i = 0; i < len * 8; i++) {
>>> +            struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>>> +
>>> +            if (irq->config == VGIC_CONFIG_LEVEL && irq->soft_pending)
>>> +                    value |= (1U << i);
>>> +            if (irq->config == VGIC_CONFIG_EDGE && irq->pending)
>>> +                    value |= (1U << i);
>>> +
>>> +            vgic_put_irq(vcpu->kvm, irq);
>>> +    }
>>> +
>>> +    return value;
>>> +}
>>> +
>>> +static void vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu,
>>> +                                      gpa_t addr, unsigned int len,
>>> +                                      unsigned long val)
>>> +{
>>> +    u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
>>> +    int i;
>>> +
>>> +    for (i = 0; i < len * 8; i++) {
>>> +            struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>>> +
>>> +            spin_lock(&irq->irq_lock);
>>> +            if (test_bit(i, &val)) {
>>> +                    /* soft_pending is set irrespective of irq type
>>> +                     * (level or edge) to avoid dependency that VM should
>>> +                     * restore irq config before pending info.
>>> +                     */
>>
>> nit: kernel commenting style
>>
>>> +                    irq->pending = true;
>>> +                    irq->soft_pending = true;
>>> +                    vgic_queue_irq_unlock(vcpu->kvm, irq);
>>> +            } else {
>>> +                    irq->soft_pending = false;
>>> +                    if (irq->config == VGIC_CONFIG_EDGE ||
>>> +                        (irq->config == VGIC_CONFIG_LEVEL &&
>>> +                        !irq->line_level))
>>> +                            irq->pending = false;
> I am confused by the comment above. Since we test the irq config here
> don't we assume the config was restored before the pending state?
>>> +                    spin_unlock(&irq->irq_lock);
>>> +            }
>>> +
>>> +            vgic_put_irq(vcpu->kvm, irq);
>>> +    }
>>> +}
>>> +
>>>  /* We want to avoid outer shareable. */
>>>  u64 vgic_sanitise_shareability(u64 field)
>>>  {
>>> @@ -356,7 +416,7 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>>   * We take some special care here to fix the calculation of the register
>>>   * offset.
>>>   */
>>> -#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, bpi, acc)       \
>>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, ur, uw, bpi, acc) \
>>>      {                                                               \
>>>              .reg_offset = off,                                      \
>>>              .bits_per_irq = bpi,                                    \
>>> @@ -371,6 +431,8 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>>              .access_flags = acc,                                    \
>>>              .read = rd,                                             \
>>>              .write = wr,                                            \
>>> +            .uaccess_read = ur,                                     \
>>> +            .uaccess_write = uw,                                    \
>>>      }
>>>
>>>  static const struct vgic_register_region vgic_v3_dist_registers[] = {
>>> @@ -378,40 +440,42 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>>              vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>>> -            vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
>>> +            vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
>>> -            vgic_mmio_read_enable, vgic_mmio_write_senable, 1,
>>> +            vgic_mmio_read_enable, vgic_mmio_write_senable, NULL, NULL, 1,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
>>> -            vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
>>> +            vgic_mmio_read_enable, vgic_mmio_write_cenable, NULL, NULL, 1,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
>>> -            vgic_mmio_read_pending, vgic_mmio_write_spending, 1,
>>> +            vgic_mmio_read_pending, vgic_mmio_write_spending,
>>> +            vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 1,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
>>> -            vgic_mmio_read_pending, vgic_mmio_write_cpending, 1,
>>> +            vgic_mmio_read_pending, vgic_mmio_write_cpending,
>>> +            vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
>>> -            vgic_mmio_read_active, vgic_mmio_write_sactive, 1,
>>> +            vgic_mmio_read_active, vgic_mmio_write_sactive, NULL, NULL, 1,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
>>> -            vgic_mmio_read_active, vgic_mmio_write_cactive, 1,
>>> +            vgic_mmio_read_active, vgic_mmio_write_cactive, NULL, NULL, 1,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
>>> -            vgic_mmio_read_priority, vgic_mmio_write_priority, 8,
>>> -            VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>>> +            vgic_mmio_read_priority, vgic_mmio_write_priority, NULL, NULL,
>>> +            8, VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
>>> -            vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
>>> +            vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 8,
>>>              VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
>>> -            vgic_mmio_read_config, vgic_mmio_write_config, 2,
>>> +            vgic_mmio_read_config, vgic_mmio_write_config, NULL, NULL, 2,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
>>> -            vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>>> +            vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
>>> -            vgic_mmio_read_irouter, vgic_mmio_write_irouter, 64,
>>> +            vgic_mmio_read_irouter, vgic_mmio_write_irouter, NULL, NULL, 64,
>>>              VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>>>              vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48,
>>> @@ -449,11 +513,13 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>>      REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
>>>              vgic_mmio_read_enable, vgic_mmio_write_cenable, 4,
>>>              VGIC_ACCESS_32bit),
>>> -    REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
>>> -            vgic_mmio_read_pending, vgic_mmio_write_spending, 4,
>>> +    REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ISPENDR0,
>>> +            vgic_mmio_read_pending, vgic_mmio_write_spending,
>>> +            vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 4,
>>>              VGIC_ACCESS_32bit),
>>> -    REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
>>> -            vgic_mmio_read_pending, vgic_mmio_write_cpending, 4,
>>> +    REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ICPENDR0,
>>> +            vgic_mmio_read_pending, vgic_mmio_write_cpending,
>>> +            vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
>>>              VGIC_ACCESS_32bit),
>>>      REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
>>>              vgic_mmio_read_active, vgic_mmio_write_sactive, 4,
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>>> index ebe1b9f..d5f3ee2 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>>> @@ -484,6 +484,74 @@ static bool check_region(const struct kvm *kvm,
>>>      return false;
>>>  }
>>>
>>> +static const struct vgic_register_region *
>>> +vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev,
>>> +                 gpa_t addr, int len)
>>> +{
>>> +    const struct vgic_register_region *region;
>>> +
>>> +    region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
>>> +                                   addr - iodev->base_addr);
>>> +    if (!region || !check_region(vcpu->kvm, region, addr, len))
>>> +            return NULL;
>>> +
>>> +    return region;
>>> +}
>>> +
>>> +static int vgic_uaccess_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>>> +                         gpa_t addr, u32 *val)
>>> +{
>>> +    struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
>>> +    const struct vgic_register_region *region;
>>> +    struct kvm_vcpu *r_vcpu;
>>> +
>>> +    region = vgic_get_mmio_region(vcpu, iodev, addr, sizeof(u32));
>>> +    if (!region) {
>>> +            *val = 0;
>>> +            return 0;
> do we really want to return 0 here? -ENXIO?
> I see that dispatch_mmio_read/write return 0 in that case but I don't
> see any reason either? Other kvm_io_device_ops seem to return
> -EOPNOTSUPP in such a case.

Yes, This was discussed and decided to fix it outside of this series.

https://www.spinics.net/lists/arm-kernel/msg533695.html

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 01/11] arm/arm64: vgic: Implement support for userspace access
  2016-12-15  7:36         ` Vijay Kilari
@ 2016-12-16 12:40           ` Auger Eric
  -1 siblings, 0 replies; 78+ messages in thread
From: Auger Eric @ 2016-12-16 12:40 UTC (permalink / raw)
  To: Vijay Kilari; +Cc: Marc Zyngier, Vijaya Kumar K, kvmarm, linux-arm-kernel

Hi Vijaya,

On 15/12/2016 08:36, Vijay Kilari wrote:
> On Tue, Dec 6, 2016 at 5:12 PM, Auger Eric <eric.auger@redhat.com> wrote:
>> Hi,
>>
>> On 28/11/2016 14:05, Christoffer Dall wrote:
>>> On Wed, Nov 23, 2016 at 06:31:48PM +0530, vijay.kilari@gmail.com wrote:
>>>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>>>
>>>> Read and write of some registers like ISPENDR and ICPENDR
>>>> from userspace requires special handling when compared to
>>>> guest access for these registers.
>>>>
>>>> Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
>>>> for handling of ISPENDR, ICPENDR registers handling.
>>>>
>>>> Add infrastructure to support guest and userspace read
>>>> and write for the required registers
>>>> Also moved vgic_uaccess from vgic-mmio-v2.c to vgic-mmio.c
>>>>
>>>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>>> ---
>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  25 ----------
>>>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 102 ++++++++++++++++++++++++++++++++-------
>>>>  virt/kvm/arm/vgic/vgic-mmio.c    |  78 +++++++++++++++++++++++++++---
>>>>  virt/kvm/arm/vgic/vgic-mmio.h    |  19 ++++++++
>>>>  4 files changed, 175 insertions(+), 49 deletions(-)
>>>>
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> index b44b359..0b32f40 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> @@ -406,31 +406,6 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>>>>      return -ENXIO;
>>>>  }
>>>>
>>>> -/*
>>>> - * When userland tries to access the VGIC register handlers, we need to
>>>> - * create a usable struct vgic_io_device to be passed to the handlers and we
>>>> - * have to set up a buffer similar to what would have happened if a guest MMIO
>>>> - * access occurred, including doing endian conversions on BE systems.
>>>> - */
>>>> -static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>>>> -                    bool is_write, int offset, u32 *val)
>>>> -{
>>>> -    unsigned int len = 4;
>>>> -    u8 buf[4];
>>>> -    int ret;
>>>> -
>>>> -    if (is_write) {
>>>> -            vgic_data_host_to_mmio_bus(buf, len, *val);
>>>> -            ret = kvm_io_gic_ops.write(vcpu, &dev->dev, offset, len, buf);
>>>> -    } else {
>>>> -            ret = kvm_io_gic_ops.read(vcpu, &dev->dev, offset, len, buf);
>>>> -            if (!ret)
>>>> -                    *val = vgic_data_mmio_bus_to_host(buf, len);
>>>> -    }
>>>> -
>>>> -    return ret;
>>>> -}
>>>> -
>>>>  int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>>>                        int offset, u32 *val)
>>>>  {
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>>> index 50f42f0..8e76d04 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>>> @@ -207,6 +207,66 @@ static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
>>>>      return 0;
>>>>  }
>>>>
>>>> +static unsigned long vgic_v3_uaccess_read_pending(struct kvm_vcpu *vcpu,
>>>> +                                              gpa_t addr, unsigned int len)
>>>> +{
>>>> +    u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
>>>> +    u32 value = 0;
>>>> +    int i;
>>>> +
>>>> +    /*
>>>> +     * A level triggerred interrupt pending state is latched in both
>>>> +     * "soft_pending" and "line_level" variables. Userspace will save
>>>> +     * and restore soft_pending and line_level separately.
>>>> +     * Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
>>>> +     * handling of ISPENDR and ICPENDR.
>>>> +     */
>>>> +    for (i = 0; i < len * 8; i++) {
>>>> +            struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>>>> +
>>>> +            if (irq->config == VGIC_CONFIG_LEVEL && irq->soft_pending)
>>>> +                    value |= (1U << i);
>>>> +            if (irq->config == VGIC_CONFIG_EDGE && irq->pending)
>>>> +                    value |= (1U << i);
>>>> +
>>>> +            vgic_put_irq(vcpu->kvm, irq);
>>>> +    }
>>>> +
>>>> +    return value;
>>>> +}
>>>> +
>>>> +static void vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu,
>>>> +                                      gpa_t addr, unsigned int len,
>>>> +                                      unsigned long val)
>>>> +{
>>>> +    u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
>>>> +    int i;
>>>> +
>>>> +    for (i = 0; i < len * 8; i++) {
>>>> +            struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>>>> +
>>>> +            spin_lock(&irq->irq_lock);
>>>> +            if (test_bit(i, &val)) {
>>>> +                    /* soft_pending is set irrespective of irq type
>>>> +                     * (level or edge) to avoid dependency that VM should
>>>> +                     * restore irq config before pending info.
>>>> +                     */
>>>
>>> nit: kernel commenting style
>>>
>>>> +                    irq->pending = true;
>>>> +                    irq->soft_pending = true;
>>>> +                    vgic_queue_irq_unlock(vcpu->kvm, irq);
>>>> +            } else {
>>>> +                    irq->soft_pending = false;
>>>> +                    if (irq->config == VGIC_CONFIG_EDGE ||
>>>> +                        (irq->config == VGIC_CONFIG_LEVEL &&
>>>> +                        !irq->line_level))
>>>> +                            irq->pending = false;
>> I am confused by the comment above. Since we test the irq config here
>> don't we assume the config was restored before the pending state?
>>>> +                    spin_unlock(&irq->irq_lock);
>>>> +            }
>>>> +
>>>> +            vgic_put_irq(vcpu->kvm, irq);
>>>> +    }
>>>> +}
>>>> +
>>>>  /* We want to avoid outer shareable. */
>>>>  u64 vgic_sanitise_shareability(u64 field)
>>>>  {
>>>> @@ -356,7 +416,7 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>>>   * We take some special care here to fix the calculation of the register
>>>>   * offset.
>>>>   */
>>>> -#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, bpi, acc)       \
>>>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, ur, uw, bpi, acc) \
>>>>      {                                                               \
>>>>              .reg_offset = off,                                      \
>>>>              .bits_per_irq = bpi,                                    \
>>>> @@ -371,6 +431,8 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>>>              .access_flags = acc,                                    \
>>>>              .read = rd,                                             \
>>>>              .write = wr,                                            \
>>>> +            .uaccess_read = ur,                                     \
>>>> +            .uaccess_write = uw,                                    \
>>>>      }
>>>>
>>>>  static const struct vgic_register_region vgic_v3_dist_registers[] = {
>>>> @@ -378,40 +440,42 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>>>              vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>>>> -            vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
>>>> +            vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
>>>> -            vgic_mmio_read_enable, vgic_mmio_write_senable, 1,
>>>> +            vgic_mmio_read_enable, vgic_mmio_write_senable, NULL, NULL, 1,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
>>>> -            vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
>>>> +            vgic_mmio_read_enable, vgic_mmio_write_cenable, NULL, NULL, 1,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
>>>> -            vgic_mmio_read_pending, vgic_mmio_write_spending, 1,
>>>> +            vgic_mmio_read_pending, vgic_mmio_write_spending,
>>>> +            vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 1,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
>>>> -            vgic_mmio_read_pending, vgic_mmio_write_cpending, 1,
>>>> +            vgic_mmio_read_pending, vgic_mmio_write_cpending,
>>>> +            vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
>>>> -            vgic_mmio_read_active, vgic_mmio_write_sactive, 1,
>>>> +            vgic_mmio_read_active, vgic_mmio_write_sactive, NULL, NULL, 1,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
>>>> -            vgic_mmio_read_active, vgic_mmio_write_cactive, 1,
>>>> +            vgic_mmio_read_active, vgic_mmio_write_cactive, NULL, NULL, 1,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
>>>> -            vgic_mmio_read_priority, vgic_mmio_write_priority, 8,
>>>> -            VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>>>> +            vgic_mmio_read_priority, vgic_mmio_write_priority, NULL, NULL,
>>>> +            8, VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
>>>> -            vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
>>>> +            vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 8,
>>>>              VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
>>>> -            vgic_mmio_read_config, vgic_mmio_write_config, 2,
>>>> +            vgic_mmio_read_config, vgic_mmio_write_config, NULL, NULL, 2,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
>>>> -            vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>>>> +            vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
>>>> -            vgic_mmio_read_irouter, vgic_mmio_write_irouter, 64,
>>>> +            vgic_mmio_read_irouter, vgic_mmio_write_irouter, NULL, NULL, 64,
>>>>              VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>>>>              vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48,
>>>> @@ -449,11 +513,13 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>>>      REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
>>>>              vgic_mmio_read_enable, vgic_mmio_write_cenable, 4,
>>>>              VGIC_ACCESS_32bit),
>>>> -    REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
>>>> -            vgic_mmio_read_pending, vgic_mmio_write_spending, 4,
>>>> +    REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ISPENDR0,
>>>> +            vgic_mmio_read_pending, vgic_mmio_write_spending,
>>>> +            vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 4,
>>>>              VGIC_ACCESS_32bit),
>>>> -    REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
>>>> -            vgic_mmio_read_pending, vgic_mmio_write_cpending, 4,
>>>> +    REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ICPENDR0,
>>>> +            vgic_mmio_read_pending, vgic_mmio_write_cpending,
>>>> +            vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
>>>>              vgic_mmio_read_active, vgic_mmio_write_sactive, 4,
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>>>> index ebe1b9f..d5f3ee2 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>>>> @@ -484,6 +484,74 @@ static bool check_region(const struct kvm *kvm,
>>>>      return false;
>>>>  }
>>>>
>>>> +static const struct vgic_register_region *
>>>> +vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev,
>>>> +                 gpa_t addr, int len)
>>>> +{
>>>> +    const struct vgic_register_region *region;
>>>> +
>>>> +    region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
>>>> +                                   addr - iodev->base_addr);
>>>> +    if (!region || !check_region(vcpu->kvm, region, addr, len))
>>>> +            return NULL;
>>>> +
>>>> +    return region;
>>>> +}
>>>> +
>>>> +static int vgic_uaccess_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>>>> +                         gpa_t addr, u32 *val)
>>>> +{
>>>> +    struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
>>>> +    const struct vgic_register_region *region;
>>>> +    struct kvm_vcpu *r_vcpu;
>>>> +
>>>> +    region = vgic_get_mmio_region(vcpu, iodev, addr, sizeof(u32));
>>>> +    if (!region) {
>>>> +            *val = 0;
>>>> +            return 0;
>> do we really want to return 0 here? -ENXIO?
>> I see that dispatch_mmio_read/write return 0 in that case but I don't
>> see any reason either? Other kvm_io_device_ops seem to return
>> -EOPNOTSUPP in such a case.
> 
> Yes, This was discussed and decided to fix it outside of this series.
> 
> https://www.spinics.net/lists/arm-kernel/msg533695.html

OK. Sorry I missed that. Other comments I sent on v9 remain applicable
on v10 I think.

Thanks

Eric
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 01/11] arm/arm64: vgic: Implement support for userspace access
@ 2016-12-16 12:40           ` Auger Eric
  0 siblings, 0 replies; 78+ messages in thread
From: Auger Eric @ 2016-12-16 12:40 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Vijaya,

On 15/12/2016 08:36, Vijay Kilari wrote:
> On Tue, Dec 6, 2016 at 5:12 PM, Auger Eric <eric.auger@redhat.com> wrote:
>> Hi,
>>
>> On 28/11/2016 14:05, Christoffer Dall wrote:
>>> On Wed, Nov 23, 2016 at 06:31:48PM +0530, vijay.kilari at gmail.com wrote:
>>>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>>>
>>>> Read and write of some registers like ISPENDR and ICPENDR
>>>> from userspace requires special handling when compared to
>>>> guest access for these registers.
>>>>
>>>> Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
>>>> for handling of ISPENDR, ICPENDR registers handling.
>>>>
>>>> Add infrastructure to support guest and userspace read
>>>> and write for the required registers
>>>> Also moved vgic_uaccess from vgic-mmio-v2.c to vgic-mmio.c
>>>>
>>>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>>> ---
>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  25 ----------
>>>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 102 ++++++++++++++++++++++++++++++++-------
>>>>  virt/kvm/arm/vgic/vgic-mmio.c    |  78 +++++++++++++++++++++++++++---
>>>>  virt/kvm/arm/vgic/vgic-mmio.h    |  19 ++++++++
>>>>  4 files changed, 175 insertions(+), 49 deletions(-)
>>>>
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> index b44b359..0b32f40 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> @@ -406,31 +406,6 @@ int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
>>>>      return -ENXIO;
>>>>  }
>>>>
>>>> -/*
>>>> - * When userland tries to access the VGIC register handlers, we need to
>>>> - * create a usable struct vgic_io_device to be passed to the handlers and we
>>>> - * have to set up a buffer similar to what would have happened if a guest MMIO
>>>> - * access occurred, including doing endian conversions on BE systems.
>>>> - */
>>>> -static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>>>> -                    bool is_write, int offset, u32 *val)
>>>> -{
>>>> -    unsigned int len = 4;
>>>> -    u8 buf[4];
>>>> -    int ret;
>>>> -
>>>> -    if (is_write) {
>>>> -            vgic_data_host_to_mmio_bus(buf, len, *val);
>>>> -            ret = kvm_io_gic_ops.write(vcpu, &dev->dev, offset, len, buf);
>>>> -    } else {
>>>> -            ret = kvm_io_gic_ops.read(vcpu, &dev->dev, offset, len, buf);
>>>> -            if (!ret)
>>>> -                    *val = vgic_data_mmio_bus_to_host(buf, len);
>>>> -    }
>>>> -
>>>> -    return ret;
>>>> -}
>>>> -
>>>>  int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>>>                        int offset, u32 *val)
>>>>  {
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>>> index 50f42f0..8e76d04 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>>> @@ -207,6 +207,66 @@ static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
>>>>      return 0;
>>>>  }
>>>>
>>>> +static unsigned long vgic_v3_uaccess_read_pending(struct kvm_vcpu *vcpu,
>>>> +                                              gpa_t addr, unsigned int len)
>>>> +{
>>>> +    u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
>>>> +    u32 value = 0;
>>>> +    int i;
>>>> +
>>>> +    /*
>>>> +     * A level triggerred interrupt pending state is latched in both
>>>> +     * "soft_pending" and "line_level" variables. Userspace will save
>>>> +     * and restore soft_pending and line_level separately.
>>>> +     * Refer to Documentation/virtual/kvm/devices/arm-vgic-v3.txt
>>>> +     * handling of ISPENDR and ICPENDR.
>>>> +     */
>>>> +    for (i = 0; i < len * 8; i++) {
>>>> +            struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>>>> +
>>>> +            if (irq->config == VGIC_CONFIG_LEVEL && irq->soft_pending)
>>>> +                    value |= (1U << i);
>>>> +            if (irq->config == VGIC_CONFIG_EDGE && irq->pending)
>>>> +                    value |= (1U << i);
>>>> +
>>>> +            vgic_put_irq(vcpu->kvm, irq);
>>>> +    }
>>>> +
>>>> +    return value;
>>>> +}
>>>> +
>>>> +static void vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu,
>>>> +                                      gpa_t addr, unsigned int len,
>>>> +                                      unsigned long val)
>>>> +{
>>>> +    u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
>>>> +    int i;
>>>> +
>>>> +    for (i = 0; i < len * 8; i++) {
>>>> +            struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>>>> +
>>>> +            spin_lock(&irq->irq_lock);
>>>> +            if (test_bit(i, &val)) {
>>>> +                    /* soft_pending is set irrespective of irq type
>>>> +                     * (level or edge) to avoid dependency that VM should
>>>> +                     * restore irq config before pending info.
>>>> +                     */
>>>
>>> nit: kernel commenting style
>>>
>>>> +                    irq->pending = true;
>>>> +                    irq->soft_pending = true;
>>>> +                    vgic_queue_irq_unlock(vcpu->kvm, irq);
>>>> +            } else {
>>>> +                    irq->soft_pending = false;
>>>> +                    if (irq->config == VGIC_CONFIG_EDGE ||
>>>> +                        (irq->config == VGIC_CONFIG_LEVEL &&
>>>> +                        !irq->line_level))
>>>> +                            irq->pending = false;
>> I am confused by the comment above. Since we test the irq config here
>> don't we assume the config was restored before the pending state?
>>>> +                    spin_unlock(&irq->irq_lock);
>>>> +            }
>>>> +
>>>> +            vgic_put_irq(vcpu->kvm, irq);
>>>> +    }
>>>> +}
>>>> +
>>>>  /* We want to avoid outer shareable. */
>>>>  u64 vgic_sanitise_shareability(u64 field)
>>>>  {
>>>> @@ -356,7 +416,7 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>>>   * We take some special care here to fix the calculation of the register
>>>>   * offset.
>>>>   */
>>>> -#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, bpi, acc)       \
>>>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, rd, wr, ur, uw, bpi, acc) \
>>>>      {                                                               \
>>>>              .reg_offset = off,                                      \
>>>>              .bits_per_irq = bpi,                                    \
>>>> @@ -371,6 +431,8 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>>>              .access_flags = acc,                                    \
>>>>              .read = rd,                                             \
>>>>              .write = wr,                                            \
>>>> +            .uaccess_read = ur,                                     \
>>>> +            .uaccess_write = uw,                                    \
>>>>      }
>>>>
>>>>  static const struct vgic_register_region vgic_v3_dist_registers[] = {
>>>> @@ -378,40 +440,42 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>>>              vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>>>> -            vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
>>>> +            vgic_mmio_read_rao, vgic_mmio_write_wi, NULL, NULL, 1,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
>>>> -            vgic_mmio_read_enable, vgic_mmio_write_senable, 1,
>>>> +            vgic_mmio_read_enable, vgic_mmio_write_senable, NULL, NULL, 1,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
>>>> -            vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
>>>> +            vgic_mmio_read_enable, vgic_mmio_write_cenable, NULL, NULL, 1,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
>>>> -            vgic_mmio_read_pending, vgic_mmio_write_spending, 1,
>>>> +            vgic_mmio_read_pending, vgic_mmio_write_spending,
>>>> +            vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 1,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
>>>> -            vgic_mmio_read_pending, vgic_mmio_write_cpending, 1,
>>>> +            vgic_mmio_read_pending, vgic_mmio_write_cpending,
>>>> +            vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
>>>> -            vgic_mmio_read_active, vgic_mmio_write_sactive, 1,
>>>> +            vgic_mmio_read_active, vgic_mmio_write_sactive, NULL, NULL, 1,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
>>>> -            vgic_mmio_read_active, vgic_mmio_write_cactive, 1,
>>>> +            vgic_mmio_read_active, vgic_mmio_write_cactive, NULL, NULL, 1,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
>>>> -            vgic_mmio_read_priority, vgic_mmio_write_priority, 8,
>>>> -            VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>>>> +            vgic_mmio_read_priority, vgic_mmio_write_priority, NULL, NULL,
>>>> +            8, VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
>>>> -            vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
>>>> +            vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 8,
>>>>              VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
>>>> -            vgic_mmio_read_config, vgic_mmio_write_config, 2,
>>>> +            vgic_mmio_read_config, vgic_mmio_write_config, NULL, NULL, 2,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
>>>> -            vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>>>> +            vgic_mmio_read_raz, vgic_mmio_write_wi, NULL, NULL, 1,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
>>>> -            vgic_mmio_read_irouter, vgic_mmio_write_irouter, 64,
>>>> +            vgic_mmio_read_irouter, vgic_mmio_write_irouter, NULL, NULL, 64,
>>>>              VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>>>>              vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48,
>>>> @@ -449,11 +513,13 @@ static void vgic_mmio_write_pendbase(struct kvm_vcpu *vcpu,
>>>>      REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
>>>>              vgic_mmio_read_enable, vgic_mmio_write_cenable, 4,
>>>>              VGIC_ACCESS_32bit),
>>>> -    REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
>>>> -            vgic_mmio_read_pending, vgic_mmio_write_spending, 4,
>>>> +    REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ISPENDR0,
>>>> +            vgic_mmio_read_pending, vgic_mmio_write_spending,
>>>> +            vgic_v3_uaccess_read_pending, vgic_v3_uaccess_write_pending, 4,
>>>>              VGIC_ACCESS_32bit),
>>>> -    REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
>>>> -            vgic_mmio_read_pending, vgic_mmio_write_cpending, 4,
>>>> +    REGISTER_DESC_WITH_LENGTH_UACCESS(GICR_ICPENDR0,
>>>> +            vgic_mmio_read_pending, vgic_mmio_write_cpending,
>>>> +            vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
>>>>              VGIC_ACCESS_32bit),
>>>>      REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
>>>>              vgic_mmio_read_active, vgic_mmio_write_sactive, 4,
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>>>> index ebe1b9f..d5f3ee2 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>>>> @@ -484,6 +484,74 @@ static bool check_region(const struct kvm *kvm,
>>>>      return false;
>>>>  }
>>>>
>>>> +static const struct vgic_register_region *
>>>> +vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev,
>>>> +                 gpa_t addr, int len)
>>>> +{
>>>> +    const struct vgic_register_region *region;
>>>> +
>>>> +    region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
>>>> +                                   addr - iodev->base_addr);
>>>> +    if (!region || !check_region(vcpu->kvm, region, addr, len))
>>>> +            return NULL;
>>>> +
>>>> +    return region;
>>>> +}
>>>> +
>>>> +static int vgic_uaccess_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
>>>> +                         gpa_t addr, u32 *val)
>>>> +{
>>>> +    struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
>>>> +    const struct vgic_register_region *region;
>>>> +    struct kvm_vcpu *r_vcpu;
>>>> +
>>>> +    region = vgic_get_mmio_region(vcpu, iodev, addr, sizeof(u32));
>>>> +    if (!region) {
>>>> +            *val = 0;
>>>> +            return 0;
>> do we really want to return 0 here? -ENXIO?
>> I see that dispatch_mmio_read/write return 0 in that case but I don't
>> see any reason either? Other kvm_io_device_ops seem to return
>> -EOPNOTSUPP in such a case.
> 
> Yes, This was discussed and decided to fix it outside of this series.
> 
> https://www.spinics.net/lists/arm-kernel/msg533695.html

OK. Sorry I missed that. Other comments I sent on v9 remain applicable
on v10 I think.

Thanks

Eric
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

^ permalink raw reply	[flat|nested] 78+ messages in thread

* Re: [PATCH v9 04/11] irqchip/gic-v3: Add missing system register definitions
  2016-12-06 13:53     ` Auger Eric
@ 2017-01-23 10:55       ` Vijay Kilari
  -1 siblings, 0 replies; 78+ messages in thread
From: Vijay Kilari @ 2017-01-23 10:55 UTC (permalink / raw)
  To: Auger Eric; +Cc: Marc Zyngier, Vijaya Kumar K, linux-arm-kernel, kvmarm

Hi Eric,

On Tue, Dec 6, 2016 at 7:23 PM, Auger Eric <eric.auger@redhat.com> wrote:
> Hi,
> On 23/11/2016 14:01, vijay.kilari@gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>
>> Define register definitions for ICH_VMCR_EL2, ICC_CTLR_EL1 and
>> ICH_VTR_EL2, ICC_BPR0_EL1, ICC_BPR1_EL1 registers.
>>
>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>
>> ---
>>  include/linux/irqchip/arm-gic-v3.h | 43 ++++++++++++++++++++++++++++++++++++--
>>  1 file changed, 41 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
>> index 0deea34..b4f8287 100644
>> --- a/include/linux/irqchip/arm-gic-v3.h
>> +++ b/include/linux/irqchip/arm-gic-v3.h
>> @@ -352,8 +352,30 @@
>>  /*
>>   * CPU interface registers
>>   */
>> -#define ICC_CTLR_EL1_EOImode_drop_dir        (0U << 1)
>> -#define ICC_CTLR_EL1_EOImode_drop    (1U << 1)
>> +#define ICC_CTLR_EL1_EOImode_SHIFT   (1)
>> +#define ICC_CTLR_EL1_EOImode_drop_dir        (0U << ICC_CTLR_EL1_EOImode_SHIFT)
>> +#define ICC_CTLR_EL1_EOImode_drop    (1U << ICC_CTLR_EL1_EOImode_SHIFT)
>> +#define ICC_CTLR_EL1_EOImode_MASK    (1 << ICC_CTLR_EL1_EOImode_SHIFT)
>> +#define ICC_CTLR_EL1_CBPR_SHIFT              0
>> +#define ICC_CTLR_EL1_CBPR_MASK               (1 << ICC_CTLR_EL1_CBPR_SHIFT)
>> +#define ICC_CTLR_EL1_PRI_BITS_SHIFT  8
>> +#define ICC_CTLR_EL1_PRI_BITS_MASK   (0x7 << ICC_CTLR_EL1_PRI_BITS_SHIFT)
>> +#define ICC_CTLR_EL1_ID_BITS_SHIFT   11
>> +#define ICC_CTLR_EL1_ID_BITS_MASK    (0x7 << ICC_CTLR_EL1_ID_BITS_SHIFT)
>> +#define ICC_CTLR_EL1_SEIS_SHIFT              14
>> +#define ICC_CTLR_EL1_SEIS_MASK               (0x1 << ICC_CTLR_EL1_SEIS_SHIFT)
>> +#define ICC_CTLR_EL1_A3V_SHIFT               15
>> +#define ICC_CTLR_EL1_A3V_MASK                (0x1 << ICC_CTLR_EL1_A3V_SHIFT)
>> +#define ICC_PMR_EL1_SHIFT            0
>> +#define ICC_PMR_EL1_MASK             (0xff << ICC_PMR_EL1_SHIFT)
>> +#define ICC_BPR0_EL1_SHIFT           0
>> +#define ICC_BPR0_EL1_MASK            (0x7 << ICC_BPR0_EL1_SHIFT)
>> +#define ICC_BPR1_EL1_SHIFT           0
>> +#define ICC_BPR1_EL1_MASK            (0x7 << ICC_BPR1_EL1_SHIFT)
>> +#define ICC_IGRPEN0_EL1_SHIFT                0
>> +#define ICC_IGRPEN0_EL1_MASK         (1 << ICC_IGRPEN0_EL1_SHIFT)
>> +#define ICC_IGRPEN1_EL1_SHIFT                0
>> +#define ICC_IGRPEN1_EL1_MASK         (1 << ICC_IGRPEN1_EL1_SHIFT)
>>  #define ICC_SRE_EL1_SRE                      (1U << 0)
>>
>>  /*
>> @@ -384,12 +406,29 @@
>>
>>  #define ICH_VMCR_CTLR_SHIFT          0
>>  #define ICH_VMCR_CTLR_MASK           (0x21f << ICH_VMCR_CTLR_SHIFT)
>> +#define ICH_VMCR_CBPR_SHIFT          4
>> +#define ICH_VMCR_CBPR_MASK           (1 << ICH_VMCR_CBPR_SHIFT)
>> +#define ICH_VMCR_EOIM_SHIFT          9
>> +#define ICH_VMCR_EOIM_MASK           (1 << ICH_VMCR_EOIM_SHIFT)
>>  #define ICH_VMCR_BPR1_SHIFT          18
>>  #define ICH_VMCR_BPR1_MASK           (7 << ICH_VMCR_BPR1_SHIFT)
>>  #define ICH_VMCR_BPR0_SHIFT          21
>>  #define ICH_VMCR_BPR0_MASK           (7 << ICH_VMCR_BPR0_SHIFT)
>>  #define ICH_VMCR_PMR_SHIFT           24
>>  #define ICH_VMCR_PMR_MASK            (0xffUL << ICH_VMCR_PMR_SHIFT)
>> +#define ICH_VMCR_ENG0_SHIFT          0
>> +#define ICH_VMCR_ENG0_MASK           (1 << ICH_VMCR_ENG0_SHIFT)
>> +#define ICH_VMCR_ENG1_SHIFT          1
>> +#define ICH_VMCR_ENG1_MASK           (1 << ICH_VMCR_ENG1_SHIFT)
> Besides the fact the V* was omitted (for instance VENG0) this looks good
> to me.

The previous definitions of has omitted V. If we have to prefix V then
it needs to be changed for all other definitions of VMCR.
I propose to ignore it for now and can clean up later as a separate patch.

>> +
>> +#define ICH_VTR_PRI_BITS_SHIFT               29
>> +#define ICH_VTR_PRI_BITS_MASK                (7 << ICH_VTR_PRI_BITS_SHIFT)
>> +#define ICH_VTR_ID_BITS_SHIFT                23
>> +#define ICH_VTR_ID_BITS_MASK         (7 << ICH_VTR_ID_BITS_SHIFT)
>> +#define ICH_VTR_SEIS_SHIFT           22
>> +#define ICH_VTR_SEIS_MASK            (1 << ICH_VTR_SEIS_SHIFT)
>> +#define ICH_VTR_A3V_SHIFT            21
>> +#define ICH_VTR_A3V_MASK             (1 << ICH_VTR_A3V_SHIFT)
> Some fields are omitted but I guess they are not used.
>
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>
> Eric
>
>>
>>  #define ICC_IAR1_EL1_SPURIOUS                0x3ff
>>
>>

^ permalink raw reply	[flat|nested] 78+ messages in thread

* [PATCH v9 04/11] irqchip/gic-v3: Add missing system register definitions
@ 2017-01-23 10:55       ` Vijay Kilari
  0 siblings, 0 replies; 78+ messages in thread
From: Vijay Kilari @ 2017-01-23 10:55 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Eric,

On Tue, Dec 6, 2016 at 7:23 PM, Auger Eric <eric.auger@redhat.com> wrote:
> Hi,
> On 23/11/2016 14:01, vijay.kilari at gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>>
>> Define register definitions for ICH_VMCR_EL2, ICC_CTLR_EL1 and
>> ICH_VTR_EL2, ICC_BPR0_EL1, ICC_BPR1_EL1 registers.
>>
>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@cavium.com>
>
>> ---
>>  include/linux/irqchip/arm-gic-v3.h | 43 ++++++++++++++++++++++++++++++++++++--
>>  1 file changed, 41 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
>> index 0deea34..b4f8287 100644
>> --- a/include/linux/irqchip/arm-gic-v3.h
>> +++ b/include/linux/irqchip/arm-gic-v3.h
>> @@ -352,8 +352,30 @@
>>  /*
>>   * CPU interface registers
>>   */
>> -#define ICC_CTLR_EL1_EOImode_drop_dir        (0U << 1)
>> -#define ICC_CTLR_EL1_EOImode_drop    (1U << 1)
>> +#define ICC_CTLR_EL1_EOImode_SHIFT   (1)
>> +#define ICC_CTLR_EL1_EOImode_drop_dir        (0U << ICC_CTLR_EL1_EOImode_SHIFT)
>> +#define ICC_CTLR_EL1_EOImode_drop    (1U << ICC_CTLR_EL1_EOImode_SHIFT)
>> +#define ICC_CTLR_EL1_EOImode_MASK    (1 << ICC_CTLR_EL1_EOImode_SHIFT)
>> +#define ICC_CTLR_EL1_CBPR_SHIFT              0
>> +#define ICC_CTLR_EL1_CBPR_MASK               (1 << ICC_CTLR_EL1_CBPR_SHIFT)
>> +#define ICC_CTLR_EL1_PRI_BITS_SHIFT  8
>> +#define ICC_CTLR_EL1_PRI_BITS_MASK   (0x7 << ICC_CTLR_EL1_PRI_BITS_SHIFT)
>> +#define ICC_CTLR_EL1_ID_BITS_SHIFT   11
>> +#define ICC_CTLR_EL1_ID_BITS_MASK    (0x7 << ICC_CTLR_EL1_ID_BITS_SHIFT)
>> +#define ICC_CTLR_EL1_SEIS_SHIFT              14
>> +#define ICC_CTLR_EL1_SEIS_MASK               (0x1 << ICC_CTLR_EL1_SEIS_SHIFT)
>> +#define ICC_CTLR_EL1_A3V_SHIFT               15
>> +#define ICC_CTLR_EL1_A3V_MASK                (0x1 << ICC_CTLR_EL1_A3V_SHIFT)
>> +#define ICC_PMR_EL1_SHIFT            0
>> +#define ICC_PMR_EL1_MASK             (0xff << ICC_PMR_EL1_SHIFT)
>> +#define ICC_BPR0_EL1_SHIFT           0
>> +#define ICC_BPR0_EL1_MASK            (0x7 << ICC_BPR0_EL1_SHIFT)
>> +#define ICC_BPR1_EL1_SHIFT           0
>> +#define ICC_BPR1_EL1_MASK            (0x7 << ICC_BPR1_EL1_SHIFT)
>> +#define ICC_IGRPEN0_EL1_SHIFT                0
>> +#define ICC_IGRPEN0_EL1_MASK         (1 << ICC_IGRPEN0_EL1_SHIFT)
>> +#define ICC_IGRPEN1_EL1_SHIFT                0
>> +#define ICC_IGRPEN1_EL1_MASK         (1 << ICC_IGRPEN1_EL1_SHIFT)
>>  #define ICC_SRE_EL1_SRE                      (1U << 0)
>>
>>  /*
>> @@ -384,12 +406,29 @@
>>
>>  #define ICH_VMCR_CTLR_SHIFT          0
>>  #define ICH_VMCR_CTLR_MASK           (0x21f << ICH_VMCR_CTLR_SHIFT)
>> +#define ICH_VMCR_CBPR_SHIFT          4
>> +#define ICH_VMCR_CBPR_MASK           (1 << ICH_VMCR_CBPR_SHIFT)
>> +#define ICH_VMCR_EOIM_SHIFT          9
>> +#define ICH_VMCR_EOIM_MASK           (1 << ICH_VMCR_EOIM_SHIFT)
>>  #define ICH_VMCR_BPR1_SHIFT          18
>>  #define ICH_VMCR_BPR1_MASK           (7 << ICH_VMCR_BPR1_SHIFT)
>>  #define ICH_VMCR_BPR0_SHIFT          21
>>  #define ICH_VMCR_BPR0_MASK           (7 << ICH_VMCR_BPR0_SHIFT)
>>  #define ICH_VMCR_PMR_SHIFT           24
>>  #define ICH_VMCR_PMR_MASK            (0xffUL << ICH_VMCR_PMR_SHIFT)
>> +#define ICH_VMCR_ENG0_SHIFT          0
>> +#define ICH_VMCR_ENG0_MASK           (1 << ICH_VMCR_ENG0_SHIFT)
>> +#define ICH_VMCR_ENG1_SHIFT          1
>> +#define ICH_VMCR_ENG1_MASK           (1 << ICH_VMCR_ENG1_SHIFT)
> Besides the fact the V* was omitted (for instance VENG0) this looks good
> to me.

The previous definitions of has omitted V. If we have to prefix V then
it needs to be changed for all other definitions of VMCR.
I propose to ignore it for now and can clean up later as a separate patch.

>> +
>> +#define ICH_VTR_PRI_BITS_SHIFT               29
>> +#define ICH_VTR_PRI_BITS_MASK                (7 << ICH_VTR_PRI_BITS_SHIFT)
>> +#define ICH_VTR_ID_BITS_SHIFT                23
>> +#define ICH_VTR_ID_BITS_MASK         (7 << ICH_VTR_ID_BITS_SHIFT)
>> +#define ICH_VTR_SEIS_SHIFT           22
>> +#define ICH_VTR_SEIS_MASK            (1 << ICH_VTR_SEIS_SHIFT)
>> +#define ICH_VTR_A3V_SHIFT            21
>> +#define ICH_VTR_A3V_MASK             (1 << ICH_VTR_A3V_SHIFT)
> Some fields are omitted but I guess they are not used.
>
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>
> Eric
>
>>
>>  #define ICC_IAR1_EL1_SPURIOUS                0x3ff
>>
>>

^ permalink raw reply	[flat|nested] 78+ messages in thread

end of thread, other threads:[~2017-01-23 10:55 UTC | newest]

Thread overview: 78+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-11-23 13:01 [PATCH v9 0/11] arm/arm64: vgic: Implement API for vGICv3 live migration vijay.kilari
2016-11-23 13:01 ` vijay.kilari at gmail.com
2016-11-23 13:01 ` [PATCH v9 01/11] arm/arm64: vgic: Implement support for userspace access vijay.kilari
2016-11-23 13:01   ` vijay.kilari at gmail.com
2016-11-28 13:05   ` Christoffer Dall
2016-11-28 13:05     ` Christoffer Dall
2016-12-06 11:42     ` Auger Eric
2016-12-06 11:42       ` Auger Eric
2016-12-06 14:30       ` Christoffer Dall
2016-12-06 14:30         ` Christoffer Dall
2016-12-15  7:36       ` Vijay Kilari
2016-12-15  7:36         ` Vijay Kilari
2016-12-16 12:40         ` Auger Eric
2016-12-16 12:40           ` Auger Eric
2016-11-23 13:01 ` [PATCH v9 02/11] arm/arm64: vgic: Add distributor and redistributor access vijay.kilari
2016-11-23 13:01   ` vijay.kilari at gmail.com
2016-11-28 13:08   ` Christoffer Dall
2016-11-28 13:08     ` Christoffer Dall
2016-12-06 13:18     ` Auger Eric
2016-12-06 13:18       ` Auger Eric
2016-11-23 13:01 ` [PATCH v9 03/11] arm/arm64: vgic: Introduce find_reg_by_id() vijay.kilari
2016-11-23 13:01   ` vijay.kilari at gmail.com
2016-12-06 13:27   ` Auger Eric
2016-12-06 13:27     ` Auger Eric
2016-11-23 13:01 ` [PATCH v9 04/11] irqchip/gic-v3: Add missing system register definitions vijay.kilari
2016-11-23 13:01   ` vijay.kilari at gmail.com
2016-12-06 13:53   ` Auger Eric
2016-12-06 13:53     ` Auger Eric
2017-01-23 10:55     ` Vijay Kilari
2017-01-23 10:55       ` Vijay Kilari
2016-11-23 13:01 ` [PATCH v9 05/11] arm/arm64: vgic: Introduce VENG0 and VENG1 fields to vmcr struct vijay.kilari
2016-11-23 13:01   ` vijay.kilari at gmail.com
2016-11-28 14:28   ` Christoffer Dall
2016-11-28 14:28     ` Christoffer Dall
2016-12-08 11:52     ` Auger Eric
2016-12-08 11:52       ` Auger Eric
2016-12-08 12:21       ` Christoffer Dall
2016-12-08 12:21         ` Christoffer Dall
2016-12-08 12:50         ` Auger Eric
2016-12-08 12:50           ` Auger Eric
2016-12-11 16:38           ` Christoffer Dall
2016-12-11 16:38             ` Christoffer Dall
2016-11-23 13:01 ` [PATCH v9 06/11] arm/arm64: vgic: Implement VGICv3 CPU interface access vijay.kilari
2016-11-23 13:01   ` vijay.kilari at gmail.com
2016-11-28 19:39   ` Christoffer Dall
2016-11-28 19:39     ` Christoffer Dall
2016-11-29  7:38     ` Vijay Kilari
2016-11-29  7:38       ` Vijay Kilari
2016-11-29  8:37       ` Christoffer Dall
2016-11-29  8:37         ` Christoffer Dall
2016-11-29 10:01         ` Vijay Kilari
2016-11-29 10:01           ` Vijay Kilari
2016-11-29 10:51           ` Christoffer Dall
2016-11-29 10:51             ` Christoffer Dall
2016-11-23 13:01 ` [PATCH v9 07/11] arm/arm64: vgic: Implement KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO ioctl vijay.kilari
2016-11-23 13:01   ` vijay.kilari at gmail.com
2016-11-28 19:50   ` Christoffer Dall
2016-11-28 19:50     ` Christoffer Dall
2016-11-29 16:36     ` Vijay Kilari
2016-11-29 16:36       ` Vijay Kilari
2016-11-29 21:09       ` Christoffer Dall
2016-11-29 21:09         ` Christoffer Dall
2016-11-30  7:10         ` Peter Maydell
2016-11-30  7:10           ` Peter Maydell
2016-11-30  8:24           ` Christoffer Dall
2016-11-30  8:24             ` Christoffer Dall
2016-11-30  8:29             ` Peter Maydell
2016-11-30  8:29               ` Peter Maydell
2016-11-23 13:01 ` [PATCH v9 08/11] arm/arm64: Documentation: Update arm-vgic-v3.txt vijay.kilari
2016-11-23 13:01   ` vijay.kilari at gmail.com
2016-11-23 13:01 ` [PATCH v9 09/11] arm: coproc: Drop const from coproc reg access function vijay.kilari
2016-11-23 13:01   ` vijay.kilari at gmail.com
2016-11-23 13:01 ` [PATCH v9 10/11] arm: coproc: Introduce find_coproc_reg_by_id() vijay.kilari
2016-11-23 13:01   ` vijay.kilari at gmail.com
2016-11-23 13:01 ` [PATCH v9 11/11] arm: vgic: Save and restore GICv3 CPU interface regs for AArch32 vijay.kilari
2016-11-23 13:01   ` vijay.kilari at gmail.com
2016-11-28 19:51 ` [PATCH v9 0/11] arm/arm64: vgic: Implement API for vGICv3 live migration Christoffer Dall
2016-11-28 19:51   ` Christoffer Dall

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.