All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 0/6] KVM: arm64: Implement API for vGICv3 live migration
@ 2015-12-07 12:29 Pavel Fedin
  2015-12-07 12:29 ` [PATCH v7 1/6] KVM: arm/arm64: Add VGICv3 save/restore API documentation Pavel Fedin
                   ` (5 more replies)
  0 siblings, 6 replies; 17+ messages in thread
From: Pavel Fedin @ 2015-12-07 12:29 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: Christoffer Dall, Marc Zyngier, Andre Przywara

This patchset adds necessary userspace API in order to support vGICv3 live
migration. GICv3 registers are accessed using device attribute ioctls,
similar to GICv2.

v6 => v7:
- Rebased on top of linux-next of 07.12.2015, thrown away unnecessary part

v5 => v6:
- Rebased on top of linux-next of 23.11.2015
- Use original API documentation patch, with minor changes only.
- Quit reusing KVM_DEV_ARM_VGIC_CPUID_MASK, do not touch vGICv2 API at all.
- Fixed some issues reported by the new checkpatch

v4 => v5:
- Adapted to new API by Peter Maydell, Marc Zyngier and Christoffer Dall.
  Acked-by's on the documentation were dropped, just in case, because i
  slightly adjusted it. Additionally, i merged all doc updates into one
  patch.

v3 => v4:
- Split pure refactoring from anything else
- Documentation brought up to date
- Cleaned up 'mmio' structure usage in vgic_attr_regs_access(),
  use call_range_handler() for 64-bit access handling
- Rebased on new linux-next

v2 => v3:
- KVM_DEV_ARM_VGIC_CPUID_MASK enlarged to 20 bits, allowing more than 256
  CPUs.
- Bug fix: Correctly set mmio->private, necessary for redistributor access.
- Added accessors for ICC_AP0R and ICC_AP1R registers
- Rebased on new linux-next

v1 => v2:
- Do not use generic register get/set API for CPU interface, use only
  device attributes.
- Introduce size specifier for distributor and redistributor register
  accesses, do not assume size any more.
- Lots of refactor and reusable code extraction.
- Added forgotten documentation

Christoffer Dall (1):
  KVM: arm/arm64: Add VGICv3 save/restore API documentation

Pavel Fedin (5):
  KVM: arm/arm64: Move endianness conversion out of
    vgic_attr_regs_access()
  KVM: arm/arm64: Refactor vGIC attributes handling code
  KVM: arm64: Implement vGICv3 distributor and redistributor access from
    userspace
  KVM: arm64: Introduce find_reg_by_id()
  KVM: arm64: Implement vGICv3 CPU interface access

 Documentation/virtual/kvm/devices/arm-vgic-v3.txt | 116 ++++++++
 Documentation/virtual/kvm/devices/arm-vgic.txt    |  21 +-
 arch/arm64/include/uapi/asm/kvm.h                 |  15 +-
 arch/arm64/kvm/sys_regs.c                         |  22 +-
 arch/arm64/kvm/sys_regs.h                         |   4 +
 arch/arm64/mm/mmap.c                              |   2 +-
 include/linux/irqchip/arm-gic-v3.h                |  19 +-
 virt/kvm/arm/vgic-v2-emul.c                       | 124 ++------
 virt/kvm/arm/vgic-v3-emul.c                       | 334 +++++++++++++++++++++-
 virt/kvm/arm/vgic.c                               |  57 ++++
 virt/kvm/arm/vgic.h                               |   3 +
 11 files changed, 577 insertions(+), 140 deletions(-)
 create mode 100644 Documentation/virtual/kvm/devices/arm-vgic-v3.txt

-- 
2.4.4


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

* [PATCH v7 1/6] KVM: arm/arm64: Add VGICv3 save/restore API documentation
  2015-12-07 12:29 [PATCH v7 0/6] KVM: arm64: Implement API for vGICv3 live migration Pavel Fedin
@ 2015-12-07 12:29 ` Pavel Fedin
  2016-02-26 15:01   ` Peter Maydell
                     ` (2 more replies)
  2015-12-07 12:29 ` [PATCH v7 2/6] KVM: arm/arm64: Move endianness conversion out of vgic_attr_regs_access() Pavel Fedin
                   ` (4 subsequent siblings)
  5 siblings, 3 replies; 17+ messages in thread
From: Pavel Fedin @ 2015-12-07 12:29 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: Marc Zyngier, Andre Przywara

From: Christoffer Dall <christoffer.dall@linaro.org>

Factor out the GICv3-specific documentation into a separate
documentation file.  Add description for how to access distributor,
redistributor, and CPU interface registers for GICv3 in this new file.

Acked-by: Peter Maydell <peter.maydell@linaro.org>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
---
 Documentation/virtual/kvm/devices/arm-vgic-v3.txt | 116 ++++++++++++++++++++++
 Documentation/virtual/kvm/devices/arm-vgic.txt    |  21 +---
 2 files changed, 120 insertions(+), 17 deletions(-)
 create mode 100644 Documentation/virtual/kvm/devices/arm-vgic-v3.txt

diff --git a/Documentation/virtual/kvm/devices/arm-vgic-v3.txt b/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
new file mode 100644
index 0000000..24e2f6b
--- /dev/null
+++ b/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
@@ -0,0 +1,116 @@
+ARM Virtual Generic Interrupt Controller v3 and later (VGICv3)
+==============================================================
+
+
+Device types supported:
+  KVM_DEV_TYPE_ARM_VGIC_V3     ARM Generic Interrupt Controller v3.0
+
+Only one VGIC instance may be instantiated through this API.  The created VGIC
+will act as the VM interrupt controller, requiring emulated user-space devices
+to inject interrupts to the VGIC instead of directly to CPUs.  It is not
+possible to create both a GICv3 and GICv2 on the same VM.
+
+Creating a guest GICv3 device requires a host GICv3 as well.
+
+Groups:
+  KVM_DEV_ARM_VGIC_GRP_ADDR
+  Attributes:
+    KVM_VGIC_V3_ADDR_TYPE_DIST (rw, 64-bit)
+      Base address in the guest physical address space of the GICv3 distributor
+      register mappings. Only valid for KVM_DEV_TYPE_ARM_VGIC_V3.
+      This address needs to be 64K aligned and the region covers 64 KByte.
+
+    KVM_VGIC_V3_ADDR_TYPE_REDIST (rw, 64-bit)
+      Base address in the guest physical address space of the GICv3
+      redistributor register mappings. There are two 64K pages for each
+      VCPU and all of the redistributor pages are contiguous.
+      Only valid for KVM_DEV_TYPE_ARM_VGIC_V3.
+      This address needs to be 64K aligned.
+
+
+  KVM_DEV_ARM_VGIC_GRP_DIST_REGS
+  KVM_DEV_ARM_VGIC_GRP_REDIST_REGS
+  Attributes:
+    The attr field of kvm_device_attr encodes two values:
+    bits:     | 63   ....  32  |  31   ....    0 |
+    values:   |      mpidr     |      offset     |
+
+    All distributor regs are (rw, 64-bit).
+
+    KVM_DEV_ARM_VGIC_GRP_DIST_REGS accesses the main distributor registers.
+    KVM_DEV_ARM_VGIC_GRP_REDIST_REGS accesses the redistributor of the CPU
+    specified by the mpidr.
+
+    The offset is relative to the "[Re]Distributor base address" as defined
+    in the GICv3/4 specs.  Getting or setting such a register has the same
+    effect as reading or writing the register on real hardware, and the mpidr
+    field is used to specify which redistributor is accessed.  The mpidr is
+    ignored for the distributor.
+
+    The mpidr encoding is based on the affinity information in the
+    architecture defined MPIDR, and the field is encoded as follows:
+      | 63 .... 56 | 55 .... 48 | 47 .... 40 | 39 .... 32 |
+      |    Aff3    |    Aff2    |    Aff1    |    Aff0    |
+
+    Note that distributor fields are not banked, but return the same value
+    regardless of the mpidr used to access the register.
+  Limitations:
+    - Priorities are not implemented, and registers are RAZ/WI
+  Errors:
+    -ENXIO: Getting or setting this register is not yet supported
+    -EBUSY: One or more VCPUs are running
+
+
+  KVM_DEV_ARM_VGIC_CPU_SYSREGS
+  Attributes:
+    The attr field of kvm_device_attr encodes two values:
+    bits:     | 63      ....       32 | 31  ....  16 | 15  ....  0 |
+    values:   |         mpidr         |      RES     |    instr    |
+
+    The mpidr field encodes the CPU ID based on the affinity information in the
+    architecture defined MPIDR, and the field is encoded as follows:
+      | 63 .... 56 | 55 .... 48 | 47 .... 40 | 39 .... 32 |
+      |    Aff3    |    Aff2    |    Aff1    |    Aff0   |
+    KVM_DEV_ARM_VGIC_SYSREG() macro is provided for building register ID.
+
+    The instr field encodes the system register to access based on the fields
+    defined in the A64 instruction set encoding for system register access
+    (RES means the bits are reserved for future use and should be zero):
+
+      | 15 ... 14 | 13 ... 11 | 10 ... 7 | 6 ... 3 | 2 ... 0 |
+      |   Op 0    |    Op1    |    CRn   |   CRm   |   Op2   |
+
+    All system regs accessed through this API are (rw, 64-bit).
+
+    KVM_DEV_ARM_VGIC_CPU_SYSREGS accesses the CPU interface registers for the
+    CPU specified by the mpidr field.
+
+
+  Limitations:
+    - Priorities are not implemented, and registers are RAZ/WI
+  Errors:
+    -ENXIO: Getting or setting this register is not yet supported
+    -EBUSY: VCPU is running
+    -EINVAL: Invalid mpidr supplied
+
+
+  KVM_DEV_ARM_VGIC_GRP_NR_IRQS
+  Attributes:
+    A value describing the number of interrupts (SGI, PPI and SPI) for
+    this GIC instance, ranging from 64 to 1024, in increments of 32.
+
+  Errors:
+    -EINVAL: Value set is out of the expected range
+    -EBUSY: Value has already be set.
+
+
+  KVM_DEV_ARM_VGIC_GRP_CTRL
+  Attributes:
+    KVM_DEV_ARM_VGIC_CTRL_INIT
+      request the initialization of the VGIC, no additional parameter in
+      kvm_device_attr.addr.
+  Errors:
+    -ENXIO: VGIC not properly configured as required prior to calling
+     this attribute
+    -ENODEV: no online VCPU
+    -ENOMEM: memory shortage when allocating vgic internal data
diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt
index 59541d4..257b854 100644
--- a/Documentation/virtual/kvm/devices/arm-vgic.txt
+++ b/Documentation/virtual/kvm/devices/arm-vgic.txt
@@ -3,16 +3,16 @@ ARM Virtual Generic Interrupt Controller (VGIC)
 
 Device types supported:
   KVM_DEV_TYPE_ARM_VGIC_V2     ARM Generic Interrupt Controller v2.0
-  KVM_DEV_TYPE_ARM_VGIC_V3     ARM Generic Interrupt Controller v3.0
 
 Only one VGIC instance may be instantiated through either this API or the
 legacy KVM_CREATE_IRQCHIP api.  The created VGIC will act as the VM interrupt
 controller, requiring emulated user-space devices to inject interrupts to the
 VGIC instead of directly to CPUs.
 
-Creating a guest GICv3 device requires a host GICv3 as well.
-GICv3 implementations with hardware compatibility support allow a guest GICv2
-as well.
+GICv3 implementations with hardware compatibility support allow creating a
+guest GICv2 through this interface.  For information on creating a guest GICv3
+device, see arm-vgic-v3.txt.  It is not possible to create both a GICv3 and
+GICv2 device on the same VM.
 
 Groups:
   KVM_DEV_ARM_VGIC_GRP_ADDR
@@ -27,19 +27,6 @@ Groups:
       interface register mappings. Only valid for KVM_DEV_TYPE_ARM_VGIC_V2.
       This address needs to be 4K aligned and the region covers 4 KByte.
 
-    KVM_VGIC_V3_ADDR_TYPE_DIST (rw, 64-bit)
-      Base address in the guest physical address space of the GICv3 distributor
-      register mappings. Only valid for KVM_DEV_TYPE_ARM_VGIC_V3.
-      This address needs to be 64K aligned and the region covers 64 KByte.
-
-    KVM_VGIC_V3_ADDR_TYPE_REDIST (rw, 64-bit)
-      Base address in the guest physical address space of the GICv3
-      redistributor register mappings. There are two 64K pages for each
-      VCPU and all of the redistributor pages are contiguous.
-      Only valid for KVM_DEV_TYPE_ARM_VGIC_V3.
-      This address needs to be 64K aligned.
-
-
   KVM_DEV_ARM_VGIC_GRP_DIST_REGS
   Attributes:
     The attr field of kvm_device_attr encodes two values:
-- 
2.4.4

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

* [PATCH v7 2/6] KVM: arm/arm64: Move endianness conversion out of vgic_attr_regs_access()
  2015-12-07 12:29 [PATCH v7 0/6] KVM: arm64: Implement API for vGICv3 live migration Pavel Fedin
  2015-12-07 12:29 ` [PATCH v7 1/6] KVM: arm/arm64: Add VGICv3 save/restore API documentation Pavel Fedin
@ 2015-12-07 12:29 ` Pavel Fedin
  2015-12-07 12:29 ` [PATCH v7 3/6] KVM: arm/arm64: Refactor vGIC attributes handling code Pavel Fedin
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 17+ messages in thread
From: Pavel Fedin @ 2015-12-07 12:29 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: Marc Zyngier, Andre Przywara

mmio_data_read() and mmio_data_write(), originally used in this function,
are limited only to 32 bits. We are going to refactor this code and
eventually let it do 64-bit I/O for vGICv3. Therefore, our first step is
to get rid of this limitation.

We open up these inlines, which consist of endianness conversion and
masking. Masking is not used here (the mask is set to ~0), so we just
move out the remaining endianness conversion.

Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
---
 virt/kvm/arm/vgic-v2-emul.c | 20 ++++++++------------
 1 file changed, 8 insertions(+), 12 deletions(-)

diff --git a/virt/kvm/arm/vgic-v2-emul.c b/virt/kvm/arm/vgic-v2-emul.c
index 1390797..959b9c6 100644
--- a/virt/kvm/arm/vgic-v2-emul.c
+++ b/virt/kvm/arm/vgic-v2-emul.c
@@ -663,7 +663,7 @@ static const struct vgic_io_range vgic_cpu_ranges[] = {
 
 static int vgic_attr_regs_access(struct kvm_device *dev,
 				 struct kvm_device_attr *attr,
-				 u32 *reg, bool is_write)
+				 __le32 *data, bool is_write)
 {
 	const struct vgic_io_range *r = NULL, *ranges;
 	phys_addr_t offset;
@@ -671,7 +671,6 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
 	struct kvm_vcpu *vcpu, *tmp_vcpu;
 	struct vgic_dist *vgic;
 	struct kvm_exit_mmio mmio;
-	u32 data;
 
 	offset = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
 	cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >>
@@ -693,9 +692,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
 
 	mmio.len = 4;
 	mmio.is_write = is_write;
-	mmio.data = &data;
-	if (is_write)
-		mmio_data_write(&mmio, ~0, *reg);
+	mmio.data = data;
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
 		mmio.phys_addr = vgic->vgic_dist_base + offset;
@@ -743,9 +740,6 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
 	offset -= r->base;
 	r->handle_mmio(vcpu, &mmio, offset);
 
-	if (!is_write)
-		*reg = mmio_data_read(&mmio, ~0);
-
 	ret = 0;
 out_vgic_unlock:
 	spin_unlock(&vgic->lock);
@@ -778,11 +772,13 @@ static int vgic_v2_set_attr(struct kvm_device *dev,
 	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: {
 		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
 		u32 reg;
+		__le32 data;
 
 		if (get_user(reg, uaddr))
 			return -EFAULT;
 
-		return vgic_attr_regs_access(dev, attr, &reg, true);
+		data = cpu_to_le32(reg);
+		return vgic_attr_regs_access(dev, attr, &data, true);
 	}
 
 	}
@@ -803,12 +799,12 @@ static int vgic_v2_get_attr(struct kvm_device *dev,
 	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
 	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: {
 		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
-		u32 reg = 0;
+		__le32 data = 0;
 
-		ret = vgic_attr_regs_access(dev, attr, &reg, false);
+		ret = vgic_attr_regs_access(dev, attr, &data, false);
 		if (ret)
 			return ret;
-		return put_user(reg, uaddr);
+		return put_user(le32_to_cpu(data), uaddr);
 	}
 
 	}
-- 
2.4.4

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

* [PATCH v7 3/6] KVM: arm/arm64: Refactor vGIC attributes handling code
  2015-12-07 12:29 [PATCH v7 0/6] KVM: arm64: Implement API for vGICv3 live migration Pavel Fedin
  2015-12-07 12:29 ` [PATCH v7 1/6] KVM: arm/arm64: Add VGICv3 save/restore API documentation Pavel Fedin
  2015-12-07 12:29 ` [PATCH v7 2/6] KVM: arm/arm64: Move endianness conversion out of vgic_attr_regs_access() Pavel Fedin
@ 2015-12-07 12:29 ` Pavel Fedin
  2015-12-07 12:29 ` [PATCH v7 4/6] KVM: arm64: Implement vGICv3 distributor and redistributor access from userspace Pavel Fedin
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 17+ messages in thread
From: Pavel Fedin @ 2015-12-07 12:29 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: Christoffer Dall, Marc Zyngier, Andre Przywara

Separate all implementation-independent code in vgic_attr_regs_access()
and move it to vgic.c. This will allow to reuse this code for vGICv3
implementation.

vcpu lookup is left where it originally was, because vGICv3 API will
expect affinity ID instead of vCPU index, therefore it will be done
differently. Also, vcpu pointer has backpointer to kvm, so 'dev' was
replaced with  'vcpu'.

Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
---
 virt/kvm/arm/vgic-v2-emul.c | 120 +++++++++++---------------------------------
 virt/kvm/arm/vgic.c         |  57 +++++++++++++++++++++
 virt/kvm/arm/vgic.h         |   3 ++
 3 files changed, 88 insertions(+), 92 deletions(-)

diff --git a/virt/kvm/arm/vgic-v2-emul.c b/virt/kvm/arm/vgic-v2-emul.c
index 959b9c6..8e769c6 100644
--- a/virt/kvm/arm/vgic-v2-emul.c
+++ b/virt/kvm/arm/vgic-v2-emul.c
@@ -661,38 +661,24 @@ static const struct vgic_io_range vgic_cpu_ranges[] = {
 	},
 };
 
-static int vgic_attr_regs_access(struct kvm_device *dev,
-				 struct kvm_device_attr *attr,
-				 __le32 *data, bool is_write)
+static int vgic_v2_attr_regs_access(struct kvm_device *dev,
+				    struct kvm_device_attr *attr,
+				    __le32 *data, bool is_write)
 {
-	const struct vgic_io_range *r = NULL, *ranges;
+	const struct vgic_io_range *ranges;
 	phys_addr_t offset;
-	int ret, cpuid, c;
-	struct kvm_vcpu *vcpu, *tmp_vcpu;
-	struct vgic_dist *vgic;
+	struct kvm_vcpu *vcpu;
+	int cpuid;
+	struct vgic_dist *vgic = &dev->kvm->arch.vgic;
 	struct kvm_exit_mmio mmio;
 
 	offset = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
 	cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >>
 		KVM_DEV_ARM_VGIC_CPUID_SHIFT;
 
-	mutex_lock(&dev->kvm->lock);
-
-	ret = vgic_init(dev->kvm);
-	if (ret)
-		goto out;
-
-	if (cpuid >= atomic_read(&dev->kvm->online_vcpus)) {
-		ret = -EINVAL;
-		goto out;
-	}
+	if (cpuid >= atomic_read(&dev->kvm->online_vcpus))
+		return -EINVAL;
 
-	vcpu = kvm_get_vcpu(dev->kvm, cpuid);
-	vgic = &dev->kvm->arch.vgic;
-
-	mmio.len = 4;
-	mmio.is_write = is_write;
-	mmio.data = data;
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
 		mmio.phys_addr = vgic->vgic_dist_base + offset;
@@ -703,49 +689,16 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
 		ranges = vgic_cpu_ranges;
 		break;
 	default:
-		BUG();
+		return -ENXIO;
 	}
-	r = vgic_find_range(ranges, 4, offset);
 
-	if (unlikely(!r || !r->handle_mmio)) {
-		ret = -ENXIO;
-		goto out;
-	}
-
-
-	spin_lock(&vgic->lock);
-
-	/*
-	 * Ensure that no other VCPU is running by checking the vcpu->cpu
-	 * field.  If no other VPCUs are running we can safely access the VGIC
-	 * state, because even if another VPU is run after this point, that
-	 * VCPU will not touch the vgic state, because it will block on
-	 * getting the vgic->lock in kvm_vgic_sync_hwstate().
-	 */
-	kvm_for_each_vcpu(c, tmp_vcpu, dev->kvm) {
-		if (unlikely(tmp_vcpu->cpu != -1)) {
-			ret = -EBUSY;
-			goto out_vgic_unlock;
-		}
-	}
-
-	/*
-	 * Move all pending IRQs from the LRs on all VCPUs so the pending
-	 * state can be properly represented in the register state accessible
-	 * through this API.
-	 */
-	kvm_for_each_vcpu(c, tmp_vcpu, dev->kvm)
-		vgic_unqueue_irqs(tmp_vcpu);
+	vcpu = kvm_get_vcpu(dev->kvm, cpuid);
 
-	offset -= r->base;
-	r->handle_mmio(vcpu, &mmio, offset);
+	mmio.len = 4;
+	mmio.is_write = is_write;
+	mmio.data = data;
 
-	ret = 0;
-out_vgic_unlock:
-	spin_unlock(&vgic->lock);
-out:
-	mutex_unlock(&dev->kvm->lock);
-	return ret;
+	return vgic_attr_regs_access(vcpu, ranges, &mmio, offset);
 }
 
 static int vgic_v2_create(struct kvm_device *dev, u32 type)
@@ -761,55 +714,38 @@ static void vgic_v2_destroy(struct kvm_device *dev)
 static int vgic_v2_set_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
+	u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+	u32 reg;
+	__le32 data;
 	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_CPU_REGS: {
-		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
-		u32 reg;
-		__le32 data;
-
-		if (get_user(reg, uaddr))
-			return -EFAULT;
-
-		data = cpu_to_le32(reg);
-		return vgic_attr_regs_access(dev, attr, &data, true);
-	}
-
-	}
+	if (get_user(reg, uaddr))
+		return -EFAULT;
 
-	return -ENXIO;
+	data = cpu_to_le32(reg);
+	return vgic_v2_attr_regs_access(dev, attr, &data, true);
 }
 
 static int vgic_v2_get_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
+	u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+	__le32 data = 0;
 	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_CPU_REGS: {
-		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
-		__le32 data = 0;
-
-		ret = vgic_attr_regs_access(dev, attr, &data, false);
-		if (ret)
-			return ret;
-		return put_user(le32_to_cpu(data), uaddr);
-	}
-
-	}
+	ret = vgic_v2_attr_regs_access(dev, attr, &data, false);
+	if (ret)
+		return ret;
 
-	return -ENXIO;
+	return put_user(le32_to_cpu(data), uaddr);
 }
 
 static int vgic_v2_has_attr(struct kvm_device *dev,
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 65461f8..b8148f2 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -2363,6 +2363,63 @@ int vgic_has_attr_regs(const struct vgic_io_range *ranges, phys_addr_t offset)
 		return -ENXIO;
 }
 
+int vgic_attr_regs_access(struct kvm_vcpu *vcpu,
+			  const struct vgic_io_range *ranges,
+			  struct kvm_exit_mmio *mmio, phys_addr_t offset)
+{
+	const struct vgic_io_range *r;
+	int ret, c;
+	struct kvm_vcpu *tmp_vcpu;
+	struct vgic_dist *vgic;
+
+	r = vgic_find_range(ranges, 4, offset);
+
+	if (unlikely(!r || !r->handle_mmio))
+		return -ENXIO;
+
+	mutex_lock(&vcpu->kvm->lock);
+
+	ret = vgic_init(vcpu->kvm);
+	if (ret)
+		goto out;
+
+	vgic = &vcpu->kvm->arch.vgic;
+
+	spin_lock(&vgic->lock);
+
+	/*
+	 * Ensure that no other VCPU is running by checking the vcpu->cpu
+	 * field.  If no other VPCUs are running we can safely access the VGIC
+	 * state, because even if another VPU is run after this point, that
+	 * VCPU will not touch the vgic state, because it will block on
+	 * getting the vgic->lock in kvm_vgic_sync_hwstate().
+	 */
+	kvm_for_each_vcpu(c, tmp_vcpu, vcpu->kvm) {
+		if (unlikely(tmp_vcpu->cpu != -1)) {
+			ret = -EBUSY;
+			goto out_vgic_unlock;
+		}
+	}
+
+	/*
+	 * Move all pending IRQs from the LRs on all VCPUs so the pending
+	 * state can be properly represented in the register state accessible
+	 * through this API.
+	 */
+	kvm_for_each_vcpu(c, tmp_vcpu, vcpu->kvm)
+		vgic_unqueue_irqs(tmp_vcpu);
+
+	offset -= r->base;
+	r->handle_mmio(vcpu, mmio, offset);
+
+	ret = 0;
+out_vgic_unlock:
+	spin_unlock(&vgic->lock);
+out:
+	mutex_unlock(&vcpu->kvm->lock);
+	return ret;
+}
+
 static void vgic_init_maintenance_interrupt(void *info)
 {
 	enable_percpu_irq(vgic->maint_irq, 0);
diff --git a/virt/kvm/arm/vgic.h b/virt/kvm/arm/vgic.h
index 0df74cb..fca89b7 100644
--- a/virt/kvm/arm/vgic.h
+++ b/virt/kvm/arm/vgic.h
@@ -132,6 +132,9 @@ void vgic_kick_vcpus(struct kvm *kvm);
 int vgic_has_attr_regs(const struct vgic_io_range *ranges, phys_addr_t offset);
 int vgic_set_common_attr(struct kvm_device *dev, struct kvm_device_attr *attr);
 int vgic_get_common_attr(struct kvm_device *dev, struct kvm_device_attr *attr);
+int vgic_attr_regs_access(struct kvm_vcpu *vcpu,
+			  const struct vgic_io_range *ranges,
+			  struct kvm_exit_mmio *mmio, phys_addr_t offset);
 
 int vgic_init(struct kvm *kvm);
 void vgic_v2_init_emulation(struct kvm *kvm);
-- 
2.4.4


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

* [PATCH v7 4/6] KVM: arm64: Implement vGICv3 distributor and redistributor access from userspace
  2015-12-07 12:29 [PATCH v7 0/6] KVM: arm64: Implement API for vGICv3 live migration Pavel Fedin
                   ` (2 preceding siblings ...)
  2015-12-07 12:29 ` [PATCH v7 3/6] KVM: arm/arm64: Refactor vGIC attributes handling code Pavel Fedin
@ 2015-12-07 12:29 ` Pavel Fedin
  2015-12-07 12:29 ` [PATCH v7 5/6] KVM: arm64: Introduce find_reg_by_id() Pavel Fedin
  2015-12-07 12:29 ` [PATCH v7 6/6] KVM: arm64: Implement vGICv3 CPU interface access Pavel Fedin
  5 siblings, 0 replies; 17+ messages in thread
From: Pavel Fedin @ 2015-12-07 12:29 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: Marc Zyngier, Andre Przywara

The access is done similar to vGICv2, 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.

Access size for vGICv3 is 64 bits, vgic_attr_regs_access() fixed to
support this. The trick with vgic_v3_get_reg_size() is necessary because
the major part of GICv3 registers is actually 32-bit, and their accessors
do not distinguish between lower and upper words (offset & 3). Accessing
these registers with len == 8 would cause rollover. For write operations
this would overwrite lower word with the upper one (which would normally
be 0), for read operations this would cause duplication of the same word
in both halves.

Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
---
 arch/arm64/include/uapi/asm/kvm.h  |   1 +
 include/linux/irqchip/arm-gic-v3.h |   1 +
 virt/kvm/arm/vgic-v3-emul.c        | 112 ++++++++++++++++++++++++++++++++-----
 virt/kvm/arm/vgic.c                |   4 +-
 4 files changed, 102 insertions(+), 16 deletions(-)

diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 2d4ca4b..98bd047 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -203,6 +203,7 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_NR_IRQS	3
 #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
+#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
 
 /* KVM_IRQ_LINE irq field index values */
 #define KVM_ARM_IRQ_TYPE_SHIFT		24
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index c9ae0c6..53fd894 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -43,6 +43,7 @@
 #define GICD_IGRPMODR			0x0D00
 #define GICD_NSACR			0x0E00
 #define GICD_IROUTER			0x6000
+#define GICD_IROUTER1019		0x7FD8
 #define GICD_IDREGS			0xFFD0
 #define GICD_PIDR2			0xFFE8
 
diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
index e661e7f..d9d644c 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -39,6 +39,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/interrupt.h>
+#include <linux/uaccess.h>
 
 #include <linux/irqchip/arm-gic-v3.h>
 #include <kvm/arm_vgic.h>
@@ -990,6 +991,77 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
 		vgic_kick_vcpus(vcpu->kvm);
 }
 
+static u32 vgic_v3_get_reg_size(u32 group, u32 offset)
+{
+	switch (group) {
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+		if (offset >= GICD_IROUTER && offset <= GICD_IROUTER1019)
+			return 8;
+		else
+			return 4;
+		break;
+
+	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
+		if ((offset == GICR_TYPER) ||
+		    (offset >= GICR_SETLPIR && offset <= GICR_INVALLR))
+			return 8;
+		else
+			return 4;
+		break;
+
+	default:
+		BUG();
+	}
+}
+
+static int vgic_v3_attr_regs_access(struct kvm_device *dev,
+				    struct kvm_device_attr *attr,
+				    u64 *reg, bool is_write)
+{
+	const struct vgic_io_range *ranges;
+	phys_addr_t offset;
+	struct kvm_vcpu *vcpu;
+	u64 cpuid;
+	struct vgic_dist *vgic = &dev->kvm->arch.vgic;
+	struct kvm_exit_mmio mmio;
+	__le64 data;
+	int ret;
+
+	offset = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+	cpuid = attr->attr >> KVM_DEV_ARM_VGIC_CPUID_SHIFT;
+
+	/* Convert affinity ID from our packed to normal form */
+	cpuid = (cpuid & 0x00ffffff) | ((cpuid & 0xff000000) << 8);
+	vcpu = kvm_mpidr_to_vcpu(dev->kvm, cpuid);
+	if (!vcpu)
+		return -EINVAL;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+		mmio.phys_addr = vgic->vgic_dist_base + offset;
+		ranges = vgic_v3_dist_ranges;
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
+		mmio.phys_addr = vgic->vgic_redist_base + offset;
+		ranges = vgic_redist_ranges;
+		break;
+	default:
+		return -ENXIO;
+	}
+
+	data = cpu_to_le64(*reg);
+
+	mmio.len = vgic_v3_get_reg_size(attr->group, offset);
+	mmio.is_write = is_write;
+	mmio.data = &data;
+	mmio.private = vcpu; /* Redistributor handlers expect this */
+
+	ret = vgic_attr_regs_access(vcpu, ranges, &mmio, offset);
+
+	*reg = le64_to_cpu(data);
+	return ret;
+}
+
 static int vgic_v3_create(struct kvm_device *dev, u32 type)
 {
 	return kvm_vgic_create(dev->kvm, type);
@@ -1003,42 +1075,45 @@ static void vgic_v3_destroy(struct kvm_device *dev)
 static int vgic_v3_set_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
+	u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+	u64 reg;
 	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_CPU_REGS:
-		return -ENXIO;
-	}
+	if (get_user(reg, uaddr))
+		return -EFAULT;
 
-	return -ENXIO;
+	return vgic_v3_attr_regs_access(dev, attr, &reg, true);
 }
 
 static int vgic_v3_get_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
+	u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+	u64 reg = 0;
 	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_CPU_REGS:
-		return -ENXIO;
-	}
+	ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
+	if (ret)
+		return ret;
 
-	return -ENXIO;
+	return put_user(reg, uaddr);
 }
 
 static int vgic_v3_has_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
+	phys_addr_t offset;
+	struct sys_reg_params params;
+	u64 regid;
+
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_ADDR:
 		switch (attr->attr) {
@@ -1051,8 +1126,17 @@ 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_CPU_REGS:
-		return -ENXIO;
+		offset = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+		return vgic_has_attr_regs(vgic_v3_dist_ranges, offset);
+	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
+		offset = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+		return vgic_has_attr_regs(vgic_redist_ranges, offset);
+	case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
+		regid = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_MASK) |
+			KVM_REG_SIZE_U64;
+		return find_reg_by_id(regid, &params, gic_v3_icc_reg_descs,
+				      ARRAY_SIZE(gic_v3_icc_reg_descs)) ?
+			0 : -ENXIO;
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
 	case KVM_DEV_ARM_VGIC_GRP_CTRL:
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index b8148f2..4047d0e 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -2372,7 +2372,7 @@ int vgic_attr_regs_access(struct kvm_vcpu *vcpu,
 	struct kvm_vcpu *tmp_vcpu;
 	struct vgic_dist *vgic;
 
-	r = vgic_find_range(ranges, 4, offset);
+	r = vgic_find_range(ranges, mmio->len, offset);
 
 	if (unlikely(!r || !r->handle_mmio))
 		return -ENXIO;
@@ -2410,7 +2410,7 @@ int vgic_attr_regs_access(struct kvm_vcpu *vcpu,
 		vgic_unqueue_irqs(tmp_vcpu);
 
 	offset -= r->base;
-	r->handle_mmio(vcpu, mmio, offset);
+	call_range_handler(vcpu, mmio, offset, r);
 
 	ret = 0;
 out_vgic_unlock:
-- 
2.4.4

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

* [PATCH v7 5/6] KVM: arm64: Introduce find_reg_by_id()
  2015-12-07 12:29 [PATCH v7 0/6] KVM: arm64: Implement API for vGICv3 live migration Pavel Fedin
                   ` (3 preceding siblings ...)
  2015-12-07 12:29 ` [PATCH v7 4/6] KVM: arm64: Implement vGICv3 distributor and redistributor access from userspace Pavel Fedin
@ 2015-12-07 12:29 ` Pavel Fedin
  2015-12-07 12:29 ` [PATCH v7 6/6] KVM: arm64: Implement vGICv3 CPU interface access Pavel Fedin
  5 siblings, 0 replies; 17+ messages in thread
From: Pavel Fedin @ 2015-12-07 12:29 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: Marc Zyngier, Andre Przywara

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>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
---
 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 d2650e8..8c4b671 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1276,6 +1276,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)
@@ -1403,10 +1414,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;
 
@@ -1420,9 +1429,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
-- 
2.4.4

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

* [PATCH v7 6/6] KVM: arm64: Implement vGICv3 CPU interface access
  2015-12-07 12:29 [PATCH v7 0/6] KVM: arm64: Implement API for vGICv3 live migration Pavel Fedin
                   ` (4 preceding siblings ...)
  2015-12-07 12:29 ` [PATCH v7 5/6] KVM: arm64: Introduce find_reg_by_id() Pavel Fedin
@ 2015-12-07 12:29 ` Pavel Fedin
  5 siblings, 0 replies; 17+ messages in thread
From: Pavel Fedin @ 2015-12-07 12:29 UTC (permalink / raw)
  To: kvmarm, kvm; +Cc: Marc Zyngier, Andre Przywara

Access size is always 64 bits. Since CPU interface state actually affects
only a single vCPU, no vGIC locking is done in order to avoid code
duplication. Just made sure that the vCPU is not running.

Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
---
 arch/arm64/include/uapi/asm/kvm.h  |  14 ++-
 arch/arm64/mm/mmap.c               |   2 +-
 include/linux/irqchip/arm-gic-v3.h |  18 ++-
 virt/kvm/arm/vgic-v3-emul.c        | 224 ++++++++++++++++++++++++++++++++++++-
 4 files changed, 251 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 98bd047..ca32fe5 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -179,14 +179,14 @@ struct kvm_arch_memory_slot {
 	KVM_REG_ARM64_SYSREG_ ## n ## _MASK)
 
 #define __ARM64_SYS_REG(op0,op1,crn,crm,op2) \
-	(KVM_REG_ARM64 | KVM_REG_ARM64_SYSREG | \
-	ARM64_SYS_REG_SHIFT_MASK(op0, OP0) | \
+	(ARM64_SYS_REG_SHIFT_MASK(op0, OP0) | \
 	ARM64_SYS_REG_SHIFT_MASK(op1, OP1) | \
 	ARM64_SYS_REG_SHIFT_MASK(crn, CRN) | \
 	ARM64_SYS_REG_SHIFT_MASK(crm, CRM) | \
 	ARM64_SYS_REG_SHIFT_MASK(op2, OP2))
 
-#define ARM64_SYS_REG(...) (__ARM64_SYS_REG(__VA_ARGS__) | KVM_REG_SIZE_U64)
+#define ARM64_SYS_REG(...) (__ARM64_SYS_REG(__VA_ARGS__) | KVM_REG_ARM64 | \
+			    KVM_REG_SIZE_U64 | KVM_REG_ARM64_SYSREG)
 
 #define KVM_REG_ARM_TIMER_CTL		ARM64_SYS_REG(3, 3, 14, 3, 1)
 #define KVM_REG_ARM_TIMER_CNT		ARM64_SYS_REG(3, 3, 14, 3, 2)
@@ -204,6 +204,14 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
 #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
+#define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6
+#define   KVM_DEV_ARM_VGIC_SYSREG_MASK	(KVM_REG_ARM64_SYSREG_OP0_MASK | \
+					 KVM_REG_ARM64_SYSREG_OP1_MASK | \
+					 KVM_REG_ARM64_SYSREG_CRN_MASK | \
+					 KVM_REG_ARM64_SYSREG_CRM_MASK | \
+					 KVM_REG_ARM64_SYSREG_OP2_MASK)
+#define   KVM_DEV_ARM_VGIC_SYSREG(op0, op1, crn, crm, op2) \
+					__ARM64_SYS_REG(op0, op1, crn, crm, op2)
 
 /* KVM_IRQ_LINE irq field index values */
 #define KVM_ARM_IRQ_TYPE_SHIFT		24
diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c
index af461b9..e59a75a 100644
--- a/arch/arm64/mm/mmap.c
+++ b/arch/arm64/mm/mmap.c
@@ -51,7 +51,7 @@ unsigned long arch_mmap_rnd(void)
 {
 	unsigned long rnd;
 
-ifdef CONFIG_COMPAT
+#ifdef CONFIG_COMPAT
 	if (test_thread_flag(TIF_32BIT))
 		rnd = (unsigned long)get_random_int() % (1 << mmap_rnd_compat_bits);
 	else
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 53fd894..bff3eee 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -259,8 +259,14 @@
 /*
  * CPU interface registers
  */
-#define ICC_CTLR_EL1_EOImode_drop_dir	(0U << 1)
-#define ICC_CTLR_EL1_EOImode_drop	(1U << 1)
+#define ICC_CTLR_EL1_CBPR_SHIFT		0
+#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_PRIbits_MASK	(7U << 8)
+#define ICC_CTLR_EL1_IDbits_MASK	(7U << 11)
+#define ICC_CTLR_EL1_SEIS		(1U << 14)
+#define ICC_CTLR_EL1_A3V		(1U << 15)
 #define ICC_SRE_EL1_SRE			(1U << 0)
 
 /*
@@ -285,6 +291,14 @@
 
 #define ICH_VMCR_CTLR_SHIFT		0
 #define ICH_VMCR_CTLR_MASK		(0x21f << ICH_VMCR_CTLR_SHIFT)
+#define ICH_VMCR_ENG0_SHIFT		0
+#define ICH_VMCR_ENG0			(1 << ICH_VMCR_ENG0_SHIFT)
+#define ICH_VMCR_ENG1_SHIFT		1
+#define ICH_VMCR_ENG1			(1 << ICH_VMCR_ENG1_SHIFT)
+#define ICH_VMCR_CBPR_SHIFT		4
+#define ICH_VMCR_CBPR			(1 << ICH_VMCR_CBPR_SHIFT)
+#define ICH_VMCR_EOIM_SHIFT		9
+#define ICH_VMCR_EOIM			(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
diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c
index d9d644c..8cae803 100644
--- a/virt/kvm/arm/vgic-v3-emul.c
+++ b/virt/kvm/arm/vgic-v3-emul.c
@@ -48,6 +48,7 @@
 #include <asm/kvm_arm.h>
 #include <asm/kvm_mmu.h>
 
+#include "sys_regs.h"
 #include "vgic.h"
 
 static bool handle_mmio_rao_wi(struct kvm_vcpu *vcpu,
@@ -991,6 +992,219 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
 		vgic_kick_vcpus(vcpu->kvm);
 }
 
+static bool access_gic_ctlr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			    const struct sys_reg_desc *r)
+{
+	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	if (p->is_write) {
+		vgicv3->vgic_vmcr &= ~(ICH_VMCR_CBPR|ICH_VMCR_EOIM);
+		vgicv3->vgic_vmcr |= (p->regval << (ICH_VMCR_CBPR_SHIFT -
+						    ICC_CTLR_EL1_CBPR_SHIFT))
+				     & ICH_VMCR_CBPR;
+		vgicv3->vgic_vmcr |= (p->regval << (ICH_VMCR_EOIM_SHIFT -
+						    ICC_CTLR_EL1_EOImode_SHIFT))
+				     & ICH_VMCR_EOIM;
+	} else {
+		asm volatile("mrs_s %0," __stringify(ICC_IAR1_EL1)
+			     : "=r" (p->regval));
+		p->regval &= (ICC_CTLR_EL1_A3V | ICC_CTLR_EL1_SEIS |
+			      ICC_CTLR_EL1_IDbits_MASK |
+			      ICC_CTLR_EL1_PRIbits_MASK);
+		p->regval |= (vgicv3->vgic_vmcr & ICH_VMCR_CBPR) >>
+			     (ICH_VMCR_CBPR_SHIFT - ICC_CTLR_EL1_CBPR_SHIFT);
+		p->regval |= (vgicv3->vgic_vmcr & ICH_VMCR_EOIM) >>
+			     (ICH_VMCR_EOIM_SHIFT - ICC_CTLR_EL1_EOImode_SHIFT);
+	}
+
+	return true;
+}
+
+static bool access_gic_pmr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			   const struct sys_reg_desc *r)
+{
+	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	if (p->is_write) {
+		vgicv3->vgic_vmcr &= ~ICH_VMCR_PMR_MASK;
+		vgicv3->vgic_vmcr |= (p->regval << ICH_VMCR_PMR_SHIFT) &
+				     ICH_VMCR_PMR_MASK;
+	} else {
+		p->regval = (vgicv3->vgic_vmcr & ICH_VMCR_PMR_MASK) >>
+			    ICH_VMCR_PMR_SHIFT;
+	}
+
+	return true;
+}
+
+static bool access_gic_bpr0(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			    const struct sys_reg_desc *r)
+{
+	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	if (p->is_write) {
+		vgicv3->vgic_vmcr &= ~ICH_VMCR_BPR0_MASK;
+		vgicv3->vgic_vmcr |= (p->regval << ICH_VMCR_BPR0_SHIFT) &
+				     ICH_VMCR_BPR0_MASK;
+	} else {
+		p->regval = (vgicv3->vgic_vmcr & ICH_VMCR_BPR0_MASK) >>
+			    ICH_VMCR_BPR0_SHIFT;
+	}
+
+	return true;
+}
+
+static bool access_gic_bpr1(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			    const struct sys_reg_desc *r)
+{
+	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	if (p->is_write) {
+		vgicv3->vgic_vmcr &= ~ICH_VMCR_BPR1_MASK;
+		vgicv3->vgic_vmcr |= (p->regval << ICH_VMCR_BPR1_SHIFT) &
+				     ICH_VMCR_BPR1_MASK;
+	} else {
+		p->regval = (vgicv3->vgic_vmcr & ICH_VMCR_BPR1_MASK) >>
+			    ICH_VMCR_BPR1_SHIFT;
+	}
+
+	return true;
+}
+
+static bool access_gic_grpen0(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			      const struct sys_reg_desc *r)
+{
+	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	if (p->is_write) {
+		vgicv3->vgic_vmcr &= ~ICH_VMCR_ENG0;
+		vgicv3->vgic_vmcr |= (p->regval << ICH_VMCR_ENG0_SHIFT) &
+				     ICH_VMCR_ENG0;
+	} else {
+		p->regval = (vgicv3->vgic_vmcr & ICH_VMCR_ENG0) >>
+			    ICH_VMCR_ENG0_SHIFT;
+	}
+
+	return true;
+}
+
+static bool access_gic_grpen1(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			      const struct sys_reg_desc *r)
+{
+	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	if (p->is_write) {
+		vgicv3->vgic_vmcr &= ~ICH_VMCR_ENG1;
+		vgicv3->vgic_vmcr |= (p->regval << ICH_VMCR_ENG1_SHIFT) &
+				     ICH_VMCR_ENG1;
+	} else {
+		p->regval = (vgicv3->vgic_vmcr & ICH_VMCR_ENG1) >>
+			    ICH_VMCR_ENG1_SHIFT;
+	}
+
+	return true;
+}
+
+static bool access_gic_ap0r(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			    const struct sys_reg_desc *r)
+{
+	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
+	u8 idx = r->Op2 & 3;
+
+	if (p->is_write)
+		vgicv3->vgic_ap0r[idx] = p->regval;
+	else
+		p->regval = vgicv3->vgic_ap0r[idx];
+
+	return true;
+}
+
+static bool access_gic_ap1r(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			    const struct sys_reg_desc *r)
+{
+	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
+	u8 idx = r->Op2 & 3;
+
+	if (p->is_write)
+		vgicv3->vgic_ap1r[idx] = p->regval;
+	else
+		p->regval = vgicv3->vgic_ap1r[idx];
+
+	return true;
+}
+
+static const struct sys_reg_desc gic_v3_icc_reg_descs[] = {
+	/* ICC_PMR_EL1 */
+	{ Op0(0b11), Op1(0b000), CRn(0b0100), CRm(0b0110), Op2(0b000),
+	  access_gic_pmr },
+	/* ICC_BPR0_EL1 */
+	{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1000), Op2(0b011),
+	  access_gic_bpr0 },
+	/* ICC_AP0R0_EL1 */
+	{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1000), Op2(0b100),
+	  access_gic_ap0r },
+	/* ICC_AP0R1_EL1 */
+	{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1000), Op2(0b101),
+	  access_gic_ap0r },
+	/* ICC_AP0R2_EL1 */
+	{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1000), Op2(0b110),
+	  access_gic_ap0r },
+	/* ICC_AP0R3_EL1 */
+	{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1000), Op2(0b111),
+	  access_gic_ap0r },
+	/* ICC_AP1R0_EL1 */
+	{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1001), Op2(0b000),
+	  access_gic_ap1r },
+	/* ICC_AP1R1_EL1 */
+	{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1001), Op2(0b001),
+	  access_gic_ap1r },
+	/* ICC_AP1R2_EL1 */
+	{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1001), Op2(0b010),
+	  access_gic_ap1r },
+	/* ICC_AP1R3_EL1 */
+	{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1001), Op2(0b011),
+	  access_gic_ap1r },
+	/* ICC_BPR1_EL1 */
+	{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1100), Op2(0b011),
+	  access_gic_bpr1 },
+	/* ICC_CTLR_EL1 */
+	{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1100), Op2(0b100),
+	  access_gic_ctlr },
+	/* ICC_IGRPEN0_EL1 */
+	{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1100), Op2(0b110),
+	  access_gic_grpen0 },
+	/* ICC_GRPEN1_EL1 */
+	{ Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1100), Op2(0b111),
+	  access_gic_grpen1 },
+};
+
+static int vgic_v3_cpu_regs_access(struct kvm_vcpu *vcpu, u64 id, u64 *reg,
+				   bool is_write)
+{
+	struct sys_reg_params params;
+	const struct sys_reg_desc *r;
+
+	params.regval = *reg;
+	params.is_write = is_write;
+	params.is_aarch32 = false;
+	params.is_32bit = false;
+
+	r = find_reg_by_id(id, &params, gic_v3_icc_reg_descs,
+			   ARRAY_SIZE(gic_v3_icc_reg_descs));
+	if (!r)
+		return -ENXIO;
+
+	/* Ensure that VCPU is not running */
+	if (unlikely(vcpu->cpu != -1))
+		return -EBUSY;
+
+	if (!r->access(vcpu, &params, r))
+		return -EINVAL;
+
+	*reg = params.regval;
+	return 0;
+}
+
 static u32 vgic_v3_get_reg_size(u32 group, u32 offset)
 {
 	switch (group) {
@@ -1021,7 +1235,7 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
 	const struct vgic_io_range *ranges;
 	phys_addr_t offset;
 	struct kvm_vcpu *vcpu;
-	u64 cpuid;
+	u64 cpuid, regid;
 	struct vgic_dist *vgic = &dev->kvm->arch.vgic;
 	struct kvm_exit_mmio mmio;
 	__le64 data;
@@ -1045,6 +1259,14 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
 		mmio.phys_addr = vgic->vgic_redist_base + offset;
 		ranges = vgic_redist_ranges;
 		break;
+	case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
+		/*
+		 * Our register ID is missing size specifier, expected by
+		 * index_to_params()
+		 */
+		regid = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_MASK) |
+			KVM_REG_SIZE_U64;
+		return vgic_v3_cpu_regs_access(vcpu, regid, reg, is_write);
 	default:
 		return -ENXIO;
 	}
-- 
2.4.4

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

* Re: [PATCH v7 1/6] KVM: arm/arm64: Add VGICv3 save/restore API documentation
  2015-12-07 12:29 ` [PATCH v7 1/6] KVM: arm/arm64: Add VGICv3 save/restore API documentation Pavel Fedin
@ 2016-02-26 15:01   ` Peter Maydell
  2016-03-02 12:48     ` Christoffer Dall
  2016-04-15 13:20   ` Peter Maydell
  2016-04-15 13:58   ` Peter Maydell
  2 siblings, 1 reply; 17+ messages in thread
From: Peter Maydell @ 2016-02-26 15:01 UTC (permalink / raw)
  To: Pavel Fedin, Christoffer Dall
  Cc: kvmarm, kvm-devel, Marc Zyngier, Andre Przywara

On 7 December 2015 at 12:29, Pavel Fedin <p.fedin@samsung.com> wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
>
> Factor out the GICv3-specific documentation into a separate
> documentation file.  Add description for how to access distributor,
> redistributor, and CPU interface registers for GICv3 in this new file.
>
> Acked-by: Peter Maydell <peter.maydell@linaro.org>
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>

I was rereading this API doc this week, and I realised we missed
something when we wrote it:

> +  KVM_DEV_ARM_VGIC_GRP_DIST_REGS
> +  KVM_DEV_ARM_VGIC_GRP_REDIST_REGS
> +  Attributes:
> +    The attr field of kvm_device_attr encodes two values:
> +    bits:     | 63   ....  32  |  31   ....    0 |
> +    values:   |      mpidr     |      offset     |
> +
> +    All distributor regs are (rw, 64-bit).

It's a bit odd to claim that distributor (or redistributor)
registers are all 64-bit, because in the hardware most of them
are really 32-bit, and at 32-bit offsets from each other.
We didn't mean to imply that you could do a 64-bit access
at offset 0 of the distributor and get both of GICD_CTLR and
GICD_TYPER at once, for instance.

I'm not quite sure what we want to say in the documentation,
though I think our general intent was clear:

 * you access a particular register at its relevant offset,
   and you only get that register
 * no support for reading half a register
 * if the register (as documented in the GICv3 architecture
   specification) is less than 64 bits wide then the returned
   result is zero-extended to 64 bits on read, and high bits
   are ignored on write
   (Only a couple of registers are really 64-bits, notably
   GICD_IROUTER<n>. The rest are 32-bits. We could probably explicitly
   list all the 64-bit regs in this doc if we didn't want to defer
   to the arch spec.)

Do we want to forbid accesses to registers which the architecture
says can be byte-accessed, like GICD_IPRIORITYR<n>? I think we have
to, because the kernel API we have here doesn't have any way to
specify access width, and it would be weird for addresses X+1,
X+2, X+3 to give you 8 bits of data when X+0 gave you 32.

What do we mean by the "rw" part? Some registers really are
architecturally RO, so does this mean "writes to architecturally
RO registers will succeed but be ignored rather than returning an
errno" ?

> +
> +    KVM_DEV_ARM_VGIC_GRP_DIST_REGS accesses the main distributor registers.
> +    KVM_DEV_ARM_VGIC_GRP_REDIST_REGS accesses the redistributor of the CPU
> +    specified by the mpidr.
> +
> +    The offset is relative to the "[Re]Distributor base address" as defined
> +    in the GICv3/4 specs.  Getting or setting such a register has the same
> +    effect as reading or writing the register on real hardware, and the mpidr
> +    field is used to specify which redistributor is accessed.  The mpidr is
> +    ignored for the distributor.
> +
> +    The mpidr encoding is based on the affinity information in the
> +    architecture defined MPIDR, and the field is encoded as follows:
> +      | 63 .... 56 | 55 .... 48 | 47 .... 40 | 39 .... 32 |
> +      |    Aff3    |    Aff2    |    Aff1    |    Aff0    |
> +
> +    Note that distributor fields are not banked, but return the same value
> +    regardless of the mpidr used to access the register.
> +  Limitations:
> +    - Priorities are not implemented, and registers are RAZ/WI
> +  Errors:
> +    -ENXIO: Getting or setting this register is not yet supported
> +    -EBUSY: One or more VCPUs are running
> +
> +
> +  KVM_DEV_ARM_VGIC_CPU_SYSREGS

In contrast it's fine for sysregs to be all 64-bit, because they correspond
to CPU system registers which are architecturally 64-bits.

thanks
-- PMM

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

* Re: [PATCH v7 1/6] KVM: arm/arm64: Add VGICv3 save/restore API documentation
  2016-02-26 15:01   ` Peter Maydell
@ 2016-03-02 12:48     ` Christoffer Dall
  0 siblings, 0 replies; 17+ messages in thread
From: Christoffer Dall @ 2016-03-02 12:48 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Pavel Fedin, kvmarm, kvm-devel, Marc Zyngier, Andre Przywara

On Fri, Feb 26, 2016 at 03:01:56PM +0000, Peter Maydell wrote:
> On 7 December 2015 at 12:29, Pavel Fedin <p.fedin@samsung.com> wrote:
> > From: Christoffer Dall <christoffer.dall@linaro.org>
> >
> > Factor out the GICv3-specific documentation into a separate
> > documentation file.  Add description for how to access distributor,
> > redistributor, and CPU interface registers for GICv3 in this new file.
> >
> > Acked-by: Peter Maydell <peter.maydell@linaro.org>
> > Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
> 
> I was rereading this API doc this week, and I realised we missed
> something when we wrote it:
> 
> > +  KVM_DEV_ARM_VGIC_GRP_DIST_REGS
> > +  KVM_DEV_ARM_VGIC_GRP_REDIST_REGS
> > +  Attributes:
> > +    The attr field of kvm_device_attr encodes two values:
> > +    bits:     | 63   ....  32  |  31   ....    0 |
> > +    values:   |      mpidr     |      offset     |
> > +
> > +    All distributor regs are (rw, 64-bit).
> 
> It's a bit odd to claim that distributor (or redistributor)
> registers are all 64-bit, because in the hardware most of them
> are really 32-bit, and at 32-bit offsets from each other.
> We didn't mean to imply that you could do a 64-bit access
> at offset 0 of the distributor and get both of GICD_CTLR and
> GICD_TYPER at once, for instance.

no we didn't, and I think this was just an oversight on my side.

Perhaps what I meant was the userspace should just provide a pointer to
a 64-bit value.

> 
> I'm not quite sure what we want to say in the documentation,
> though I think our general intent was clear:
> 
>  * you access a particular register at its relevant offset,
>    and you only get that register
>  * no support for reading half a register
>  * if the register (as documented in the GICv3 architecture
>    specification) is less than 64 bits wide then the returned
>    result is zero-extended to 64 bits on read, and high bits
>    are ignored on write
>    (Only a couple of registers are really 64-bits, notably
>    GICD_IROUTER<n>. The rest are 32-bits. We could probably explicitly
>    list all the 64-bit regs in this doc if we didn't want to defer
>    to the arch spec.)
> 
> Do we want to forbid accesses to registers which the architecture
> says can be byte-accessed, like GICD_IPRIORITYR<n>? I think we have
> to, because the kernel API we have here doesn't have any way to
> specify access width, and it would be weird for addresses X+1,
> X+2, X+3 to give you 8 bits of data when X+0 gave you 32.

yes, for the gicv2 API we only allow accesses on 32-bit aligned
boundaries and always assume a 32-bit access.

> 
> What do we mean by the "rw" part? Some registers really are
> architecturally RO, so does this mean "writes to architecturally
> RO registers will succeed but be ignored rather than returning an
> errno" ?

I think my intention was that this would work like the invariant
sysregs, where if you write anything else than what the kernel has
defined, then you get an error.  Not sure if this is something we'd want
to do here though.  Seems like the GICv2 implementation just ignores
writes in line with the architecture.

> 
> > +
> > +    KVM_DEV_ARM_VGIC_GRP_DIST_REGS accesses the main distributor registers.
> > +    KVM_DEV_ARM_VGIC_GRP_REDIST_REGS accesses the redistributor of the CPU
> > +    specified by the mpidr.
> > +
> > +    The offset is relative to the "[Re]Distributor base address" as defined
> > +    in the GICv3/4 specs.  Getting or setting such a register has the same
> > +    effect as reading or writing the register on real hardware, and the mpidr
> > +    field is used to specify which redistributor is accessed.  The mpidr is
> > +    ignored for the distributor.
> > +
> > +    The mpidr encoding is based on the affinity information in the
> > +    architecture defined MPIDR, and the field is encoded as follows:
> > +      | 63 .... 56 | 55 .... 48 | 47 .... 40 | 39 .... 32 |
> > +      |    Aff3    |    Aff2    |    Aff1    |    Aff0    |
> > +
> > +    Note that distributor fields are not banked, but return the same value
> > +    regardless of the mpidr used to access the register.
> > +  Limitations:
> > +    - Priorities are not implemented, and registers are RAZ/WI
> > +  Errors:
> > +    -ENXIO: Getting or setting this register is not yet supported
> > +    -EBUSY: One or more VCPUs are running
> > +
> > +
> > +  KVM_DEV_ARM_VGIC_CPU_SYSREGS
> 
> In contrast it's fine for sysregs to be all 64-bit, because they correspond
> to CPU system registers which are architecturally 64-bits.
> 

Right, perhaps this was my confusion.

Thanks,
-Christoffer

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

* Re: [PATCH v7 1/6] KVM: arm/arm64: Add VGICv3 save/restore API documentation
  2015-12-07 12:29 ` [PATCH v7 1/6] KVM: arm/arm64: Add VGICv3 save/restore API documentation Pavel Fedin
  2016-02-26 15:01   ` Peter Maydell
@ 2016-04-15 13:20   ` Peter Maydell
  2016-04-15 13:58   ` Peter Maydell
  2 siblings, 0 replies; 17+ messages in thread
From: Peter Maydell @ 2016-04-15 13:20 UTC (permalink / raw)
  To: Pavel Fedin; +Cc: kvmarm, kvm-devel, Marc Zyngier, Andre Przywara

On 7 December 2015 at 12:29, Pavel Fedin <p.fedin@samsung.com> wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
>
> Factor out the GICv3-specific documentation into a separate
> documentation file.  Add description for how to access distributor,
> redistributor, and CPU interface registers for GICv3 in this new file.

> +  KVM_DEV_ARM_VGIC_GRP_DIST_REGS
> +  KVM_DEV_ARM_VGIC_GRP_REDIST_REGS
> +  Attributes:
> +    The attr field of kvm_device_attr encodes two values:
> +    bits:     | 63   ....  32  |  31   ....    0 |
> +    values:   |      mpidr     |      offset     |
> +
> +    All distributor regs are (rw, 64-bit).
> +
> +    KVM_DEV_ARM_VGIC_GRP_DIST_REGS accesses the main distributor registers.
> +    KVM_DEV_ARM_VGIC_GRP_REDIST_REGS accesses the redistributor of the CPU
> +    specified by the mpidr.
> +
> +    The offset is relative to the "[Re]Distributor base address" as defined
> +    in the GICv3/4 specs.  Getting or setting such a register has the same
> +    effect as reading or writing the register on real hardware, and the mpidr
> +    field is used to specify which redistributor is accessed.  The mpidr is
> +    ignored for the distributor.

I've just noticed an awkward wrinkle here. The (optional) registers
GICR_STATUSR and GICD_STATUSR are both architecturally "write-1-to-clear",
with no mechanism in the hardware to write 1 bits back into them.
So if we want to support migrating these state fields, the behaviour
of the userspace accessor has to be something different from the effect
of writing the register on real hardware (eg "writes actually write the
specified value")...

thanks
-- PMM

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

* Re: [PATCH v7 1/6] KVM: arm/arm64: Add VGICv3 save/restore API documentation
  2015-12-07 12:29 ` [PATCH v7 1/6] KVM: arm/arm64: Add VGICv3 save/restore API documentation Pavel Fedin
  2016-02-26 15:01   ` Peter Maydell
  2016-04-15 13:20   ` Peter Maydell
@ 2016-04-15 13:58   ` Peter Maydell
  2016-04-18 10:33     ` Peter Maydell
  2016-04-20 10:59     ` Christoffer Dall
  2 siblings, 2 replies; 17+ messages in thread
From: Peter Maydell @ 2016-04-15 13:58 UTC (permalink / raw)
  To: Pavel Fedin; +Cc: kvmarm, kvm-devel, Marc Zyngier, Andre Przywara

On 7 December 2015 at 12:29, Pavel Fedin <p.fedin@samsung.com> wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
>
> Factor out the GICv3-specific documentation into a separate
> documentation file.  Add description for how to access distributor,
> redistributor, and CPU interface registers for GICv3 in this new file.
>
> Acked-by: Peter Maydell <peter.maydell@linaro.org>
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>

Nothing in here describes a mechanism for reading or writing the
current interrupt line_level state from the kernel (which doesn't
matter for edge triggered interrupts but does for level triggered
interrupts). Do we need accessors for these or does somebody
have a good rationale for why we don't need to migrate that data?
(Christoffer?)

(GICv2 doesn't do this either and I suspect it's wrong too.)

thanks
-- PMM

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

* Re: [PATCH v7 1/6] KVM: arm/arm64: Add VGICv3 save/restore API documentation
  2016-04-15 13:58   ` Peter Maydell
@ 2016-04-18 10:33     ` Peter Maydell
  2016-04-20 11:03       ` Christoffer Dall
  2016-04-20 10:59     ` Christoffer Dall
  1 sibling, 1 reply; 17+ messages in thread
From: Peter Maydell @ 2016-04-18 10:33 UTC (permalink / raw)
  To: Pavel Fedin; +Cc: Marc Zyngier, Andre Przywara, kvmarm, kvm-devel

On 15 April 2016 at 14:58, Peter Maydell <peter.maydell@linaro.org> wrote:
> Nothing in here describes a mechanism for reading or writing the
> current interrupt line_level state from the kernel (which doesn't
> matter for edge triggered interrupts but does for level triggered
> interrupts). Do we need accessors for these or does somebody
> have a good rationale for why we don't need to migrate that data?
> (Christoffer?)

Relatedly, we should have a mechanism for directly reading and
writing the pending-latch state in the KVM GIC, which for
a level triggered interrupt is not the same as the behaviour
of reading and writing the PENDING register.

thanks
-- PMM

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

* Re: [PATCH v7 1/6] KVM: arm/arm64: Add VGICv3 save/restore API documentation
  2016-04-15 13:58   ` Peter Maydell
  2016-04-18 10:33     ` Peter Maydell
@ 2016-04-20 10:59     ` Christoffer Dall
  2016-04-20 13:28       ` Peter Maydell
  1 sibling, 1 reply; 17+ messages in thread
From: Christoffer Dall @ 2016-04-20 10:59 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Marc Zyngier, Andre Przywara, kvmarm, kvm-devel


[-- Attachment #1.1: Type: text/plain, Size: 1692 bytes --]

On Friday, 15 April 2016, Peter Maydell <peter.maydell@linaro.org> wrote:

> On 7 December 2015 at 12:29, Pavel Fedin <p.fedin@samsung.com
> <javascript:;>> wrote:
> > From: Christoffer Dall <christoffer.dall@linaro.org <javascript:;>>
> >
> > Factor out the GICv3-specific documentation into a separate
> > documentation file.  Add description for how to access distributor,
> > redistributor, and CPU interface registers for GICv3 in this new file.
> >
> > Acked-by: Peter Maydell <peter.maydell@linaro.org <javascript:;>>
> > Acked-by: Marc Zyngier <marc.zyngier@arm.com <javascript:;>>
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org
> <javascript:;>>
> > Signed-off-by: Pavel Fedin <p.fedin@samsung.com <javascript:;>>
>
> Nothing in here describes a mechanism for reading or writing the
> current interrupt line_level state from the kernel (which doesn't
> matter for edge triggered interrupts but does for level triggered
> interrupts). Do we need accessors for these or does somebody
> have a good rationale for why we don't need to migrate that data?
> (Christoffer?)
>
> (GICv2 doesn't do this either and I suspect it's wrong too.)
>
>
I thought we relied on user space to migrate its device state including the
interrupt line output state and set the corresponding line state to the
kernel, but that may have been wrong, and would rely on userspace to call
the IRQ_LINE ioctl again.  Would that work?

How is it again, does QEMU preserve the IRQ output line state per device?

This may just work currently because we rely on the reads/writes to SPENDR
to preserve the state and apparently level triggered interrupts are
reinjected as needed.

Thanks,
-Christoffer

[-- Attachment #1.2: Type: text/html, Size: 2642 bytes --]

[-- Attachment #2: Type: text/plain, Size: 151 bytes --]

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

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

* Re: [PATCH v7 1/6] KVM: arm/arm64: Add VGICv3 save/restore API documentation
  2016-04-18 10:33     ` Peter Maydell
@ 2016-04-20 11:03       ` Christoffer Dall
  0 siblings, 0 replies; 17+ messages in thread
From: Christoffer Dall @ 2016-04-20 11:03 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Marc Zyngier, Andre Przywara, kvmarm, kvm-devel


[-- Attachment #1.1: Type: text/plain, Size: 1045 bytes --]

On Monday, 18 April 2016, Peter Maydell <peter.maydell@linaro.org> wrote:

> On 15 April 2016 at 14:58, Peter Maydell <peter.maydell@linaro.org
> <javascript:;>> wrote:
> > Nothing in here describes a mechanism for reading or writing the
> > current interrupt line_level state from the kernel (which doesn't
> > matter for edge triggered interrupts but does for level triggered
> > interrupts). Do we need accessors for these or does somebody
> > have a good rationale for why we don't need to migrate that data?
> > (Christoffer?)
>
> Relatedly, we should have a mechanism for directly reading and
> writing the pending-latch state in the KVM GIC, which for
> a level triggered interrupt is not the same as the behaviour
> of reading and writing the PENDING register.
>
>
Strictly speaking, yes. But can we think of a use case that would really
need this?

(I saw this as a thing that was implemented for software to capture the
state of the gic and restore it, but since that's what we're doing here, it
seems redundant)

Thanks,
-Christoffer

[-- Attachment #1.2: Type: text/html, Size: 1467 bytes --]

[-- Attachment #2: Type: text/plain, Size: 151 bytes --]

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

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

* Re: [PATCH v7 1/6] KVM: arm/arm64: Add VGICv3 save/restore API documentation
  2016-04-20 10:59     ` Christoffer Dall
@ 2016-04-20 13:28       ` Peter Maydell
  2016-04-21 18:30         ` Christoffer Dall
  0 siblings, 1 reply; 17+ messages in thread
From: Peter Maydell @ 2016-04-20 13:28 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Pavel Fedin, kvmarm, kvm-devel, Marc Zyngier, Andre Przywara

On 20 April 2016 at 11:59, Christoffer Dall <christoffer.dall@linaro.org> wrote:
> On Friday, 15 April 2016, Peter Maydell <peter.maydell@linaro.org> wrote:
>> Nothing in here describes a mechanism for reading or writing the
>> current interrupt line_level state from the kernel (which doesn't
>> matter for edge triggered interrupts but does for level triggered
>> interrupts). Do we need accessors for these or does somebody
>> have a good rationale for why we don't need to migrate that data?
>> (Christoffer?)

> I thought we relied on user space to migrate its device state including the
> interrupt line output state and set the corresponding line state to the
> kernel, but that may have been wrong, and would rely on userspace to call
> the IRQ_LINE ioctl again.  Would that work?

I'm not sure; it's definitely not what we do today, anyway...

> How is it again, does QEMU preserve the IRQ output line state per device?

In QEMU device models, each device has its own state and generally
tracks the level of its input lines as necessary. When state
restore happens, the device on the sending end restores its own
state but doesn't reassert the irq line; the assumption is that
the device on the receiving end restores its own state including
the level of its input lines.

> This may just work currently because we rely on the reads/writes to SPENDR
> to preserve the state and apparently level triggered interrupts are
> reinjected as needed.

I think the reason it more or less works is that as you say we
write the pending bits back to the PENDR registers. There are
two cases where this goes wrong for level triggered interrupts,
though:
(1) if a device deasserts its interrupt output before the
guest OS gets round to acknowledging the interrupt, then
what should happen is that the interrupt stops being pending;
since we wrote to PENDR then the latch means we'll deliver
the guest a spurious interrupt
(2) if a guest OS's interrupt handler doesn't quiesce the
device such that it deasserts the interrupt output, then
what should happen is that when the interrupt is dismissed
it remains pending and will trigger again; since we didn't
copy the level state into the kernel then the kernel won't
notice and won't deliver the interrupt again

Since the distributor/redistributor is fully emulated inside
the kernel, we have the underlying state separately for
levels and for the pending-latch, right? We don't need to
make it impossible to access the latch separately just
because that's what the hardware does...

thanks
-- PMM

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

* Re: [PATCH v7 1/6] KVM: arm/arm64: Add VGICv3 save/restore API documentation
  2016-04-20 13:28       ` Peter Maydell
@ 2016-04-21 18:30         ` Christoffer Dall
  2016-04-21 18:44           ` Peter Maydell
  0 siblings, 1 reply; 17+ messages in thread
From: Christoffer Dall @ 2016-04-21 18:30 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Pavel Fedin, kvmarm, kvm-devel, Marc Zyngier, Andre Przywara

On Wed, Apr 20, 2016 at 02:28:05PM +0100, Peter Maydell wrote:
> On 20 April 2016 at 11:59, Christoffer Dall <christoffer.dall@linaro.org> wrote:
> > On Friday, 15 April 2016, Peter Maydell <peter.maydell@linaro.org> wrote:
> >> Nothing in here describes a mechanism for reading or writing the
> >> current interrupt line_level state from the kernel (which doesn't
> >> matter for edge triggered interrupts but does for level triggered
> >> interrupts). Do we need accessors for these or does somebody
> >> have a good rationale for why we don't need to migrate that data?
> >> (Christoffer?)
> 
> > I thought we relied on user space to migrate its device state including the
> > interrupt line output state and set the corresponding line state to the
> > kernel, but that may have been wrong, and would rely on userspace to call
> > the IRQ_LINE ioctl again.  Would that work?
> 
> I'm not sure; it's definitely not what we do today, anyway...
> 
> > How is it again, does QEMU preserve the IRQ output line state per device?
> 
> In QEMU device models, each device has its own state and generally
> tracks the level of its input lines as necessary. When state
> restore happens, the device on the sending end restores its own
> state but doesn't reassert the irq line; the assumption is that
> the device on the receiving end restores its own state including
> the level of its input lines.
> 
> > This may just work currently because we rely on the reads/writes to SPENDR
> > to preserve the state and apparently level triggered interrupts are
> > reinjected as needed.
> 
> I think the reason it more or less works is that as you say we
> write the pending bits back to the PENDR registers. There are
> two cases where this goes wrong for level triggered interrupts,
> though:
> (1) if a device deasserts its interrupt output before the
> guest OS gets round to acknowledging the interrupt, then
> what should happen is that the interrupt stops being pending;
> since we wrote to PENDR then the latch means we'll deliver
> the guest a spurious interrupt
> (2) if a guest OS's interrupt handler doesn't quiesce the
> device such that it deasserts the interrupt output, then
> what should happen is that when the interrupt is dismissed
> it remains pending and will trigger again; since we didn't
> copy the level state into the kernel then the kernel won't
> notice and won't deliver the interrupt again
> 
> Since the distributor/redistributor is fully emulated inside
> the kernel, we have the underlying state separately for
> levels and for the pending-latch, right? We don't need to
> make it impossible to access the latch separately just
> because that's what the hardware does...
> 
So I agree about the latch state, that should be exported, if nothing
else so that a VM can't use this particular change to detect a
migration, for example.

However, for the input level, I really do see this as a wire state
between userspace and the kernel, and as something that userspace should
re-establish after migration, since userspace already knows what the
line level is, why does it need to pull it out of the kernel again?

-Christoffer

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

* Re: [PATCH v7 1/6] KVM: arm/arm64: Add VGICv3 save/restore API documentation
  2016-04-21 18:30         ` Christoffer Dall
@ 2016-04-21 18:44           ` Peter Maydell
  0 siblings, 0 replies; 17+ messages in thread
From: Peter Maydell @ 2016-04-21 18:44 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Pavel Fedin, kvmarm, kvm-devel, Marc Zyngier, Andre Przywara

On 21 April 2016 at 19:30, Christoffer Dall <christoffer.dall@linaro.org> wrote:
> So I agree about the latch state, that should be exported, if nothing
> else so that a VM can't use this particular change to detect a
> migration, for example.
>
> However, for the input level, I really do see this as a wire state
> between userspace and the kernel, and as something that userspace should
> re-establish after migration, since userspace already knows what the
> line level is, why does it need to pull it out of the kernel again?

I guess userspace could track the line level as well as telling the
kernel about it, but we would still need an API for telling the
kernel "here is your line level state after a migration", because
that's not the same as "the line level just changed because the
device signaled an interrupt". (For the former, we just want to set
your 'level' struct field value. For the latter, a 0->1 level change
may mean "set pending"; but for migration we're already telling you
the current pending state via a different ioctl and don't want to
mess that up when we're telling you about the 'level' info.)
And if we have to have migration API for directly writing level bits we
might as well have the corresponding directly-read-level-bits one...

thanks
-- PMM

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

end of thread, other threads:[~2016-04-21 18:45 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-07 12:29 [PATCH v7 0/6] KVM: arm64: Implement API for vGICv3 live migration Pavel Fedin
2015-12-07 12:29 ` [PATCH v7 1/6] KVM: arm/arm64: Add VGICv3 save/restore API documentation Pavel Fedin
2016-02-26 15:01   ` Peter Maydell
2016-03-02 12:48     ` Christoffer Dall
2016-04-15 13:20   ` Peter Maydell
2016-04-15 13:58   ` Peter Maydell
2016-04-18 10:33     ` Peter Maydell
2016-04-20 11:03       ` Christoffer Dall
2016-04-20 10:59     ` Christoffer Dall
2016-04-20 13:28       ` Peter Maydell
2016-04-21 18:30         ` Christoffer Dall
2016-04-21 18:44           ` Peter Maydell
2015-12-07 12:29 ` [PATCH v7 2/6] KVM: arm/arm64: Move endianness conversion out of vgic_attr_regs_access() Pavel Fedin
2015-12-07 12:29 ` [PATCH v7 3/6] KVM: arm/arm64: Refactor vGIC attributes handling code Pavel Fedin
2015-12-07 12:29 ` [PATCH v7 4/6] KVM: arm64: Implement vGICv3 distributor and redistributor access from userspace Pavel Fedin
2015-12-07 12:29 ` [PATCH v7 5/6] KVM: arm64: Introduce find_reg_by_id() Pavel Fedin
2015-12-07 12:29 ` [PATCH v7 6/6] KVM: arm64: Implement vGICv3 CPU interface access Pavel Fedin

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.