All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/55] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-05-06 10:45 ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

Hi,

another week, another rework of the new-VGIC series.
Mostly minor changes this time, some moving and streamlining of patches
(move prototypes to the same patch as the definition etc.)
The most prominent change though is the rework of the GICv2 CPU
interface access functionality. It turns out that this was not properly
wired, so now we treat is very similar to the distributor registers
and declare the registers in our register structure.
Find a summary changelog below and more details in the respective patches.

As this new VGIC emulation will probably become the default very shortly,
please test it full steam on whatever setup you have access to.
Any reports are warmly welcome.

This series is still based on v4.6-rc5 as the previous version, though
a test rebase to -rc6 didn't trigger any issues.
A git tree containing this series can be found on linux-arm.org:

git://linux-arm.org/linux-ap.git	branch: vgic-new/v3
http://www.linux-arm.org/git?p=linux-ap.git;a=log;h=refs/heads/vgic-new/v3

Cheers,
Andre.

Changelog v2 .. v3:
- arch_timer: remove bogus validity check from kvm_vgic_unmap_phys_irq()
- arch_timer: simplify return in kvm_timer_vcpu_reset()
- move some code between patches to fix rebase artifacts
- add patch 12/55 to move some definitions into arm-vgic-v3.h
- replace inclusions of vgic/vgic.h with arm_vgic.h
- rename v3 redist register description variables to _rdbase_ and _sgibase_
- don't export VMCR accessor wrappers
- rework CPU i/f access from userland, moving code into vgic-mmio-v2.c
- make ich_vtr_el2 variable local

===========================
This series is a joint effort to re-implement KVM's GIC emulation.

While the current implementation is centered around providing
efficient MMIO emulation, the hot path for most guests is actually
the guest entry and exit, which currently is rather costly.
Also the existing emulation has a global distributor lock, which
quickly becomes a bottleneck once the number of VCPUs increases.
Additionally the emulation was originally designed for GICv2, adding
GICv3 ITS emulation support to this proved to be rather painful.
Last, but not least the existing code became less and less
maintainable, with many special cases handled explicitly.

The new implementation is build around a struct vgic_irq data
structure, which holds all information about a virtual interrupt.
Interruts which should be injected are held in a per-VCPU list, this
make the entry/exit path much more efficient. Also the new structure
allows to have more fine grained locking - per IRQ and per VCPU -
getting rid of the global distributor lock.
As a result of the new design ITS emulation fits in more nicely, the
respective code will be provided as a follow-up series.

This series implements the same feature set as the existing emulation,
as a goodie we now implement priorities correctly.
To allow an easy transition with good test coverage, but still maintain
stability, both implementations live side by side, selectable via a
Kconfig option. The default is the new implementation.
If this code proves to be reliable, we will later remove the current
implementation with an extra patch set.

Please have a look at the series, review it and give the code some
serious testing (and possibly debugging). All feedback is appreciated.

Cheers,
Andre.

Andre Przywara (29):
  KVM: arm/arm64: vgic: streamline vgic_update_irq_pending() interface
  KVM: arm/arm64: vgic: avoid map in kvm_vgic_inject_mapped_irq()
  KVM: arm/arm64: vgic: avoid map in kvm_vgic_map_is_active()
  KVM: arm/arm64: vgic: avoid map in kvm_vgic_unmap_phys_irq()
  KVM: arm/arm64: arch_timer: Remove irq_phys_map
  KVM: arm/arm64: vgic: Remove irq_phys_map from interface
  KVM: arm/arm64: pmu: abstract access to number of SPIs
  KVM: arm/arm64: move GICv2 emulation defines into arm-gic-v3.h
  KVM: arm/arm64: vgic-new: Add GICv2 MMIO handling framework
  KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  KVM: arm/arm64: vgic-new: Add PENDING registers handlers
  KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
  KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
  KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
  KVM: arm/arm64: vgic-new: Add TARGET registers handlers
  KVM: arm/arm64: vgic-new: Add SGIR register handler
  KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
  KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
  KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
  KVM: arm/arm64: vgic-new: Add GICv3 redistributor IIDR and TYPER handler
  KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
  KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
  KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
  KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
  KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors
  KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
  KVM: arm/arm64: vgic-new: Wire up irqfd injection
  KVM: arm/arm64: vgic-new: implement mapped IRQ handling
  KVM: arm/arm64: vgic-new: enable build

Christoffer Dall (9):
  KVM: arm/arm64: Remove the IRQ field from struct irq_phys_map
  KVM: arm/arm64: Get rid of vgic_cpu->nr_lr
  KVM: arm/arm64: Fix MMIO emulation data handling
  KVM: arm/arm64: Export mmio_read/write_bus
  KVM: arm/arm64: vgic-new: Add data structure definitions
  KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
  KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
  KVM: arm/arm64: vgic-new: Add IRQ sorting
  KVM: arm/arm64: vgic-new: Export register access interface

Eric Auger (12):
  KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
  KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration
  KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS
  KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL
  KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr
  KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR
  KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
  KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
  KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create
  KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
  KVM: arm/arm64: vgic-new: vgic_init: implement map_resources
  KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable

Marc Zyngier (5):
  KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
  KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
  KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
  KVM: arm/arm64: vgic-new: Add MMIO handling framework
  KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers

 arch/arm/include/asm/kvm_mmio.h     |   3 +
 arch/arm/kvm/Kconfig                |   7 +
 arch/arm/kvm/Makefile               |  11 +
 arch/arm/kvm/mmio.c                 |  24 +-
 arch/arm64/include/asm/kvm_mmio.h   |   3 +
 arch/arm64/kvm/Kconfig              |   7 +
 arch/arm64/kvm/Makefile             |  12 +
 include/kvm/arm_arch_timer.h        |   3 -
 include/kvm/arm_vgic.h              |  20 +-
 include/kvm/vgic/vgic.h             | 253 +++++++++++++++
 include/linux/irqchip/arm-gic-v3.h  |   6 +
 include/linux/irqchip/arm-gic.h     |   2 +
 virt/kvm/arm/arch_timer.c           |  42 ++-
 virt/kvm/arm/hyp/vgic-v2-sr.c       |  17 +-
 virt/kvm/arm/pmu.c                  |   2 +-
 virt/kvm/arm/vgic-v2.c              |   4 +-
 virt/kvm/arm/vgic-v3.c              |   8 +-
 virt/kvm/arm/vgic.c                 |  86 ++---
 virt/kvm/arm/vgic/vgic-init.c       | 446 ++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-irqfd.c      |  52 +++
 virt/kvm/arm/vgic/vgic-kvm-device.c | 452 ++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio-v2.c    | 422 +++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio-v3.c    | 464 +++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.c       | 523 ++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.h       | 128 ++++++++
 virt/kvm/arm/vgic/vgic-v2.c         | 358 +++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c         | 333 +++++++++++++++++++
 virt/kvm/arm/vgic/vgic.c            | 615 ++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h            | 121 +++++++
 29 files changed, 4309 insertions(+), 115 deletions(-)
 create mode 100644 include/kvm/vgic/vgic.h
 create mode 100644 virt/kvm/arm/vgic/vgic-init.c
 create mode 100644 virt/kvm/arm/vgic/vgic-irqfd.c
 create mode 100644 virt/kvm/arm/vgic/vgic-kvm-device.c
 create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v2.c
 create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
 create mode 100644 virt/kvm/arm/vgic/vgic-mmio.c
 create mode 100644 virt/kvm/arm/vgic/vgic-mmio.h
 create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
 create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
 create mode 100644 virt/kvm/arm/vgic/vgic.c
 create mode 100644 virt/kvm/arm/vgic/vgic.h

-- 
2.7.3

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

* [PATCH v3 00/55] KVM: arm/arm64: Rework virtual GIC emulation
@ 2016-05-06 10:45 ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

another week, another rework of the new-VGIC series.
Mostly minor changes this time, some moving and streamlining of patches
(move prototypes to the same patch as the definition etc.)
The most prominent change though is the rework of the GICv2 CPU
interface access functionality. It turns out that this was not properly
wired, so now we treat is very similar to the distributor registers
and declare the registers in our register structure.
Find a summary changelog below and more details in the respective patches.

As this new VGIC emulation will probably become the default very shortly,
please test it full steam on whatever setup you have access to.
Any reports are warmly welcome.

This series is still based on v4.6-rc5 as the previous version, though
a test rebase to -rc6 didn't trigger any issues.
A git tree containing this series can be found on linux-arm.org:

git://linux-arm.org/linux-ap.git	branch: vgic-new/v3
http://www.linux-arm.org/git?p=linux-ap.git;a=log;h=refs/heads/vgic-new/v3

Cheers,
Andre.

Changelog v2 .. v3:
- arch_timer: remove bogus validity check from kvm_vgic_unmap_phys_irq()
- arch_timer: simplify return in kvm_timer_vcpu_reset()
- move some code between patches to fix rebase artifacts
- add patch 12/55 to move some definitions into arm-vgic-v3.h
- replace inclusions of vgic/vgic.h with arm_vgic.h
- rename v3 redist register description variables to _rdbase_ and _sgibase_
- don't export VMCR accessor wrappers
- rework CPU i/f access from userland, moving code into vgic-mmio-v2.c
- make ich_vtr_el2 variable local

===========================
This series is a joint effort to re-implement KVM's GIC emulation.

While the current implementation is centered around providing
efficient MMIO emulation, the hot path for most guests is actually
the guest entry and exit, which currently is rather costly.
Also the existing emulation has a global distributor lock, which
quickly becomes a bottleneck once the number of VCPUs increases.
Additionally the emulation was originally designed for GICv2, adding
GICv3 ITS emulation support to this proved to be rather painful.
Last, but not least the existing code became less and less
maintainable, with many special cases handled explicitly.

The new implementation is build around a struct vgic_irq data
structure, which holds all information about a virtual interrupt.
Interruts which should be injected are held in a per-VCPU list, this
make the entry/exit path much more efficient. Also the new structure
allows to have more fine grained locking - per IRQ and per VCPU -
getting rid of the global distributor lock.
As a result of the new design ITS emulation fits in more nicely, the
respective code will be provided as a follow-up series.

This series implements the same feature set as the existing emulation,
as a goodie we now implement priorities correctly.
To allow an easy transition with good test coverage, but still maintain
stability, both implementations live side by side, selectable via a
Kconfig option. The default is the new implementation.
If this code proves to be reliable, we will later remove the current
implementation with an extra patch set.

Please have a look at the series, review it and give the code some
serious testing (and possibly debugging). All feedback is appreciated.

Cheers,
Andre.

Andre Przywara (29):
  KVM: arm/arm64: vgic: streamline vgic_update_irq_pending() interface
  KVM: arm/arm64: vgic: avoid map in kvm_vgic_inject_mapped_irq()
  KVM: arm/arm64: vgic: avoid map in kvm_vgic_map_is_active()
  KVM: arm/arm64: vgic: avoid map in kvm_vgic_unmap_phys_irq()
  KVM: arm/arm64: arch_timer: Remove irq_phys_map
  KVM: arm/arm64: vgic: Remove irq_phys_map from interface
  KVM: arm/arm64: pmu: abstract access to number of SPIs
  KVM: arm/arm64: move GICv2 emulation defines into arm-gic-v3.h
  KVM: arm/arm64: vgic-new: Add GICv2 MMIO handling framework
  KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  KVM: arm/arm64: vgic-new: Add PENDING registers handlers
  KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
  KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
  KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
  KVM: arm/arm64: vgic-new: Add TARGET registers handlers
  KVM: arm/arm64: vgic-new: Add SGIR register handler
  KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
  KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
  KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
  KVM: arm/arm64: vgic-new: Add GICv3 redistributor IIDR and TYPER handler
  KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
  KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
  KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
  KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
  KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors
  KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
  KVM: arm/arm64: vgic-new: Wire up irqfd injection
  KVM: arm/arm64: vgic-new: implement mapped IRQ handling
  KVM: arm/arm64: vgic-new: enable build

Christoffer Dall (9):
  KVM: arm/arm64: Remove the IRQ field from struct irq_phys_map
  KVM: arm/arm64: Get rid of vgic_cpu->nr_lr
  KVM: arm/arm64: Fix MMIO emulation data handling
  KVM: arm/arm64: Export mmio_read/write_bus
  KVM: arm/arm64: vgic-new: Add data structure definitions
  KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
  KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
  KVM: arm/arm64: vgic-new: Add IRQ sorting
  KVM: arm/arm64: vgic-new: Export register access interface

Eric Auger (12):
  KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
  KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration
  KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS
  KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL
  KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr
  KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR
  KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
  KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
  KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create
  KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
  KVM: arm/arm64: vgic-new: vgic_init: implement map_resources
  KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable

Marc Zyngier (5):
  KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
  KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
  KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
  KVM: arm/arm64: vgic-new: Add MMIO handling framework
  KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers

 arch/arm/include/asm/kvm_mmio.h     |   3 +
 arch/arm/kvm/Kconfig                |   7 +
 arch/arm/kvm/Makefile               |  11 +
 arch/arm/kvm/mmio.c                 |  24 +-
 arch/arm64/include/asm/kvm_mmio.h   |   3 +
 arch/arm64/kvm/Kconfig              |   7 +
 arch/arm64/kvm/Makefile             |  12 +
 include/kvm/arm_arch_timer.h        |   3 -
 include/kvm/arm_vgic.h              |  20 +-
 include/kvm/vgic/vgic.h             | 253 +++++++++++++++
 include/linux/irqchip/arm-gic-v3.h  |   6 +
 include/linux/irqchip/arm-gic.h     |   2 +
 virt/kvm/arm/arch_timer.c           |  42 ++-
 virt/kvm/arm/hyp/vgic-v2-sr.c       |  17 +-
 virt/kvm/arm/pmu.c                  |   2 +-
 virt/kvm/arm/vgic-v2.c              |   4 +-
 virt/kvm/arm/vgic-v3.c              |   8 +-
 virt/kvm/arm/vgic.c                 |  86 ++---
 virt/kvm/arm/vgic/vgic-init.c       | 446 ++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-irqfd.c      |  52 +++
 virt/kvm/arm/vgic/vgic-kvm-device.c | 452 ++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio-v2.c    | 422 +++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio-v3.c    | 464 +++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.c       | 523 ++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.h       | 128 ++++++++
 virt/kvm/arm/vgic/vgic-v2.c         | 358 +++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c         | 333 +++++++++++++++++++
 virt/kvm/arm/vgic/vgic.c            | 615 ++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h            | 121 +++++++
 29 files changed, 4309 insertions(+), 115 deletions(-)
 create mode 100644 include/kvm/vgic/vgic.h
 create mode 100644 virt/kvm/arm/vgic/vgic-init.c
 create mode 100644 virt/kvm/arm/vgic/vgic-irqfd.c
 create mode 100644 virt/kvm/arm/vgic/vgic-kvm-device.c
 create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v2.c
 create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
 create mode 100644 virt/kvm/arm/vgic/vgic-mmio.c
 create mode 100644 virt/kvm/arm/vgic/vgic-mmio.h
 create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
 create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
 create mode 100644 virt/kvm/arm/vgic/vgic.c
 create mode 100644 virt/kvm/arm/vgic/vgic.h

-- 
2.7.3

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

* [PATCH v3 01/55] KVM: arm/arm64: vgic: streamline vgic_update_irq_pending() interface
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

We actually don't use the irq_phys_map parameter in
vgic_update_irq_pending(), so let's just remove it.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
 virt/kvm/arm/vgic.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 00429b3..7282881 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1522,7 +1522,6 @@ static int vgic_validate_injection(struct kvm_vcpu *vcpu, int irq, int level)
 }
 
 static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
-				   struct irq_phys_map *map,
 				   unsigned int irq_num, bool level)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
@@ -1661,7 +1660,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
 	if (map)
 		return -EINVAL;
 
-	return vgic_update_irq_pending(kvm, cpuid, NULL, irq_num, level);
+	return vgic_update_irq_pending(kvm, cpuid, irq_num, level);
 }
 
 /**
@@ -1687,7 +1686,7 @@ int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
 	if (ret)
 		return ret;
 
-	return vgic_update_irq_pending(kvm, cpuid, map, map->virt_irq, level);
+	return vgic_update_irq_pending(kvm, cpuid, map->virt_irq, level);
 }
 
 static irqreturn_t vgic_maintenance_handler(int irq, void *data)
-- 
2.7.3


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

* [PATCH v3 01/55] KVM: arm/arm64: vgic: streamline vgic_update_irq_pending() interface
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

We actually don't use the irq_phys_map parameter in
vgic_update_irq_pending(), so let's just remove it.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
 virt/kvm/arm/vgic.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 00429b3..7282881 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1522,7 +1522,6 @@ static int vgic_validate_injection(struct kvm_vcpu *vcpu, int irq, int level)
 }
 
 static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
-				   struct irq_phys_map *map,
 				   unsigned int irq_num, bool level)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
@@ -1661,7 +1660,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
 	if (map)
 		return -EINVAL;
 
-	return vgic_update_irq_pending(kvm, cpuid, NULL, irq_num, level);
+	return vgic_update_irq_pending(kvm, cpuid, irq_num, level);
 }
 
 /**
@@ -1687,7 +1686,7 @@ int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
 	if (ret)
 		return ret;
 
-	return vgic_update_irq_pending(kvm, cpuid, map, map->virt_irq, level);
+	return vgic_update_irq_pending(kvm, cpuid, map->virt_irq, level);
 }
 
 static irqreturn_t vgic_maintenance_handler(int irq, void *data)
-- 
2.7.3

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

* [PATCH v3 02/55] KVM: arm/arm64: vgic: avoid map in kvm_vgic_inject_mapped_irq()
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

When we want to inject a hardware mapped IRQ into a guest, we actually
only need the virtual IRQ number from the irq_phys_map.
So let's pass this number directly from the arch timer to the VGIC
to avoid using the map as a parameter.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
 include/kvm/arm_vgic.h    | 2 +-
 virt/kvm/arm/arch_timer.c | 2 +-
 virt/kvm/arm/vgic.c       | 6 +++---
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 281caf8..c4574da 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -341,7 +341,7 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
 			bool level);
 int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
-			       struct irq_phys_map *map, bool level);
+			       unsigned int virt_irq, bool level);
 void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 9aaa35d..ceec146 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -178,7 +178,7 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level)
 	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->map->virt_irq,
 				   timer->irq.level);
 	ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id,
-					 timer->map,
+					 timer->map->virt_irq,
 					 timer->irq.level);
 	WARN_ON(ret);
 }
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 7282881..9937d41 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1667,7 +1667,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
  * kvm_vgic_inject_mapped_irq - Inject a physically mapped IRQ to the vgic
  * @kvm:     The VM structure pointer
  * @cpuid:   The CPU for PPIs
- * @map:     Pointer to a irq_phys_map structure describing the mapping
+ * @virt_irq: The virtual IRQ to be injected
  * @level:   Edge-triggered:  true:  to trigger the interrupt
  *			      false: to ignore the call
  *	     Level-sensitive  true:  raise the input signal
@@ -1678,7 +1678,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
  * being HIGH and 0 being LOW and all devices being active-HIGH.
  */
 int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
-			       struct irq_phys_map *map, bool level)
+			       unsigned int virt_irq, bool level)
 {
 	int ret;
 
@@ -1686,7 +1686,7 @@ int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
 	if (ret)
 		return ret;
 
-	return vgic_update_irq_pending(kvm, cpuid, map->virt_irq, level);
+	return vgic_update_irq_pending(kvm, cpuid, virt_irq, level);
 }
 
 static irqreturn_t vgic_maintenance_handler(int irq, void *data)
-- 
2.7.3


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

* [PATCH v3 02/55] KVM: arm/arm64: vgic: avoid map in kvm_vgic_inject_mapped_irq()
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

When we want to inject a hardware mapped IRQ into a guest, we actually
only need the virtual IRQ number from the irq_phys_map.
So let's pass this number directly from the arch timer to the VGIC
to avoid using the map as a parameter.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
 include/kvm/arm_vgic.h    | 2 +-
 virt/kvm/arm/arch_timer.c | 2 +-
 virt/kvm/arm/vgic.c       | 6 +++---
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 281caf8..c4574da 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -341,7 +341,7 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
 			bool level);
 int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
-			       struct irq_phys_map *map, bool level);
+			       unsigned int virt_irq, bool level);
 void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 9aaa35d..ceec146 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -178,7 +178,7 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level)
 	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->map->virt_irq,
 				   timer->irq.level);
 	ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id,
-					 timer->map,
+					 timer->map->virt_irq,
 					 timer->irq.level);
 	WARN_ON(ret);
 }
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 7282881..9937d41 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1667,7 +1667,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
  * kvm_vgic_inject_mapped_irq - Inject a physically mapped IRQ to the vgic
  * @kvm:     The VM structure pointer
  * @cpuid:   The CPU for PPIs
- * @map:     Pointer to a irq_phys_map structure describing the mapping
+ * @virt_irq: The virtual IRQ to be injected
  * @level:   Edge-triggered:  true:  to trigger the interrupt
  *			      false: to ignore the call
  *	     Level-sensitive  true:  raise the input signal
@@ -1678,7 +1678,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
  * being HIGH and 0 being LOW and all devices being active-HIGH.
  */
 int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
-			       struct irq_phys_map *map, bool level)
+			       unsigned int virt_irq, bool level)
 {
 	int ret;
 
@@ -1686,7 +1686,7 @@ int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
 	if (ret)
 		return ret;
 
-	return vgic_update_irq_pending(kvm, cpuid, map->virt_irq, level);
+	return vgic_update_irq_pending(kvm, cpuid, virt_irq, level);
 }
 
 static irqreturn_t vgic_maintenance_handler(int irq, void *data)
-- 
2.7.3

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

* [PATCH v3 03/55] KVM: arm/arm64: vgic: avoid map in kvm_vgic_map_is_active()
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

For getting the active state of a mapped IRQ, we actually only need
the virtual IRQ number, not the pointer to the mapping entry.
Pass the virtual IRQ number from the arch timer to the VGIC directly.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
Changelog v1 .. v2:
- rewrap phys_active determination to fit in 80 characters

 include/kvm/arm_vgic.h    | 2 +-
 virt/kvm/arm/arch_timer.c | 6 ++----
 virt/kvm/arm/vgic.c       | 6 +++---
 3 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index c4574da..5a34adc 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -347,7 +347,7 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
 					   int virt_irq, int irq);
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
-bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index ceec146..f601471 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -275,10 +275,8 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
 	* to ensure that hardware interrupts from the timer triggers a guest
 	* exit.
 	*/
-	if (timer->irq.level || kvm_vgic_map_is_active(vcpu, timer->map))
-		phys_active = true;
-	else
-		phys_active = false;
+	phys_active = timer->irq.level ||
+			kvm_vgic_map_is_active(vcpu, timer->map->virt_irq);
 
 	/*
 	 * We want to avoid hitting the (re)distributor as much as
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 9937d41..6911327 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1103,18 +1103,18 @@ static bool dist_active_irq(struct kvm_vcpu *vcpu)
 	return test_bit(vcpu->vcpu_id, dist->irq_active_on_cpu);
 }
 
-bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map)
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq)
 {
 	int i;
 
 	for (i = 0; i < vcpu->arch.vgic_cpu.nr_lr; i++) {
 		struct vgic_lr vlr = vgic_get_lr(vcpu, i);
 
-		if (vlr.irq == map->virt_irq && vlr.state & LR_STATE_ACTIVE)
+		if (vlr.irq == virt_irq && vlr.state & LR_STATE_ACTIVE)
 			return true;
 	}
 
-	return vgic_irq_is_active(vcpu, map->virt_irq);
+	return vgic_irq_is_active(vcpu, virt_irq);
 }
 
 /*
-- 
2.7.3


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

* [PATCH v3 03/55] KVM: arm/arm64: vgic: avoid map in kvm_vgic_map_is_active()
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

For getting the active state of a mapped IRQ, we actually only need
the virtual IRQ number, not the pointer to the mapping entry.
Pass the virtual IRQ number from the arch timer to the VGIC directly.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
Changelog v1 .. v2:
- rewrap phys_active determination to fit in 80 characters

 include/kvm/arm_vgic.h    | 2 +-
 virt/kvm/arm/arch_timer.c | 6 ++----
 virt/kvm/arm/vgic.c       | 6 +++---
 3 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index c4574da..5a34adc 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -347,7 +347,7 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
 					   int virt_irq, int irq);
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
-bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index ceec146..f601471 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -275,10 +275,8 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
 	* to ensure that hardware interrupts from the timer triggers a guest
 	* exit.
 	*/
-	if (timer->irq.level || kvm_vgic_map_is_active(vcpu, timer->map))
-		phys_active = true;
-	else
-		phys_active = false;
+	phys_active = timer->irq.level ||
+			kvm_vgic_map_is_active(vcpu, timer->map->virt_irq);
 
 	/*
 	 * We want to avoid hitting the (re)distributor as much as
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 9937d41..6911327 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1103,18 +1103,18 @@ static bool dist_active_irq(struct kvm_vcpu *vcpu)
 	return test_bit(vcpu->vcpu_id, dist->irq_active_on_cpu);
 }
 
-bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map)
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq)
 {
 	int i;
 
 	for (i = 0; i < vcpu->arch.vgic_cpu.nr_lr; i++) {
 		struct vgic_lr vlr = vgic_get_lr(vcpu, i);
 
-		if (vlr.irq == map->virt_irq && vlr.state & LR_STATE_ACTIVE)
+		if (vlr.irq == virt_irq && vlr.state & LR_STATE_ACTIVE)
 			return true;
 	}
 
-	return vgic_irq_is_active(vcpu, map->virt_irq);
+	return vgic_irq_is_active(vcpu, virt_irq);
 }
 
 /*
-- 
2.7.3

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

* [PATCH v3 04/55] KVM: arm/arm64: vgic: avoid map in kvm_vgic_unmap_phys_irq()
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

kvm_vgic_unmap_phys_irq() only needs the virtual IRQ number, so let's
just pass that between the arch timer and the VGIC to get rid of
the irq_phys_map pointer.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
 include/kvm/arm_vgic.h    |  2 +-
 virt/kvm/arm/arch_timer.c |  2 +-
 virt/kvm/arm/vgic.c       | 11 ++++-------
 3 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 5a34adc..43eeb18 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -346,7 +346,7 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
 					   int virt_irq, int irq);
-int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index f601471..58b2439 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -504,7 +504,7 @@ void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu)
 
 	timer_disarm(timer);
 	if (timer->map)
-		kvm_vgic_unmap_phys_irq(vcpu, timer->map);
+		kvm_vgic_unmap_phys_irq(vcpu, timer->map->virt_irq);
 }
 
 void kvm_timer_enable(struct kvm *kvm)
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 6911327..2d7ae35 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1813,25 +1813,22 @@ static void vgic_free_phys_irq_map_rcu(struct rcu_head *rcu)
 /**
  * kvm_vgic_unmap_phys_irq - Remove a virtual to physical IRQ mapping
  * @vcpu: The VCPU pointer
- * @map: The pointer to a mapping obtained through kvm_vgic_map_phys_irq
+ * @virt_irq: The virtual IRQ number to be unmapped
  *
  * Remove an existing mapping between virtual and physical interrupts.
  */
-int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map)
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq)
 {
 	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
 	struct irq_phys_map_entry *entry;
 	struct list_head *root;
 
-	if (!map)
-		return -EINVAL;
-
-	root = vgic_get_irq_phys_map_list(vcpu, map->virt_irq);
+	root = vgic_get_irq_phys_map_list(vcpu, virt_irq);
 
 	spin_lock(&dist->irq_phys_map_lock);
 
 	list_for_each_entry(entry, root, entry) {
-		if (&entry->map == map) {
+		if (entry->map.virt_irq == virt_irq) {
 			list_del_rcu(&entry->entry);
 			call_rcu(&entry->rcu, vgic_free_phys_irq_map_rcu);
 			break;
-- 
2.7.3


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

* [PATCH v3 04/55] KVM: arm/arm64: vgic: avoid map in kvm_vgic_unmap_phys_irq()
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

kvm_vgic_unmap_phys_irq() only needs the virtual IRQ number, so let's
just pass that between the arch timer and the VGIC to get rid of
the irq_phys_map pointer.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
 include/kvm/arm_vgic.h    |  2 +-
 virt/kvm/arm/arch_timer.c |  2 +-
 virt/kvm/arm/vgic.c       | 11 ++++-------
 3 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 5a34adc..43eeb18 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -346,7 +346,7 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
 					   int virt_irq, int irq);
-int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index f601471..58b2439 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -504,7 +504,7 @@ void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu)
 
 	timer_disarm(timer);
 	if (timer->map)
-		kvm_vgic_unmap_phys_irq(vcpu, timer->map);
+		kvm_vgic_unmap_phys_irq(vcpu, timer->map->virt_irq);
 }
 
 void kvm_timer_enable(struct kvm *kvm)
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 6911327..2d7ae35 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1813,25 +1813,22 @@ static void vgic_free_phys_irq_map_rcu(struct rcu_head *rcu)
 /**
  * kvm_vgic_unmap_phys_irq - Remove a virtual to physical IRQ mapping
  * @vcpu: The VCPU pointer
- * @map: The pointer to a mapping obtained through kvm_vgic_map_phys_irq
+ * @virt_irq: The virtual IRQ number to be unmapped
  *
  * Remove an existing mapping between virtual and physical interrupts.
  */
-int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map)
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq)
 {
 	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
 	struct irq_phys_map_entry *entry;
 	struct list_head *root;
 
-	if (!map)
-		return -EINVAL;
-
-	root = vgic_get_irq_phys_map_list(vcpu, map->virt_irq);
+	root = vgic_get_irq_phys_map_list(vcpu, virt_irq);
 
 	spin_lock(&dist->irq_phys_map_lock);
 
 	list_for_each_entry(entry, root, entry) {
-		if (&entry->map == map) {
+		if (entry->map.virt_irq == virt_irq) {
 			list_del_rcu(&entry->entry);
 			call_rcu(&entry->rcu, vgic_free_phys_irq_map_rcu);
 			break;
-- 
2.7.3

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

* [PATCH v3 05/55] KVM: arm/arm64: Remove the IRQ field from struct irq_phys_map
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

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

The communication of a Linux IRQ number from outside the VGIC to the
vgic was a leftover from the day when the vgic code cared about how a
particular device injects virtual interrupts mapped to a physical
interrupt.

We can safely remove this notion, leaving all physical IRQ handling to
be done in the device driver (the arch timer in this case), which makes
room for a saner API for the new VGIC.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
Changelog v1 .. v2:
- update kerneldoc comments on kvm_vgic_map_phys_irq()

Changelog v2 .. v3:
- include <linux/irq.h>

 include/kvm/arm_vgic.h    |  3 +--
 virt/kvm/arm/arch_timer.c | 23 +++++++++++++++++++++--
 virt/kvm/arm/vgic.c       | 28 ++++++----------------------
 3 files changed, 28 insertions(+), 26 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 43eeb18..49c559e 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -157,7 +157,6 @@ struct vgic_io_device {
 struct irq_phys_map {
 	u32			virt_irq;
 	u32			phys_irq;
-	u32			irq;
 };
 
 struct irq_phys_map_entry {
@@ -345,7 +344,7 @@ int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
 void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
-					   int virt_irq, int irq);
+					   int virt_irq, int phys_irq);
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 58b2439..29d597d 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -21,6 +21,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 
 #include <clocksource/arm_arch_timer.h>
 #include <asm/arch_timer.h>
@@ -301,7 +302,7 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
 	if (timer->active_cleared_last && !phys_active)
 		return;
 
-	ret = irq_set_irqchip_state(timer->map->irq,
+	ret = irq_set_irqchip_state(host_vtimer_irq,
 				    IRQCHIP_STATE_ACTIVE,
 				    phys_active);
 	WARN_ON(ret);
@@ -334,6 +335,9 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 {
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
 	struct irq_phys_map *map;
+	struct irq_desc *desc;
+	struct irq_data *data;
+	int phys_irq;
 
 	/*
 	 * The vcpu timer irq number cannot be determined in
@@ -353,10 +357,25 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 	kvm_timer_update_state(vcpu);
 
 	/*
+	 * Find the physical IRQ number corresponding to the host_vtimer_irq
+	 */
+	desc = irq_to_desc(host_vtimer_irq);
+	if (!desc) {
+		kvm_err("%s: no interrupt descriptor\n", __func__);
+		return -EINVAL;
+	}
+
+	data = irq_desc_get_irq_data(desc);
+	while (data->parent_data)
+		data = data->parent_data;
+
+	phys_irq = data->hwirq;
+
+	/*
 	 * Tell the VGIC that the virtual interrupt is tied to a
 	 * physical interrupt. We do that once per VCPU.
 	 */
-	map = kvm_vgic_map_phys_irq(vcpu, irq->irq, host_vtimer_irq);
+	map = kvm_vgic_map_phys_irq(vcpu, irq->irq, phys_irq);
 	if (WARN_ON(IS_ERR(map)))
 		return PTR_ERR(map);
 
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 2d7ae35..41792c0 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1712,38 +1712,24 @@ static struct list_head *vgic_get_irq_phys_map_list(struct kvm_vcpu *vcpu,
 /**
  * kvm_vgic_map_phys_irq - map a virtual IRQ to a physical IRQ
  * @vcpu: The VCPU pointer
- * @virt_irq: The virtual irq number
- * @irq: The Linux IRQ number
+ * @virt_irq: The virtual IRQ number for the guest
+ * @phys_irq: The hardware IRQ number of the host
  *
  * Establish a mapping between a guest visible irq (@virt_irq) and a
- * Linux irq (@irq). On injection, @virt_irq will be associated with
- * the physical interrupt represented by @irq. This mapping can be
+ * hardware irq (@phys_irq). On injection, @virt_irq will be associated with
+ * the physical interrupt represented by @phys_irq. This mapping can be
  * established multiple times as long as the parameters are the same.
  *
  * Returns a valid pointer on success, and an error pointer otherwise
  */
 struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
-					   int virt_irq, int irq)
+					   int virt_irq, int phys_irq)
 {
 	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
 	struct list_head *root = vgic_get_irq_phys_map_list(vcpu, virt_irq);
 	struct irq_phys_map *map;
 	struct irq_phys_map_entry *entry;
-	struct irq_desc *desc;
-	struct irq_data *data;
-	int phys_irq;
 
-	desc = irq_to_desc(irq);
-	if (!desc) {
-		kvm_err("%s: no interrupt descriptor\n", __func__);
-		return ERR_PTR(-EINVAL);
-	}
-
-	data = irq_desc_get_irq_data(desc);
-	while (data->parent_data)
-		data = data->parent_data;
-
-	phys_irq = data->hwirq;
 
 	/* Create a new mapping */
 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
@@ -1756,8 +1742,7 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
 	map = vgic_irq_map_search(vcpu, virt_irq);
 	if (map) {
 		/* Make sure this mapping matches */
-		if (map->phys_irq != phys_irq	||
-		    map->irq      != irq)
+		if (map->phys_irq != phys_irq)
 			map = ERR_PTR(-EINVAL);
 
 		/* Found an existing, valid mapping */
@@ -1767,7 +1752,6 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
 	map           = &entry->map;
 	map->virt_irq = virt_irq;
 	map->phys_irq = phys_irq;
-	map->irq      = irq;
 
 	list_add_tail_rcu(&entry->entry, root);
 
-- 
2.7.3

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

* [PATCH v3 05/55] KVM: arm/arm64: Remove the IRQ field from struct irq_phys_map
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

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

The communication of a Linux IRQ number from outside the VGIC to the
vgic was a leftover from the day when the vgic code cared about how a
particular device injects virtual interrupts mapped to a physical
interrupt.

We can safely remove this notion, leaving all physical IRQ handling to
be done in the device driver (the arch timer in this case), which makes
room for a saner API for the new VGIC.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
Changelog v1 .. v2:
- update kerneldoc comments on kvm_vgic_map_phys_irq()

Changelog v2 .. v3:
- include <linux/irq.h>

 include/kvm/arm_vgic.h    |  3 +--
 virt/kvm/arm/arch_timer.c | 23 +++++++++++++++++++++--
 virt/kvm/arm/vgic.c       | 28 ++++++----------------------
 3 files changed, 28 insertions(+), 26 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 43eeb18..49c559e 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -157,7 +157,6 @@ struct vgic_io_device {
 struct irq_phys_map {
 	u32			virt_irq;
 	u32			phys_irq;
-	u32			irq;
 };
 
 struct irq_phys_map_entry {
@@ -345,7 +344,7 @@ int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
 void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
-					   int virt_irq, int irq);
+					   int virt_irq, int phys_irq);
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 58b2439..29d597d 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -21,6 +21,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 
 #include <clocksource/arm_arch_timer.h>
 #include <asm/arch_timer.h>
@@ -301,7 +302,7 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
 	if (timer->active_cleared_last && !phys_active)
 		return;
 
-	ret = irq_set_irqchip_state(timer->map->irq,
+	ret = irq_set_irqchip_state(host_vtimer_irq,
 				    IRQCHIP_STATE_ACTIVE,
 				    phys_active);
 	WARN_ON(ret);
@@ -334,6 +335,9 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 {
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
 	struct irq_phys_map *map;
+	struct irq_desc *desc;
+	struct irq_data *data;
+	int phys_irq;
 
 	/*
 	 * The vcpu timer irq number cannot be determined in
@@ -353,10 +357,25 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 	kvm_timer_update_state(vcpu);
 
 	/*
+	 * Find the physical IRQ number corresponding to the host_vtimer_irq
+	 */
+	desc = irq_to_desc(host_vtimer_irq);
+	if (!desc) {
+		kvm_err("%s: no interrupt descriptor\n", __func__);
+		return -EINVAL;
+	}
+
+	data = irq_desc_get_irq_data(desc);
+	while (data->parent_data)
+		data = data->parent_data;
+
+	phys_irq = data->hwirq;
+
+	/*
 	 * Tell the VGIC that the virtual interrupt is tied to a
 	 * physical interrupt. We do that once per VCPU.
 	 */
-	map = kvm_vgic_map_phys_irq(vcpu, irq->irq, host_vtimer_irq);
+	map = kvm_vgic_map_phys_irq(vcpu, irq->irq, phys_irq);
 	if (WARN_ON(IS_ERR(map)))
 		return PTR_ERR(map);
 
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 2d7ae35..41792c0 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1712,38 +1712,24 @@ static struct list_head *vgic_get_irq_phys_map_list(struct kvm_vcpu *vcpu,
 /**
  * kvm_vgic_map_phys_irq - map a virtual IRQ to a physical IRQ
  * @vcpu: The VCPU pointer
- * @virt_irq: The virtual irq number
- * @irq: The Linux IRQ number
+ * @virt_irq: The virtual IRQ number for the guest
+ * @phys_irq: The hardware IRQ number of the host
  *
  * Establish a mapping between a guest visible irq (@virt_irq) and a
- * Linux irq (@irq). On injection, @virt_irq will be associated with
- * the physical interrupt represented by @irq. This mapping can be
+ * hardware irq (@phys_irq). On injection, @virt_irq will be associated with
+ * the physical interrupt represented by @phys_irq. This mapping can be
  * established multiple times as long as the parameters are the same.
  *
  * Returns a valid pointer on success, and an error pointer otherwise
  */
 struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
-					   int virt_irq, int irq)
+					   int virt_irq, int phys_irq)
 {
 	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
 	struct list_head *root = vgic_get_irq_phys_map_list(vcpu, virt_irq);
 	struct irq_phys_map *map;
 	struct irq_phys_map_entry *entry;
-	struct irq_desc *desc;
-	struct irq_data *data;
-	int phys_irq;
 
-	desc = irq_to_desc(irq);
-	if (!desc) {
-		kvm_err("%s: no interrupt descriptor\n", __func__);
-		return ERR_PTR(-EINVAL);
-	}
-
-	data = irq_desc_get_irq_data(desc);
-	while (data->parent_data)
-		data = data->parent_data;
-
-	phys_irq = data->hwirq;
 
 	/* Create a new mapping */
 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
@@ -1756,8 +1742,7 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
 	map = vgic_irq_map_search(vcpu, virt_irq);
 	if (map) {
 		/* Make sure this mapping matches */
-		if (map->phys_irq != phys_irq	||
-		    map->irq      != irq)
+		if (map->phys_irq != phys_irq)
 			map = ERR_PTR(-EINVAL);
 
 		/* Found an existing, valid mapping */
@@ -1767,7 +1752,6 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
 	map           = &entry->map;
 	map->virt_irq = virt_irq;
 	map->phys_irq = phys_irq;
-	map->irq      = irq;
 
 	list_add_tail_rcu(&entry->entry, root);
 
-- 
2.7.3

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

* [PATCH v3 06/55] KVM: arm/arm64: arch_timer: Remove irq_phys_map
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Now that the interface between the arch timer and the VGIC does not
require passing the irq_phys_map entry pointer anymore, let's remove
it from the virtual arch timer and use the virtual IRQ number instead
directly.
The remaining pointer returned by kvm_vgic_map_phys_irq() will be
removed in the following patch.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- remove extra virt_irq member from struct, instead use irq.irq directly

Changelog v2 .. v3:
- remove bogus validity check from kvm_vgic_unmap_phys_irq()

 include/kvm/arm_arch_timer.h |  3 ---
 virt/kvm/arm/arch_timer.c    | 10 ++++------
 2 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index b651aed..a47b7de 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -53,9 +53,6 @@ struct arch_timer_cpu {
 	/* Timer IRQ */
 	struct kvm_irq_level		irq;
 
-	/* VGIC mapping */
-	struct irq_phys_map		*map;
-
 	/* Active IRQ state caching */
 	bool				active_cleared_last;
 };
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 29d597d..f2cd188 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -176,10 +176,10 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level)
 
 	timer->active_cleared_last = false;
 	timer->irq.level = new_level;
-	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->map->virt_irq,
+	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->irq.irq,
 				   timer->irq.level);
 	ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id,
-					 timer->map->virt_irq,
+					 timer->irq.irq,
 					 timer->irq.level);
 	WARN_ON(ret);
 }
@@ -277,7 +277,7 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
 	* exit.
 	*/
 	phys_active = timer->irq.level ||
-			kvm_vgic_map_is_active(vcpu, timer->map->virt_irq);
+			kvm_vgic_map_is_active(vcpu, timer->irq.irq);
 
 	/*
 	 * We want to avoid hitting the (re)distributor as much as
@@ -379,7 +379,6 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 	if (WARN_ON(IS_ERR(map)))
 		return PTR_ERR(map);
 
-	timer->map = map;
 	return 0;
 }
 
@@ -522,8 +521,7 @@ void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu)
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
 
 	timer_disarm(timer);
-	if (timer->map)
-		kvm_vgic_unmap_phys_irq(vcpu, timer->map->virt_irq);
+	kvm_vgic_unmap_phys_irq(vcpu, timer->irq.irq);
 }
 
 void kvm_timer_enable(struct kvm *kvm)
-- 
2.7.3

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

* [PATCH v3 06/55] KVM: arm/arm64: arch_timer: Remove irq_phys_map
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

Now that the interface between the arch timer and the VGIC does not
require passing the irq_phys_map entry pointer anymore, let's remove
it from the virtual arch timer and use the virtual IRQ number instead
directly.
The remaining pointer returned by kvm_vgic_map_phys_irq() will be
removed in the following patch.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- remove extra virt_irq member from struct, instead use irq.irq directly

Changelog v2 .. v3:
- remove bogus validity check from kvm_vgic_unmap_phys_irq()

 include/kvm/arm_arch_timer.h |  3 ---
 virt/kvm/arm/arch_timer.c    | 10 ++++------
 2 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index b651aed..a47b7de 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -53,9 +53,6 @@ struct arch_timer_cpu {
 	/* Timer IRQ */
 	struct kvm_irq_level		irq;
 
-	/* VGIC mapping */
-	struct irq_phys_map		*map;
-
 	/* Active IRQ state caching */
 	bool				active_cleared_last;
 };
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 29d597d..f2cd188 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -176,10 +176,10 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level)
 
 	timer->active_cleared_last = false;
 	timer->irq.level = new_level;
-	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->map->virt_irq,
+	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->irq.irq,
 				   timer->irq.level);
 	ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id,
-					 timer->map->virt_irq,
+					 timer->irq.irq,
 					 timer->irq.level);
 	WARN_ON(ret);
 }
@@ -277,7 +277,7 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
 	* exit.
 	*/
 	phys_active = timer->irq.level ||
-			kvm_vgic_map_is_active(vcpu, timer->map->virt_irq);
+			kvm_vgic_map_is_active(vcpu, timer->irq.irq);
 
 	/*
 	 * We want to avoid hitting the (re)distributor as much as
@@ -379,7 +379,6 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 	if (WARN_ON(IS_ERR(map)))
 		return PTR_ERR(map);
 
-	timer->map = map;
 	return 0;
 }
 
@@ -522,8 +521,7 @@ void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu)
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
 
 	timer_disarm(timer);
-	if (timer->map)
-		kvm_vgic_unmap_phys_irq(vcpu, timer->map->virt_irq);
+	kvm_vgic_unmap_phys_irq(vcpu, timer->irq.irq);
 }
 
 void kvm_timer_enable(struct kvm *kvm)
-- 
2.7.3

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

* [PATCH v3 07/55] KVM: arm/arm64: vgic: Remove irq_phys_map from interface
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

Now that the virtual arch timer does not care about the irq_phys_map
anymore, let's rework kvm_vgic_map_phys_irq() to return an error
value instead. Any reference to that mapping can later be done by
passing the correct combination of VCPU and virtual IRQ number.
This makes the irq_phys_map handling completely private to the
VGIC code.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
Changelog v1 .. v2:
- adaptations to changes in previous patches (removal of virt_irq)

Changelog v2 .. v3:
- simplify return in kvm_timer_vcpu_reset()

 include/kvm/arm_vgic.h    |  3 +--
 virt/kvm/arm/arch_timer.c |  7 +------
 virt/kvm/arm/vgic.c       | 15 +++++++--------
 3 files changed, 9 insertions(+), 16 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 49c559e..f842d7d 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -343,8 +343,7 @@ int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
 			       unsigned int virt_irq, bool level);
 void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
-struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
-					   int virt_irq, int phys_irq);
+int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, int virt_irq, int phys_irq);
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index f2cd188..ebc4616 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -334,7 +334,6 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 			 const struct kvm_irq_level *irq)
 {
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
-	struct irq_phys_map *map;
 	struct irq_desc *desc;
 	struct irq_data *data;
 	int phys_irq;
@@ -375,11 +374,7 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 	 * Tell the VGIC that the virtual interrupt is tied to a
 	 * physical interrupt. We do that once per VCPU.
 	 */
-	map = kvm_vgic_map_phys_irq(vcpu, irq->irq, phys_irq);
-	if (WARN_ON(IS_ERR(map)))
-		return PTR_ERR(map);
-
-	return 0;
+	return kvm_vgic_map_phys_irq(vcpu, irq->irq, phys_irq);
 }
 
 void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 41792c0..00386df 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1720,21 +1720,20 @@ static struct list_head *vgic_get_irq_phys_map_list(struct kvm_vcpu *vcpu,
  * the physical interrupt represented by @phys_irq. This mapping can be
  * established multiple times as long as the parameters are the same.
  *
- * Returns a valid pointer on success, and an error pointer otherwise
+ * Returns 0 on success or an error value otherwise.
  */
-struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
-					   int virt_irq, int phys_irq)
+int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, int virt_irq, int phys_irq)
 {
 	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
 	struct list_head *root = vgic_get_irq_phys_map_list(vcpu, virt_irq);
 	struct irq_phys_map *map;
 	struct irq_phys_map_entry *entry;
-
+	int ret = 0;
 
 	/* Create a new mapping */
 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
 	if (!entry)
-		return ERR_PTR(-ENOMEM);
+		return -ENOMEM;
 
 	spin_lock(&dist->irq_phys_map_lock);
 
@@ -1743,7 +1742,7 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
 	if (map) {
 		/* Make sure this mapping matches */
 		if (map->phys_irq != phys_irq)
-			map = ERR_PTR(-EINVAL);
+			ret = -EINVAL;
 
 		/* Found an existing, valid mapping */
 		goto out;
@@ -1759,9 +1758,9 @@ out:
 	spin_unlock(&dist->irq_phys_map_lock);
 	/* If we've found a hit in the existing list, free the useless
 	 * entry */
-	if (IS_ERR(map) || map != &entry->map)
+	if (ret || map != &entry->map)
 		kfree(entry);
-	return map;
+	return ret;
 }
 
 static struct irq_phys_map *vgic_irq_map_search(struct kvm_vcpu *vcpu,
-- 
2.7.3


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

* [PATCH v3 07/55] KVM: arm/arm64: vgic: Remove irq_phys_map from interface
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

Now that the virtual arch timer does not care about the irq_phys_map
anymore, let's rework kvm_vgic_map_phys_irq() to return an error
value instead. Any reference to that mapping can later be done by
passing the correct combination of VCPU and virtual IRQ number.
This makes the irq_phys_map handling completely private to the
VGIC code.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
Changelog v1 .. v2:
- adaptations to changes in previous patches (removal of virt_irq)

Changelog v2 .. v3:
- simplify return in kvm_timer_vcpu_reset()

 include/kvm/arm_vgic.h    |  3 +--
 virt/kvm/arm/arch_timer.c |  7 +------
 virt/kvm/arm/vgic.c       | 15 +++++++--------
 3 files changed, 9 insertions(+), 16 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 49c559e..f842d7d 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -343,8 +343,7 @@ int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
 			       unsigned int virt_irq, bool level);
 void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
-struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
-					   int virt_irq, int phys_irq);
+int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, int virt_irq, int phys_irq);
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index f2cd188..ebc4616 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -334,7 +334,6 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 			 const struct kvm_irq_level *irq)
 {
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
-	struct irq_phys_map *map;
 	struct irq_desc *desc;
 	struct irq_data *data;
 	int phys_irq;
@@ -375,11 +374,7 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 	 * Tell the VGIC that the virtual interrupt is tied to a
 	 * physical interrupt. We do that once per VCPU.
 	 */
-	map = kvm_vgic_map_phys_irq(vcpu, irq->irq, phys_irq);
-	if (WARN_ON(IS_ERR(map)))
-		return PTR_ERR(map);
-
-	return 0;
+	return kvm_vgic_map_phys_irq(vcpu, irq->irq, phys_irq);
 }
 
 void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 41792c0..00386df 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1720,21 +1720,20 @@ static struct list_head *vgic_get_irq_phys_map_list(struct kvm_vcpu *vcpu,
  * the physical interrupt represented by @phys_irq. This mapping can be
  * established multiple times as long as the parameters are the same.
  *
- * Returns a valid pointer on success, and an error pointer otherwise
+ * Returns 0 on success or an error value otherwise.
  */
-struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
-					   int virt_irq, int phys_irq)
+int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, int virt_irq, int phys_irq)
 {
 	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
 	struct list_head *root = vgic_get_irq_phys_map_list(vcpu, virt_irq);
 	struct irq_phys_map *map;
 	struct irq_phys_map_entry *entry;
-
+	int ret = 0;
 
 	/* Create a new mapping */
 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
 	if (!entry)
-		return ERR_PTR(-ENOMEM);
+		return -ENOMEM;
 
 	spin_lock(&dist->irq_phys_map_lock);
 
@@ -1743,7 +1742,7 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
 	if (map) {
 		/* Make sure this mapping matches */
 		if (map->phys_irq != phys_irq)
-			map = ERR_PTR(-EINVAL);
+			ret = -EINVAL;
 
 		/* Found an existing, valid mapping */
 		goto out;
@@ -1759,9 +1758,9 @@ out:
 	spin_unlock(&dist->irq_phys_map_lock);
 	/* If we've found a hit in the existing list, free the useless
 	 * entry */
-	if (IS_ERR(map) || map != &entry->map)
+	if (ret || map != &entry->map)
 		kfree(entry);
-	return map;
+	return ret;
 }
 
 static struct irq_phys_map *vgic_irq_map_search(struct kvm_vcpu *vcpu,
-- 
2.7.3

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

* [PATCH v3 08/55] KVM: arm/arm64: Get rid of vgic_cpu->nr_lr
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

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

The number of list registers is a property of the underlying system, not
of emulated VGIC CPU interface.

As we are about to move this variable to global state in the new vgic
for clarity, move it from the legacy implementation as well to make the
merge of the new code easier.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/arm_vgic.h        |  3 ---
 virt/kvm/arm/hyp/vgic-v2-sr.c | 12 +++++++-----
 virt/kvm/arm/vgic-v2.c        |  4 +++-
 virt/kvm/arm/vgic.c           | 12 ++----------
 4 files changed, 12 insertions(+), 19 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index f842d7d..452bb85 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -303,9 +303,6 @@ struct vgic_cpu {
 	unsigned long   *active_shared;
 	unsigned long   *pend_act_shared;
 
-	/* Number of list registers on this CPU */
-	int		nr_lr;
-
 	/* CPU vif control registers for world switch */
 	union {
 		struct vgic_v2_cpu_if	vgic_v2;
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index 674bdf8..caac41f 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -21,11 +21,13 @@
 
 #include <asm/kvm_hyp.h>
 
+extern struct vgic_params vgic_v2_params;
+
 static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu,
 					    void __iomem *base)
 {
 	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
-	int nr_lr = vcpu->arch.vgic_cpu.nr_lr;
+	int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
 	u32 eisr0, eisr1;
 	int i;
 	bool expect_mi;
@@ -67,7 +69,7 @@ static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu,
 static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base)
 {
 	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
-	int nr_lr = vcpu->arch.vgic_cpu.nr_lr;
+	int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
 	u32 elrsr0, elrsr1;
 
 	elrsr0 = readl_relaxed(base + GICH_ELRSR0);
@@ -86,7 +88,7 @@ static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base)
 static void __hyp_text save_lrs(struct kvm_vcpu *vcpu, void __iomem *base)
 {
 	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
-	int nr_lr = vcpu->arch.vgic_cpu.nr_lr;
+	int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
 	int i;
 
 	for (i = 0; i < nr_lr; i++) {
@@ -141,13 +143,13 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
 	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
 	struct vgic_dist *vgic = &kvm->arch.vgic;
 	void __iomem *base = kern_hyp_va(vgic->vctrl_base);
-	int i, nr_lr;
+	int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
+	int i;
 	u64 live_lrs = 0;
 
 	if (!base)
 		return;
 
-	nr_lr = vcpu->arch.vgic_cpu.nr_lr;
 
 	for (i = 0; i < nr_lr; i++)
 		if (cpu_if->vgic_lr[i] & GICH_LR_STATE)
diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c
index 67ec334..6aaf5f7 100644
--- a/virt/kvm/arm/vgic-v2.c
+++ b/virt/kvm/arm/vgic-v2.c
@@ -174,7 +174,7 @@ static const struct vgic_ops vgic_v2_ops = {
 	.enable			= vgic_v2_enable,
 };
 
-static struct vgic_params vgic_v2_params;
+struct vgic_params __section(.hyp.text) vgic_v2_params;
 
 static void vgic_cpu_init_lrs(void *params)
 {
@@ -204,6 +204,8 @@ int vgic_v2_probe(struct device_node *vgic_node,
 	struct resource vcpu_res;
 	struct vgic_params *vgic = &vgic_v2_params;
 
+	memset(vgic, 0, sizeof(*vgic));
+
 	vgic->maint_irq = irq_of_parse_and_map(vgic_node, 0);
 	if (!vgic->maint_irq) {
 		kvm_err("error getting vgic maintenance irq from DT\n");
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 00386df..5efc298 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -691,12 +691,11 @@ bool vgic_handle_cfg_reg(u32 *reg, struct kvm_exit_mmio *mmio,
  */
 void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
 {
-	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 	u64 elrsr = vgic_get_elrsr(vcpu);
 	unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
 	int i;
 
-	for_each_clear_bit(i, elrsr_ptr, vgic_cpu->nr_lr) {
+	for_each_clear_bit(i, elrsr_ptr, vgic->nr_lr) {
 		struct vgic_lr lr = vgic_get_lr(vcpu, i);
 
 		/*
@@ -1107,7 +1106,7 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq)
 {
 	int i;
 
-	for (i = 0; i < vcpu->arch.vgic_cpu.nr_lr; i++) {
+	for (i = 0; i < vgic->nr_lr; i++) {
 		struct vgic_lr vlr = vgic_get_lr(vcpu, i);
 
 		if (vlr.irq == virt_irq && vlr.state & LR_STATE_ACTIVE)
@@ -1867,13 +1866,6 @@ static int vgic_vcpu_init_maps(struct kvm_vcpu *vcpu, int nr_irqs)
 		return -ENOMEM;
 	}
 
-	/*
-	 * Store the number of LRs per vcpu, so we don't have to go
-	 * all the way to the distributor structure to find out. Only
-	 * assembly code should use this one.
-	 */
-	vgic_cpu->nr_lr = vgic->nr_lr;
-
 	return 0;
 }
 
-- 
2.7.3

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

* [PATCH v3 08/55] KVM: arm/arm64: Get rid of vgic_cpu->nr_lr
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

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

The number of list registers is a property of the underlying system, not
of emulated VGIC CPU interface.

As we are about to move this variable to global state in the new vgic
for clarity, move it from the legacy implementation as well to make the
merge of the new code easier.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/arm_vgic.h        |  3 ---
 virt/kvm/arm/hyp/vgic-v2-sr.c | 12 +++++++-----
 virt/kvm/arm/vgic-v2.c        |  4 +++-
 virt/kvm/arm/vgic.c           | 12 ++----------
 4 files changed, 12 insertions(+), 19 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index f842d7d..452bb85 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -303,9 +303,6 @@ struct vgic_cpu {
 	unsigned long   *active_shared;
 	unsigned long   *pend_act_shared;
 
-	/* Number of list registers on this CPU */
-	int		nr_lr;
-
 	/* CPU vif control registers for world switch */
 	union {
 		struct vgic_v2_cpu_if	vgic_v2;
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index 674bdf8..caac41f 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -21,11 +21,13 @@
 
 #include <asm/kvm_hyp.h>
 
+extern struct vgic_params vgic_v2_params;
+
 static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu,
 					    void __iomem *base)
 {
 	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
-	int nr_lr = vcpu->arch.vgic_cpu.nr_lr;
+	int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
 	u32 eisr0, eisr1;
 	int i;
 	bool expect_mi;
@@ -67,7 +69,7 @@ static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu,
 static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base)
 {
 	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
-	int nr_lr = vcpu->arch.vgic_cpu.nr_lr;
+	int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
 	u32 elrsr0, elrsr1;
 
 	elrsr0 = readl_relaxed(base + GICH_ELRSR0);
@@ -86,7 +88,7 @@ static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base)
 static void __hyp_text save_lrs(struct kvm_vcpu *vcpu, void __iomem *base)
 {
 	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
-	int nr_lr = vcpu->arch.vgic_cpu.nr_lr;
+	int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
 	int i;
 
 	for (i = 0; i < nr_lr; i++) {
@@ -141,13 +143,13 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
 	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
 	struct vgic_dist *vgic = &kvm->arch.vgic;
 	void __iomem *base = kern_hyp_va(vgic->vctrl_base);
-	int i, nr_lr;
+	int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
+	int i;
 	u64 live_lrs = 0;
 
 	if (!base)
 		return;
 
-	nr_lr = vcpu->arch.vgic_cpu.nr_lr;
 
 	for (i = 0; i < nr_lr; i++)
 		if (cpu_if->vgic_lr[i] & GICH_LR_STATE)
diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c
index 67ec334..6aaf5f7 100644
--- a/virt/kvm/arm/vgic-v2.c
+++ b/virt/kvm/arm/vgic-v2.c
@@ -174,7 +174,7 @@ static const struct vgic_ops vgic_v2_ops = {
 	.enable			= vgic_v2_enable,
 };
 
-static struct vgic_params vgic_v2_params;
+struct vgic_params __section(.hyp.text) vgic_v2_params;
 
 static void vgic_cpu_init_lrs(void *params)
 {
@@ -204,6 +204,8 @@ int vgic_v2_probe(struct device_node *vgic_node,
 	struct resource vcpu_res;
 	struct vgic_params *vgic = &vgic_v2_params;
 
+	memset(vgic, 0, sizeof(*vgic));
+
 	vgic->maint_irq = irq_of_parse_and_map(vgic_node, 0);
 	if (!vgic->maint_irq) {
 		kvm_err("error getting vgic maintenance irq from DT\n");
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 00386df..5efc298 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -691,12 +691,11 @@ bool vgic_handle_cfg_reg(u32 *reg, struct kvm_exit_mmio *mmio,
  */
 void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
 {
-	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 	u64 elrsr = vgic_get_elrsr(vcpu);
 	unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
 	int i;
 
-	for_each_clear_bit(i, elrsr_ptr, vgic_cpu->nr_lr) {
+	for_each_clear_bit(i, elrsr_ptr, vgic->nr_lr) {
 		struct vgic_lr lr = vgic_get_lr(vcpu, i);
 
 		/*
@@ -1107,7 +1106,7 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq)
 {
 	int i;
 
-	for (i = 0; i < vcpu->arch.vgic_cpu.nr_lr; i++) {
+	for (i = 0; i < vgic->nr_lr; i++) {
 		struct vgic_lr vlr = vgic_get_lr(vcpu, i);
 
 		if (vlr.irq == virt_irq && vlr.state & LR_STATE_ACTIVE)
@@ -1867,13 +1866,6 @@ static int vgic_vcpu_init_maps(struct kvm_vcpu *vcpu, int nr_irqs)
 		return -ENOMEM;
 	}
 
-	/*
-	 * Store the number of LRs per vcpu, so we don't have to go
-	 * all the way to the distributor structure to find out. Only
-	 * assembly code should use this one.
-	 */
-	vgic_cpu->nr_lr = vgic->nr_lr;
-
 	return 0;
 }
 
-- 
2.7.3

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

* [PATCH v3 09/55] KVM: arm/arm64: Fix MMIO emulation data handling
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

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

When the kernel was handling a guest MMIO read access internally, we
need to copy the emulation result into the run->mmio structure in order
for the kvm_handle_mmio_return() function to pick it up and inject the
	result back into the guest.

Currently the only user of kvm_io_bus for ARM is the VGIC, which did
this copying itself, so this was not causing issues so far.

But with the upcoming new vgic implementation we need this done
properly.

Update the kvm_handle_mmio_return description and cleanup the code to
only perform a single copying when needed.

Code and commit message inspired by Andre Przywara.

Reported-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 arch/arm/kvm/mmio.c | 14 +++++++-------
 virt/kvm/arm/vgic.c |  7 -------
 2 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
index 0f6600f..0158e9e 100644
--- a/arch/arm/kvm/mmio.c
+++ b/arch/arm/kvm/mmio.c
@@ -87,11 +87,10 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len)
 
 /**
  * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
+ *			     or in-kernel IO emulation
+ *
  * @vcpu: The VCPU pointer
  * @run:  The VCPU run struct containing the mmio data
- *
- * This should only be called after returning from userspace for MMIO load
- * emulation.
  */
 int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
@@ -206,18 +205,19 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
 	run->mmio.is_write	= is_write;
 	run->mmio.phys_addr	= fault_ipa;
 	run->mmio.len		= len;
-	if (is_write)
-		memcpy(run->mmio.data, data_buf, len);
 
 	if (!ret) {
 		/* We handled the access successfully in the kernel. */
+		if (!is_write)
+			memcpy(run->mmio.data, data_buf, len);
 		vcpu->stat.mmio_exit_kernel++;
 		kvm_handle_mmio_return(vcpu, run);
 		return 1;
-	} else {
-		vcpu->stat.mmio_exit_user++;
 	}
 
+	if (is_write)
+		memcpy(run->mmio.data, data_buf, len);
+	vcpu->stat.mmio_exit_user++;
 	run->exit_reason	= KVM_EXIT_MMIO;
 	return 0;
 }
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 5efc298..e70cee4 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -820,7 +820,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu,
 	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
 	struct vgic_io_device *iodev = container_of(this,
 						    struct vgic_io_device, dev);
-	struct kvm_run *run = vcpu->run;
 	const struct vgic_io_range *range;
 	struct kvm_exit_mmio mmio;
 	bool updated_state;
@@ -849,12 +848,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu,
 		updated_state = false;
 	}
 	spin_unlock(&dist->lock);
-	run->mmio.is_write	= is_write;
-	run->mmio.len		= len;
-	run->mmio.phys_addr	= addr;
-	memcpy(run->mmio.data, val, len);
-
-	kvm_handle_mmio_return(vcpu, run);
 
 	if (updated_state)
 		vgic_kick_vcpus(vcpu->kvm);
-- 
2.7.3

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

* [PATCH v3 09/55] KVM: arm/arm64: Fix MMIO emulation data handling
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

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

When the kernel was handling a guest MMIO read access internally, we
need to copy the emulation result into the run->mmio structure in order
for the kvm_handle_mmio_return() function to pick it up and inject the
	result back into the guest.

Currently the only user of kvm_io_bus for ARM is the VGIC, which did
this copying itself, so this was not causing issues so far.

But with the upcoming new vgic implementation we need this done
properly.

Update the kvm_handle_mmio_return description and cleanup the code to
only perform a single copying when needed.

Code and commit message inspired by Andre Przywara.

Reported-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 arch/arm/kvm/mmio.c | 14 +++++++-------
 virt/kvm/arm/vgic.c |  7 -------
 2 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
index 0f6600f..0158e9e 100644
--- a/arch/arm/kvm/mmio.c
+++ b/arch/arm/kvm/mmio.c
@@ -87,11 +87,10 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len)
 
 /**
  * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
+ *			     or in-kernel IO emulation
+ *
  * @vcpu: The VCPU pointer
  * @run:  The VCPU run struct containing the mmio data
- *
- * This should only be called after returning from userspace for MMIO load
- * emulation.
  */
 int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
@@ -206,18 +205,19 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
 	run->mmio.is_write	= is_write;
 	run->mmio.phys_addr	= fault_ipa;
 	run->mmio.len		= len;
-	if (is_write)
-		memcpy(run->mmio.data, data_buf, len);
 
 	if (!ret) {
 		/* We handled the access successfully in the kernel. */
+		if (!is_write)
+			memcpy(run->mmio.data, data_buf, len);
 		vcpu->stat.mmio_exit_kernel++;
 		kvm_handle_mmio_return(vcpu, run);
 		return 1;
-	} else {
-		vcpu->stat.mmio_exit_user++;
 	}
 
+	if (is_write)
+		memcpy(run->mmio.data, data_buf, len);
+	vcpu->stat.mmio_exit_user++;
 	run->exit_reason	= KVM_EXIT_MMIO;
 	return 0;
 }
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 5efc298..e70cee4 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -820,7 +820,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu,
 	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
 	struct vgic_io_device *iodev = container_of(this,
 						    struct vgic_io_device, dev);
-	struct kvm_run *run = vcpu->run;
 	const struct vgic_io_range *range;
 	struct kvm_exit_mmio mmio;
 	bool updated_state;
@@ -849,12 +848,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu,
 		updated_state = false;
 	}
 	spin_unlock(&dist->lock);
-	run->mmio.is_write	= is_write;
-	run->mmio.len		= len;
-	run->mmio.phys_addr	= addr;
-	memcpy(run->mmio.data, val, len);
-
-	kvm_handle_mmio_return(vcpu, run);
 
 	if (updated_state)
 		vgic_kick_vcpus(vcpu->kvm);
-- 
2.7.3

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

* [PATCH v3 10/55] KVM: arm/arm64: Export mmio_read/write_bus
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

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

Rename mmio_{read,write}_bus to kvm_mmio_{read,write}_bus and export
them out of mmio.c.
This will be needed later for the new VGIC implementation.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 arch/arm/include/asm/kvm_mmio.h   |  3 +++
 arch/arm/kvm/mmio.c               | 10 +++++-----
 arch/arm64/include/asm/kvm_mmio.h |  3 +++
 3 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/arch/arm/include/asm/kvm_mmio.h b/arch/arm/include/asm/kvm_mmio.h
index d8e90c8..f3a7de7 100644
--- a/arch/arm/include/asm/kvm_mmio.h
+++ b/arch/arm/include/asm/kvm_mmio.h
@@ -28,6 +28,9 @@ struct kvm_decode {
 	bool sign_extend;
 };
 
+void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
+unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
+
 int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
 int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
 		 phys_addr_t fault_ipa);
diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
index 0158e9e..10f80a6 100644
--- a/arch/arm/kvm/mmio.c
+++ b/arch/arm/kvm/mmio.c
@@ -23,7 +23,7 @@
 
 #include "trace.h"
 
-static void mmio_write_buf(char *buf, unsigned int len, unsigned long data)
+void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data)
 {
 	void *datap = NULL;
 	union {
@@ -55,7 +55,7 @@ static void mmio_write_buf(char *buf, unsigned int len, unsigned long data)
 	memcpy(buf, datap, len);
 }
 
-static unsigned long mmio_read_buf(char *buf, unsigned int len)
+unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len)
 {
 	unsigned long data = 0;
 	union {
@@ -66,7 +66,7 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len)
 
 	switch (len) {
 	case 1:
-		data = buf[0];
+		data = *(u8 *)buf;
 		break;
 	case 2:
 		memcpy(&tmp.hword, buf, len);
@@ -103,7 +103,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		if (len > sizeof(unsigned long))
 			return -EINVAL;
 
-		data = mmio_read_buf(run->mmio.data, len);
+		data = kvm_mmio_read_buf(run->mmio.data, len);
 
 		if (vcpu->arch.mmio_decode.sign_extend &&
 		    len < sizeof(unsigned long)) {
@@ -189,7 +189,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
 					       len);
 
 		trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data);
-		mmio_write_buf(data_buf, len, data);
+		kvm_mmio_write_buf(data_buf, len, data);
 
 		ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len,
 				       data_buf);
diff --git a/arch/arm64/include/asm/kvm_mmio.h b/arch/arm64/include/asm/kvm_mmio.h
index fe612a9..75ea420 100644
--- a/arch/arm64/include/asm/kvm_mmio.h
+++ b/arch/arm64/include/asm/kvm_mmio.h
@@ -30,6 +30,9 @@ struct kvm_decode {
 	bool sign_extend;
 };
 
+void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
+unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
+
 int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
 int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
 		 phys_addr_t fault_ipa);
-- 
2.7.3


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

* [PATCH v3 10/55] KVM: arm/arm64: Export mmio_read/write_bus
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

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

Rename mmio_{read,write}_bus to kvm_mmio_{read,write}_bus and export
them out of mmio.c.
This will be needed later for the new VGIC implementation.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 arch/arm/include/asm/kvm_mmio.h   |  3 +++
 arch/arm/kvm/mmio.c               | 10 +++++-----
 arch/arm64/include/asm/kvm_mmio.h |  3 +++
 3 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/arch/arm/include/asm/kvm_mmio.h b/arch/arm/include/asm/kvm_mmio.h
index d8e90c8..f3a7de7 100644
--- a/arch/arm/include/asm/kvm_mmio.h
+++ b/arch/arm/include/asm/kvm_mmio.h
@@ -28,6 +28,9 @@ struct kvm_decode {
 	bool sign_extend;
 };
 
+void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
+unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
+
 int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
 int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
 		 phys_addr_t fault_ipa);
diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
index 0158e9e..10f80a6 100644
--- a/arch/arm/kvm/mmio.c
+++ b/arch/arm/kvm/mmio.c
@@ -23,7 +23,7 @@
 
 #include "trace.h"
 
-static void mmio_write_buf(char *buf, unsigned int len, unsigned long data)
+void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data)
 {
 	void *datap = NULL;
 	union {
@@ -55,7 +55,7 @@ static void mmio_write_buf(char *buf, unsigned int len, unsigned long data)
 	memcpy(buf, datap, len);
 }
 
-static unsigned long mmio_read_buf(char *buf, unsigned int len)
+unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len)
 {
 	unsigned long data = 0;
 	union {
@@ -66,7 +66,7 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len)
 
 	switch (len) {
 	case 1:
-		data = buf[0];
+		data = *(u8 *)buf;
 		break;
 	case 2:
 		memcpy(&tmp.hword, buf, len);
@@ -103,7 +103,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		if (len > sizeof(unsigned long))
 			return -EINVAL;
 
-		data = mmio_read_buf(run->mmio.data, len);
+		data = kvm_mmio_read_buf(run->mmio.data, len);
 
 		if (vcpu->arch.mmio_decode.sign_extend &&
 		    len < sizeof(unsigned long)) {
@@ -189,7 +189,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
 					       len);
 
 		trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data);
-		mmio_write_buf(data_buf, len, data);
+		kvm_mmio_write_buf(data_buf, len, data);
 
 		ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len,
 				       data_buf);
diff --git a/arch/arm64/include/asm/kvm_mmio.h b/arch/arm64/include/asm/kvm_mmio.h
index fe612a9..75ea420 100644
--- a/arch/arm64/include/asm/kvm_mmio.h
+++ b/arch/arm64/include/asm/kvm_mmio.h
@@ -30,6 +30,9 @@ struct kvm_decode {
 	bool sign_extend;
 };
 
+void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
+unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
+
 int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
 int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
 		 phys_addr_t fault_ipa);
-- 
2.7.3

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

* [PATCH v3 11/55] KVM: arm/arm64: pmu: abstract access to number of SPIs
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Currently the PMU uses a member of the struct vgic_dist directly,
which not only breaks abstraction, but will fail with the new VGIC.
Abstract this access in the VGIC header file.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/arm_vgic.h | 2 ++
 virt/kvm/arm/pmu.c     | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 452bb85..c14ff77 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -347,6 +347,8 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
 #define vgic_ready(k)		((k)->arch.vgic.ready)
+#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
+				 ((i) < (k)->arch.vgic.nr_irqs))
 
 int vgic_v2_probe(struct device_node *vgic_node,
 		  const struct vgic_ops **ops,
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 575c7aa..bd2e872 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -477,7 +477,7 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
 		 * the interrupt number is the same for all vcpus, while as an
 		 * SPI it must be a separate number per vcpu.
 		 */
-		if (irq < VGIC_NR_SGIS || irq >= vcpu->kvm->arch.vgic.nr_irqs ||
+		if (irq < VGIC_NR_SGIS || !vgic_valid_spi(vcpu->kvm, irq) ||
 		    !irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
 			return -EINVAL;
 
-- 
2.7.3

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

* [PATCH v3 11/55] KVM: arm/arm64: pmu: abstract access to number of SPIs
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

Currently the PMU uses a member of the struct vgic_dist directly,
which not only breaks abstraction, but will fail with the new VGIC.
Abstract this access in the VGIC header file.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/arm_vgic.h | 2 ++
 virt/kvm/arm/pmu.c     | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 452bb85..c14ff77 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -347,6 +347,8 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
 #define vgic_ready(k)		((k)->arch.vgic.ready)
+#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
+				 ((i) < (k)->arch.vgic.nr_irqs))
 
 int vgic_v2_probe(struct device_node *vgic_node,
 		  const struct vgic_ops **ops,
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 575c7aa..bd2e872 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -477,7 +477,7 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
 		 * the interrupt number is the same for all vcpus, while as an
 		 * SPI it must be a separate number per vcpu.
 		 */
-		if (irq < VGIC_NR_SGIS || irq >= vcpu->kvm->arch.vgic.nr_irqs ||
+		if (irq < VGIC_NR_SGIS || !vgic_valid_spi(vcpu->kvm, irq) ||
 		    !irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
 			return -EINVAL;
 
-- 
2.7.3

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

* [PATCH v3 12/55] KVM: arm/arm64: move GICv2 emulation defines into arm-gic-v3.h
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

As (some) GICv3 hosts can emulate a GICv2, some GICv2 specific masks
for the list register definition also apply to GICv3 LRs.
At the moment we have those definitions in the KVM VGICv3
implementation, so let's move them into the GICv3 header file to
have them automatically defined.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/linux/irqchip/arm-gic-v3.h | 5 +++++
 virt/kvm/arm/vgic-v3.c             | 8 +-------
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index d5d798b..ec938d1 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -276,6 +276,11 @@
 #define ICH_LR_PHYS_ID_SHIFT		32
 #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
 
+/* These are for GICv2 emulation only */
+#define GICH_LR_VIRTUALID		(0x3ffUL << 0)
+#define GICH_LR_PHYSID_CPUID_SHIFT	(10)
+#define GICH_LR_PHYSID_CPUID		(7UL << GICH_LR_PHYSID_CPUID_SHIFT)
+
 #define ICH_MISR_EOI			(1 << 0)
 #define ICH_MISR_U			(1 << 1)
 
diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c
index 999bdc6..9c5cfc2 100644
--- a/virt/kvm/arm/vgic-v3.c
+++ b/virt/kvm/arm/vgic-v3.c
@@ -31,12 +31,6 @@
 #include <asm/kvm_asm.h>
 #include <asm/kvm_mmu.h>
 
-/* These are for GICv2 emulation only */
-#define GICH_LR_VIRTUALID		(0x3ffUL << 0)
-#define GICH_LR_PHYSID_CPUID_SHIFT	(10)
-#define GICH_LR_PHYSID_CPUID		(7UL << GICH_LR_PHYSID_CPUID_SHIFT)
-#define ICH_LR_VIRTUALID_MASK		(BIT_ULL(32) - 1)
-
 static u32 ich_vtr_el2;
 
 static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
@@ -45,7 +39,7 @@ static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
 	u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr];
 
 	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
-		lr_desc.irq = val & ICH_LR_VIRTUALID_MASK;
+		lr_desc.irq = val & ICH_LR_VIRTUAL_ID_MASK;
 	else
 		lr_desc.irq = val & GICH_LR_VIRTUALID;
 
-- 
2.7.3


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

* [PATCH v3 12/55] KVM: arm/arm64: move GICv2 emulation defines into arm-gic-v3.h
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

As (some) GICv3 hosts can emulate a GICv2, some GICv2 specific masks
for the list register definition also apply to GICv3 LRs.
At the moment we have those definitions in the KVM VGICv3
implementation, so let's move them into the GICv3 header file to
have them automatically defined.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/linux/irqchip/arm-gic-v3.h | 5 +++++
 virt/kvm/arm/vgic-v3.c             | 8 +-------
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index d5d798b..ec938d1 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -276,6 +276,11 @@
 #define ICH_LR_PHYS_ID_SHIFT		32
 #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
 
+/* These are for GICv2 emulation only */
+#define GICH_LR_VIRTUALID		(0x3ffUL << 0)
+#define GICH_LR_PHYSID_CPUID_SHIFT	(10)
+#define GICH_LR_PHYSID_CPUID		(7UL << GICH_LR_PHYSID_CPUID_SHIFT)
+
 #define ICH_MISR_EOI			(1 << 0)
 #define ICH_MISR_U			(1 << 1)
 
diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c
index 999bdc6..9c5cfc2 100644
--- a/virt/kvm/arm/vgic-v3.c
+++ b/virt/kvm/arm/vgic-v3.c
@@ -31,12 +31,6 @@
 #include <asm/kvm_asm.h>
 #include <asm/kvm_mmu.h>
 
-/* These are for GICv2 emulation only */
-#define GICH_LR_VIRTUALID		(0x3ffUL << 0)
-#define GICH_LR_PHYSID_CPUID_SHIFT	(10)
-#define GICH_LR_PHYSID_CPUID		(7UL << GICH_LR_PHYSID_CPUID_SHIFT)
-#define ICH_LR_VIRTUALID_MASK		(BIT_ULL(32) - 1)
-
 static u32 ich_vtr_el2;
 
 static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
@@ -45,7 +39,7 @@ static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
 	u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr];
 
 	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
-		lr_desc.irq = val & ICH_LR_VIRTUALID_MASK;
+		lr_desc.irq = val & ICH_LR_VIRTUAL_ID_MASK;
 	else
 		lr_desc.irq = val & GICH_LR_VIRTUALID;
 
-- 
2.7.3

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

* [PATCH v3 13/55] KVM: arm/arm64: vgic-new: Add data structure definitions
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

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

Add a new header file for the new and improved GIC implementation.
The big change is that we now have a struct vgic_irq per IRQ instead
of spreading all the information over various bitmaps.

We include this new header conditionally from within the old header
file for the time being to avoid touching all the users.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changes RFC .. v1:
- adapt to 4.6-rc (adding live_lrs member)
- elaborate on ap_list usage

Changes v1 .. v2:
- change data type of dist->enabled to bool

 include/kvm/arm_vgic.h  |   5 ++
 include/kvm/vgic/vgic.h | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 206 insertions(+)
 create mode 100644 include/kvm/vgic/vgic.h

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index c14ff77..d406f8e 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -19,6 +19,10 @@
 #ifndef __ASM_ARM_KVM_VGIC_H
 #define __ASM_ARM_KVM_VGIC_H
 
+#ifdef CONFIG_KVM_NEW_VGIC
+#include <kvm/vgic/vgic.h>
+#else
+
 #include <linux/kernel.h>
 #include <linux/kvm.h>
 #include <linux/irqreturn.h>
@@ -366,4 +370,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
 }
 #endif
 
+#endif	/* old VGIC include */
 #endif
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
new file mode 100644
index 0000000..39933ee
--- /dev/null
+++ b/include/kvm/vgic/vgic.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_ARM_KVM_VGIC_VGIC_H
+#define __ASM_ARM_KVM_VGIC_VGIC_H
+
+#include <linux/kernel.h>
+#include <linux/kvm.h>
+#include <linux/irqreturn.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <kvm/iodev.h>
+
+#define VGIC_V3_MAX_CPUS	255
+#define VGIC_V2_MAX_CPUS	8
+#define VGIC_NR_IRQS_LEGACY     256
+#define VGIC_NR_SGIS		16
+#define VGIC_NR_PPIS		16
+#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
+#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
+#define VGIC_MAX_SPI		1019
+#define VGIC_MAX_RESERVED	1023
+#define VGIC_MIN_LPI		8192
+
+enum vgic_type {
+	VGIC_V2,		/* Good ol' GICv2 */
+	VGIC_V3,		/* New fancy GICv3 */
+};
+
+/* same for all guests, as depending only on the _host's_ GIC model */
+struct vgic_global {
+	/* type of the host GIC */
+	enum vgic_type		type;
+
+	/* Physical address of vgic virtual cpu interface */
+	phys_addr_t		vcpu_base;
+
+	/* virtual control interface mapping */
+	void __iomem		*vctrl_base;
+
+	/* Number of implemented list registers */
+	int			nr_lr;
+
+	/* Maintenance IRQ number */
+	unsigned int		maint_irq;
+
+	/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
+	int			max_gic_vcpus;
+
+	/* Only needed for the legacy KVM_CREATE_IRQCHIP */
+	bool			can_emulate_gicv2;
+};
+
+extern struct vgic_global kvm_vgic_global_state;
+
+#define VGIC_V2_MAX_LRS		(1 << 6)
+#define VGIC_V3_MAX_LRS		16
+#define VGIC_V3_LR_INDEX(lr)	(VGIC_V3_MAX_LRS - 1 - lr)
+
+enum vgic_irq_config {
+	VGIC_CONFIG_EDGE = 0,
+	VGIC_CONFIG_LEVEL
+};
+
+struct vgic_irq {
+	spinlock_t irq_lock;		/* Protects the content of the struct */
+	struct list_head ap_list;
+
+	struct kvm_vcpu *vcpu;		/* SGIs and PPIs: The VCPU
+					 * SPIs and LPIs: The VCPU whose ap_list
+					 * on which this is queued.
+					 */
+
+	struct kvm_vcpu *target_vcpu;	/* The VCPU that this interrupt should
+					 * be send to, as a result of the
+					 * targets reg (v2) or the
+					 * affinity reg (v3).
+					 */
+
+	u32 intid;			/* Guest visible INTID */
+	bool pending;
+	bool line_level;		/* Level only */
+	bool soft_pending;		/* Level only */
+	bool active;			/* not used for LPIs */
+	bool enabled;
+	bool hw;			/* Tied to HW IRQ */
+	u32 hwintid;			/* HW INTID number */
+	union {
+		u8 targets;			/* GICv2 target VCPUs mask */
+		u32 mpidr;			/* GICv3 target VCPU */
+	};
+	u8 source;			/* GICv2 SGIs only */
+	u8 priority;
+	enum vgic_irq_config config;	/* Level or edge */
+};
+
+struct vgic_dist {
+	bool			in_kernel;
+	bool			ready;
+
+	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
+	u32			vgic_model;
+
+	int			nr_spis;
+
+	/* TODO: Consider moving to global state */
+	/* Virtual control interface mapping */
+	void __iomem		*vctrl_base;
+
+	/* base addresses in guest physical address space: */
+	gpa_t			vgic_dist_base;		/* distributor */
+	union {
+		/* either a GICv2 CPU interface */
+		gpa_t			vgic_cpu_base;
+		/* or a number of GICv3 redistributor regions */
+		gpa_t			vgic_redist_base;
+	};
+
+	/* distributor enabled */
+	bool			enabled;
+
+	struct vgic_irq		*spis;
+};
+
+struct vgic_v2_cpu_if {
+	u32		vgic_hcr;
+	u32		vgic_vmcr;
+	u32		vgic_misr;	/* Saved only */
+	u64		vgic_eisr;	/* Saved only */
+	u64		vgic_elrsr;	/* Saved only */
+	u32		vgic_apr;
+	u32		vgic_lr[VGIC_V2_MAX_LRS];
+};
+
+struct vgic_v3_cpu_if {
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+	u32		vgic_hcr;
+	u32		vgic_vmcr;
+	u32		vgic_sre;	/* Restored only, change ignored */
+	u32		vgic_misr;	/* Saved only */
+	u32		vgic_eisr;	/* Saved only */
+	u32		vgic_elrsr;	/* Saved only */
+	u32		vgic_ap0r[4];
+	u32		vgic_ap1r[4];
+	u64		vgic_lr[VGIC_V3_MAX_LRS];
+#endif
+};
+
+struct vgic_cpu {
+	/* CPU vif control registers for world switch */
+	union {
+		struct vgic_v2_cpu_if	vgic_v2;
+		struct vgic_v3_cpu_if	vgic_v3;
+	};
+
+	unsigned int used_lrs;
+	struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
+
+	spinlock_t ap_list_lock;	/* Protects the ap_list */
+
+	/*
+	 * List of IRQs that this VCPU should consider because they are either
+	 * Active or Pending (hence the name; AP list), or because they recently
+	 * were one of the two and need to be migrated off this list to another
+	 * VCPU.
+	 */
+	struct list_head ap_list_head;
+
+	u64 live_lrs;
+};
+
+#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
+#define vgic_initialized(k)	(false)
+#define vgic_ready(k)		((k)->arch.vgic.ready)
+#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
+			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
+
+/**
+ * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
+ *
+ * The host's GIC naturally limits the maximum amount of VCPUs a guest
+ * can use.
+ */
+static inline int kvm_vgic_get_max_vcpus(void)
+{
+	return kvm_vgic_global_state.max_gic_vcpus;
+}
+
+#endif /* __ASM_ARM_KVM_VGIC_VGIC_H */
-- 
2.7.3


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

* [PATCH v3 13/55] KVM: arm/arm64: vgic-new: Add data structure definitions
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

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

Add a new header file for the new and improved GIC implementation.
The big change is that we now have a struct vgic_irq per IRQ instead
of spreading all the information over various bitmaps.

We include this new header conditionally from within the old header
file for the time being to avoid touching all the users.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changes RFC .. v1:
- adapt to 4.6-rc (adding live_lrs member)
- elaborate on ap_list usage

Changes v1 .. v2:
- change data type of dist->enabled to bool

 include/kvm/arm_vgic.h  |   5 ++
 include/kvm/vgic/vgic.h | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 206 insertions(+)
 create mode 100644 include/kvm/vgic/vgic.h

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index c14ff77..d406f8e 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -19,6 +19,10 @@
 #ifndef __ASM_ARM_KVM_VGIC_H
 #define __ASM_ARM_KVM_VGIC_H
 
+#ifdef CONFIG_KVM_NEW_VGIC
+#include <kvm/vgic/vgic.h>
+#else
+
 #include <linux/kernel.h>
 #include <linux/kvm.h>
 #include <linux/irqreturn.h>
@@ -366,4 +370,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
 }
 #endif
 
+#endif	/* old VGIC include */
 #endif
diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
new file mode 100644
index 0000000..39933ee
--- /dev/null
+++ b/include/kvm/vgic/vgic.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_ARM_KVM_VGIC_VGIC_H
+#define __ASM_ARM_KVM_VGIC_VGIC_H
+
+#include <linux/kernel.h>
+#include <linux/kvm.h>
+#include <linux/irqreturn.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <kvm/iodev.h>
+
+#define VGIC_V3_MAX_CPUS	255
+#define VGIC_V2_MAX_CPUS	8
+#define VGIC_NR_IRQS_LEGACY     256
+#define VGIC_NR_SGIS		16
+#define VGIC_NR_PPIS		16
+#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
+#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
+#define VGIC_MAX_SPI		1019
+#define VGIC_MAX_RESERVED	1023
+#define VGIC_MIN_LPI		8192
+
+enum vgic_type {
+	VGIC_V2,		/* Good ol' GICv2 */
+	VGIC_V3,		/* New fancy GICv3 */
+};
+
+/* same for all guests, as depending only on the _host's_ GIC model */
+struct vgic_global {
+	/* type of the host GIC */
+	enum vgic_type		type;
+
+	/* Physical address of vgic virtual cpu interface */
+	phys_addr_t		vcpu_base;
+
+	/* virtual control interface mapping */
+	void __iomem		*vctrl_base;
+
+	/* Number of implemented list registers */
+	int			nr_lr;
+
+	/* Maintenance IRQ number */
+	unsigned int		maint_irq;
+
+	/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
+	int			max_gic_vcpus;
+
+	/* Only needed for the legacy KVM_CREATE_IRQCHIP */
+	bool			can_emulate_gicv2;
+};
+
+extern struct vgic_global kvm_vgic_global_state;
+
+#define VGIC_V2_MAX_LRS		(1 << 6)
+#define VGIC_V3_MAX_LRS		16
+#define VGIC_V3_LR_INDEX(lr)	(VGIC_V3_MAX_LRS - 1 - lr)
+
+enum vgic_irq_config {
+	VGIC_CONFIG_EDGE = 0,
+	VGIC_CONFIG_LEVEL
+};
+
+struct vgic_irq {
+	spinlock_t irq_lock;		/* Protects the content of the struct */
+	struct list_head ap_list;
+
+	struct kvm_vcpu *vcpu;		/* SGIs and PPIs: The VCPU
+					 * SPIs and LPIs: The VCPU whose ap_list
+					 * on which this is queued.
+					 */
+
+	struct kvm_vcpu *target_vcpu;	/* The VCPU that this interrupt should
+					 * be send to, as a result of the
+					 * targets reg (v2) or the
+					 * affinity reg (v3).
+					 */
+
+	u32 intid;			/* Guest visible INTID */
+	bool pending;
+	bool line_level;		/* Level only */
+	bool soft_pending;		/* Level only */
+	bool active;			/* not used for LPIs */
+	bool enabled;
+	bool hw;			/* Tied to HW IRQ */
+	u32 hwintid;			/* HW INTID number */
+	union {
+		u8 targets;			/* GICv2 target VCPUs mask */
+		u32 mpidr;			/* GICv3 target VCPU */
+	};
+	u8 source;			/* GICv2 SGIs only */
+	u8 priority;
+	enum vgic_irq_config config;	/* Level or edge */
+};
+
+struct vgic_dist {
+	bool			in_kernel;
+	bool			ready;
+
+	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
+	u32			vgic_model;
+
+	int			nr_spis;
+
+	/* TODO: Consider moving to global state */
+	/* Virtual control interface mapping */
+	void __iomem		*vctrl_base;
+
+	/* base addresses in guest physical address space: */
+	gpa_t			vgic_dist_base;		/* distributor */
+	union {
+		/* either a GICv2 CPU interface */
+		gpa_t			vgic_cpu_base;
+		/* or a number of GICv3 redistributor regions */
+		gpa_t			vgic_redist_base;
+	};
+
+	/* distributor enabled */
+	bool			enabled;
+
+	struct vgic_irq		*spis;
+};
+
+struct vgic_v2_cpu_if {
+	u32		vgic_hcr;
+	u32		vgic_vmcr;
+	u32		vgic_misr;	/* Saved only */
+	u64		vgic_eisr;	/* Saved only */
+	u64		vgic_elrsr;	/* Saved only */
+	u32		vgic_apr;
+	u32		vgic_lr[VGIC_V2_MAX_LRS];
+};
+
+struct vgic_v3_cpu_if {
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+	u32		vgic_hcr;
+	u32		vgic_vmcr;
+	u32		vgic_sre;	/* Restored only, change ignored */
+	u32		vgic_misr;	/* Saved only */
+	u32		vgic_eisr;	/* Saved only */
+	u32		vgic_elrsr;	/* Saved only */
+	u32		vgic_ap0r[4];
+	u32		vgic_ap1r[4];
+	u64		vgic_lr[VGIC_V3_MAX_LRS];
+#endif
+};
+
+struct vgic_cpu {
+	/* CPU vif control registers for world switch */
+	union {
+		struct vgic_v2_cpu_if	vgic_v2;
+		struct vgic_v3_cpu_if	vgic_v3;
+	};
+
+	unsigned int used_lrs;
+	struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
+
+	spinlock_t ap_list_lock;	/* Protects the ap_list */
+
+	/*
+	 * List of IRQs that this VCPU should consider because they are either
+	 * Active or Pending (hence the name; AP list), or because they recently
+	 * were one of the two and need to be migrated off this list to another
+	 * VCPU.
+	 */
+	struct list_head ap_list_head;
+
+	u64 live_lrs;
+};
+
+#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
+#define vgic_initialized(k)	(false)
+#define vgic_ready(k)		((k)->arch.vgic.ready)
+#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
+			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
+
+/**
+ * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
+ *
+ * The host's GIC naturally limits the maximum amount of VCPUs a guest
+ * can use.
+ */
+static inline int kvm_vgic_get_max_vcpus(void)
+{
+	return kvm_vgic_global_state.max_gic_vcpus;
+}
+
+#endif /* __ASM_ARM_KVM_VGIC_VGIC_H */
-- 
2.7.3

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

* [PATCH v3 14/55] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

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

The new VGIC implementation centers around a struct vgic_irq instance
per virtual IRQ.
Provide a function to retrieve the right instance for a given IRQ
number and (in case of private interrupts) the right VCPU.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic.c | 41 +++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h | 22 ++++++++++++++++++++++
 2 files changed, 63 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic.c
 create mode 100644 virt/kvm/arm/vgic/vgic.h

diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
new file mode 100644
index 0000000..fb45537
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+
+#include "vgic.h"
+
+struct vgic_global __section(.hyp.text) kvm_vgic_global_state;
+
+struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
+			      u32 intid)
+{
+	/* SGIs and PPIs */
+	if (intid <= VGIC_MAX_PRIVATE)
+		return &vcpu->arch.vgic_cpu.private_irqs[intid];
+
+	/* SPIs */
+	if (intid <= VGIC_MAX_SPI)
+		return &kvm->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS];
+
+	/* LPIs are not yet covered */
+	if (intid >= VGIC_MIN_LPI)
+		return NULL;
+
+	WARN(1, "Looking up struct vgic_irq for reserved INTID");
+	return NULL;
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
new file mode 100644
index 0000000..61b8d22
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __KVM_ARM_VGIC_NEW_H__
+#define __KVM_ARM_VGIC_NEW_H__
+
+struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
+			      u32 intid);
+
+#endif
-- 
2.7.3

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

* [PATCH v3 14/55] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

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

The new VGIC implementation centers around a struct vgic_irq instance
per virtual IRQ.
Provide a function to retrieve the right instance for a given IRQ
number and (in case of private interrupts) the right VCPU.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic.c | 41 +++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h | 22 ++++++++++++++++++++++
 2 files changed, 63 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic.c
 create mode 100644 virt/kvm/arm/vgic/vgic.h

diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
new file mode 100644
index 0000000..fb45537
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+
+#include "vgic.h"
+
+struct vgic_global __section(.hyp.text) kvm_vgic_global_state;
+
+struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
+			      u32 intid)
+{
+	/* SGIs and PPIs */
+	if (intid <= VGIC_MAX_PRIVATE)
+		return &vcpu->arch.vgic_cpu.private_irqs[intid];
+
+	/* SPIs */
+	if (intid <= VGIC_MAX_SPI)
+		return &kvm->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS];
+
+	/* LPIs are not yet covered */
+	if (intid >= VGIC_MIN_LPI)
+		return NULL;
+
+	WARN(1, "Looking up struct vgic_irq for reserved INTID");
+	return NULL;
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
new file mode 100644
index 0000000..61b8d22
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __KVM_ARM_VGIC_NEW_H__
+#define __KVM_ARM_VGIC_NEW_H__
+
+struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
+			      u32 intid);
+
+#endif
-- 
2.7.3

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

* [PATCH v3 15/55] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

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

Provide a vgic_queue_irq() function which decides whether a given
IRQ needs to be queued to a VCPU's ap_list.
This should be called whenever an IRQ becomes pending or enabled,
either as a result of userspace injection, from in-kernel emulated
devices like the architected timer or from MMIO accesses to the
distributor emulation.
Also provides the necessary functions to allow userland to inject an
IRQ to a guest.
Since this is the first code that starts using our locking mechanism, we
add some (hopefully) clear documentation of our locking strategy and
requirements along with this patch.

[Andre: refactor out vgic_queue_irq_unlock()]

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- add spinlock checks protected by CONFIG_DEBUG_SPINLOCK
- add more comments to vgic_target_oracle
- remove BUG_ON() if IRQ is neither edge or level
- rename vgic_queue_irq() to vgic_queue_irq_unlock()
- simplify initial check in vgic_queue_irq_unlock()
- extend retry loop to ask the oracle again
- minor comment fixes

Changelog v1 .. v2:
- move most IRQ injection code into vgic_update_irq_pending()

 include/kvm/vgic/vgic.h  |   3 +
 virt/kvm/arm/vgic/vgic.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h |   1 +
 3 files changed, 213 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 39933ee..2bfb42c 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -181,6 +181,9 @@ struct vgic_cpu {
 	u64 live_lrs;
 };
 
+int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+			bool level);
+
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	(false)
 #define vgic_ready(k)		((k)->arch.vgic.ready)
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index fb45537..92b78a0 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -19,8 +19,31 @@
 
 #include "vgic.h"
 
+#define CREATE_TRACE_POINTS
+#include "../trace.h"
+
+#ifdef CONFIG_DEBUG_SPINLOCK
+#define DEBUG_SPINLOCK_BUG_ON(p) BUG_ON(p)
+#else
+#define DEBUG_SPINLOCK_BUG_ON(p)
+#endif
+
 struct vgic_global __section(.hyp.text) kvm_vgic_global_state;
 
+/*
+ * Locking order is always:
+ *   vgic_cpu->ap_list_lock
+ *     vgic_irq->irq_lock
+ *
+ * (that is, always take the ap_list_lock before the struct vgic_irq lock).
+ *
+ * When taking more than one ap_list_lock at the same time, always take the
+ * lowest numbered VCPU's ap_list_lock first, so:
+ *   vcpuX->vcpu_id < vcpuY->vcpu_id:
+ *     spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
+ *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
+ */
+
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid)
 {
@@ -39,3 +62,189 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 	WARN(1, "Looking up struct vgic_irq for reserved INTID");
 	return NULL;
 }
+
+/**
+ * kvm_vgic_target_oracle - compute the target vcpu for an irq
+ *
+ * @irq:	The irq to route. Must be already locked.
+ *
+ * Based on the current state of the interrupt (enabled, pending,
+ * active, vcpu and target_vcpu), compute the next vcpu this should be
+ * given to. Return NULL if this shouldn't be injected at all.
+ *
+ * Requires the IRQ lock to be held.
+ */
+static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
+{
+	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
+
+	/* If the interrupt is active, it must stay on the current vcpu */
+	if (irq->active)
+		return irq->vcpu;
+
+	/*
+	 * If the IRQ is not active but enabled and pending, we should direct
+	 * it to its configured target VCPU.
+	 */
+	if (irq->enabled && irq->pending)
+		return irq->target_vcpu;
+
+	/* If neither active nor pending and enabled, then this IRQ should not
+	 * be queued to any VCPU.
+	 */
+	return NULL;
+}
+
+/*
+ * Only valid injection if changing level for level-triggered IRQs or for a
+ * rising edge.
+ */
+static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
+{
+	switch (irq->config) {
+	case VGIC_CONFIG_LEVEL:
+		return irq->line_level != level;
+	case VGIC_CONFIG_EDGE:
+		return level;
+	}
+
+	return false;
+}
+
+/*
+ * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
+ * Do the queuing if necessary, taking the right locks in the right order.
+ * Returns true when the IRQ was queued, false otherwise.
+ *
+ * Needs to be entered with the IRQ lock already held, but will return
+ * with all locks dropped.
+ */
+bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq)
+{
+	struct kvm_vcpu *vcpu;
+
+	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
+
+retry:
+	vcpu = vgic_target_oracle(irq);
+	if (irq->vcpu || !vcpu) {
+		/*
+		 * If this IRQ is already on a VCPU's ap_list, then it
+		 * cannot be moved or modified and there is no more work for
+		 * us to do.
+		 *
+		 * Otherwise, if the irq is not pending and enabled, it does
+		 * not need to be inserted into an ap_list and there is also
+		 * no more work for us to do.
+		 */
+		spin_unlock(&irq->irq_lock);
+		return false;
+	}
+
+	/*
+	 * We must unlock the irq lock to take the ap_list_lock where
+	 * we are going to insert this new pending interrupt.
+	 */
+	spin_unlock(&irq->irq_lock);
+
+	/* someone can do stuff here, which we re-check below */
+
+	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
+	spin_lock(&irq->irq_lock);
+
+	/*
+	 * Did something change behind our backs?
+	 *
+	 * There are two cases:
+	 * 1) The irq became pending or active behind our backs and/or
+	 *    the irq->vcpu field was set correspondingly when putting
+	 *    the irq on an ap_list. Then drop the locks and return.
+	 * 2) Someone changed the affinity on this irq behind our
+	 *    backs and we are now holding the wrong ap_list_lock.
+	 *    Then drop the locks and try the new VCPU.
+	 */
+	if (irq->vcpu || !(irq->pending && irq->enabled)) {
+		spin_unlock(&irq->irq_lock);
+		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+		return false;
+	}
+
+	if (irq->target_vcpu != vcpu) {
+		spin_unlock(&irq->irq_lock);
+		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+		spin_lock(&irq->irq_lock);
+		goto retry;
+	}
+
+	list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
+	irq->vcpu = vcpu;
+
+	spin_unlock(&irq->irq_lock);
+	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+	kvm_vcpu_kick(vcpu);
+
+	return true;
+}
+
+static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
+				   unsigned int intid, bool level,
+				   bool mapped_irq)
+{
+	struct kvm_vcpu *vcpu;
+	struct vgic_irq *irq;
+	int ret;
+
+	trace_vgic_update_irq_pending(cpuid, intid, level);
+
+	vcpu = kvm_get_vcpu(kvm, cpuid);
+	if (!vcpu && intid < VGIC_NR_PRIVATE_IRQS)
+		return -EINVAL;
+
+	irq = vgic_get_irq(kvm, vcpu, intid);
+	if (!irq)
+		return -EINVAL;
+
+	if (irq->hw != mapped_irq)
+		return -EINVAL;
+
+	spin_lock(&irq->irq_lock);
+
+	if (!vgic_validate_injection(irq, level)) {
+		/* Nothing to see here, move along... */
+		spin_unlock(&irq->irq_lock);
+		return 0;
+	}
+
+	if (irq->config == VGIC_CONFIG_LEVEL) {
+		irq->line_level = level;
+		irq->pending = level || irq->soft_pending;
+	} else {
+		irq->pending = true;
+	}
+
+	vgic_queue_irq_unlock(kvm, irq);
+
+	return 0;
+}
+
+/**
+ * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
+ * @kvm:     The VM structure pointer
+ * @cpuid:   The CPU for PPIs
+ * @intid:   The INTID to inject a new state to.
+ * @level:   Edge-triggered:  true:  to trigger the interrupt
+ *			      false: to ignore the call
+ *	     Level-sensitive  true:  raise the input signal
+ *			      false: lower the input signal
+ *
+ * The VGIC is not concerned with devices being active-LOW or active-HIGH for
+ * level-sensitive interrupts.  You can think of the level parameter as 1
+ * being HIGH and 0 being LOW and all devices being active-HIGH.
+ */
+int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+			bool level)
+{
+	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 61b8d22..c625767 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -18,5 +18,6 @@
 
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
+bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
 
 #endif
-- 
2.7.3

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

* [PATCH v3 15/55] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

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

Provide a vgic_queue_irq() function which decides whether a given
IRQ needs to be queued to a VCPU's ap_list.
This should be called whenever an IRQ becomes pending or enabled,
either as a result of userspace injection, from in-kernel emulated
devices like the architected timer or from MMIO accesses to the
distributor emulation.
Also provides the necessary functions to allow userland to inject an
IRQ to a guest.
Since this is the first code that starts using our locking mechanism, we
add some (hopefully) clear documentation of our locking strategy and
requirements along with this patch.

[Andre: refactor out vgic_queue_irq_unlock()]

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- add spinlock checks protected by CONFIG_DEBUG_SPINLOCK
- add more comments to vgic_target_oracle
- remove BUG_ON() if IRQ is neither edge or level
- rename vgic_queue_irq() to vgic_queue_irq_unlock()
- simplify initial check in vgic_queue_irq_unlock()
- extend retry loop to ask the oracle again
- minor comment fixes

Changelog v1 .. v2:
- move most IRQ injection code into vgic_update_irq_pending()

 include/kvm/vgic/vgic.h  |   3 +
 virt/kvm/arm/vgic/vgic.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h |   1 +
 3 files changed, 213 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 39933ee..2bfb42c 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -181,6 +181,9 @@ struct vgic_cpu {
 	u64 live_lrs;
 };
 
+int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+			bool level);
+
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	(false)
 #define vgic_ready(k)		((k)->arch.vgic.ready)
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index fb45537..92b78a0 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -19,8 +19,31 @@
 
 #include "vgic.h"
 
+#define CREATE_TRACE_POINTS
+#include "../trace.h"
+
+#ifdef CONFIG_DEBUG_SPINLOCK
+#define DEBUG_SPINLOCK_BUG_ON(p) BUG_ON(p)
+#else
+#define DEBUG_SPINLOCK_BUG_ON(p)
+#endif
+
 struct vgic_global __section(.hyp.text) kvm_vgic_global_state;
 
+/*
+ * Locking order is always:
+ *   vgic_cpu->ap_list_lock
+ *     vgic_irq->irq_lock
+ *
+ * (that is, always take the ap_list_lock before the struct vgic_irq lock).
+ *
+ * When taking more than one ap_list_lock at the same time, always take the
+ * lowest numbered VCPU's ap_list_lock first, so:
+ *   vcpuX->vcpu_id < vcpuY->vcpu_id:
+ *     spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
+ *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
+ */
+
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid)
 {
@@ -39,3 +62,189 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 	WARN(1, "Looking up struct vgic_irq for reserved INTID");
 	return NULL;
 }
+
+/**
+ * kvm_vgic_target_oracle - compute the target vcpu for an irq
+ *
+ * @irq:	The irq to route. Must be already locked.
+ *
+ * Based on the current state of the interrupt (enabled, pending,
+ * active, vcpu and target_vcpu), compute the next vcpu this should be
+ * given to. Return NULL if this shouldn't be injected at all.
+ *
+ * Requires the IRQ lock to be held.
+ */
+static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
+{
+	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
+
+	/* If the interrupt is active, it must stay on the current vcpu */
+	if (irq->active)
+		return irq->vcpu;
+
+	/*
+	 * If the IRQ is not active but enabled and pending, we should direct
+	 * it to its configured target VCPU.
+	 */
+	if (irq->enabled && irq->pending)
+		return irq->target_vcpu;
+
+	/* If neither active nor pending and enabled, then this IRQ should not
+	 * be queued to any VCPU.
+	 */
+	return NULL;
+}
+
+/*
+ * Only valid injection if changing level for level-triggered IRQs or for a
+ * rising edge.
+ */
+static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
+{
+	switch (irq->config) {
+	case VGIC_CONFIG_LEVEL:
+		return irq->line_level != level;
+	case VGIC_CONFIG_EDGE:
+		return level;
+	}
+
+	return false;
+}
+
+/*
+ * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
+ * Do the queuing if necessary, taking the right locks in the right order.
+ * Returns true when the IRQ was queued, false otherwise.
+ *
+ * Needs to be entered with the IRQ lock already held, but will return
+ * with all locks dropped.
+ */
+bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq)
+{
+	struct kvm_vcpu *vcpu;
+
+	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
+
+retry:
+	vcpu = vgic_target_oracle(irq);
+	if (irq->vcpu || !vcpu) {
+		/*
+		 * If this IRQ is already on a VCPU's ap_list, then it
+		 * cannot be moved or modified and there is no more work for
+		 * us to do.
+		 *
+		 * Otherwise, if the irq is not pending and enabled, it does
+		 * not need to be inserted into an ap_list and there is also
+		 * no more work for us to do.
+		 */
+		spin_unlock(&irq->irq_lock);
+		return false;
+	}
+
+	/*
+	 * We must unlock the irq lock to take the ap_list_lock where
+	 * we are going to insert this new pending interrupt.
+	 */
+	spin_unlock(&irq->irq_lock);
+
+	/* someone can do stuff here, which we re-check below */
+
+	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
+	spin_lock(&irq->irq_lock);
+
+	/*
+	 * Did something change behind our backs?
+	 *
+	 * There are two cases:
+	 * 1) The irq became pending or active behind our backs and/or
+	 *    the irq->vcpu field was set correspondingly when putting
+	 *    the irq on an ap_list. Then drop the locks and return.
+	 * 2) Someone changed the affinity on this irq behind our
+	 *    backs and we are now holding the wrong ap_list_lock.
+	 *    Then drop the locks and try the new VCPU.
+	 */
+	if (irq->vcpu || !(irq->pending && irq->enabled)) {
+		spin_unlock(&irq->irq_lock);
+		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+		return false;
+	}
+
+	if (irq->target_vcpu != vcpu) {
+		spin_unlock(&irq->irq_lock);
+		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+		spin_lock(&irq->irq_lock);
+		goto retry;
+	}
+
+	list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
+	irq->vcpu = vcpu;
+
+	spin_unlock(&irq->irq_lock);
+	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+	kvm_vcpu_kick(vcpu);
+
+	return true;
+}
+
+static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
+				   unsigned int intid, bool level,
+				   bool mapped_irq)
+{
+	struct kvm_vcpu *vcpu;
+	struct vgic_irq *irq;
+	int ret;
+
+	trace_vgic_update_irq_pending(cpuid, intid, level);
+
+	vcpu = kvm_get_vcpu(kvm, cpuid);
+	if (!vcpu && intid < VGIC_NR_PRIVATE_IRQS)
+		return -EINVAL;
+
+	irq = vgic_get_irq(kvm, vcpu, intid);
+	if (!irq)
+		return -EINVAL;
+
+	if (irq->hw != mapped_irq)
+		return -EINVAL;
+
+	spin_lock(&irq->irq_lock);
+
+	if (!vgic_validate_injection(irq, level)) {
+		/* Nothing to see here, move along... */
+		spin_unlock(&irq->irq_lock);
+		return 0;
+	}
+
+	if (irq->config == VGIC_CONFIG_LEVEL) {
+		irq->line_level = level;
+		irq->pending = level || irq->soft_pending;
+	} else {
+		irq->pending = true;
+	}
+
+	vgic_queue_irq_unlock(kvm, irq);
+
+	return 0;
+}
+
+/**
+ * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
+ * @kvm:     The VM structure pointer
+ * @cpuid:   The CPU for PPIs
+ * @intid:   The INTID to inject a new state to.
+ * @level:   Edge-triggered:  true:  to trigger the interrupt
+ *			      false: to ignore the call
+ *	     Level-sensitive  true:  raise the input signal
+ *			      false: lower the input signal
+ *
+ * The VGIC is not concerned with devices being active-LOW or active-HIGH for
+ * level-sensitive interrupts.  You can think of the level parameter as 1
+ * being HIGH and 0 being LOW and all devices being active-HIGH.
+ */
+int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+			bool level)
+{
+	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 61b8d22..c625767 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -18,5 +18,6 @@
 
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
+bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
 
 #endif
-- 
2.7.3

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

* [PATCH v3 16/55] KVM: arm/arm64: vgic-new: Add IRQ sorting
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

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

Adds the sorting function to cover the case where you have more IRQs
to consider than you have LRs. We now consider priorities.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 92b78a0..4fb20fd 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -16,6 +16,7 @@
 
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
+#include <linux/list_sort.h>
 
 #include "vgic.h"
 
@@ -96,6 +97,62 @@ static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
 }
 
 /*
+ * The order of items in the ap_lists defines how we'll pack things in LRs as
+ * well, the first items in the list being the first things populated in the
+ * LRs.
+ *
+ * A hard rule is that active interrupts can never be pushed out of the LRs
+ * (and therefore take priority) since we cannot reliably trap on deactivation
+ * of IRQs and therefore they have to be present in the LRs.
+ *
+ * Otherwise things should be sorted by the priority field and the GIC
+ * hardware support will take care of preemption of priority groups etc.
+ *
+ * Return negative if "a" sorts before "b", 0 to preserve order, and positive
+ * to sort "b" before "a".
+ */
+static int vgic_irq_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+	struct vgic_irq *irqa = container_of(a, struct vgic_irq, ap_list);
+	struct vgic_irq *irqb = container_of(b, struct vgic_irq, ap_list);
+	bool penda, pendb;
+	int ret;
+
+	spin_lock(&irqa->irq_lock);
+	spin_lock(&irqb->irq_lock);
+
+	if (irqa->active || irqb->active) {
+		ret = (int)irqb->active - (int)irqa->active;
+		goto out;
+	}
+
+	penda = irqa->enabled && irqa->pending;
+	pendb = irqb->enabled && irqb->pending;
+
+	if (!penda || !pendb) {
+		ret = (int)pendb - (int)penda;
+		goto out;
+	}
+
+	/* Both pending and enabled, sort by priority */
+	ret = irqa->priority - irqb->priority;
+out:
+	spin_unlock(&irqb->irq_lock);
+	spin_unlock(&irqa->irq_lock);
+	return ret;
+}
+
+/* Must be called with the ap_list_lock held */
+static void vgic_sort_ap_list(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+
+	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
+
+	list_sort(NULL, &vgic_cpu->ap_list_head, vgic_irq_cmp);
+}
+
+/*
  * Only valid injection if changing level for level-triggered IRQs or for a
  * rising edge.
  */
-- 
2.7.3

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

* [PATCH v3 16/55] KVM: arm/arm64: vgic-new: Add IRQ sorting
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

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

Adds the sorting function to cover the case where you have more IRQs
to consider than you have LRs. We now consider priorities.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 92b78a0..4fb20fd 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -16,6 +16,7 @@
 
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
+#include <linux/list_sort.h>
 
 #include "vgic.h"
 
@@ -96,6 +97,62 @@ static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
 }
 
 /*
+ * The order of items in the ap_lists defines how we'll pack things in LRs as
+ * well, the first items in the list being the first things populated in the
+ * LRs.
+ *
+ * A hard rule is that active interrupts can never be pushed out of the LRs
+ * (and therefore take priority) since we cannot reliably trap on deactivation
+ * of IRQs and therefore they have to be present in the LRs.
+ *
+ * Otherwise things should be sorted by the priority field and the GIC
+ * hardware support will take care of preemption of priority groups etc.
+ *
+ * Return negative if "a" sorts before "b", 0 to preserve order, and positive
+ * to sort "b" before "a".
+ */
+static int vgic_irq_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+	struct vgic_irq *irqa = container_of(a, struct vgic_irq, ap_list);
+	struct vgic_irq *irqb = container_of(b, struct vgic_irq, ap_list);
+	bool penda, pendb;
+	int ret;
+
+	spin_lock(&irqa->irq_lock);
+	spin_lock(&irqb->irq_lock);
+
+	if (irqa->active || irqb->active) {
+		ret = (int)irqb->active - (int)irqa->active;
+		goto out;
+	}
+
+	penda = irqa->enabled && irqa->pending;
+	pendb = irqb->enabled && irqb->pending;
+
+	if (!penda || !pendb) {
+		ret = (int)pendb - (int)penda;
+		goto out;
+	}
+
+	/* Both pending and enabled, sort by priority */
+	ret = irqa->priority - irqb->priority;
+out:
+	spin_unlock(&irqb->irq_lock);
+	spin_unlock(&irqa->irq_lock);
+	return ret;
+}
+
+/* Must be called with the ap_list_lock held */
+static void vgic_sort_ap_list(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+
+	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
+
+	list_sort(NULL, &vgic_cpu->ap_list_head, vgic_irq_cmp);
+}
+
+/*
  * Only valid injection if changing level for level-triggered IRQs or for a
  * rising edge.
  */
-- 
2.7.3

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

* [PATCH v3 17/55] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

From: Marc Zyngier <marc.zyngier@arm.com>

Implement the framework for syncing IRQs between our emulation and
the list registers, which represent the guest's view of IRQs.
This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
which gets called on guest entry and exit.
The code talking to the actual GICv2/v3 hardware is added in the
following patches.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- split out vgic_clear_lr() from vgic_populate_lr()
- rename vgic_populate_lrs() to vgic_flush_lr_state()
- clean all LRs when the distributor is disabled
- use list_del() instead of list_del_init()
- add comments to explain the direction of sync/flush_hwstate
- remove unneeded BUG_ON(in_interrupt()

Changelog v2 .. v3:
- remove bogus v2 specific rebase leftovers

 include/kvm/vgic/vgic.h  |   4 +
 virt/kvm/arm/vgic/vgic.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h |   2 +
 3 files changed, 199 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 2bfb42c..5fae4a9 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -190,6 +190,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
 			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
 
+bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
+void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
+void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
+
 /**
  * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
  *
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 4fb20fd..c6f8b9b 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -305,3 +305,196 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 {
 	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
 }
+
+/**
+ * vgic_prune_ap_list - Remove non-relevant interrupts from the list
+ *
+ * @vcpu: The VCPU pointer
+ *
+ * Go over the list of "interesting" interrupts, and prune those that we
+ * won't have to consider in the near future.
+ */
+static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	struct vgic_irq *irq, *tmp;
+
+retry:
+	spin_lock(&vgic_cpu->ap_list_lock);
+
+	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
+		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
+
+		spin_lock(&irq->irq_lock);
+
+		BUG_ON(vcpu != irq->vcpu);
+
+		target_vcpu = vgic_target_oracle(irq);
+
+		if (!target_vcpu) {
+			/*
+			 * We don't need to process this interrupt any
+			 * further, move it off the list.
+			 */
+			list_del(&irq->ap_list);
+			irq->vcpu = NULL;
+			spin_unlock(&irq->irq_lock);
+			continue;
+		}
+
+		if (target_vcpu == vcpu) {
+			/* We're on the right CPU */
+			spin_unlock(&irq->irq_lock);
+			continue;
+		}
+
+		/* This interrupt looks like it has to be migrated. */
+
+		spin_unlock(&irq->irq_lock);
+		spin_unlock(&vgic_cpu->ap_list_lock);
+
+		/*
+		 * Ensure locking order by always locking the smallest
+		 * ID first.
+		 */
+		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
+			vcpuA = vcpu;
+			vcpuB = target_vcpu;
+		} else {
+			vcpuA = target_vcpu;
+			vcpuB = vcpu;
+		}
+
+		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
+		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
+		spin_lock(&irq->irq_lock);
+
+		/*
+		 * If the affinity has been preserved, move the
+		 * interrupt around. Otherwise, it means things have
+		 * changed while the interrupt was unlocked, and we
+		 * need to replay this.
+		 *
+		 * In all cases, we cannot trust the list not to have
+		 * changed, so we restart from the beginning.
+		 */
+		if (target_vcpu == vgic_target_oracle(irq)) {
+			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
+
+			list_del(&irq->ap_list);
+			irq->vcpu = target_vcpu;
+			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
+		}
+
+		spin_unlock(&irq->irq_lock);
+		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
+		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
+		goto retry;
+	}
+
+	spin_unlock(&vgic_cpu->ap_list_lock);
+}
+
+static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
+{
+}
+
+static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
+{
+}
+
+/* Requires the ap_list_lock and the irq_lock to be held. */
+static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
+				    struct vgic_irq *irq, int lr)
+{
+	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
+	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
+}
+
+static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
+{
+}
+
+static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
+{
+}
+
+static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	struct vgic_irq *irq;
+	int count = 0;
+
+	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
+		spin_lock(&irq->irq_lock);
+		/* GICv2 SGIs can count for more than one... */
+		if (vgic_irq_is_sgi(irq->intid) && irq->source)
+			count += hweight8(irq->source);
+		else
+			count++;
+		spin_unlock(&irq->irq_lock);
+	}
+	return count;
+}
+
+/* Requires the VCPU's ap_list_lock to be held. */
+static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	struct vgic_irq *irq;
+	int count = 0;
+
+	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
+
+	if (unlikely(!vcpu->kvm->arch.vgic.enabled))
+		goto out_clean;
+
+	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
+		vgic_set_underflow(vcpu);
+		vgic_sort_ap_list(vcpu);
+	}
+
+	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
+		spin_lock(&irq->irq_lock);
+
+		if (unlikely(vgic_target_oracle(irq) != vcpu))
+			goto next;
+
+		/*
+		 * If we get an SGI with multiple sources, try to get
+		 * them in all at once.
+		 */
+		do {
+			vgic_populate_lr(vcpu, irq, count++);
+		} while (irq->source && count < kvm_vgic_global_state.nr_lr);
+
+next:
+		spin_unlock(&irq->irq_lock);
+
+		if (count == kvm_vgic_global_state.nr_lr)
+			break;
+	}
+
+out_clean:
+	vcpu->arch.vgic_cpu.used_lrs = count;
+
+	/* Nuke remaining LRs */
+	for ( ; count < kvm_vgic_global_state.nr_lr; count++)
+		vgic_clear_lr(vcpu, count);
+}
+
+/* Sync back the hardware VGIC state into our emulation after a guest's run. */
+void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
+{
+	vgic_process_maintenance_interrupt(vcpu);
+	vgic_fold_lr_state(vcpu);
+	vgic_prune_ap_list(vcpu);
+}
+
+/* Flush our emulation state into the GIC hardware before entering the guest. */
+void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
+{
+	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
+	vgic_flush_lr_state(vcpu);
+	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index c625767..29b96b9 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -16,6 +16,8 @@
 #ifndef __KVM_ARM_VGIC_NEW_H__
 #define __KVM_ARM_VGIC_NEW_H__
 
+#define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
+
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
 bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
-- 
2.7.3

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

* [PATCH v3 17/55] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

From: Marc Zyngier <marc.zyngier@arm.com>

Implement the framework for syncing IRQs between our emulation and
the list registers, which represent the guest's view of IRQs.
This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
which gets called on guest entry and exit.
The code talking to the actual GICv2/v3 hardware is added in the
following patches.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- split out vgic_clear_lr() from vgic_populate_lr()
- rename vgic_populate_lrs() to vgic_flush_lr_state()
- clean all LRs when the distributor is disabled
- use list_del() instead of list_del_init()
- add comments to explain the direction of sync/flush_hwstate
- remove unneeded BUG_ON(in_interrupt()

Changelog v2 .. v3:
- remove bogus v2 specific rebase leftovers

 include/kvm/vgic/vgic.h  |   4 +
 virt/kvm/arm/vgic/vgic.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h |   2 +
 3 files changed, 199 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 2bfb42c..5fae4a9 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -190,6 +190,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
 			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
 
+bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
+void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
+void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
+
 /**
  * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
  *
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 4fb20fd..c6f8b9b 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -305,3 +305,196 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 {
 	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
 }
+
+/**
+ * vgic_prune_ap_list - Remove non-relevant interrupts from the list
+ *
+ * @vcpu: The VCPU pointer
+ *
+ * Go over the list of "interesting" interrupts, and prune those that we
+ * won't have to consider in the near future.
+ */
+static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	struct vgic_irq *irq, *tmp;
+
+retry:
+	spin_lock(&vgic_cpu->ap_list_lock);
+
+	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
+		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
+
+		spin_lock(&irq->irq_lock);
+
+		BUG_ON(vcpu != irq->vcpu);
+
+		target_vcpu = vgic_target_oracle(irq);
+
+		if (!target_vcpu) {
+			/*
+			 * We don't need to process this interrupt any
+			 * further, move it off the list.
+			 */
+			list_del(&irq->ap_list);
+			irq->vcpu = NULL;
+			spin_unlock(&irq->irq_lock);
+			continue;
+		}
+
+		if (target_vcpu == vcpu) {
+			/* We're on the right CPU */
+			spin_unlock(&irq->irq_lock);
+			continue;
+		}
+
+		/* This interrupt looks like it has to be migrated. */
+
+		spin_unlock(&irq->irq_lock);
+		spin_unlock(&vgic_cpu->ap_list_lock);
+
+		/*
+		 * Ensure locking order by always locking the smallest
+		 * ID first.
+		 */
+		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
+			vcpuA = vcpu;
+			vcpuB = target_vcpu;
+		} else {
+			vcpuA = target_vcpu;
+			vcpuB = vcpu;
+		}
+
+		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
+		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
+		spin_lock(&irq->irq_lock);
+
+		/*
+		 * If the affinity has been preserved, move the
+		 * interrupt around. Otherwise, it means things have
+		 * changed while the interrupt was unlocked, and we
+		 * need to replay this.
+		 *
+		 * In all cases, we cannot trust the list not to have
+		 * changed, so we restart from the beginning.
+		 */
+		if (target_vcpu == vgic_target_oracle(irq)) {
+			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
+
+			list_del(&irq->ap_list);
+			irq->vcpu = target_vcpu;
+			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
+		}
+
+		spin_unlock(&irq->irq_lock);
+		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
+		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
+		goto retry;
+	}
+
+	spin_unlock(&vgic_cpu->ap_list_lock);
+}
+
+static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
+{
+}
+
+static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
+{
+}
+
+/* Requires the ap_list_lock and the irq_lock to be held. */
+static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
+				    struct vgic_irq *irq, int lr)
+{
+	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
+	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
+}
+
+static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
+{
+}
+
+static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
+{
+}
+
+static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	struct vgic_irq *irq;
+	int count = 0;
+
+	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
+		spin_lock(&irq->irq_lock);
+		/* GICv2 SGIs can count for more than one... */
+		if (vgic_irq_is_sgi(irq->intid) && irq->source)
+			count += hweight8(irq->source);
+		else
+			count++;
+		spin_unlock(&irq->irq_lock);
+	}
+	return count;
+}
+
+/* Requires the VCPU's ap_list_lock to be held. */
+static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	struct vgic_irq *irq;
+	int count = 0;
+
+	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
+
+	if (unlikely(!vcpu->kvm->arch.vgic.enabled))
+		goto out_clean;
+
+	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
+		vgic_set_underflow(vcpu);
+		vgic_sort_ap_list(vcpu);
+	}
+
+	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
+		spin_lock(&irq->irq_lock);
+
+		if (unlikely(vgic_target_oracle(irq) != vcpu))
+			goto next;
+
+		/*
+		 * If we get an SGI with multiple sources, try to get
+		 * them in all at once.
+		 */
+		do {
+			vgic_populate_lr(vcpu, irq, count++);
+		} while (irq->source && count < kvm_vgic_global_state.nr_lr);
+
+next:
+		spin_unlock(&irq->irq_lock);
+
+		if (count == kvm_vgic_global_state.nr_lr)
+			break;
+	}
+
+out_clean:
+	vcpu->arch.vgic_cpu.used_lrs = count;
+
+	/* Nuke remaining LRs */
+	for ( ; count < kvm_vgic_global_state.nr_lr; count++)
+		vgic_clear_lr(vcpu, count);
+}
+
+/* Sync back the hardware VGIC state into our emulation after a guest's run. */
+void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
+{
+	vgic_process_maintenance_interrupt(vcpu);
+	vgic_fold_lr_state(vcpu);
+	vgic_prune_ap_list(vcpu);
+}
+
+/* Flush our emulation state into the GIC hardware before entering the guest. */
+void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
+{
+	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
+	vgic_flush_lr_state(vcpu);
+	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index c625767..29b96b9 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -16,6 +16,8 @@
 #ifndef __KVM_ARM_VGIC_NEW_H__
 #define __KVM_ARM_VGIC_NEW_H__
 
+#define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
+
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
 bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
-- 
2.7.3

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

* [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

From: Marc Zyngier <marc.zyngier@arm.com>

Processing maintenance interrupts and accessing the list registers
are dependent on the host's GIC version.
Introduce vgic-v2.c to contain GICv2 specific functions.
Implement the GICv2 specific code for syncing the emulation state
into the VGIC registers.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- remove explicit LR_STATE clearing on maintenance interrupt handling
- improve documentation for vgic_v2_populate_lr()
- remove WARN_ON on non-edge IRQs in maintenance interrupts
- simplify multi-CPU source SGI handling

Changelog v1 .. v2:
- inject the IRQ priority into the list register

Changelog v2 .. v3:
- cleanup diff containing rebase artifacts

 include/linux/irqchip/arm-gic.h |   1 +
 virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.c        |   6 ++
 virt/kvm/arm/vgic/vgic.h        |   6 ++
 4 files changed, 191 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic-v2.c

diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 9c94026..be0d26f 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -76,6 +76,7 @@
 #define GICH_LR_VIRTUALID		(0x3ff << 0)
 #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
 #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
+#define GICH_LR_PRIORITY_SHIFT		23
 #define GICH_LR_STATE			(3 << 28)
 #define GICH_LR_PENDING_BIT		(1 << 28)
 #define GICH_LR_ACTIVE_BIT		(1 << 29)
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
new file mode 100644
index 0000000..4cee616
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/irqchip/arm-gic.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+
+#include "vgic.h"
+
+/*
+ * Call this function to convert a u64 value to an unsigned long * bitmask
+ * in a way that works on both 32-bit and 64-bit LE and BE platforms.
+ *
+ * Warning: Calling this function may modify *val.
+ */
+static unsigned long *u64_to_bitmask(u64 *val)
+{
+#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
+	*val = (*val >> 32) | (*val << 32);
+#endif
+	return (unsigned long *)val;
+}
+
+void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
+
+	if (cpuif->vgic_misr & GICH_MISR_EOI) {
+		u64 eisr = cpuif->vgic_eisr;
+		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
+		int lr;
+
+		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
+			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
+
+			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
+
+			kvm_notify_acked_irq(vcpu->kvm, 0,
+					     intid - VGIC_NR_PRIVATE_IRQS);
+
+			cpuif->vgic_elrsr |= 1ULL << lr;
+		}
+	}
+
+	/* check and disable underflow maintenance IRQ */
+	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
+
+	/*
+	 * In the next iterations of the vcpu loop, if we sync the
+	 * vgic state after flushing it, but before entering the guest
+	 * (this happens for pending signals and vmid rollovers), then
+	 * make sure we don't pick up any old maintenance interrupts
+	 * here.
+	 */
+	cpuif->vgic_eisr = 0;
+}
+
+void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
+
+	cpuif->vgic_hcr |= GICH_HCR_UIE;
+}
+
+/*
+ * transfer the content of the LRs back into the corresponding ap_list:
+ * - active bit is transferred as is
+ * - pending bit is
+ *   - transferred as is in case of edge sensitive IRQs
+ *   - set to the line-level (resample time) for level sensitive IRQs
+ */
+void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
+	int lr;
+
+	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
+		u32 val = cpuif->vgic_lr[lr];
+		u32 intid = val & GICH_LR_VIRTUALID;
+		struct vgic_irq *irq;
+
+		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
+
+		spin_lock(&irq->irq_lock);
+
+		/* Always preserve the active bit */
+		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
+
+		/* Edge is the only case where we preserve the pending bit */
+		if (irq->config == VGIC_CONFIG_EDGE &&
+		    (val & GICH_LR_PENDING_BIT)) {
+			irq->pending = true;
+
+			if (vgic_irq_is_sgi(intid)) {
+				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
+
+				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
+				irq->source |= (1 << cpuid);
+			}
+		}
+
+		/* Clear soft pending state when level IRQs have been acked */
+		if (irq->config == VGIC_CONFIG_LEVEL &&
+		    !(val & GICH_LR_PENDING_BIT)) {
+			irq->soft_pending = false;
+			irq->pending = irq->line_level;
+		}
+
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
+/*
+ * Populates the particular LR with the state of a given IRQ:
+ * - for an edge sensitive IRQ the pending state is cleared in struct vgic_irq
+ * - for a level sensitive IRQ the pending state value is unchanged;
+ *   it is dictated directly by the input level
+ *
+ * If @irq describes an SGI with multiple sources, we choose the
+ * lowest-numbered source VCPU and clear that bit in the source bitmap.
+ *
+ * The irq_lock must be held by the caller.
+ */
+void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
+{
+	u32 val = irq->intid;
+
+	if (irq->pending) {
+		val |= GICH_LR_PENDING_BIT;
+
+		if (irq->config == VGIC_CONFIG_EDGE)
+			irq->pending = false;
+
+		if (vgic_irq_is_sgi(irq->intid)) {
+			u32 src = ffs(irq->source);
+
+			BUG_ON(!src);
+			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
+			irq->source &= ~(1 << (src - 1));
+			if (irq->source)
+				irq->pending = true;
+		}
+	}
+
+	if (irq->active)
+		val |= GICH_LR_ACTIVE_BIT;
+
+	if (irq->hw) {
+		val |= GICH_LR_HW;
+		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
+	} else {
+		if (irq->config == VGIC_CONFIG_LEVEL)
+			val |= GICH_LR_EOI;
+	}
+
+	/* The GICv2 LR only holds five bits of priority. */
+	val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
+
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
+}
+
+void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
+{
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
+}
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index c6f8b9b..68d885c 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -397,10 +397,12 @@ retry:
 
 static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
 {
+	vgic_v2_process_maintenance(vcpu);
 }
 
 static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
 {
+	vgic_v2_fold_lr_state(vcpu);
 }
 
 /* Requires the ap_list_lock and the irq_lock to be held. */
@@ -409,14 +411,18 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
 {
 	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
 	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
+
+	vgic_v2_populate_lr(vcpu, irq, lr);
 }
 
 static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
 {
+	vgic_v2_clear_lr(vcpu, lr);
 }
 
 static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
 {
+	vgic_v2_set_underflow(vcpu);
 }
 
 static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 29b96b9..0db490e 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -22,4 +22,10 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
 bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
 
+void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
+void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
+void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
+void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
+void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
+
 #endif
-- 
2.7.3


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

* [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

From: Marc Zyngier <marc.zyngier@arm.com>

Processing maintenance interrupts and accessing the list registers
are dependent on the host's GIC version.
Introduce vgic-v2.c to contain GICv2 specific functions.
Implement the GICv2 specific code for syncing the emulation state
into the VGIC registers.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- remove explicit LR_STATE clearing on maintenance interrupt handling
- improve documentation for vgic_v2_populate_lr()
- remove WARN_ON on non-edge IRQs in maintenance interrupts
- simplify multi-CPU source SGI handling

Changelog v1 .. v2:
- inject the IRQ priority into the list register

Changelog v2 .. v3:
- cleanup diff containing rebase artifacts

 include/linux/irqchip/arm-gic.h |   1 +
 virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.c        |   6 ++
 virt/kvm/arm/vgic/vgic.h        |   6 ++
 4 files changed, 191 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic-v2.c

diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 9c94026..be0d26f 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -76,6 +76,7 @@
 #define GICH_LR_VIRTUALID		(0x3ff << 0)
 #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
 #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
+#define GICH_LR_PRIORITY_SHIFT		23
 #define GICH_LR_STATE			(3 << 28)
 #define GICH_LR_PENDING_BIT		(1 << 28)
 #define GICH_LR_ACTIVE_BIT		(1 << 29)
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
new file mode 100644
index 0000000..4cee616
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/irqchip/arm-gic.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+
+#include "vgic.h"
+
+/*
+ * Call this function to convert a u64 value to an unsigned long * bitmask
+ * in a way that works on both 32-bit and 64-bit LE and BE platforms.
+ *
+ * Warning: Calling this function may modify *val.
+ */
+static unsigned long *u64_to_bitmask(u64 *val)
+{
+#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
+	*val = (*val >> 32) | (*val << 32);
+#endif
+	return (unsigned long *)val;
+}
+
+void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
+
+	if (cpuif->vgic_misr & GICH_MISR_EOI) {
+		u64 eisr = cpuif->vgic_eisr;
+		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
+		int lr;
+
+		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
+			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
+
+			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
+
+			kvm_notify_acked_irq(vcpu->kvm, 0,
+					     intid - VGIC_NR_PRIVATE_IRQS);
+
+			cpuif->vgic_elrsr |= 1ULL << lr;
+		}
+	}
+
+	/* check and disable underflow maintenance IRQ */
+	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
+
+	/*
+	 * In the next iterations of the vcpu loop, if we sync the
+	 * vgic state after flushing it, but before entering the guest
+	 * (this happens for pending signals and vmid rollovers), then
+	 * make sure we don't pick up any old maintenance interrupts
+	 * here.
+	 */
+	cpuif->vgic_eisr = 0;
+}
+
+void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
+
+	cpuif->vgic_hcr |= GICH_HCR_UIE;
+}
+
+/*
+ * transfer the content of the LRs back into the corresponding ap_list:
+ * - active bit is transferred as is
+ * - pending bit is
+ *   - transferred as is in case of edge sensitive IRQs
+ *   - set to the line-level (resample time) for level sensitive IRQs
+ */
+void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
+	int lr;
+
+	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
+		u32 val = cpuif->vgic_lr[lr];
+		u32 intid = val & GICH_LR_VIRTUALID;
+		struct vgic_irq *irq;
+
+		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
+
+		spin_lock(&irq->irq_lock);
+
+		/* Always preserve the active bit */
+		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
+
+		/* Edge is the only case where we preserve the pending bit */
+		if (irq->config == VGIC_CONFIG_EDGE &&
+		    (val & GICH_LR_PENDING_BIT)) {
+			irq->pending = true;
+
+			if (vgic_irq_is_sgi(intid)) {
+				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
+
+				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
+				irq->source |= (1 << cpuid);
+			}
+		}
+
+		/* Clear soft pending state when level IRQs have been acked */
+		if (irq->config == VGIC_CONFIG_LEVEL &&
+		    !(val & GICH_LR_PENDING_BIT)) {
+			irq->soft_pending = false;
+			irq->pending = irq->line_level;
+		}
+
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
+/*
+ * Populates the particular LR with the state of a given IRQ:
+ * - for an edge sensitive IRQ the pending state is cleared in struct vgic_irq
+ * - for a level sensitive IRQ the pending state value is unchanged;
+ *   it is dictated directly by the input level
+ *
+ * If @irq describes an SGI with multiple sources, we choose the
+ * lowest-numbered source VCPU and clear that bit in the source bitmap.
+ *
+ * The irq_lock must be held by the caller.
+ */
+void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
+{
+	u32 val = irq->intid;
+
+	if (irq->pending) {
+		val |= GICH_LR_PENDING_BIT;
+
+		if (irq->config == VGIC_CONFIG_EDGE)
+			irq->pending = false;
+
+		if (vgic_irq_is_sgi(irq->intid)) {
+			u32 src = ffs(irq->source);
+
+			BUG_ON(!src);
+			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
+			irq->source &= ~(1 << (src - 1));
+			if (irq->source)
+				irq->pending = true;
+		}
+	}
+
+	if (irq->active)
+		val |= GICH_LR_ACTIVE_BIT;
+
+	if (irq->hw) {
+		val |= GICH_LR_HW;
+		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
+	} else {
+		if (irq->config == VGIC_CONFIG_LEVEL)
+			val |= GICH_LR_EOI;
+	}
+
+	/* The GICv2 LR only holds five bits of priority. */
+	val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
+
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
+}
+
+void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
+{
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
+}
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index c6f8b9b..68d885c 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -397,10 +397,12 @@ retry:
 
 static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
 {
+	vgic_v2_process_maintenance(vcpu);
 }
 
 static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
 {
+	vgic_v2_fold_lr_state(vcpu);
 }
 
 /* Requires the ap_list_lock and the irq_lock to be held. */
@@ -409,14 +411,18 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
 {
 	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
 	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
+
+	vgic_v2_populate_lr(vcpu, irq, lr);
 }
 
 static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
 {
+	vgic_v2_clear_lr(vcpu, lr);
 }
 
 static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
 {
+	vgic_v2_set_underflow(vcpu);
 }
 
 static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 29b96b9..0db490e 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -22,4 +22,10 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
 bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
 
+void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
+void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
+void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
+void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
+void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
+
 #endif
-- 
2.7.3

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

* [PATCH v3 19/55] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

From: Marc Zyngier <marc.zyngier@arm.com>

As the GICv3 virtual interface registers differ from their GICv2
siblings, we need different handlers for processing maintenance
interrupts and reading/writing to the LRs.
Implement the respective handler functions and connect them to
existing code to be called if the host is using a GICv3.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- remove outdated comment about the dist_lock
- add WARN_ON about LR_STATE not being 0 in maintenance interrupts

Changelog v1 .. v2:
- inject the IRQ priority into the list register

Changelog v2 .. v3:
- remove no longer needed irqchip/arm-gic.h inclusion

 include/linux/irqchip/arm-gic-v3.h |   1 +
 virt/kvm/arm/vgic/vgic-v3.c        | 168 +++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.c           |  25 ++++--
 virt/kvm/arm/vgic/vgic.h           |  29 +++++++
 4 files changed, 218 insertions(+), 5 deletions(-)
 create mode 100644 virt/kvm/arm/vgic/vgic-v3.c

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index ec938d1..35e93cf 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -275,6 +275,7 @@
 #define ICH_LR_ACTIVE_BIT		(1ULL << 63)
 #define ICH_LR_PHYS_ID_SHIFT		32
 #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
+#define ICH_LR_PRIORITY_SHIFT		48
 
 /* These are for GICv2 emulation only */
 #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
new file mode 100644
index 0000000..43d1dd7
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -0,0 +1,168 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/irqchip/arm-gic-v3.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+
+#include "vgic.h"
+
+void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
+	u32 model = vcpu->kvm->arch.vgic.vgic_model;
+
+	if (cpuif->vgic_misr & ICH_MISR_EOI) {
+		unsigned long eisr_bmap = cpuif->vgic_eisr;
+		int lr;
+
+		for_each_set_bit(lr, &eisr_bmap, kvm_vgic_global_state.nr_lr) {
+			u32 intid;
+			u64 val = cpuif->vgic_lr[lr];
+
+			if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
+				intid = val & ICH_LR_VIRTUAL_ID_MASK;
+			else
+				intid = val & GICH_LR_VIRTUALID;
+
+			WARN_ON(cpuif->vgic_lr[lr] & ICH_LR_STATE);
+
+			kvm_notify_acked_irq(vcpu->kvm, 0,
+					     intid - VGIC_NR_PRIVATE_IRQS);
+
+			cpuif->vgic_elrsr |= 1ULL << lr;
+		}
+
+		/*
+		 * In the next iterations of the vcpu loop, if we sync
+		 * the vgic state after flushing it, but before
+		 * entering the guest (this happens for pending
+		 * signals and vmid rollovers), then make sure we
+		 * don't pick up any old maintenance interrupts here.
+		 */
+		cpuif->vgic_eisr = 0;
+	}
+
+	cpuif->vgic_hcr &= ~ICH_HCR_UIE;
+}
+
+void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	cpuif->vgic_hcr |= ICH_HCR_UIE;
+}
+
+void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
+	u32 model = vcpu->kvm->arch.vgic.vgic_model;
+	int lr;
+
+	/* Assumes ap_list_lock held */
+
+	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
+		u64 val = cpuif->vgic_lr[lr];
+		u32 intid;
+		struct vgic_irq *irq;
+
+		if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
+			intid = val & ICH_LR_VIRTUAL_ID_MASK;
+		else
+			intid = val & GICH_LR_VIRTUALID;
+		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
+
+		spin_lock(&irq->irq_lock);
+
+		/* Always preserve the active bit */
+		irq->active = !!(val & ICH_LR_ACTIVE_BIT);
+
+		/* Edge is the only case where we preserve the pending bit */
+		if (irq->config == VGIC_CONFIG_EDGE &&
+		    (val & ICH_LR_PENDING_BIT)) {
+			irq->pending = true;
+
+			if (vgic_irq_is_sgi(intid) &&
+			    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
+				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
+
+				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
+				irq->source |= (1 << cpuid);
+			}
+		}
+
+		/* Clear soft pending state when level irqs have been acked */
+		if (irq->config == VGIC_CONFIG_LEVEL &&
+		    !(val & ICH_LR_PENDING_BIT)) {
+			irq->soft_pending = false;
+			irq->pending = irq->line_level;
+		}
+
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
+/* Requires the irq to be locked already */
+void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
+{
+	u32 model = vcpu->kvm->arch.vgic.vgic_model;
+	u64 val = irq->intid;
+
+	if (irq->pending) {
+		val |= ICH_LR_PENDING_BIT;
+
+		if (irq->config == VGIC_CONFIG_EDGE)
+			irq->pending = false;
+
+		if (vgic_irq_is_sgi(irq->intid) &&
+		    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
+			u32 src = ffs(irq->source);
+
+			BUG_ON(!src);
+			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
+			irq->source &= ~(1 << (src - 1));
+			if (irq->source)
+				irq->pending = true;
+		}
+	}
+
+	if (irq->active)
+		val |= ICH_LR_ACTIVE_BIT;
+
+	if (irq->hw) {
+		val |= ICH_LR_HW;
+		val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
+	} else {
+		if (irq->config == VGIC_CONFIG_LEVEL)
+			val |= ICH_LR_EOI;
+	}
+
+	/*
+	 * Currently all guest IRQs are Group1, as Group0 would result
+	 * in a FIQ in the guest, which it wouldn't expect.
+	 * Eventually we want to make this configurable, so we may
+	 * revisit this in the future.
+	 */
+	if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
+		val |= ICH_LR_GROUP;
+
+	val |= (u64)irq->priority << ICH_LR_PRIORITY_SHIFT;
+
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = val;
+}
+
+void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
+{
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = 0;
+}
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 68d885c..64d5b45 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -397,12 +397,18 @@ retry:
 
 static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
 {
-	vgic_v2_process_maintenance(vcpu);
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_process_maintenance(vcpu);
+	else
+		vgic_v3_process_maintenance(vcpu);
 }
 
 static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
 {
-	vgic_v2_fold_lr_state(vcpu);
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_fold_lr_state(vcpu);
+	else
+		vgic_v3_fold_lr_state(vcpu);
 }
 
 /* Requires the ap_list_lock and the irq_lock to be held. */
@@ -412,17 +418,26 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
 	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
 	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
 
-	vgic_v2_populate_lr(vcpu, irq, lr);
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_populate_lr(vcpu, irq, lr);
+	else
+		vgic_v3_populate_lr(vcpu, irq, lr);
 }
 
 static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
 {
-	vgic_v2_clear_lr(vcpu, lr);
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_clear_lr(vcpu, lr);
+	else
+		vgic_v3_clear_lr(vcpu, lr);
 }
 
 static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
 {
-	vgic_v2_set_underflow(vcpu);
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_set_underflow(vcpu);
+	else
+		vgic_v3_set_underflow(vcpu);
 }
 
 static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 0db490e..81b1a20 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -28,4 +28,33 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
 
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
+void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
+void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
+void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
+void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
+#else
+static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
+{
+}
+
+static inline void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
+{
+}
+
+static inline void vgic_v3_populate_lr(struct kvm_vcpu *vcpu,
+				       struct vgic_irq *irq, int lr)
+{
+}
+
+static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
+{
+}
+
+static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
+{
+}
+#endif
+
 #endif
-- 
2.7.3

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

* [PATCH v3 19/55] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

From: Marc Zyngier <marc.zyngier@arm.com>

As the GICv3 virtual interface registers differ from their GICv2
siblings, we need different handlers for processing maintenance
interrupts and reading/writing to the LRs.
Implement the respective handler functions and connect them to
existing code to be called if the host is using a GICv3.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- remove outdated comment about the dist_lock
- add WARN_ON about LR_STATE not being 0 in maintenance interrupts

Changelog v1 .. v2:
- inject the IRQ priority into the list register

Changelog v2 .. v3:
- remove no longer needed irqchip/arm-gic.h inclusion

 include/linux/irqchip/arm-gic-v3.h |   1 +
 virt/kvm/arm/vgic/vgic-v3.c        | 168 +++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.c           |  25 ++++--
 virt/kvm/arm/vgic/vgic.h           |  29 +++++++
 4 files changed, 218 insertions(+), 5 deletions(-)
 create mode 100644 virt/kvm/arm/vgic/vgic-v3.c

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index ec938d1..35e93cf 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -275,6 +275,7 @@
 #define ICH_LR_ACTIVE_BIT		(1ULL << 63)
 #define ICH_LR_PHYS_ID_SHIFT		32
 #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
+#define ICH_LR_PRIORITY_SHIFT		48
 
 /* These are for GICv2 emulation only */
 #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
new file mode 100644
index 0000000..43d1dd7
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -0,0 +1,168 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/irqchip/arm-gic-v3.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+
+#include "vgic.h"
+
+void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
+	u32 model = vcpu->kvm->arch.vgic.vgic_model;
+
+	if (cpuif->vgic_misr & ICH_MISR_EOI) {
+		unsigned long eisr_bmap = cpuif->vgic_eisr;
+		int lr;
+
+		for_each_set_bit(lr, &eisr_bmap, kvm_vgic_global_state.nr_lr) {
+			u32 intid;
+			u64 val = cpuif->vgic_lr[lr];
+
+			if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
+				intid = val & ICH_LR_VIRTUAL_ID_MASK;
+			else
+				intid = val & GICH_LR_VIRTUALID;
+
+			WARN_ON(cpuif->vgic_lr[lr] & ICH_LR_STATE);
+
+			kvm_notify_acked_irq(vcpu->kvm, 0,
+					     intid - VGIC_NR_PRIVATE_IRQS);
+
+			cpuif->vgic_elrsr |= 1ULL << lr;
+		}
+
+		/*
+		 * In the next iterations of the vcpu loop, if we sync
+		 * the vgic state after flushing it, but before
+		 * entering the guest (this happens for pending
+		 * signals and vmid rollovers), then make sure we
+		 * don't pick up any old maintenance interrupts here.
+		 */
+		cpuif->vgic_eisr = 0;
+	}
+
+	cpuif->vgic_hcr &= ~ICH_HCR_UIE;
+}
+
+void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	cpuif->vgic_hcr |= ICH_HCR_UIE;
+}
+
+void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
+	u32 model = vcpu->kvm->arch.vgic.vgic_model;
+	int lr;
+
+	/* Assumes ap_list_lock held */
+
+	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
+		u64 val = cpuif->vgic_lr[lr];
+		u32 intid;
+		struct vgic_irq *irq;
+
+		if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
+			intid = val & ICH_LR_VIRTUAL_ID_MASK;
+		else
+			intid = val & GICH_LR_VIRTUALID;
+		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
+
+		spin_lock(&irq->irq_lock);
+
+		/* Always preserve the active bit */
+		irq->active = !!(val & ICH_LR_ACTIVE_BIT);
+
+		/* Edge is the only case where we preserve the pending bit */
+		if (irq->config == VGIC_CONFIG_EDGE &&
+		    (val & ICH_LR_PENDING_BIT)) {
+			irq->pending = true;
+
+			if (vgic_irq_is_sgi(intid) &&
+			    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
+				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
+
+				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
+				irq->source |= (1 << cpuid);
+			}
+		}
+
+		/* Clear soft pending state when level irqs have been acked */
+		if (irq->config == VGIC_CONFIG_LEVEL &&
+		    !(val & ICH_LR_PENDING_BIT)) {
+			irq->soft_pending = false;
+			irq->pending = irq->line_level;
+		}
+
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
+/* Requires the irq to be locked already */
+void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
+{
+	u32 model = vcpu->kvm->arch.vgic.vgic_model;
+	u64 val = irq->intid;
+
+	if (irq->pending) {
+		val |= ICH_LR_PENDING_BIT;
+
+		if (irq->config == VGIC_CONFIG_EDGE)
+			irq->pending = false;
+
+		if (vgic_irq_is_sgi(irq->intid) &&
+		    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
+			u32 src = ffs(irq->source);
+
+			BUG_ON(!src);
+			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
+			irq->source &= ~(1 << (src - 1));
+			if (irq->source)
+				irq->pending = true;
+		}
+	}
+
+	if (irq->active)
+		val |= ICH_LR_ACTIVE_BIT;
+
+	if (irq->hw) {
+		val |= ICH_LR_HW;
+		val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
+	} else {
+		if (irq->config == VGIC_CONFIG_LEVEL)
+			val |= ICH_LR_EOI;
+	}
+
+	/*
+	 * Currently all guest IRQs are Group1, as Group0 would result
+	 * in a FIQ in the guest, which it wouldn't expect.
+	 * Eventually we want to make this configurable, so we may
+	 * revisit this in the future.
+	 */
+	if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
+		val |= ICH_LR_GROUP;
+
+	val |= (u64)irq->priority << ICH_LR_PRIORITY_SHIFT;
+
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = val;
+}
+
+void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
+{
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = 0;
+}
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 68d885c..64d5b45 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -397,12 +397,18 @@ retry:
 
 static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
 {
-	vgic_v2_process_maintenance(vcpu);
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_process_maintenance(vcpu);
+	else
+		vgic_v3_process_maintenance(vcpu);
 }
 
 static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
 {
-	vgic_v2_fold_lr_state(vcpu);
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_fold_lr_state(vcpu);
+	else
+		vgic_v3_fold_lr_state(vcpu);
 }
 
 /* Requires the ap_list_lock and the irq_lock to be held. */
@@ -412,17 +418,26 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
 	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
 	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
 
-	vgic_v2_populate_lr(vcpu, irq, lr);
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_populate_lr(vcpu, irq, lr);
+	else
+		vgic_v3_populate_lr(vcpu, irq, lr);
 }
 
 static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
 {
-	vgic_v2_clear_lr(vcpu, lr);
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_clear_lr(vcpu, lr);
+	else
+		vgic_v3_clear_lr(vcpu, lr);
 }
 
 static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
 {
-	vgic_v2_set_underflow(vcpu);
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_set_underflow(vcpu);
+	else
+		vgic_v3_set_underflow(vcpu);
 }
 
 static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 0db490e..81b1a20 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -28,4 +28,33 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
 
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
+void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
+void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
+void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
+void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
+#else
+static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
+{
+}
+
+static inline void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
+{
+}
+
+static inline void vgic_v3_populate_lr(struct kvm_vcpu *vcpu,
+				       struct vgic_irq *irq, int lr)
+{
+}
+
+static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
+{
+}
+
+static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
+{
+}
+#endif
+
 #endif
-- 
2.7.3

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

* [PATCH v3 20/55] KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

Tell KVM whether a particular VCPU has an IRQ that needs handling
in the guest. This is used to decide whether a VCPU is runnable.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- return false if distributor is disabled
- add vgic_kick_vcpus() implementations

Changelog v2 .. v3:
- remove vgic_kick_vcpus() implementation from this patch

 include/kvm/vgic/vgic.h  |  2 ++
 virt/kvm/arm/vgic/vgic.c | 25 +++++++++++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 5fae4a9..2615205 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -184,6 +184,8 @@ struct vgic_cpu {
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level);
 
+int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
+
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	(false)
 #define vgic_ready(k)		((k)->arch.vgic.ready)
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 64d5b45..c3dbcf3 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -519,3 +519,28 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 	vgic_flush_lr_state(vcpu);
 	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
 }
+
+int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	struct vgic_irq *irq;
+	bool pending = false;
+
+	if (!vcpu->kvm->arch.vgic.enabled)
+		return false;
+
+	spin_lock(&vgic_cpu->ap_list_lock);
+
+	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
+		spin_lock(&irq->irq_lock);
+		pending = irq->pending && irq->enabled;
+		spin_unlock(&irq->irq_lock);
+
+		if (pending)
+			break;
+	}
+
+	spin_unlock(&vgic_cpu->ap_list_lock);
+
+	return pending;
+}
-- 
2.7.3

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

* [PATCH v3 20/55] KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

Tell KVM whether a particular VCPU has an IRQ that needs handling
in the guest. This is used to decide whether a VCPU is runnable.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- return false if distributor is disabled
- add vgic_kick_vcpus() implementations

Changelog v2 .. v3:
- remove vgic_kick_vcpus() implementation from this patch

 include/kvm/vgic/vgic.h  |  2 ++
 virt/kvm/arm/vgic/vgic.c | 25 +++++++++++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 5fae4a9..2615205 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -184,6 +184,8 @@ struct vgic_cpu {
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level);
 
+int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
+
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	(false)
 #define vgic_ready(k)		((k)->arch.vgic.ready)
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 64d5b45..c3dbcf3 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -519,3 +519,28 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 	vgic_flush_lr_state(vcpu);
 	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
 }
+
+int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	struct vgic_irq *irq;
+	bool pending = false;
+
+	if (!vcpu->kvm->arch.vgic.enabled)
+		return false;
+
+	spin_lock(&vgic_cpu->ap_list_lock);
+
+	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
+		spin_lock(&irq->irq_lock);
+		pending = irq->pending && irq->enabled;
+		spin_unlock(&irq->irq_lock);
+
+		if (pending)
+			break;
+	}
+
+	spin_unlock(&vgic_cpu->ap_list_lock);
+
+	return pending;
+}
-- 
2.7.3

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

* [PATCH v3 21/55] KVM: arm/arm64: vgic-new: Add MMIO handling framework
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

From: Marc Zyngier <marc.zyngier@arm.com>

Add an MMIO handling framework to the VGIC emulation:
Each register is described by its offset, size (or number of bits per
IRQ, if applicable) and the read/write handler functions. We provide
initialization macros to describe each GIC register later easily.

Separate dispatch functions for read and write accesses are connected
to the kvm_io_bus framework and binary-search for the responsible
register handler based on the offset address within the region.
We convert the incoming data (referenced by a pointer) to the host's
endianess and use pass-by-value to hand the data over to the actual
handler functions.

The register handler prototype and the endianess conversion are
courtesy of Christoffer Dall.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- rework MMIO dispatching to use only one kvm_io_bus device
- document purpose of register region macros
- rename "this" parameter to "dev"
- change IGROUPR to be RAO (returning 1 => Group1 IRQs)

Changelog v1 .. v2:
* MASSIVE rework:
- store register_region pointer in kvm_io_bus linked struct
- replace write_mask_xxx functions with extract_bytes() implementation
- change handler functions' prototypes to take and return unsigned long
- use binary search to find matching register handler
- convert endianess of input data in dispatch_mmio_xxx functions
- improve readability of register initializer macros
- remove any GICv2/GICv3 specific functions from vgic-mmio.c
- rename file from vgic_mmio.c to vgic-mmio.c

Changelog v2 .. v3:
- replace inclusion of vgic/vgic.h with arm_vgic.h

 include/kvm/vgic/vgic.h       |  13 ++++
 virt/kvm/arm/vgic/vgic-mmio.c | 171 ++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.h |  77 +++++++++++++++++++
 3 files changed, 261 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic-mmio.c
 create mode 100644 virt/kvm/arm/vgic/vgic-mmio.h

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 2615205..4ec1270 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -106,6 +106,16 @@ struct vgic_irq {
 	enum vgic_irq_config config;	/* Level or edge */
 };
 
+struct vgic_register_region;
+
+struct vgic_io_device {
+	gpa_t base_addr;
+	struct kvm_vcpu *redist_vcpu;
+	const struct vgic_register_region *regions;
+	int nr_regions;
+	struct kvm_io_device dev;
+};
+
 struct vgic_dist {
 	bool			in_kernel;
 	bool			ready;
@@ -132,6 +142,9 @@ struct vgic_dist {
 	bool			enabled;
 
 	struct vgic_irq		*spis;
+
+	struct vgic_io_device	dist_iodev;
+	struct vgic_io_device	*redist_iodevs;
 };
 
 struct vgic_v2_cpu_if {
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
new file mode 100644
index 0000000..f5628cb
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -0,0 +1,171 @@
+/*
+ * VGIC MMIO 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/bitops.h>
+#include <linux/bsearch.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <kvm/iodev.h>
+#include <kvm/arm_vgic.h>
+
+#include "vgic.h"
+#include "vgic-mmio.h"
+
+/* extract @num bytes at @offset bytes offset in data */
+unsigned long extract_bytes(unsigned long data,
+			    unsigned int offset, unsigned int num)
+{
+	return (data >> (offset * 8)) & GENMASK_ULL(num * 8 - 1, 0);
+}
+
+unsigned long vgic_mmio_read_raz(struct kvm_vcpu *vcpu,
+				 gpa_t addr, unsigned int len)
+{
+	return 0;
+}
+
+unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
+				 gpa_t addr, unsigned int len)
+{
+	return -1UL;
+}
+
+void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
+			unsigned int len, unsigned long val)
+{
+	/* Ignore */
+}
+
+static int match_region(const void *key, const void *elt)
+{
+	const unsigned int offset = (unsigned long)key;
+	const struct vgic_register_region *region = elt;
+
+	if (offset < region->reg_offset)
+		return -1;
+
+	if (offset >= region->reg_offset + region->len)
+		return 1;
+
+	return 0;
+}
+
+/* Find the proper register handler entry given a certain address offset. */
+static const struct vgic_register_region *
+vgic_find_mmio_region(const struct vgic_register_region *region, int nr_regions,
+		      unsigned int offset)
+{
+	return bsearch((void *)(uintptr_t)offset, region, nr_regions,
+		       sizeof(region[0]), match_region);
+}
+
+/*
+ * 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
+ * in memory if it had done the store itself, which is LE for the GIC, as the
+ * guest knows the GIC is always LE.
+ *
+ * We convert this value to the CPUs native format to deal with it as a data
+ * value.
+ */
+unsigned long vgic_data_mmio_bus_to_host(const void *val, unsigned int len)
+{
+	unsigned long data = kvm_mmio_read_buf(val, len);
+
+	switch (len) {
+	case 1:
+		return data;
+	case 2:
+		return le16_to_cpu(data);
+	case 4:
+		return le32_to_cpu(data);
+	default:
+		return le64_to_cpu(data);
+	}
+}
+
+/*
+ * kvm_mmio_write_buf() expects a value in a format such that if converted to
+ * a byte array it is observed as the guest would see it if it could perform
+ * the load directly.  Since the GIC is LE, and the guest knows this, the
+ * guest expects a value in little endian format.
+ *
+ * We convert the data value from the CPUs native format to LE so that the
+ * value is returned in the proper format.
+ */
+void vgic_data_host_to_mmio_bus(void *buf, unsigned int len,
+				unsigned long data)
+{
+	switch (len) {
+	case 1:
+		break;
+	case 2:
+		data = cpu_to_le16(data);
+		break;
+	case 4:
+		data = cpu_to_le32(data);
+		break;
+	default:
+		data = cpu_to_le64(data);
+	}
+
+	kvm_mmio_write_buf(buf, len, data);
+}
+
+static
+struct vgic_io_device *kvm_to_vgic_iodev(const struct kvm_io_device *dev)
+{
+	return container_of(dev, struct vgic_io_device, dev);
+}
+
+static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+			      gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
+	const struct vgic_register_region *region;
+	struct kvm_vcpu *r_vcpu;
+	unsigned long data;
+
+	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
+				       addr - iodev->base_addr);
+	if (!region)
+		return -EOPNOTSUPP;
+
+	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
+	data = region->read(r_vcpu, addr, len);
+	vgic_data_host_to_mmio_bus(val, len, data);
+	return 0;
+}
+
+static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+			       gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
+	const struct vgic_register_region *region;
+	struct kvm_vcpu *r_vcpu;
+	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)
+		return -EOPNOTSUPP;
+
+	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
+	region->write(r_vcpu, addr, len, data);
+	return 0;
+}
+
+struct kvm_io_device_ops kvm_io_gic_ops = {
+	.read = dispatch_mmio_read,
+	.write = dispatch_mmio_write,
+};
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
new file mode 100644
index 0000000..18d3869
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __KVM_ARM_VGIC_MMIO_H__
+#define __KVM_ARM_VGIC_MMIO_H__
+
+struct vgic_register_region {
+	unsigned int reg_offset;
+	unsigned int len;
+	unsigned int bits_per_irq;
+	unsigned long (*read)(struct kvm_vcpu *vcpu, gpa_t addr,
+			      unsigned int len);
+	void (*write)(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len,
+		      unsigned long val);
+};
+
+extern struct kvm_io_device_ops kvm_io_gic_ops;
+
+/*
+ * Some VGIC registers store per-IRQ information, with a different number
+ * of bits per IRQ. For those registers this macro is used.
+ * The _WITH_LENGTH version instantiates registers with a fixed length
+ * and is mutually exclusive with the _PER_IRQ version.
+ */
+#define REGISTER_DESC_WITH_BITS_PER_IRQ(off, read_ops, write_ops, bpi)	\
+	{								\
+		.reg_offset = off,					\
+		.bits_per_irq = bpi,					\
+		.len = bpi * 1024 / 8,					\
+		.read = read_ops,					\
+		.write = write_ops,					\
+	}
+
+#define REGISTER_DESC_WITH_LENGTH(off, read_ops, write_ops, length)	\
+	{								\
+		.reg_offset = off,					\
+		.bits_per_irq = 0,					\
+		.len = length,						\
+		.read = read_ops,					\
+		.write = write_ops,					\
+	}
+
+int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
+				  struct vgic_register_region *reg_desc,
+				  struct vgic_io_device *region,
+				  int nr_irqs, bool offset_private);
+
+unsigned long vgic_data_mmio_bus_to_host(const void *val, unsigned int len);
+
+void vgic_data_host_to_mmio_bus(void *buf, unsigned int len,
+				unsigned long data);
+
+unsigned long extract_bytes(unsigned long data,
+			    unsigned int offset, unsigned int num);
+
+unsigned long vgic_mmio_read_raz(struct kvm_vcpu *vcpu,
+				 gpa_t addr, unsigned int len);
+
+unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
+				 gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
+			unsigned int len, unsigned long val);
+
+#endif
-- 
2.7.3

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

* [PATCH v3 21/55] KVM: arm/arm64: vgic-new: Add MMIO handling framework
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

From: Marc Zyngier <marc.zyngier@arm.com>

Add an MMIO handling framework to the VGIC emulation:
Each register is described by its offset, size (or number of bits per
IRQ, if applicable) and the read/write handler functions. We provide
initialization macros to describe each GIC register later easily.

Separate dispatch functions for read and write accesses are connected
to the kvm_io_bus framework and binary-search for the responsible
register handler based on the offset address within the region.
We convert the incoming data (referenced by a pointer) to the host's
endianess and use pass-by-value to hand the data over to the actual
handler functions.

The register handler prototype and the endianess conversion are
courtesy of Christoffer Dall.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- rework MMIO dispatching to use only one kvm_io_bus device
- document purpose of register region macros
- rename "this" parameter to "dev"
- change IGROUPR to be RAO (returning 1 => Group1 IRQs)

Changelog v1 .. v2:
* MASSIVE rework:
- store register_region pointer in kvm_io_bus linked struct
- replace write_mask_xxx functions with extract_bytes() implementation
- change handler functions' prototypes to take and return unsigned long
- use binary search to find matching register handler
- convert endianess of input data in dispatch_mmio_xxx functions
- improve readability of register initializer macros
- remove any GICv2/GICv3 specific functions from vgic-mmio.c
- rename file from vgic_mmio.c to vgic-mmio.c

Changelog v2 .. v3:
- replace inclusion of vgic/vgic.h with arm_vgic.h

 include/kvm/vgic/vgic.h       |  13 ++++
 virt/kvm/arm/vgic/vgic-mmio.c | 171 ++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.h |  77 +++++++++++++++++++
 3 files changed, 261 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic-mmio.c
 create mode 100644 virt/kvm/arm/vgic/vgic-mmio.h

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 2615205..4ec1270 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -106,6 +106,16 @@ struct vgic_irq {
 	enum vgic_irq_config config;	/* Level or edge */
 };
 
+struct vgic_register_region;
+
+struct vgic_io_device {
+	gpa_t base_addr;
+	struct kvm_vcpu *redist_vcpu;
+	const struct vgic_register_region *regions;
+	int nr_regions;
+	struct kvm_io_device dev;
+};
+
 struct vgic_dist {
 	bool			in_kernel;
 	bool			ready;
@@ -132,6 +142,9 @@ struct vgic_dist {
 	bool			enabled;
 
 	struct vgic_irq		*spis;
+
+	struct vgic_io_device	dist_iodev;
+	struct vgic_io_device	*redist_iodevs;
 };
 
 struct vgic_v2_cpu_if {
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
new file mode 100644
index 0000000..f5628cb
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -0,0 +1,171 @@
+/*
+ * VGIC MMIO 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/bitops.h>
+#include <linux/bsearch.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <kvm/iodev.h>
+#include <kvm/arm_vgic.h>
+
+#include "vgic.h"
+#include "vgic-mmio.h"
+
+/* extract @num bytes at @offset bytes offset in data */
+unsigned long extract_bytes(unsigned long data,
+			    unsigned int offset, unsigned int num)
+{
+	return (data >> (offset * 8)) & GENMASK_ULL(num * 8 - 1, 0);
+}
+
+unsigned long vgic_mmio_read_raz(struct kvm_vcpu *vcpu,
+				 gpa_t addr, unsigned int len)
+{
+	return 0;
+}
+
+unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
+				 gpa_t addr, unsigned int len)
+{
+	return -1UL;
+}
+
+void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
+			unsigned int len, unsigned long val)
+{
+	/* Ignore */
+}
+
+static int match_region(const void *key, const void *elt)
+{
+	const unsigned int offset = (unsigned long)key;
+	const struct vgic_register_region *region = elt;
+
+	if (offset < region->reg_offset)
+		return -1;
+
+	if (offset >= region->reg_offset + region->len)
+		return 1;
+
+	return 0;
+}
+
+/* Find the proper register handler entry given a certain address offset. */
+static const struct vgic_register_region *
+vgic_find_mmio_region(const struct vgic_register_region *region, int nr_regions,
+		      unsigned int offset)
+{
+	return bsearch((void *)(uintptr_t)offset, region, nr_regions,
+		       sizeof(region[0]), match_region);
+}
+
+/*
+ * 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
+ * in memory if it had done the store itself, which is LE for the GIC, as the
+ * guest knows the GIC is always LE.
+ *
+ * We convert this value to the CPUs native format to deal with it as a data
+ * value.
+ */
+unsigned long vgic_data_mmio_bus_to_host(const void *val, unsigned int len)
+{
+	unsigned long data = kvm_mmio_read_buf(val, len);
+
+	switch (len) {
+	case 1:
+		return data;
+	case 2:
+		return le16_to_cpu(data);
+	case 4:
+		return le32_to_cpu(data);
+	default:
+		return le64_to_cpu(data);
+	}
+}
+
+/*
+ * kvm_mmio_write_buf() expects a value in a format such that if converted to
+ * a byte array it is observed as the guest would see it if it could perform
+ * the load directly.  Since the GIC is LE, and the guest knows this, the
+ * guest expects a value in little endian format.
+ *
+ * We convert the data value from the CPUs native format to LE so that the
+ * value is returned in the proper format.
+ */
+void vgic_data_host_to_mmio_bus(void *buf, unsigned int len,
+				unsigned long data)
+{
+	switch (len) {
+	case 1:
+		break;
+	case 2:
+		data = cpu_to_le16(data);
+		break;
+	case 4:
+		data = cpu_to_le32(data);
+		break;
+	default:
+		data = cpu_to_le64(data);
+	}
+
+	kvm_mmio_write_buf(buf, len, data);
+}
+
+static
+struct vgic_io_device *kvm_to_vgic_iodev(const struct kvm_io_device *dev)
+{
+	return container_of(dev, struct vgic_io_device, dev);
+}
+
+static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+			      gpa_t addr, int len, void *val)
+{
+	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
+	const struct vgic_register_region *region;
+	struct kvm_vcpu *r_vcpu;
+	unsigned long data;
+
+	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
+				       addr - iodev->base_addr);
+	if (!region)
+		return -EOPNOTSUPP;
+
+	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
+	data = region->read(r_vcpu, addr, len);
+	vgic_data_host_to_mmio_bus(val, len, data);
+	return 0;
+}
+
+static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+			       gpa_t addr, int len, const void *val)
+{
+	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
+	const struct vgic_register_region *region;
+	struct kvm_vcpu *r_vcpu;
+	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)
+		return -EOPNOTSUPP;
+
+	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
+	region->write(r_vcpu, addr, len, data);
+	return 0;
+}
+
+struct kvm_io_device_ops kvm_io_gic_ops = {
+	.read = dispatch_mmio_read,
+	.write = dispatch_mmio_write,
+};
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
new file mode 100644
index 0000000..18d3869
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __KVM_ARM_VGIC_MMIO_H__
+#define __KVM_ARM_VGIC_MMIO_H__
+
+struct vgic_register_region {
+	unsigned int reg_offset;
+	unsigned int len;
+	unsigned int bits_per_irq;
+	unsigned long (*read)(struct kvm_vcpu *vcpu, gpa_t addr,
+			      unsigned int len);
+	void (*write)(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len,
+		      unsigned long val);
+};
+
+extern struct kvm_io_device_ops kvm_io_gic_ops;
+
+/*
+ * Some VGIC registers store per-IRQ information, with a different number
+ * of bits per IRQ. For those registers this macro is used.
+ * The _WITH_LENGTH version instantiates registers with a fixed length
+ * and is mutually exclusive with the _PER_IRQ version.
+ */
+#define REGISTER_DESC_WITH_BITS_PER_IRQ(off, read_ops, write_ops, bpi)	\
+	{								\
+		.reg_offset = off,					\
+		.bits_per_irq = bpi,					\
+		.len = bpi * 1024 / 8,					\
+		.read = read_ops,					\
+		.write = write_ops,					\
+	}
+
+#define REGISTER_DESC_WITH_LENGTH(off, read_ops, write_ops, length)	\
+	{								\
+		.reg_offset = off,					\
+		.bits_per_irq = 0,					\
+		.len = length,						\
+		.read = read_ops,					\
+		.write = write_ops,					\
+	}
+
+int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
+				  struct vgic_register_region *reg_desc,
+				  struct vgic_io_device *region,
+				  int nr_irqs, bool offset_private);
+
+unsigned long vgic_data_mmio_bus_to_host(const void *val, unsigned int len);
+
+void vgic_data_host_to_mmio_bus(void *buf, unsigned int len,
+				unsigned long data);
+
+unsigned long extract_bytes(unsigned long data,
+			    unsigned int offset, unsigned int num);
+
+unsigned long vgic_mmio_read_raz(struct kvm_vcpu *vcpu,
+				 gpa_t addr, unsigned int len);
+
+unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
+				 gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
+			unsigned int len, unsigned long val);
+
+#endif
-- 
2.7.3

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

* [PATCH v3 22/55] KVM: arm/arm64: vgic-new: Add GICv2 MMIO handling framework
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

Create vgic-mmio-v2.c to describe GICv2 emulation specific handlers
using the initializer macros provided by the VGIC MMIO framework.
Provide a function to register the GICv2 distributor registers to
the kvm_io_bus framework.
The actual handler functions are still stubs in this patch.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
Changelog v1 .. v2:
- new patch, split out from the generic MMIO framework patch
- use a separate file to hold GICv2 emulation specific handlers
- replace _nyi stub functions with raz/wi versions

Changelog v2 .. v3:
- replace kvm/vgic/vgic.h with kvm/arm_vgic.h
- add vgic_register_dist_iodev() prototype

 virt/kvm/arm/vgic/vgic-mmio-v2.c | 62 ++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.c    | 26 +++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.h    |  2 ++
 virt/kvm/arm/vgic/vgic.h         |  2 ++
 4 files changed, 92 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v2.c

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
new file mode 100644
index 0000000..2729a22
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -0,0 +1,62 @@
+/*
+ * VGICv2 MMIO 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.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <kvm/iodev.h>
+#include <kvm/arm_vgic.h>
+
+#include "vgic.h"
+#include "vgic-mmio.h"
+
+static const struct vgic_register_region vgic_v2_dist_registers[] = {
+	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 12),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
+		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 2),
+	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+};
+
+unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
+{
+	dev->regions = vgic_v2_dist_registers;
+	dev->nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
+
+	kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
+
+	return SZ_4K;
+}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index f5628cb..41cf4f4 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -169,3 +169,29 @@ struct kvm_io_device_ops kvm_io_gic_ops = {
 	.read = dispatch_mmio_read,
 	.write = dispatch_mmio_write,
 };
+
+int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
+			     enum vgic_type type)
+{
+	struct vgic_io_device *io_device = &kvm->arch.vgic.dist_iodev;
+	int ret = 0;
+	unsigned int len;
+
+	switch (type) {
+	case VGIC_V2:
+		len = vgic_v2_init_dist_iodev(io_device);
+		break;
+	default:
+		BUG_ON(1);
+	}
+
+	io_device->base_addr = dist_base_address;
+	io_device->redist_vcpu = NULL;
+
+	mutex_lock(&kvm->slots_lock);
+	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, dist_base_address,
+				      len, &io_device->dev);
+	mutex_unlock(&kvm->slots_lock);
+
+	return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 18d3869..4f4dd2b 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -74,4 +74,6 @@ unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
 void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
 			unsigned int len, unsigned long val);
 
+unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
+
 #endif
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 81b1a20..fd9acaa 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -27,6 +27,8 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
 void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
+int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
+			     enum vgic_type);
 
 #ifdef CONFIG_KVM_ARM_VGIC_V3
 void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
-- 
2.7.3


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

* [PATCH v3 22/55] KVM: arm/arm64: vgic-new: Add GICv2 MMIO handling framework
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

Create vgic-mmio-v2.c to describe GICv2 emulation specific handlers
using the initializer macros provided by the VGIC MMIO framework.
Provide a function to register the GICv2 distributor registers to
the kvm_io_bus framework.
The actual handler functions are still stubs in this patch.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
Changelog v1 .. v2:
- new patch, split out from the generic MMIO framework patch
- use a separate file to hold GICv2 emulation specific handlers
- replace _nyi stub functions with raz/wi versions

Changelog v2 .. v3:
- replace kvm/vgic/vgic.h with kvm/arm_vgic.h
- add vgic_register_dist_iodev() prototype

 virt/kvm/arm/vgic/vgic-mmio-v2.c | 62 ++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.c    | 26 +++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.h    |  2 ++
 virt/kvm/arm/vgic/vgic.h         |  2 ++
 4 files changed, 92 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v2.c

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
new file mode 100644
index 0000000..2729a22
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -0,0 +1,62 @@
+/*
+ * VGICv2 MMIO 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.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <kvm/iodev.h>
+#include <kvm/arm_vgic.h>
+
+#include "vgic.h"
+#include "vgic-mmio.h"
+
+static const struct vgic_register_region vgic_v2_dist_registers[] = {
+	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 12),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
+		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 2),
+	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+};
+
+unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
+{
+	dev->regions = vgic_v2_dist_registers;
+	dev->nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
+
+	kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
+
+	return SZ_4K;
+}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index f5628cb..41cf4f4 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -169,3 +169,29 @@ struct kvm_io_device_ops kvm_io_gic_ops = {
 	.read = dispatch_mmio_read,
 	.write = dispatch_mmio_write,
 };
+
+int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
+			     enum vgic_type type)
+{
+	struct vgic_io_device *io_device = &kvm->arch.vgic.dist_iodev;
+	int ret = 0;
+	unsigned int len;
+
+	switch (type) {
+	case VGIC_V2:
+		len = vgic_v2_init_dist_iodev(io_device);
+		break;
+	default:
+		BUG_ON(1);
+	}
+
+	io_device->base_addr = dist_base_address;
+	io_device->redist_vcpu = NULL;
+
+	mutex_lock(&kvm->slots_lock);
+	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, dist_base_address,
+				      len, &io_device->dev);
+	mutex_unlock(&kvm->slots_lock);
+
+	return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 18d3869..4f4dd2b 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -74,4 +74,6 @@ unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
 void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
 			unsigned int len, unsigned long val);
 
+unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
+
 #endif
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 81b1a20..fd9acaa 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -27,6 +27,8 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
 void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
+int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
+			     enum vgic_type);
 
 #ifdef CONFIG_KVM_ARM_VGIC_V3
 void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
-- 
2.7.3

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

* [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

From: Marc Zyngier <marc.zyngier@arm.com>

Those three registers are v2 emulation specific, so their implementation
lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
as their implementation is pretty simple.
When the guest enables the distributor, we kick all VCPUs to get
potentially pending interrupts serviced.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- kick VCPUs is the distributor gets enabled
- improve comment

Changelog v1 .. v2:
- adapt to new MMIO framework
- use switch() statements to improve readability

Changelog v2 .. v3:
- add vgic_kick_vcpus() implementation

 include/linux/irqchip/arm-gic.h  |  1 +
 virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
 virt/kvm/arm/vgic/vgic.c         | 15 +++++++++++++
 virt/kvm/arm/vgic/vgic.h         |  4 ++++
 4 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index be0d26f..fd05185 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -33,6 +33,7 @@
 
 #define GIC_DIST_CTRL			0x000
 #define GIC_DIST_CTR			0x004
+#define GIC_DIST_IIDR			0x008
 #define GIC_DIST_IGROUP			0x080
 #define GIC_DIST_ENABLE_SET		0x100
 #define GIC_DIST_ENABLE_CLEAR		0x180
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 2729a22..69e96f7 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -20,9 +20,55 @@
 #include "vgic.h"
 #include "vgic-mmio.h"
 
+static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
+					    gpa_t addr, unsigned int len)
+{
+	u32 value;
+
+	switch (addr & 0x0c) {
+	case GIC_DIST_CTRL:
+		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
+		break;
+	case GIC_DIST_CTR:
+		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+		value = (value >> 5) - 1;
+		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
+		break;
+	case GIC_DIST_IIDR:
+		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
+		break;
+	default:
+		return 0;
+	}
+
+	return extract_bytes(value, addr & 3, len);
+}
+
+static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
+				    gpa_t addr, unsigned int len,
+				    unsigned long val)
+{
+	switch (addr & 0x0c) {
+	case GIC_DIST_CTRL:
+		if (!(addr & 1)) {
+			struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+			bool was_enabled = dist->enabled;
+
+			dist->enabled = val & GICD_ENABLE;
+			if (!was_enabled && dist->enabled)
+				vgic_kick_vcpus(vcpu->kvm);
+		}
+		break;
+	case GIC_DIST_CTR:
+	case GIC_DIST_IIDR:
+		/* Nothing to do */
+		return;
+	}
+}
+
 static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 12),
+		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
 		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index c3dbcf3..5355de6 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -544,3 +544,18 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
 
 	return pending;
 }
+
+void vgic_kick_vcpus(struct kvm *kvm)
+{
+	struct kvm_vcpu *vcpu;
+	int c;
+
+	/*
+	 * We've injected an interrupt, time to find out who deserves
+	 * a good kick...
+	 */
+	kvm_for_each_vcpu(c, vcpu, kvm) {
+		if (kvm_vgic_vcpu_pending_irq(vcpu))
+			kvm_vcpu_kick(vcpu);
+	}
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index fd9acaa..cf62015 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -16,11 +16,15 @@
 #ifndef __KVM_ARM_VGIC_NEW_H__
 #define __KVM_ARM_VGIC_NEW_H__
 
+#define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
+#define IMPLEMENTER_ARM		0x43b
+
 #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
 
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
 bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
+void vgic_kick_vcpus(struct kvm *kvm);
 
 void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
 void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
-- 
2.7.3

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

* [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

From: Marc Zyngier <marc.zyngier@arm.com>

Those three registers are v2 emulation specific, so their implementation
lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
as their implementation is pretty simple.
When the guest enables the distributor, we kick all VCPUs to get
potentially pending interrupts serviced.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- kick VCPUs is the distributor gets enabled
- improve comment

Changelog v1 .. v2:
- adapt to new MMIO framework
- use switch() statements to improve readability

Changelog v2 .. v3:
- add vgic_kick_vcpus() implementation

 include/linux/irqchip/arm-gic.h  |  1 +
 virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
 virt/kvm/arm/vgic/vgic.c         | 15 +++++++++++++
 virt/kvm/arm/vgic/vgic.h         |  4 ++++
 4 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index be0d26f..fd05185 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -33,6 +33,7 @@
 
 #define GIC_DIST_CTRL			0x000
 #define GIC_DIST_CTR			0x004
+#define GIC_DIST_IIDR			0x008
 #define GIC_DIST_IGROUP			0x080
 #define GIC_DIST_ENABLE_SET		0x100
 #define GIC_DIST_ENABLE_CLEAR		0x180
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 2729a22..69e96f7 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -20,9 +20,55 @@
 #include "vgic.h"
 #include "vgic-mmio.h"
 
+static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
+					    gpa_t addr, unsigned int len)
+{
+	u32 value;
+
+	switch (addr & 0x0c) {
+	case GIC_DIST_CTRL:
+		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
+		break;
+	case GIC_DIST_CTR:
+		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+		value = (value >> 5) - 1;
+		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
+		break;
+	case GIC_DIST_IIDR:
+		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
+		break;
+	default:
+		return 0;
+	}
+
+	return extract_bytes(value, addr & 3, len);
+}
+
+static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
+				    gpa_t addr, unsigned int len,
+				    unsigned long val)
+{
+	switch (addr & 0x0c) {
+	case GIC_DIST_CTRL:
+		if (!(addr & 1)) {
+			struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+			bool was_enabled = dist->enabled;
+
+			dist->enabled = val & GICD_ENABLE;
+			if (!was_enabled && dist->enabled)
+				vgic_kick_vcpus(vcpu->kvm);
+		}
+		break;
+	case GIC_DIST_CTR:
+	case GIC_DIST_IIDR:
+		/* Nothing to do */
+		return;
+	}
+}
+
 static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 12),
+		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
 		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index c3dbcf3..5355de6 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -544,3 +544,18 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
 
 	return pending;
 }
+
+void vgic_kick_vcpus(struct kvm *kvm)
+{
+	struct kvm_vcpu *vcpu;
+	int c;
+
+	/*
+	 * We've injected an interrupt, time to find out who deserves
+	 * a good kick...
+	 */
+	kvm_for_each_vcpu(c, vcpu, kvm) {
+		if (kvm_vgic_vcpu_pending_irq(vcpu))
+			kvm_vcpu_kick(vcpu);
+	}
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index fd9acaa..cf62015 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -16,11 +16,15 @@
 #ifndef __KVM_ARM_VGIC_NEW_H__
 #define __KVM_ARM_VGIC_NEW_H__
 
+#define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
+#define IMPLEMENTER_ARM		0x43b
+
 #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
 
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
 bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
+void vgic_kick_vcpus(struct kvm *kvm);
 
 void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
 void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
-- 
2.7.3

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

* [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

As the enable register handlers are shared between the v2 and v3
emulation, their implementation goes into vgic-mmio.c, to be easily
referenced from the v3 emulation as well later.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- use lower bits of address to determine IRQ number
- remove TODO, confirmed to be fine

Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
 virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
 3 files changed, 69 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 69e96f7..448d1da 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
 		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 41cf4f4..077ae86 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
 	/* Ignore */
 }
 
+/*
+ * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
+ * of the enabled bit, so there is only one function for both here.
+ */
+unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
+				    gpa_t addr, unsigned int len)
+{
+	u32 intid = (addr & 0x7f) * 8;
+	u32 value = 0;
+	int i;
+
+	/* Loop over all IRQs affected by this read */
+	for (i = 0; i < len * 8; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (irq->enabled)
+			value |= (1U << i);
+	}
+
+	return extract_bytes(value, addr & 3, len);
+}
+
+void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
+			     gpa_t addr, unsigned int len,
+			     unsigned long val)
+{
+	u32 intid = (addr & 0x7f) * 8;
+	int i;
+
+	for_each_set_bit(i, &val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		irq->enabled = true;
+		vgic_queue_irq_unlock(vcpu->kvm, irq);
+	}
+}
+
+void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
+			     gpa_t addr, unsigned int len,
+			     unsigned long val)
+{
+	u32 intid = (addr & 0x7f) * 8;
+	int i;
+
+	for_each_set_bit(i, &val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		irq->enabled = false;
+
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
 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 4f4dd2b..188909a 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -74,6 +74,17 @@ unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
 void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
 			unsigned int len, unsigned long val);
 
+unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
+				    gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
+			     gpa_t addr, unsigned int len,
+			     unsigned long val);
+
+void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
+			     gpa_t addr, unsigned int len,
+			     unsigned long val);
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 #endif
-- 
2.7.3

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

* [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

As the enable register handlers are shared between the v2 and v3
emulation, their implementation goes into vgic-mmio.c, to be easily
referenced from the v3 emulation as well later.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- use lower bits of address to determine IRQ number
- remove TODO, confirmed to be fine

Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
 virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
 3 files changed, 69 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 69e96f7..448d1da 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
 		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 41cf4f4..077ae86 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
 	/* Ignore */
 }
 
+/*
+ * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
+ * of the enabled bit, so there is only one function for both here.
+ */
+unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
+				    gpa_t addr, unsigned int len)
+{
+	u32 intid = (addr & 0x7f) * 8;
+	u32 value = 0;
+	int i;
+
+	/* Loop over all IRQs affected by this read */
+	for (i = 0; i < len * 8; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (irq->enabled)
+			value |= (1U << i);
+	}
+
+	return extract_bytes(value, addr & 3, len);
+}
+
+void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
+			     gpa_t addr, unsigned int len,
+			     unsigned long val)
+{
+	u32 intid = (addr & 0x7f) * 8;
+	int i;
+
+	for_each_set_bit(i, &val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		irq->enabled = true;
+		vgic_queue_irq_unlock(vcpu->kvm, irq);
+	}
+}
+
+void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
+			     gpa_t addr, unsigned int len,
+			     unsigned long val)
+{
+	u32 intid = (addr & 0x7f) * 8;
+	int i;
+
+	for_each_set_bit(i, &val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		irq->enabled = false;
+
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
 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 4f4dd2b..188909a 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -74,6 +74,17 @@ unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
 void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
 			unsigned int len, unsigned long val);
 
+unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
+				    gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
+			     gpa_t addr, unsigned int len,
+			     unsigned long val);
+
+void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
+			     gpa_t addr, unsigned int len,
+			     unsigned long val);
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 #endif
-- 
2.7.3

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

* [PATCH v3 25/55] KVM: arm/arm64: vgic-new: Add PENDING registers handlers
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

The pending register handlers are shared between the v2 and v3
emulation, so their implementation goes into vgic-mmio.c, to be easily
referenced from the v3 emulation as well later.
For level triggered interrupts the real line level is unaffected by
this write, so we keep this state separate and combine it with the
device's level to get the actual pending state.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- remove IRQ lock from read handler
- remove TODO from clear pending handler

Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
 virt/kvm/arm/vgic/vgic-mmio.c    | 60 ++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.h    | 12 ++++++++
 3 files changed, 74 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 448d1da..4b87e0a 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -76,9 +76,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
 		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 077ae86..4df1af7 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -102,6 +102,66 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
 	}
 }
 
+unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
+				     gpa_t addr, unsigned int len)
+{
+	u32 intid = (addr & 0x7f) * 8;
+	u32 value = 0;
+	int i;
+
+	/* Loop over all IRQs affected by this read */
+	for (i = 0; i < len * 8; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (irq->pending)
+			value |= (1U << i);
+	}
+
+	return extract_bytes(value, addr & 3, len);
+}
+
+void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
+			      gpa_t addr, unsigned int len,
+			      unsigned long val)
+{
+	u32 intid = (addr & 0x7f) * 8;
+	int i;
+
+	for_each_set_bit(i, &val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		irq->pending = true;
+		if (irq->config == VGIC_CONFIG_LEVEL)
+			irq->soft_pending = true;
+
+		vgic_queue_irq_unlock(vcpu->kvm, irq);
+	}
+}
+
+void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
+			      gpa_t addr, unsigned int len,
+			      unsigned long val)
+{
+	u32 intid = (addr & 0x7f) * 8;
+	int i;
+
+	for_each_set_bit(i, &val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		if (irq->config == VGIC_CONFIG_LEVEL) {
+			irq->soft_pending = false;
+			irq->pending = irq->line_level;
+		} else {
+			irq->pending = false;
+		}
+
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
 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 188909a..d4fc029 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -85,6 +85,18 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
 			     gpa_t addr, unsigned int len,
 			     unsigned long val);
 
+unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
+				     gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
+			      gpa_t addr, unsigned int len,
+			      unsigned long val);
+
+void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
+			      gpa_t addr, unsigned int len,
+			      unsigned long val);
+
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 #endif
-- 
2.7.3


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

* [PATCH v3 25/55] KVM: arm/arm64: vgic-new: Add PENDING registers handlers
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

The pending register handlers are shared between the v2 and v3
emulation, so their implementation goes into vgic-mmio.c, to be easily
referenced from the v3 emulation as well later.
For level triggered interrupts the real line level is unaffected by
this write, so we keep this state separate and combine it with the
device's level to get the actual pending state.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- remove IRQ lock from read handler
- remove TODO from clear pending handler

Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
 virt/kvm/arm/vgic/vgic-mmio.c    | 60 ++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.h    | 12 ++++++++
 3 files changed, 74 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 448d1da..4b87e0a 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -76,9 +76,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
 		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 077ae86..4df1af7 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -102,6 +102,66 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
 	}
 }
 
+unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
+				     gpa_t addr, unsigned int len)
+{
+	u32 intid = (addr & 0x7f) * 8;
+	u32 value = 0;
+	int i;
+
+	/* Loop over all IRQs affected by this read */
+	for (i = 0; i < len * 8; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (irq->pending)
+			value |= (1U << i);
+	}
+
+	return extract_bytes(value, addr & 3, len);
+}
+
+void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
+			      gpa_t addr, unsigned int len,
+			      unsigned long val)
+{
+	u32 intid = (addr & 0x7f) * 8;
+	int i;
+
+	for_each_set_bit(i, &val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		irq->pending = true;
+		if (irq->config == VGIC_CONFIG_LEVEL)
+			irq->soft_pending = true;
+
+		vgic_queue_irq_unlock(vcpu->kvm, irq);
+	}
+}
+
+void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
+			      gpa_t addr, unsigned int len,
+			      unsigned long val)
+{
+	u32 intid = (addr & 0x7f) * 8;
+	int i;
+
+	for_each_set_bit(i, &val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		if (irq->config == VGIC_CONFIG_LEVEL) {
+			irq->soft_pending = false;
+			irq->pending = irq->line_level;
+		} else {
+			irq->pending = false;
+		}
+
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
 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 188909a..d4fc029 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -85,6 +85,18 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
 			     gpa_t addr, unsigned int len,
 			     unsigned long val);
 
+unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
+				     gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
+			      gpa_t addr, unsigned int len,
+			      unsigned long val);
+
+void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
+			      gpa_t addr, unsigned int len,
+			      unsigned long val);
+
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 #endif
-- 
2.7.3

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

* [PATCH v3 26/55] KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

The active register handlers are shared between the v2 and v3
emulation, so their implementation goes into vgic-mmio.c, to be
easily referenced from the v3 emulation as well later.
Since activation/deactivation of an interrupt may happen entirely
in the guest without it ever exiting, we need some extra logic to
properly track the active state.
Putting it on an ap_list on activation is similar to the normal case
handled by vgic_queue_irq_unlock(), but differs in some details that
make a separate implementation worthwhile.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- handling queueing in write handler
- remove IRQ lock from read handler

Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v2.c |   4 +-
 virt/kvm/arm/vgic/vgic-mmio.c    | 120 +++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.h    |  10 ++++
 3 files changed, 132 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 4b87e0a..054b52d 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -80,9 +80,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
 		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 4df1af7..dbf683e 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -162,6 +162,126 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
 	}
 }
 
+unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
+				    gpa_t addr, unsigned int len)
+{
+	u32 intid = (addr & 0x7f) * 8;
+	u32 value = 0;
+	int i;
+
+	/* Loop over all IRQs affected by this read */
+	for (i = 0; i < len * 8; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (irq->active)
+			value |= (1U << i);
+	}
+
+	return extract_bytes(value, addr & 3, len);
+}
+
+void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
+			     gpa_t addr, unsigned int len,
+			     unsigned long val)
+{
+	u32 intid = (addr & 0x7f) * 8;
+	int i;
+
+	for_each_set_bit(i, &val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		irq->active = false;
+
+		/*
+		 * Christoffer wrote:
+		 * The question is what to do if the vcpu for this irq is
+		 * running and the LR there has the active bit set, then we'll
+		 * overwrite this change when we fold the LR state back into
+		 * the vgic_irq struct.
+		 *
+		 * Since I expect this to be extremely rare, one option is to
+		 * force irq->vcpu to exit (if non-null) and then do you
+		 * thing here after you've confirm it has exited while holding
+		 * some lock preventing it from re-entering again.
+		 * Slightly crazy.
+		 *
+		 * The alternative is to put a big fat comment nothing that
+		 * this is non-supported bad race, and wait until someone
+		 * submits a bug report relating to this...
+		 */
+
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
+void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
+			     gpa_t addr, unsigned int len,
+			     unsigned long val)
+{
+	u32 intid = (addr & 0x7f) * 8;
+	int i;
+
+	for_each_set_bit(i, &val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		/* As this is a special case, we can't use the
+		 * vgic_queue_irq_unlock() function to put this on a VCPU.
+		 * So deal with this here explicitly unless the IRQs was
+		 * already active, it was on a VCPU before or there is no
+		 * target VCPU assigned at the moment.
+		 */
+		if (irq->active || irq->vcpu || !irq->target_vcpu) {
+			irq->active = true;
+
+			spin_unlock(&irq->irq_lock);
+			continue;
+		}
+
+		spin_unlock(&irq->irq_lock);
+retry:
+		vcpu = irq->target_vcpu;
+
+		spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
+		spin_lock(&irq->irq_lock);
+
+		/*
+		 * Recheck after dropping the IRQ lock to see if we should
+		 * still care about queueing it.
+		 */
+		if (irq->active || irq->vcpu) {
+			irq->active = true;
+
+			spin_unlock(&irq->irq_lock);
+			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+			continue;
+		}
+
+		/* Did the target VCPU change while we had the lock dropped? */
+		if (vcpu != irq->target_vcpu) {
+			spin_unlock(&irq->irq_lock);
+			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+			goto retry;
+		}
+
+		/* Now queue the IRQ to the VCPU's ap_list. */
+		list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
+		irq->vcpu = vcpu;
+
+		irq->active = true;
+
+		spin_unlock(&irq->irq_lock);
+		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+		kvm_vcpu_kick(vcpu);
+	}
+}
+
 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 d4fc029..fa875dc 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -96,6 +96,16 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
 			      gpa_t addr, unsigned int len,
 			      unsigned long val);
 
+unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
+				    gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
+			     gpa_t addr, unsigned int len,
+			     unsigned long val);
+
+void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
+			     gpa_t addr, unsigned int len,
+			     unsigned long val);
 
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
-- 
2.7.3

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

* [PATCH v3 26/55] KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

The active register handlers are shared between the v2 and v3
emulation, so their implementation goes into vgic-mmio.c, to be
easily referenced from the v3 emulation as well later.
Since activation/deactivation of an interrupt may happen entirely
in the guest without it ever exiting, we need some extra logic to
properly track the active state.
Putting it on an ap_list on activation is similar to the normal case
handled by vgic_queue_irq_unlock(), but differs in some details that
make a separate implementation worthwhile.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- handling queueing in write handler
- remove IRQ lock from read handler

Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v2.c |   4 +-
 virt/kvm/arm/vgic/vgic-mmio.c    | 120 +++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.h    |  10 ++++
 3 files changed, 132 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 4b87e0a..054b52d 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -80,9 +80,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
 		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 4df1af7..dbf683e 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -162,6 +162,126 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
 	}
 }
 
+unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
+				    gpa_t addr, unsigned int len)
+{
+	u32 intid = (addr & 0x7f) * 8;
+	u32 value = 0;
+	int i;
+
+	/* Loop over all IRQs affected by this read */
+	for (i = 0; i < len * 8; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (irq->active)
+			value |= (1U << i);
+	}
+
+	return extract_bytes(value, addr & 3, len);
+}
+
+void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
+			     gpa_t addr, unsigned int len,
+			     unsigned long val)
+{
+	u32 intid = (addr & 0x7f) * 8;
+	int i;
+
+	for_each_set_bit(i, &val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		irq->active = false;
+
+		/*
+		 * Christoffer wrote:
+		 * The question is what to do if the vcpu for this irq is
+		 * running and the LR there has the active bit set, then we'll
+		 * overwrite this change when we fold the LR state back into
+		 * the vgic_irq struct.
+		 *
+		 * Since I expect this to be extremely rare, one option is to
+		 * force irq->vcpu to exit (if non-null) and then do you
+		 * thing here after you've confirm it has exited while holding
+		 * some lock preventing it from re-entering again.
+		 * Slightly crazy.
+		 *
+		 * The alternative is to put a big fat comment nothing that
+		 * this is non-supported bad race, and wait until someone
+		 * submits a bug report relating to this...
+		 */
+
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
+void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
+			     gpa_t addr, unsigned int len,
+			     unsigned long val)
+{
+	u32 intid = (addr & 0x7f) * 8;
+	int i;
+
+	for_each_set_bit(i, &val, len * 8) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		/* As this is a special case, we can't use the
+		 * vgic_queue_irq_unlock() function to put this on a VCPU.
+		 * So deal with this here explicitly unless the IRQs was
+		 * already active, it was on a VCPU before or there is no
+		 * target VCPU assigned at the moment.
+		 */
+		if (irq->active || irq->vcpu || !irq->target_vcpu) {
+			irq->active = true;
+
+			spin_unlock(&irq->irq_lock);
+			continue;
+		}
+
+		spin_unlock(&irq->irq_lock);
+retry:
+		vcpu = irq->target_vcpu;
+
+		spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
+		spin_lock(&irq->irq_lock);
+
+		/*
+		 * Recheck after dropping the IRQ lock to see if we should
+		 * still care about queueing it.
+		 */
+		if (irq->active || irq->vcpu) {
+			irq->active = true;
+
+			spin_unlock(&irq->irq_lock);
+			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+			continue;
+		}
+
+		/* Did the target VCPU change while we had the lock dropped? */
+		if (vcpu != irq->target_vcpu) {
+			spin_unlock(&irq->irq_lock);
+			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+			goto retry;
+		}
+
+		/* Now queue the IRQ to the VCPU's ap_list. */
+		list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
+		irq->vcpu = vcpu;
+
+		irq->active = true;
+
+		spin_unlock(&irq->irq_lock);
+		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+		kvm_vcpu_kick(vcpu);
+	}
+}
+
 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 d4fc029..fa875dc 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -96,6 +96,16 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
 			      gpa_t addr, unsigned int len,
 			      unsigned long val);
 
+unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
+				    gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
+			     gpa_t addr, unsigned int len,
+			     unsigned long val);
+
+void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
+			     gpa_t addr, unsigned int len,
+			     unsigned long val);
 
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
-- 
2.7.3

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

* [PATCH v3 27/55] KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

The priority register handlers are shared between the v2 and v3
emulation, so their implementation goes into vgic-mmio.c, to be
easily referenced from the v3 emulation as well later.
There is a corner case when we change the priority of a pending
interrupt which we don't handle at the moment.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v2.c |  2 +-
 virt/kvm/arm/vgic/vgic-mmio.c    | 39 +++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.h    |  7 +++++++
 3 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 054b52d..2e17250 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -84,7 +84,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
 		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index dbf683e..d7fe9e6 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -282,6 +282,45 @@ retry:
 	}
 }
 
+unsigned long vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
+				      gpa_t addr, unsigned int len)
+{
+	u32 intid = addr & 0x3ff;
+	int i;
+	u64 val = 0;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		val |= (u64)irq->priority << (i * 8);
+	}
+
+	return val;
+}
+
+/*
+ * We currently don't handle changing the priority of an interrupt that
+ * is already pending on a VCPU. If there is a need for this, we would
+ * need to make this VCPU exit and re-evaluate the priorities, potentially
+ * leading to this interrupt getting presented now to the guest (if it has
+ * been masked by the priority mask before).
+ */
+void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
+			      gpa_t addr, unsigned int len,
+			      unsigned long val)
+{
+	u32 intid = addr & 0x3ff;
+	int i;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		irq->priority = (val >> (i * 8)) & 0xff;
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
 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 fa875dc..cd04ac5 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -107,6 +107,13 @@ void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
 			     gpa_t addr, unsigned int len,
 			     unsigned long val);
 
+unsigned long vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
+				      gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
+			      gpa_t addr, unsigned int len,
+			      unsigned long val);
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 #endif
-- 
2.7.3

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

* [PATCH v3 27/55] KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

The priority register handlers are shared between the v2 and v3
emulation, so their implementation goes into vgic-mmio.c, to be
easily referenced from the v3 emulation as well later.
There is a corner case when we change the priority of a pending
interrupt which we don't handle at the moment.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v2.c |  2 +-
 virt/kvm/arm/vgic/vgic-mmio.c    | 39 +++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.h    |  7 +++++++
 3 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 054b52d..2e17250 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -84,7 +84,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
 		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index dbf683e..d7fe9e6 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -282,6 +282,45 @@ retry:
 	}
 }
 
+unsigned long vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
+				      gpa_t addr, unsigned int len)
+{
+	u32 intid = addr & 0x3ff;
+	int i;
+	u64 val = 0;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		val |= (u64)irq->priority << (i * 8);
+	}
+
+	return val;
+}
+
+/*
+ * We currently don't handle changing the priority of an interrupt that
+ * is already pending on a VCPU. If there is a need for this, we would
+ * need to make this VCPU exit and re-evaluate the priorities, potentially
+ * leading to this interrupt getting presented now to the guest (if it has
+ * been masked by the priority mask before).
+ */
+void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
+			      gpa_t addr, unsigned int len,
+			      unsigned long val)
+{
+	u32 intid = addr & 0x3ff;
+	int i;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+		irq->priority = (val >> (i * 8)) & 0xff;
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
 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 fa875dc..cd04ac5 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -107,6 +107,13 @@ void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
 			     gpa_t addr, unsigned int len,
 			     unsigned long val);
 
+unsigned long vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
+				      gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
+			      gpa_t addr, unsigned int len,
+			      unsigned long val);
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 #endif
-- 
2.7.3

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

* [PATCH v3 28/55] KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

The config register handlers are shared between the v2 and v3
emulation, so their implementation goes into vgic-mmio.c, to be
easily referenced from the v3 emulation as well later.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v2.c |  2 +-
 virt/kvm/arm/vgic/vgic-mmio.c    | 46 ++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.h    |  7 ++++++
 3 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 2e17250..2a953ec 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -88,7 +88,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 2),
+		vgic_mmio_read_config, vgic_mmio_write_config, 2),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index d7fe9e6..19fed56 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -321,6 +321,52 @@ void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
 	}
 }
 
+unsigned long vgic_mmio_read_config(struct kvm_vcpu *vcpu,
+				    gpa_t addr, unsigned int len)
+{
+	u32 intid = (addr & 0xff) * 4;
+	u32 value = 0;
+	int i;
+
+	for (i = 0; i < len * 4; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (irq->config == VGIC_CONFIG_EDGE)
+			value |= (2U << (i * 2));
+	}
+
+	return extract_bytes(value, addr & 3, len);
+}
+
+void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
+			    gpa_t addr, unsigned int len,
+			    unsigned long val)
+{
+	u32 intid = (addr & 0xff) * 4;
+	int i;
+
+	for (i = 0; i < len * 4; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (intid + i < 16)
+			continue;
+
+		/*
+		 * The spec says that interrupts must be disabled before
+		 * changing the configuration to avoid UNDEFINED behaviour.
+		 */
+
+		spin_lock(&irq->irq_lock);
+		if (test_bit(i * 2 + 1, &val)) {
+			irq->config = VGIC_CONFIG_EDGE;
+		} else {
+			irq->config = VGIC_CONFIG_LEVEL;
+			irq->pending = irq->line_level | irq->soft_pending;
+		}
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
 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 cd04ac5..884eb71 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -114,6 +114,13 @@ void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
 			      gpa_t addr, unsigned int len,
 			      unsigned long val);
 
+unsigned long vgic_mmio_read_config(struct kvm_vcpu *vcpu,
+				    gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
+			    gpa_t addr, unsigned int len,
+			    unsigned long val);
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 #endif
-- 
2.7.3


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

* [PATCH v3 28/55] KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

The config register handlers are shared between the v2 and v3
emulation, so their implementation goes into vgic-mmio.c, to be
easily referenced from the v3 emulation as well later.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v2.c |  2 +-
 virt/kvm/arm/vgic/vgic-mmio.c    | 46 ++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.h    |  7 ++++++
 3 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 2e17250..2a953ec 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -88,7 +88,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 2),
+		vgic_mmio_read_config, vgic_mmio_write_config, 2),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index d7fe9e6..19fed56 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -321,6 +321,52 @@ void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
 	}
 }
 
+unsigned long vgic_mmio_read_config(struct kvm_vcpu *vcpu,
+				    gpa_t addr, unsigned int len)
+{
+	u32 intid = (addr & 0xff) * 4;
+	u32 value = 0;
+	int i;
+
+	for (i = 0; i < len * 4; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (irq->config == VGIC_CONFIG_EDGE)
+			value |= (2U << (i * 2));
+	}
+
+	return extract_bytes(value, addr & 3, len);
+}
+
+void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
+			    gpa_t addr, unsigned int len,
+			    unsigned long val)
+{
+	u32 intid = (addr & 0xff) * 4;
+	int i;
+
+	for (i = 0; i < len * 4; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		if (intid + i < 16)
+			continue;
+
+		/*
+		 * The spec says that interrupts must be disabled before
+		 * changing the configuration to avoid UNDEFINED behaviour.
+		 */
+
+		spin_lock(&irq->irq_lock);
+		if (test_bit(i * 2 + 1, &val)) {
+			irq->config = VGIC_CONFIG_EDGE;
+		} else {
+			irq->config = VGIC_CONFIG_LEVEL;
+			irq->pending = irq->line_level | irq->soft_pending;
+		}
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
 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 cd04ac5..884eb71 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -114,6 +114,13 @@ void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
 			      gpa_t addr, unsigned int len,
 			      unsigned long val);
 
+unsigned long vgic_mmio_read_config(struct kvm_vcpu *vcpu,
+				    gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
+			    gpa_t addr, unsigned int len,
+			    unsigned long val);
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 #endif
-- 
2.7.3

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

* [PATCH v3 29/55] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

The target register handlers are v2 emulation specific, so their
implementation lives entirely in vgic-mmio-v2.c.
We copy the old VGIC behaviour of assigning an IRQ to the first VCPU
set in the target mask instead of making it possibly pending on
multiple VCPUs.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- remove runtime VCPU determination from this v2-only register
- fold in implementation of vgic_v2_irq_change_affinity()
- replace ffs() with __ffs()

Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v2.c | 43 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 2a953ec..888529e 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -66,6 +66,47 @@ static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
 	}
 }
 
+static unsigned long vgic_mmio_read_target(struct kvm_vcpu *vcpu,
+					   gpa_t addr, unsigned int len)
+{
+	u32 intid = addr & 0x3ff;
+	int i;
+	u64 val = 0;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		val |= (u64)irq->targets << (i * 8);
+	}
+
+	return val;
+}
+
+static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
+				   gpa_t addr, unsigned int len,
+				   unsigned long val)
+{
+	u32 intid = addr & 0x3ff;
+	int i;
+
+	/* GICD_ITARGETSR[0-7] are read-only */
+	if (intid < VGIC_NR_PRIVATE_IRQS)
+		return;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid + i);
+		int target;
+
+		spin_lock(&irq->irq_lock);
+
+		irq->targets = (val >> (i * 8)) & 0xff;
+		target = irq->targets ? __ffs(irq->targets) : 0;
+		irq->target_vcpu = kvm_get_vcpu(vcpu->kvm, target);
+
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
 static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -86,7 +127,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
 		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+		vgic_mmio_read_target, vgic_mmio_write_target, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
 		vgic_mmio_read_config, vgic_mmio_write_config, 2),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
-- 
2.7.3


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

* [PATCH v3 29/55] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

The target register handlers are v2 emulation specific, so their
implementation lives entirely in vgic-mmio-v2.c.
We copy the old VGIC behaviour of assigning an IRQ to the first VCPU
set in the target mask instead of making it possibly pending on
multiple VCPUs.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- remove runtime VCPU determination from this v2-only register
- fold in implementation of vgic_v2_irq_change_affinity()
- replace ffs() with __ffs()

Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v2.c | 43 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 2a953ec..888529e 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -66,6 +66,47 @@ static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
 	}
 }
 
+static unsigned long vgic_mmio_read_target(struct kvm_vcpu *vcpu,
+					   gpa_t addr, unsigned int len)
+{
+	u32 intid = addr & 0x3ff;
+	int i;
+	u64 val = 0;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		val |= (u64)irq->targets << (i * 8);
+	}
+
+	return val;
+}
+
+static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
+				   gpa_t addr, unsigned int len,
+				   unsigned long val)
+{
+	u32 intid = addr & 0x3ff;
+	int i;
+
+	/* GICD_ITARGETSR[0-7] are read-only */
+	if (intid < VGIC_NR_PRIVATE_IRQS)
+		return;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid + i);
+		int target;
+
+		spin_lock(&irq->irq_lock);
+
+		irq->targets = (val >> (i * 8)) & 0xff;
+		target = irq->targets ? __ffs(irq->targets) : 0;
+		irq->target_vcpu = kvm_get_vcpu(vcpu->kvm, target);
+
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
 static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -86,7 +127,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
 		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+		vgic_mmio_read_target, vgic_mmio_write_target, 8),
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
 		vgic_mmio_read_config, vgic_mmio_write_config, 2),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
-- 
2.7.3

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

* [PATCH v3 30/55] KVM: arm/arm64: vgic-new: Add SGIR register handler
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Triggering an IPI via this register is v2 specific, so the
implementation lives entirely in vgic-mmio-v2.c.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- silently return on illegal TargetListFilter value (=3)

Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v2.c | 43 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 888529e..8f8ea57 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -66,6 +66,47 @@ static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
 	}
 }
 
+static void vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
+				 gpa_t addr, unsigned int len,
+				 unsigned long val)
+{
+	int nr_vcpus = atomic_read(&source_vcpu->kvm->online_vcpus);
+	int intid = val & 0xf;
+	int targets = (val >> 16) & 0xff;
+	int mode = (val >> 24) & 0x03;
+	int c;
+	struct kvm_vcpu *vcpu;
+
+	switch (mode) {
+	case 0x0:		/* as specified by targets */
+		break;
+	case 0x1:
+		targets = (1U << nr_vcpus) - 1;			/* all, ... */
+		targets &= ~(1U << source_vcpu->vcpu_id);	/* but self */
+		break;
+	case 0x2:		/* this very vCPU only */
+		targets = (1U << source_vcpu->vcpu_id);
+		break;
+	case 0x3:		/* reserved */
+		return;
+	}
+
+	kvm_for_each_vcpu(c, vcpu, source_vcpu->kvm) {
+		struct vgic_irq *irq;
+
+		if (!(targets & (1U << c)))
+			continue;
+
+		irq = vgic_get_irq(source_vcpu->kvm, vcpu, intid);
+
+		spin_lock(&irq->irq_lock);
+		irq->pending = true;
+		irq->source |= 1U << source_vcpu->vcpu_id;
+
+		vgic_queue_irq_unlock(source_vcpu->kvm, irq);
+	}
+}
+
 static unsigned long vgic_mmio_read_target(struct kvm_vcpu *vcpu,
 					   gpa_t addr, unsigned int len)
 {
@@ -131,7 +172,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
 		vgic_mmio_read_config, vgic_mmio_write_config, 2),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+		vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
-- 
2.7.3

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

* [PATCH v3 30/55] KVM: arm/arm64: vgic-new: Add SGIR register handler
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

Triggering an IPI via this register is v2 specific, so the
implementation lives entirely in vgic-mmio-v2.c.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- silently return on illegal TargetListFilter value (=3)

Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v2.c | 43 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 888529e..8f8ea57 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -66,6 +66,47 @@ static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
 	}
 }
 
+static void vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
+				 gpa_t addr, unsigned int len,
+				 unsigned long val)
+{
+	int nr_vcpus = atomic_read(&source_vcpu->kvm->online_vcpus);
+	int intid = val & 0xf;
+	int targets = (val >> 16) & 0xff;
+	int mode = (val >> 24) & 0x03;
+	int c;
+	struct kvm_vcpu *vcpu;
+
+	switch (mode) {
+	case 0x0:		/* as specified by targets */
+		break;
+	case 0x1:
+		targets = (1U << nr_vcpus) - 1;			/* all, ... */
+		targets &= ~(1U << source_vcpu->vcpu_id);	/* but self */
+		break;
+	case 0x2:		/* this very vCPU only */
+		targets = (1U << source_vcpu->vcpu_id);
+		break;
+	case 0x3:		/* reserved */
+		return;
+	}
+
+	kvm_for_each_vcpu(c, vcpu, source_vcpu->kvm) {
+		struct vgic_irq *irq;
+
+		if (!(targets & (1U << c)))
+			continue;
+
+		irq = vgic_get_irq(source_vcpu->kvm, vcpu, intid);
+
+		spin_lock(&irq->irq_lock);
+		irq->pending = true;
+		irq->source |= 1U << source_vcpu->vcpu_id;
+
+		vgic_queue_irq_unlock(source_vcpu->kvm, irq);
+	}
+}
+
 static unsigned long vgic_mmio_read_target(struct kvm_vcpu *vcpu,
 					   gpa_t addr, unsigned int len)
 {
@@ -131,7 +172,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
 		vgic_mmio_read_config, vgic_mmio_write_config, 2),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+		vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
-- 
2.7.3

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

* [PATCH v3 31/55] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

As this register is v2 specific, its implementation lives entirely
in vgic-mmio-v2.c.
This register allows setting the source mask of an IPI.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- remove IRQ lock from read handler
- update pending bit on setting the first / clearing the last bit
- queue virtual IRQ if necessary

Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v2.c | 62 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 60 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 8f8ea57..8006ac0 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -148,6 +148,64 @@ static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
 	}
 }
 
+static unsigned long vgic_mmio_read_sgipend(struct kvm_vcpu *vcpu,
+					    gpa_t addr, unsigned int len)
+{
+	u32 intid = addr & 0x0f;
+	int i;
+	u64 val = 0;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		val |= (u64)irq->source << (i * 8);
+	}
+	return val;
+}
+
+static void vgic_mmio_write_sgipendc(struct kvm_vcpu *vcpu,
+				     gpa_t addr, unsigned int len,
+				     unsigned long val)
+{
+	u32 intid = addr & 0x0f;
+	int i;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		irq->source &= ~((val >> (i * 8)) & 0xff);
+		if (!irq->source)
+			irq->pending = false;
+
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
+static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
+				     gpa_t addr, unsigned int len,
+				     unsigned long val)
+{
+	u32 intid = addr & 0x0f;
+	int i;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		irq->source |= (val >> (i * 8)) & 0xff;
+
+		if (irq->source) {
+			irq->pending = true;
+			vgic_queue_irq_unlock(vcpu->kvm, irq);
+		} else {
+			spin_unlock(&irq->irq_lock);
+		}
+	}
+}
+
 static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -174,9 +232,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
 		vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+		vgic_mmio_read_sgipend, vgic_mmio_write_sgipendc, 16),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
 };
 
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
-- 
2.7.3

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

* [PATCH v3 31/55] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

As this register is v2 specific, its implementation lives entirely
in vgic-mmio-v2.c.
This register allows setting the source mask of an IPI.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- remove IRQ lock from read handler
- update pending bit on setting the first / clearing the last bit
- queue virtual IRQ if necessary

Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v2.c | 62 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 60 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index 8f8ea57..8006ac0 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -148,6 +148,64 @@ static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
 	}
 }
 
+static unsigned long vgic_mmio_read_sgipend(struct kvm_vcpu *vcpu,
+					    gpa_t addr, unsigned int len)
+{
+	u32 intid = addr & 0x0f;
+	int i;
+	u64 val = 0;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		val |= (u64)irq->source << (i * 8);
+	}
+	return val;
+}
+
+static void vgic_mmio_write_sgipendc(struct kvm_vcpu *vcpu,
+				     gpa_t addr, unsigned int len,
+				     unsigned long val)
+{
+	u32 intid = addr & 0x0f;
+	int i;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		irq->source &= ~((val >> (i * 8)) & 0xff);
+		if (!irq->source)
+			irq->pending = false;
+
+		spin_unlock(&irq->irq_lock);
+	}
+}
+
+static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
+				     gpa_t addr, unsigned int len,
+				     unsigned long val)
+{
+	u32 intid = addr & 0x0f;
+	int i;
+
+	for (i = 0; i < len; i++) {
+		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+		spin_lock(&irq->irq_lock);
+
+		irq->source |= (val >> (i * 8)) & 0xff;
+
+		if (irq->source) {
+			irq->pending = true;
+			vgic_queue_irq_unlock(vcpu->kvm, irq);
+		} else {
+			spin_unlock(&irq->irq_lock);
+		}
+	}
+}
+
 static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -174,9 +232,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
 		vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+		vgic_mmio_read_sgipend, vgic_mmio_write_sgipendc, 16),
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
 };
 
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
-- 
2.7.3

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

* [PATCH v3 32/55] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Create a new file called vgic-mmio-v3.c and describe the GICv3
distributor and redistributor registers there.
This adds a special macro to deal with the split of SGI/PPI in the
redistributor and SPIs in the distributor, which allows us to reuse
the existing GICv2 handlers for those registers which are compatible.
Also we provide a function to deal with the registration of the two
separate redistributor frames per VCPU.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
Changelog RFC..v1:
- adapt to new MMIO registration approach:
  register one device for the distributor and two for each VCPU
- implement special handling for private interrupts
- remove empty stub functions
- make IGROUPR return RAO

Changelog v1 .. v2:
- adapt to new framework, introduce vgic-mmio-v3.c
- remove userland register access functions (for now)
- precompute .len when describing a VGIC register
- add missed pointer incrementation on registering redist regions
- replace _nyi stub functions with raz/wi versions

Changelog v2 .. v3:
- replace inclusion of kvm/vgic/vgic.h with kvm/arm_vgic.h
- add prototype and stub code for vgic_register_redist_iodevs
- rename register struct variables _rdbase_ and _sgibase_

 virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.c    |   5 +
 virt/kvm/arm/vgic/vgic-mmio.h    |   2 +
 virt/kvm/arm/vgic/vgic.h         |   7 ++
 4 files changed, 205 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
new file mode 100644
index 0000000..06c7ec5
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -0,0 +1,191 @@
+/*
+ * VGICv3 MMIO 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 <kvm/iodev.h>
+#include <kvm/arm_vgic.h>
+
+#include <asm/kvm_emulate.h>
+
+#include "vgic.h"
+#include "vgic-mmio.h"
+
+/*
+ * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
+ * redistributors, while SPIs are covered by registers in the distributor
+ * block. Trying to set private IRQs in this block gets ignored.
+ * We take some special care here to fix the calculation of the register
+ * offset.
+ */
+#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, read_ops, write_ops, bpi) \
+	{								\
+		.reg_offset = off,					\
+		.bits_per_irq = bpi,					\
+		.len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8,		\
+		.read = vgic_mmio_read_raz,				\
+		.write = vgic_mmio_write_wi,				\
+	}, {								\
+		.reg_offset = off + (bpi * VGIC_NR_PRIVATE_IRQS) / 8,	\
+		.bits_per_irq = bpi,					\
+		.len = (bpi * (1024 - VGIC_NR_PRIVATE_IRQS)) / 8,	\
+		.read = read_ops,					\
+		.write = write_ops,					\
+	}
+
+static const struct vgic_register_region vgic_v3_dist_registers[] = {
+	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
+		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
+		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
+		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
+		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
+		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
+		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
+		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
+		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
+		vgic_mmio_read_config, vgic_mmio_write_config, 2),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
+	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
+};
+
+static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
+	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
+};
+
+static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
+	REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
+		vgic_mmio_read_rao, vgic_mmio_write_wi, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
+		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
+		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
+		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
+		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
+		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
+		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
+		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
+		vgic_mmio_read_config, vgic_mmio_write_config, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+};
+
+unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
+{
+	dev->regions = vgic_v3_dist_registers;
+	dev->nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
+
+	kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
+
+	return SZ_64K;
+}
+
+int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
+{
+	int nr_vcpus = atomic_read(&kvm->online_vcpus);
+	struct kvm_vcpu *vcpu;
+	struct vgic_io_device *devices, *device;
+	int c, ret = 0;
+
+	devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
+			  GFP_KERNEL);
+	if (!devices)
+		return -ENOMEM;
+
+	device = devices;
+	kvm_for_each_vcpu(c, vcpu, kvm) {
+		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
+		device->base_addr = redist_base_address;
+		device->regions = vgic_v3_rdbase_registers;
+		device->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
+		device->redist_vcpu = vcpu;
+
+		mutex_lock(&kvm->slots_lock);
+		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
+					      redist_base_address,
+					      SZ_64K, &device->dev);
+		mutex_unlock(&kvm->slots_lock);
+
+		if (ret)
+			break;
+
+		device++;
+		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
+		device->base_addr = redist_base_address + SZ_64K;
+		device->regions = vgic_v3_sgibase_registers;
+		device->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
+		device->redist_vcpu = vcpu;
+
+		mutex_lock(&kvm->slots_lock);
+		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
+					      redist_base_address + SZ_64K,
+					      SZ_64K, &device->dev);
+		mutex_unlock(&kvm->slots_lock);
+		if (ret) {
+			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
+						  &devices[c * 2].dev);
+			break;
+		}
+		device++;
+		redist_base_address += 2 * SZ_64K;
+	}
+
+	if (ret) {
+		for (c--; c >= 0; c--) {
+			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
+						  &devices[c * 2].dev);
+			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
+						  &devices[c * 2 + 1].dev);
+		}
+		kfree(devices);
+	} else {
+		kvm->arch.vgic.redist_iodevs = devices;
+	}
+
+	return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 19fed56..d1b88d2 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -502,6 +502,11 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
 	case VGIC_V2:
 		len = vgic_v2_init_dist_iodev(io_device);
 		break;
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+	case VGIC_V3:
+		len = vgic_v3_init_dist_iodev(io_device);
+		break;
+#endif
 	default:
 		BUG_ON(1);
 	}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 884eb71..3585ac6 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -123,4 +123,6 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
 
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
+unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
+
 #endif
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index cf62015..39a8a65 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -40,6 +40,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
 void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
+int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
 #else
 static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
 {
@@ -61,6 +62,12 @@ static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
 static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
 {
 }
+
+static inline int vgic_register_redist_iodevs(struct kvm *kvm,
+					      gpa_t dist_base_address)
+{
+	return -ENODEV;
+}
 #endif
 
 #endif
-- 
2.7.3

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

* [PATCH v3 32/55] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

Create a new file called vgic-mmio-v3.c and describe the GICv3
distributor and redistributor registers there.
This adds a special macro to deal with the split of SGI/PPI in the
redistributor and SPIs in the distributor, which allows us to reuse
the existing GICv2 handlers for those registers which are compatible.
Also we provide a function to deal with the registration of the two
separate redistributor frames per VCPU.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
---
Changelog RFC..v1:
- adapt to new MMIO registration approach:
  register one device for the distributor and two for each VCPU
- implement special handling for private interrupts
- remove empty stub functions
- make IGROUPR return RAO

Changelog v1 .. v2:
- adapt to new framework, introduce vgic-mmio-v3.c
- remove userland register access functions (for now)
- precompute .len when describing a VGIC register
- add missed pointer incrementation on registering redist regions
- replace _nyi stub functions with raz/wi versions

Changelog v2 .. v3:
- replace inclusion of kvm/vgic/vgic.h with kvm/arm_vgic.h
- add prototype and stub code for vgic_register_redist_iodevs
- rename register struct variables _rdbase_ and _sgibase_

 virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-mmio.c    |   5 +
 virt/kvm/arm/vgic/vgic-mmio.h    |   2 +
 virt/kvm/arm/vgic/vgic.h         |   7 ++
 4 files changed, 205 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
new file mode 100644
index 0000000..06c7ec5
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -0,0 +1,191 @@
+/*
+ * VGICv3 MMIO 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 <kvm/iodev.h>
+#include <kvm/arm_vgic.h>
+
+#include <asm/kvm_emulate.h>
+
+#include "vgic.h"
+#include "vgic-mmio.h"
+
+/*
+ * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
+ * redistributors, while SPIs are covered by registers in the distributor
+ * block. Trying to set private IRQs in this block gets ignored.
+ * We take some special care here to fix the calculation of the register
+ * offset.
+ */
+#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, read_ops, write_ops, bpi) \
+	{								\
+		.reg_offset = off,					\
+		.bits_per_irq = bpi,					\
+		.len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8,		\
+		.read = vgic_mmio_read_raz,				\
+		.write = vgic_mmio_write_wi,				\
+	}, {								\
+		.reg_offset = off + (bpi * VGIC_NR_PRIVATE_IRQS) / 8,	\
+		.bits_per_irq = bpi,					\
+		.len = (bpi * (1024 - VGIC_NR_PRIVATE_IRQS)) / 8,	\
+		.read = read_ops,					\
+		.write = write_ops,					\
+	}
+
+static const struct vgic_register_region vgic_v3_dist_registers[] = {
+	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
+		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
+		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
+		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
+		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
+		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
+		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
+		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
+		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
+		vgic_mmio_read_config, vgic_mmio_write_config, 2),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
+	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
+	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
+};
+
+static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
+	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
+};
+
+static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
+	REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
+		vgic_mmio_read_rao, vgic_mmio_write_wi, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
+		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
+		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
+		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
+		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
+		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
+		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
+		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
+	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
+		vgic_mmio_read_config, vgic_mmio_write_config, 8),
+	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+};
+
+unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
+{
+	dev->regions = vgic_v3_dist_registers;
+	dev->nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
+
+	kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
+
+	return SZ_64K;
+}
+
+int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
+{
+	int nr_vcpus = atomic_read(&kvm->online_vcpus);
+	struct kvm_vcpu *vcpu;
+	struct vgic_io_device *devices, *device;
+	int c, ret = 0;
+
+	devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
+			  GFP_KERNEL);
+	if (!devices)
+		return -ENOMEM;
+
+	device = devices;
+	kvm_for_each_vcpu(c, vcpu, kvm) {
+		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
+		device->base_addr = redist_base_address;
+		device->regions = vgic_v3_rdbase_registers;
+		device->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
+		device->redist_vcpu = vcpu;
+
+		mutex_lock(&kvm->slots_lock);
+		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
+					      redist_base_address,
+					      SZ_64K, &device->dev);
+		mutex_unlock(&kvm->slots_lock);
+
+		if (ret)
+			break;
+
+		device++;
+		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
+		device->base_addr = redist_base_address + SZ_64K;
+		device->regions = vgic_v3_sgibase_registers;
+		device->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
+		device->redist_vcpu = vcpu;
+
+		mutex_lock(&kvm->slots_lock);
+		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
+					      redist_base_address + SZ_64K,
+					      SZ_64K, &device->dev);
+		mutex_unlock(&kvm->slots_lock);
+		if (ret) {
+			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
+						  &devices[c * 2].dev);
+			break;
+		}
+		device++;
+		redist_base_address += 2 * SZ_64K;
+	}
+
+	if (ret) {
+		for (c--; c >= 0; c--) {
+			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
+						  &devices[c * 2].dev);
+			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
+						  &devices[c * 2 + 1].dev);
+		}
+		kfree(devices);
+	} else {
+		kvm->arch.vgic.redist_iodevs = devices;
+	}
+
+	return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 19fed56..d1b88d2 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -502,6 +502,11 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
 	case VGIC_V2:
 		len = vgic_v2_init_dist_iodev(io_device);
 		break;
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+	case VGIC_V3:
+		len = vgic_v3_init_dist_iodev(io_device);
+		break;
+#endif
 	default:
 		BUG_ON(1);
 	}
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 884eb71..3585ac6 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -123,4 +123,6 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
 
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
+unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
+
 #endif
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index cf62015..39a8a65 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -40,6 +40,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
 void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
+int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
 #else
 static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
 {
@@ -61,6 +62,12 @@ static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
 static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
 {
 }
+
+static inline int vgic_register_redist_iodevs(struct kvm *kvm,
+					      gpa_t dist_base_address)
+{
+	return -ENODEV;
+}
 #endif
 
 #endif
-- 
2.7.3

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

* [PATCH v3 33/55] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

As in the GICv2 emulation we handle those three registers in one
function.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- kick VCPUs if distributor gets enabled

Changelog v1 .. v2:
- rewrite write handler to use switch statement

 virt/kvm/arm/vgic/vgic-mmio-v3.c | 50 +++++++++++++++++++++++++++++++++++++++-
 virt/kvm/arm/vgic/vgic.h         |  2 ++
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 06c7ec5..5f4558c 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -22,6 +22,54 @@
 #include "vgic.h"
 #include "vgic-mmio.h"
 
+static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
+					    gpa_t addr, unsigned int len)
+{
+	u32 value = 0;
+
+	switch (addr & 0x0c) {
+	case GICD_CTLR:
+		if (vcpu->kvm->arch.vgic.enabled)
+			value |= GICD_CTLR_ENABLE_SS_G1;
+		value |= GICD_CTLR_ARE_NS | GICD_CTLR_DS;
+		break;
+	case GICD_TYPER:
+		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+		value = (value >> 5) - 1;
+		value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
+		break;
+	case GICD_IIDR:
+		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
+		break;
+	default:
+		return 0;
+	}
+
+	return extract_bytes(value, addr & 3, len);
+}
+
+static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
+				    gpa_t addr, unsigned int len,
+				    unsigned long val)
+{
+	switch (addr & 0x0c) {
+	case GICD_CTLR:
+		if (!(addr & 1)) {
+			struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+			bool was_enabled = dist->enabled;
+
+			dist->enabled = val & GICD_CTLR_ENABLE_SS_G1;
+
+			if (!was_enabled && dist->enabled)
+				vgic_kick_vcpus(vcpu->kvm);
+		}
+		break;
+	case GICD_TYPER:
+	case GICD_IIDR:
+		return;
+	}
+}
+
 /*
  * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
  * redistributors, while SPIs are covered by registers in the distributor
@@ -46,7 +94,7 @@
 
 static const struct vgic_register_region vgic_v3_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
 		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 39a8a65..635e2e2 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -19,6 +19,8 @@
 #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
 #define IMPLEMENTER_ARM		0x43b
 
+#define INTERRUPT_ID_BITS_SPIS	10
+
 #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
 
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
-- 
2.7.3

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

* [PATCH v3 33/55] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

As in the GICv2 emulation we handle those three registers in one
function.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- kick VCPUs if distributor gets enabled

Changelog v1 .. v2:
- rewrite write handler to use switch statement

 virt/kvm/arm/vgic/vgic-mmio-v3.c | 50 +++++++++++++++++++++++++++++++++++++++-
 virt/kvm/arm/vgic/vgic.h         |  2 ++
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 06c7ec5..5f4558c 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -22,6 +22,54 @@
 #include "vgic.h"
 #include "vgic-mmio.h"
 
+static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
+					    gpa_t addr, unsigned int len)
+{
+	u32 value = 0;
+
+	switch (addr & 0x0c) {
+	case GICD_CTLR:
+		if (vcpu->kvm->arch.vgic.enabled)
+			value |= GICD_CTLR_ENABLE_SS_G1;
+		value |= GICD_CTLR_ARE_NS | GICD_CTLR_DS;
+		break;
+	case GICD_TYPER:
+		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+		value = (value >> 5) - 1;
+		value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
+		break;
+	case GICD_IIDR:
+		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
+		break;
+	default:
+		return 0;
+	}
+
+	return extract_bytes(value, addr & 3, len);
+}
+
+static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
+				    gpa_t addr, unsigned int len,
+				    unsigned long val)
+{
+	switch (addr & 0x0c) {
+	case GICD_CTLR:
+		if (!(addr & 1)) {
+			struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+			bool was_enabled = dist->enabled;
+
+			dist->enabled = val & GICD_CTLR_ENABLE_SS_G1;
+
+			if (!was_enabled && dist->enabled)
+				vgic_kick_vcpus(vcpu->kvm);
+		}
+		break;
+	case GICD_TYPER:
+	case GICD_IIDR:
+		return;
+	}
+}
+
 /*
  * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
  * redistributors, while SPIs are covered by registers in the distributor
@@ -46,7 +94,7 @@
 
 static const struct vgic_register_region vgic_v3_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
 		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 39a8a65..635e2e2 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -19,6 +19,8 @@
 #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
 #define IMPLEMENTER_ARM		0x43b
 
+#define INTERRUPT_ID_BITS_SPIS	10
+
 #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
 
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
-- 
2.7.3

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

* [PATCH v3 34/55] KVM: arm/arm64: vgic-new: Add GICv3 redistributor IIDR and TYPER handler
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

The redistributor TYPER tells the OS about the associated MPIDR,
also the LAST bit is crucial to determine the number of redistributors.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v3.c | 44 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 42 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 5f4558c..d137242 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -71,6 +71,46 @@ static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
 }
 
 /*
+ * We use a compressed version of the MPIDR (all 32 bits in one 32-bit word)
+ * when we store the target MPIDR written by the guest.
+ */
+static u32 compress_mpidr(unsigned long mpidr)
+{
+	u32 ret;
+
+	ret = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	ret |= MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8;
+	ret |= MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16;
+	ret |= MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24;
+
+	return ret;
+}
+
+static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
+					      gpa_t addr, unsigned int len)
+{
+	unsigned long mpidr = kvm_vcpu_get_mpidr_aff(vcpu);
+	int target_vcpu_id = vcpu->vcpu_id;
+	u64 value;
+
+	value = (u64)compress_mpidr(mpidr) << 32;
+	value |= ((target_vcpu_id & 0xffff) << 8);
+	if (target_vcpu_id == atomic_read(&vcpu->kvm->online_vcpus) - 1)
+		value |= GICR_TYPER_LAST;
+
+	return extract_bytes(value, addr & 7, len);
+}
+
+static unsigned long vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
+					     gpa_t addr, unsigned int len)
+{
+	u32 value;
+
+	value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
+	return extract_bytes(value, addr & 3, len);
+}
+
+/*
  * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
  * redistributors, while SPIs are covered by registers in the distributor
  * block. Trying to set private IRQs in this block gets ignored.
@@ -127,9 +167,9 @@ static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
 	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+		vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4),
 	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+		vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8),
 	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
 	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
-- 
2.7.3

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

* [PATCH v3 34/55] KVM: arm/arm64: vgic-new: Add GICv3 redistributor IIDR and TYPER handler
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

The redistributor TYPER tells the OS about the associated MPIDR,
also the LAST bit is crucial to determine the number of redistributors.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v3.c | 44 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 42 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 5f4558c..d137242 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -71,6 +71,46 @@ static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
 }
 
 /*
+ * We use a compressed version of the MPIDR (all 32 bits in one 32-bit word)
+ * when we store the target MPIDR written by the guest.
+ */
+static u32 compress_mpidr(unsigned long mpidr)
+{
+	u32 ret;
+
+	ret = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	ret |= MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8;
+	ret |= MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16;
+	ret |= MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24;
+
+	return ret;
+}
+
+static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
+					      gpa_t addr, unsigned int len)
+{
+	unsigned long mpidr = kvm_vcpu_get_mpidr_aff(vcpu);
+	int target_vcpu_id = vcpu->vcpu_id;
+	u64 value;
+
+	value = (u64)compress_mpidr(mpidr) << 32;
+	value |= ((target_vcpu_id & 0xffff) << 8);
+	if (target_vcpu_id == atomic_read(&vcpu->kvm->online_vcpus) - 1)
+		value |= GICR_TYPER_LAST;
+
+	return extract_bytes(value, addr & 7, len);
+}
+
+static unsigned long vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
+					     gpa_t addr, unsigned int len)
+{
+	u32 value;
+
+	value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
+	return extract_bytes(value, addr & 3, len);
+}
+
+/*
  * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
  * redistributors, while SPIs are covered by registers in the distributor
  * block. Trying to set private IRQs in this block gets ignored.
@@ -127,9 +167,9 @@ static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
 	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
+		vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4),
 	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
+		vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8),
 	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
 	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
-- 
2.7.3

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

* [PATCH v3 35/55] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

We implement the only one ID register that is required by the
architecture, also this is the one that Linux actually checks.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v3.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index d137242..48fba9c 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -110,6 +110,22 @@ static unsigned long vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
 	return extract_bytes(value, addr & 3, len);
 }
 
+static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
+					      gpa_t addr, unsigned int len)
+{
+	u32 regnr = (addr & 0x3f) - (GICD_IDREGS & 0x3f);
+	u32 reg = 0;
+
+	switch (regnr + GICD_IDREGS) {
+	case GICD_PIDR2:
+		/* report a GICv3 compliant implementation */
+		reg = 0x3b;
+		break;
+	}
+
+	return extract_bytes(reg, addr & 3, len);
+}
+
 /*
  * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
  * redistributors, while SPIs are covered by registers in the distributor
@@ -160,7 +176,7 @@ static const struct vgic_register_region vgic_v3_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
 	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
+		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
 };
 
 static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
@@ -175,7 +191,7 @@ static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
 	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
+		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
 };
 
 static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
-- 
2.7.3

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

* [PATCH v3 35/55] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

We implement the only one ID register that is required by the
architecture, also this is the one that Linux actually checks.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v3.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index d137242..48fba9c 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -110,6 +110,22 @@ static unsigned long vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
 	return extract_bytes(value, addr & 3, len);
 }
 
+static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
+					      gpa_t addr, unsigned int len)
+{
+	u32 regnr = (addr & 0x3f) - (GICD_IDREGS & 0x3f);
+	u32 reg = 0;
+
+	switch (regnr + GICD_IDREGS) {
+	case GICD_PIDR2:
+		/* report a GICv3 compliant implementation */
+		reg = 0x3b;
+		break;
+	}
+
+	return extract_bytes(reg, addr & 3, len);
+}
+
 /*
  * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
  * redistributors, while SPIs are covered by registers in the distributor
@@ -160,7 +176,7 @@ static const struct vgic_register_region vgic_v3_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
 	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
+		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
 };
 
 static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
@@ -175,7 +191,7 @@ static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
 	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
+		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
 };
 
 static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
-- 
2.7.3

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

* [PATCH v3 36/55] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Since GICv3 supports much more than the 8 CPUs the GICv2 ITARGETSR
register can handle, the new IROUTER register covers the whole range
of possible target (V)CPUs by using the same MPIDR that the cores
report themselves.
In addition to translating this MPIDR into a vcpu pointer we store
the originally written value as well. The architecture allows to
write any values into the register, which must be read back as written.

Since we don't support affinity level 3, we don't need to take care
about the upper word of this 64-bit register, which simplifies the
handling a bit.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- fold in and simplify vgic_v3_irq_change_affinity

Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v3.c | 65 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 64 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 48fba9c..3bcc2c4 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -86,6 +86,69 @@ static u32 compress_mpidr(unsigned long mpidr)
 	return ret;
 }
 
+static unsigned long decompress_mpidr(u32 value)
+{
+	unsigned long mpidr;
+
+	mpidr  = ((value >>  0) & 0xFF) << MPIDR_LEVEL_SHIFT(0);
+	mpidr |= ((value >>  8) & 0xFF) << MPIDR_LEVEL_SHIFT(1);
+	mpidr |= ((value >> 16) & 0xFF) << MPIDR_LEVEL_SHIFT(2);
+	mpidr |= (u64)((value >> 24) & 0xFF) << MPIDR_LEVEL_SHIFT(3);
+
+	return mpidr;
+}
+
+static unsigned long vgic_mmio_read_irouter(struct kvm_vcpu *vcpu,
+					    gpa_t addr, unsigned int len)
+{
+	int intid = (addr & 0x1fff) / 8;
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
+	unsigned long mpidr;
+
+	if (!irq)
+		return 0;
+
+	mpidr = decompress_mpidr(irq->mpidr);
+	return extract_bytes(mpidr, addr & 7, len);
+}
+
+static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
+				    gpa_t addr, unsigned int len,
+				    unsigned long val)
+{
+	int intid = (addr & 0x1fff) / 8;
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
+	unsigned long mask = 0xffffffff;	/* upper word is WI */
+	u64 mpidr;
+
+	if (!irq)
+		return;
+
+	/*
+	 * There are only two supported options:
+	 * (1) aligned 64-bit access
+	 * (2) aligned 32-bit access
+	 *
+	 * TODO: make this check generic and move it to dispatch_...()
+	 */
+	if (len != 4 && len != 8)
+		return;
+
+
+	/* The upper word is WI for us since we don't implement Aff3. */
+	if (addr & 4)
+		return;
+
+	spin_lock(&irq->irq_lock);
+
+	mpidr = decompress_mpidr(irq->mpidr);
+	mpidr = (mpidr & ~mask) | (val & mask);
+	irq->mpidr = compress_mpidr(mpidr);
+	irq->target_vcpu = kvm_mpidr_to_vcpu(vcpu->kvm, mpidr);
+
+	spin_unlock(&irq->irq_lock);
+}
+
 static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
 					      gpa_t addr, unsigned int len)
 {
@@ -174,7 +237,7 @@ static const struct vgic_register_region vgic_v3_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
+		vgic_mmio_read_irouter, vgic_mmio_write_irouter, 64),
 	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
 		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
 };
-- 
2.7.3

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

* [PATCH v3 36/55] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

Since GICv3 supports much more than the 8 CPUs the GICv2 ITARGETSR
register can handle, the new IROUTER register covers the whole range
of possible target (V)CPUs by using the same MPIDR that the cores
report themselves.
In addition to translating this MPIDR into a vcpu pointer we store
the originally written value as well. The architecture allows to
write any values into the register, which must be read back as written.

Since we don't support affinity level 3, we don't need to take care
about the upper word of this 64-bit register, which simplifies the
handling a bit.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- fold in and simplify vgic_v3_irq_change_affinity

Changelog v1 .. v2:
- adapt to new MMIO framework

 virt/kvm/arm/vgic/vgic-mmio-v3.c | 65 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 64 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 48fba9c..3bcc2c4 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -86,6 +86,69 @@ static u32 compress_mpidr(unsigned long mpidr)
 	return ret;
 }
 
+static unsigned long decompress_mpidr(u32 value)
+{
+	unsigned long mpidr;
+
+	mpidr  = ((value >>  0) & 0xFF) << MPIDR_LEVEL_SHIFT(0);
+	mpidr |= ((value >>  8) & 0xFF) << MPIDR_LEVEL_SHIFT(1);
+	mpidr |= ((value >> 16) & 0xFF) << MPIDR_LEVEL_SHIFT(2);
+	mpidr |= (u64)((value >> 24) & 0xFF) << MPIDR_LEVEL_SHIFT(3);
+
+	return mpidr;
+}
+
+static unsigned long vgic_mmio_read_irouter(struct kvm_vcpu *vcpu,
+					    gpa_t addr, unsigned int len)
+{
+	int intid = (addr & 0x1fff) / 8;
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
+	unsigned long mpidr;
+
+	if (!irq)
+		return 0;
+
+	mpidr = decompress_mpidr(irq->mpidr);
+	return extract_bytes(mpidr, addr & 7, len);
+}
+
+static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
+				    gpa_t addr, unsigned int len,
+				    unsigned long val)
+{
+	int intid = (addr & 0x1fff) / 8;
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
+	unsigned long mask = 0xffffffff;	/* upper word is WI */
+	u64 mpidr;
+
+	if (!irq)
+		return;
+
+	/*
+	 * There are only two supported options:
+	 * (1) aligned 64-bit access
+	 * (2) aligned 32-bit access
+	 *
+	 * TODO: make this check generic and move it to dispatch_...()
+	 */
+	if (len != 4 && len != 8)
+		return;
+
+
+	/* The upper word is WI for us since we don't implement Aff3. */
+	if (addr & 4)
+		return;
+
+	spin_lock(&irq->irq_lock);
+
+	mpidr = decompress_mpidr(irq->mpidr);
+	mpidr = (mpidr & ~mask) | (val & mask);
+	irq->mpidr = compress_mpidr(mpidr);
+	irq->target_vcpu = kvm_mpidr_to_vcpu(vcpu->kvm, mpidr);
+
+	spin_unlock(&irq->irq_lock);
+}
+
 static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
 					      gpa_t addr, unsigned int len)
 {
@@ -174,7 +237,7 @@ static const struct vgic_register_region vgic_v3_dist_registers[] = {
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
 		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
 	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
-		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
+		vgic_mmio_read_irouter, vgic_mmio_write_irouter, 64),
 	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
 		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
 };
-- 
2.7.3

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

* [PATCH v3 37/55] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

In contrast to GICv2 SGIs in a GICv3 implementation are not triggered
by a MMIO write, but with a system register write. KVM knows about
that register already, we just need to implement the handler and wire
it up to the core KVM/ARM code.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- add comment about SGI_AFFINITY_LEVEL macro

 include/kvm/vgic/vgic.h          |   8 +++
 virt/kvm/arm/vgic/vgic-mmio-v3.c | 106 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 114 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 4ec1270..2c43eb8 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -209,6 +209,14 @@ bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
 void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
 void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
 
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
+#else
+static inline void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
+{
+}
+#endif
+
 /**
  * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
  *
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 3bcc2c4..af12592 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -356,3 +356,109 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
 
 	return ret;
 }
+
+/*
+ * Compare a given affinity (level 1-3 and a level 0 mask, from the SGI
+ * generation register ICC_SGI1R_EL1) with a given VCPU.
+ * If the VCPU's MPIDR matches, return the level0 affinity, otherwise
+ * return -1.
+ */
+static int match_mpidr(u64 sgi_aff, u16 sgi_cpu_mask, struct kvm_vcpu *vcpu)
+{
+	unsigned long affinity;
+	int level0;
+
+	/*
+	 * Split the current VCPU's MPIDR into affinity level 0 and the
+	 * rest as this is what we have to compare against.
+	 */
+	affinity = kvm_vcpu_get_mpidr_aff(vcpu);
+	level0 = MPIDR_AFFINITY_LEVEL(affinity, 0);
+	affinity &= ~MPIDR_LEVEL_MASK;
+
+	/* bail out if the upper three levels don't match */
+	if (sgi_aff != affinity)
+		return -1;
+
+	/* Is this VCPU's bit set in the mask ? */
+	if (!(sgi_cpu_mask & BIT(level0)))
+		return -1;
+
+	return level0;
+}
+
+/*
+ * The ICC_SGI* registers encode the affinity differently from the MPIDR,
+ * so provide a wrapper to use the existing defines to isolate a certain
+ * affinity level.
+ */
+#define SGI_AFFINITY_LEVEL(reg, level) \
+	((((reg) & ICC_SGI1R_AFFINITY_## level ##_MASK) \
+	>> ICC_SGI1R_AFFINITY_## level ##_SHIFT) << MPIDR_LEVEL_SHIFT(level))
+
+/**
+ * vgic_v3_dispatch_sgi - handle SGI requests from VCPUs
+ * @vcpu: The VCPU requesting a SGI
+ * @reg: The value written into the ICC_SGI1R_EL1 register by that VCPU
+ *
+ * With GICv3 (and ARE=1) CPUs trigger SGIs by writing to a system register.
+ * This will trap in sys_regs.c and call this function.
+ * This ICC_SGI1R_EL1 register contains the upper three affinity levels of the
+ * target processors as well as a bitmask of 16 Aff0 CPUs.
+ * If the interrupt routing mode bit is not set, we iterate over all VCPUs to
+ * check for matching ones. If this bit is set, we signal all, but not the
+ * calling VCPU.
+ */
+void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
+{
+	struct kvm *kvm = vcpu->kvm;
+	struct kvm_vcpu *c_vcpu;
+	u16 target_cpus;
+	u64 mpidr;
+	int sgi, c;
+	int vcpu_id = vcpu->vcpu_id;
+	bool broadcast;
+
+	sgi = (reg & ICC_SGI1R_SGI_ID_MASK) >> ICC_SGI1R_SGI_ID_SHIFT;
+	broadcast = reg & BIT(ICC_SGI1R_IRQ_ROUTING_MODE_BIT);
+	target_cpus = (reg & ICC_SGI1R_TARGET_LIST_MASK) >> ICC_SGI1R_TARGET_LIST_SHIFT;
+	mpidr = SGI_AFFINITY_LEVEL(reg, 3);
+	mpidr |= SGI_AFFINITY_LEVEL(reg, 2);
+	mpidr |= SGI_AFFINITY_LEVEL(reg, 1);
+
+	/*
+	 * We iterate over all VCPUs to find the MPIDRs matching the request.
+	 * If we have handled one CPU, we clear its bit to detect early
+	 * if we are already finished. This avoids iterating through all
+	 * VCPUs when most of the times we just signal a single VCPU.
+	 */
+	kvm_for_each_vcpu(c, c_vcpu, kvm) {
+		struct vgic_irq *irq;
+
+		/* Exit early if we have dealt with all requested CPUs */
+		if (!broadcast && target_cpus == 0)
+			break;
+
+		/* Don't signal the calling VCPU */
+		if (broadcast && c == vcpu_id)
+			continue;
+
+		if (!broadcast) {
+			int level0;
+
+			level0 = match_mpidr(mpidr, target_cpus, c_vcpu);
+			if (level0 == -1)
+				continue;
+
+			/* remove this matching VCPU from the mask */
+			target_cpus &= ~BIT(level0);
+		}
+
+		irq = vgic_get_irq(vcpu->kvm, c_vcpu, sgi);
+
+		spin_lock(&irq->irq_lock);
+		irq->pending = true;
+
+		vgic_queue_irq_unlock(vcpu->kvm, irq);
+	}
+}
-- 
2.7.3

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

* [PATCH v3 37/55] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

In contrast to GICv2 SGIs in a GICv3 implementation are not triggered
by a MMIO write, but with a system register write. KVM knows about
that register already, we just need to implement the handler and wire
it up to the core KVM/ARM code.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- add comment about SGI_AFFINITY_LEVEL macro

 include/kvm/vgic/vgic.h          |   8 +++
 virt/kvm/arm/vgic/vgic-mmio-v3.c | 106 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 114 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 4ec1270..2c43eb8 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -209,6 +209,14 @@ bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
 void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
 void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
 
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
+#else
+static inline void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
+{
+}
+#endif
+
 /**
  * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
  *
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 3bcc2c4..af12592 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -356,3 +356,109 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
 
 	return ret;
 }
+
+/*
+ * Compare a given affinity (level 1-3 and a level 0 mask, from the SGI
+ * generation register ICC_SGI1R_EL1) with a given VCPU.
+ * If the VCPU's MPIDR matches, return the level0 affinity, otherwise
+ * return -1.
+ */
+static int match_mpidr(u64 sgi_aff, u16 sgi_cpu_mask, struct kvm_vcpu *vcpu)
+{
+	unsigned long affinity;
+	int level0;
+
+	/*
+	 * Split the current VCPU's MPIDR into affinity level 0 and the
+	 * rest as this is what we have to compare against.
+	 */
+	affinity = kvm_vcpu_get_mpidr_aff(vcpu);
+	level0 = MPIDR_AFFINITY_LEVEL(affinity, 0);
+	affinity &= ~MPIDR_LEVEL_MASK;
+
+	/* bail out if the upper three levels don't match */
+	if (sgi_aff != affinity)
+		return -1;
+
+	/* Is this VCPU's bit set in the mask ? */
+	if (!(sgi_cpu_mask & BIT(level0)))
+		return -1;
+
+	return level0;
+}
+
+/*
+ * The ICC_SGI* registers encode the affinity differently from the MPIDR,
+ * so provide a wrapper to use the existing defines to isolate a certain
+ * affinity level.
+ */
+#define SGI_AFFINITY_LEVEL(reg, level) \
+	((((reg) & ICC_SGI1R_AFFINITY_## level ##_MASK) \
+	>> ICC_SGI1R_AFFINITY_## level ##_SHIFT) << MPIDR_LEVEL_SHIFT(level))
+
+/**
+ * vgic_v3_dispatch_sgi - handle SGI requests from VCPUs
+ * @vcpu: The VCPU requesting a SGI
+ * @reg: The value written into the ICC_SGI1R_EL1 register by that VCPU
+ *
+ * With GICv3 (and ARE=1) CPUs trigger SGIs by writing to a system register.
+ * This will trap in sys_regs.c and call this function.
+ * This ICC_SGI1R_EL1 register contains the upper three affinity levels of the
+ * target processors as well as a bitmask of 16 Aff0 CPUs.
+ * If the interrupt routing mode bit is not set, we iterate over all VCPUs to
+ * check for matching ones. If this bit is set, we signal all, but not the
+ * calling VCPU.
+ */
+void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
+{
+	struct kvm *kvm = vcpu->kvm;
+	struct kvm_vcpu *c_vcpu;
+	u16 target_cpus;
+	u64 mpidr;
+	int sgi, c;
+	int vcpu_id = vcpu->vcpu_id;
+	bool broadcast;
+
+	sgi = (reg & ICC_SGI1R_SGI_ID_MASK) >> ICC_SGI1R_SGI_ID_SHIFT;
+	broadcast = reg & BIT(ICC_SGI1R_IRQ_ROUTING_MODE_BIT);
+	target_cpus = (reg & ICC_SGI1R_TARGET_LIST_MASK) >> ICC_SGI1R_TARGET_LIST_SHIFT;
+	mpidr = SGI_AFFINITY_LEVEL(reg, 3);
+	mpidr |= SGI_AFFINITY_LEVEL(reg, 2);
+	mpidr |= SGI_AFFINITY_LEVEL(reg, 1);
+
+	/*
+	 * We iterate over all VCPUs to find the MPIDRs matching the request.
+	 * If we have handled one CPU, we clear its bit to detect early
+	 * if we are already finished. This avoids iterating through all
+	 * VCPUs when most of the times we just signal a single VCPU.
+	 */
+	kvm_for_each_vcpu(c, c_vcpu, kvm) {
+		struct vgic_irq *irq;
+
+		/* Exit early if we have dealt with all requested CPUs */
+		if (!broadcast && target_cpus == 0)
+			break;
+
+		/* Don't signal the calling VCPU */
+		if (broadcast && c == vcpu_id)
+			continue;
+
+		if (!broadcast) {
+			int level0;
+
+			level0 = match_mpidr(mpidr, target_cpus, c_vcpu);
+			if (level0 == -1)
+				continue;
+
+			/* remove this matching VCPU from the mask */
+			target_cpus &= ~BIT(level0);
+		}
+
+		irq = vgic_get_irq(vcpu->kvm, c_vcpu, sgi);
+
+		spin_lock(&irq->irq_lock);
+		irq->pending = true;
+
+		vgic_queue_irq_unlock(vcpu->kvm, irq);
+	}
+}
-- 
2.7.3

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

* [PATCH v3 38/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

This patch introduces the skeleton for the KVM device operations
associated to KVM_DEV_TYPE_ARM_VGIC_V2 and KVM_DEV_TYPE_ARM_VGIC_V3.

At that stage kvm_vgic_create is stubbed.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- rename vgic_kvm_device.c to vgic-kvm-device.c

Changelog v2 .. v3:
- replace inclusion of vgic/vgic.h with arm_vgic.h
- add kvm_register_vgic_device() prototype to this patch

 virt/kvm/arm/vgic/vgic-kvm-device.c | 108 ++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h            |   2 +
 2 files changed, 110 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic-kvm-device.c

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
new file mode 100644
index 0000000..ff332f3
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -0,0 +1,108 @@
+/*
+ * VGIC: KVM DEVICE API
+ *
+ * Copyright (C) 2015 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * 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_host.h>
+#include <kvm/arm_vgic.h>
+
+/* common helpers */
+
+static int vgic_create(struct kvm_device *dev, u32 type)
+{
+	return kvm_vgic_create(dev->kvm, type);
+}
+
+static void vgic_destroy(struct kvm_device *dev)
+{
+	kfree(dev);
+}
+
+void kvm_register_vgic_device(unsigned long type)
+{
+	switch (type) {
+	case KVM_DEV_TYPE_ARM_VGIC_V2:
+		kvm_register_device_ops(&kvm_arm_vgic_v2_ops,
+					KVM_DEV_TYPE_ARM_VGIC_V2);
+		break;
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+	case KVM_DEV_TYPE_ARM_VGIC_V3:
+		kvm_register_device_ops(&kvm_arm_vgic_v3_ops,
+					KVM_DEV_TYPE_ARM_VGIC_V3);
+		break;
+#endif
+	}
+}
+
+/* V2 ops */
+
+static int vgic_v2_set_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+static int vgic_v2_get_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+static int vgic_v2_has_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+struct kvm_device_ops kvm_arm_vgic_v2_ops = {
+	.name = "kvm-arm-vgic-v2",
+	.create = vgic_create,
+	.destroy = vgic_destroy,
+	.set_attr = vgic_v2_set_attr,
+	.get_attr = vgic_v2_get_attr,
+	.has_attr = vgic_v2_has_attr,
+};
+
+/* V3 ops */
+
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+
+static int vgic_v3_set_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+static int vgic_v3_get_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+static int vgic_v3_has_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+struct kvm_device_ops kvm_arm_vgic_v3_ops = {
+	.name = "kvm-arm-vgic-v3",
+	.create = vgic_create,
+	.destroy = vgic_destroy,
+	.set_attr = vgic_v3_set_attr,
+	.get_attr = vgic_v3_get_attr,
+	.has_attr = vgic_v3_has_attr,
+};
+
+#endif /* CONFIG_KVM_ARM_VGIC_V3 */
+
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 635e2e2..e7c66a5 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -72,4 +72,6 @@ static inline int vgic_register_redist_iodevs(struct kvm *kvm,
 }
 #endif
 
+void kvm_register_vgic_device(unsigned long type);
+
 #endif
-- 
2.7.3

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

* [PATCH v3 38/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

This patch introduces the skeleton for the KVM device operations
associated to KVM_DEV_TYPE_ARM_VGIC_V2 and KVM_DEV_TYPE_ARM_VGIC_V3.

At that stage kvm_vgic_create is stubbed.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- rename vgic_kvm_device.c to vgic-kvm-device.c

Changelog v2 .. v3:
- replace inclusion of vgic/vgic.h with arm_vgic.h
- add kvm_register_vgic_device() prototype to this patch

 virt/kvm/arm/vgic/vgic-kvm-device.c | 108 ++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h            |   2 +
 2 files changed, 110 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic-kvm-device.c

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
new file mode 100644
index 0000000..ff332f3
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -0,0 +1,108 @@
+/*
+ * VGIC: KVM DEVICE API
+ *
+ * Copyright (C) 2015 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * 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_host.h>
+#include <kvm/arm_vgic.h>
+
+/* common helpers */
+
+static int vgic_create(struct kvm_device *dev, u32 type)
+{
+	return kvm_vgic_create(dev->kvm, type);
+}
+
+static void vgic_destroy(struct kvm_device *dev)
+{
+	kfree(dev);
+}
+
+void kvm_register_vgic_device(unsigned long type)
+{
+	switch (type) {
+	case KVM_DEV_TYPE_ARM_VGIC_V2:
+		kvm_register_device_ops(&kvm_arm_vgic_v2_ops,
+					KVM_DEV_TYPE_ARM_VGIC_V2);
+		break;
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+	case KVM_DEV_TYPE_ARM_VGIC_V3:
+		kvm_register_device_ops(&kvm_arm_vgic_v3_ops,
+					KVM_DEV_TYPE_ARM_VGIC_V3);
+		break;
+#endif
+	}
+}
+
+/* V2 ops */
+
+static int vgic_v2_set_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+static int vgic_v2_get_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+static int vgic_v2_has_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+struct kvm_device_ops kvm_arm_vgic_v2_ops = {
+	.name = "kvm-arm-vgic-v2",
+	.create = vgic_create,
+	.destroy = vgic_destroy,
+	.set_attr = vgic_v2_set_attr,
+	.get_attr = vgic_v2_get_attr,
+	.has_attr = vgic_v2_has_attr,
+};
+
+/* V3 ops */
+
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+
+static int vgic_v3_set_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+static int vgic_v3_get_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+static int vgic_v3_has_attr(struct kvm_device *dev,
+			    struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+struct kvm_device_ops kvm_arm_vgic_v3_ops = {
+	.name = "kvm-arm-vgic-v3",
+	.create = vgic_create,
+	.destroy = vgic_destroy,
+	.set_attr = vgic_v3_set_attr,
+	.get_attr = vgic_v3_get_attr,
+	.has_attr = vgic_v3_has_attr,
+};
+
+#endif /* CONFIG_KVM_ARM_VGIC_V3 */
+
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 635e2e2..e7c66a5 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -72,4 +72,6 @@ static inline int vgic_register_redist_iodevs(struct kvm *kvm,
 }
 #endif
 
+void kvm_register_vgic_device(unsigned long type);
+
 #endif
-- 
2.7.3

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

* [PATCH v3 39/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

This patch implements the KVM_DEV_ARM_VGIC_GRP_NR_IRQS group. This
modality is supported by both VGIC V2 and V3 KVM device as will be
other groups, hence the introduction of common helpers.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic-kvm-device.c | 83 +++++++++++++++++++++++++++++++++++--
 1 file changed, 79 insertions(+), 4 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index ff332f3..05ff925 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -15,9 +15,69 @@
  */
 #include <linux/kvm_host.h>
 #include <kvm/arm_vgic.h>
+#include <linux/uaccess.h>
+#include "vgic.h"
 
 /* common helpers */
 
+static int vgic_set_common_attr(struct kvm_device *dev,
+				struct kvm_device_attr *attr)
+{
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+		u32 val;
+		int ret = 0;
+
+		if (get_user(val, uaddr))
+			return -EFAULT;
+
+		/*
+		 * We require:
+		 * - at least 32 SPIs on top of the 16 SGIs and 16 PPIs
+		 * - at most 1024 interrupts
+		 * - a multiple of 32 interrupts
+		 */
+		if (val < (VGIC_NR_PRIVATE_IRQS + 32) ||
+		    val > VGIC_MAX_RESERVED ||
+		    (val & 31))
+			return -EINVAL;
+
+		mutex_lock(&dev->kvm->lock);
+
+		if (vgic_ready(dev->kvm) || dev->kvm->arch.vgic.nr_spis)
+			ret = -EBUSY;
+		else
+			dev->kvm->arch.vgic.nr_spis =
+				val - VGIC_NR_PRIVATE_IRQS;
+
+		mutex_unlock(&dev->kvm->lock);
+
+		return ret;
+	}
+	}
+
+	return -ENXIO;
+}
+
+static int vgic_get_common_attr(struct kvm_device *dev,
+				struct kvm_device_attr *attr)
+{
+	int r = -ENXIO;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+
+		r = put_user(dev->kvm->arch.vgic.nr_spis +
+			     VGIC_NR_PRIVATE_IRQS, uaddr);
+		break;
+	}
+	}
+
+	return r;
+}
+
 static int vgic_create(struct kvm_device *dev, u32 type)
 {
 	return kvm_vgic_create(dev->kvm, type);
@@ -49,18 +109,29 @@ void kvm_register_vgic_device(unsigned long type)
 static int vgic_v2_set_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return -ENXIO;
+	int ret;
+
+	ret = vgic_set_common_attr(dev, attr);
+	return ret;
+
 }
 
 static int vgic_v2_get_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return -ENXIO;
+	int ret;
+
+	ret = vgic_get_common_attr(dev, attr);
+	return ret;
 }
 
 static int vgic_v2_has_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
+		return 0;
+	}
 	return -ENXIO;
 }
 
@@ -80,18 +151,22 @@ struct kvm_device_ops kvm_arm_vgic_v2_ops = {
 static int vgic_v3_set_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return -ENXIO;
+	return vgic_set_common_attr(dev, attr);
 }
 
 static int vgic_v3_get_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return -ENXIO;
+	return vgic_get_common_attr(dev, attr);
 }
 
 static int vgic_v3_has_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
+		return 0;
+	}
 	return -ENXIO;
 }
 
-- 
2.7.3

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

* [PATCH v3 39/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

This patch implements the KVM_DEV_ARM_VGIC_GRP_NR_IRQS group. This
modality is supported by both VGIC V2 and V3 KVM device as will be
other groups, hence the introduction of common helpers.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic-kvm-device.c | 83 +++++++++++++++++++++++++++++++++++--
 1 file changed, 79 insertions(+), 4 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index ff332f3..05ff925 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -15,9 +15,69 @@
  */
 #include <linux/kvm_host.h>
 #include <kvm/arm_vgic.h>
+#include <linux/uaccess.h>
+#include "vgic.h"
 
 /* common helpers */
 
+static int vgic_set_common_attr(struct kvm_device *dev,
+				struct kvm_device_attr *attr)
+{
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+		u32 val;
+		int ret = 0;
+
+		if (get_user(val, uaddr))
+			return -EFAULT;
+
+		/*
+		 * We require:
+		 * - at least 32 SPIs on top of the 16 SGIs and 16 PPIs
+		 * - at most 1024 interrupts
+		 * - a multiple of 32 interrupts
+		 */
+		if (val < (VGIC_NR_PRIVATE_IRQS + 32) ||
+		    val > VGIC_MAX_RESERVED ||
+		    (val & 31))
+			return -EINVAL;
+
+		mutex_lock(&dev->kvm->lock);
+
+		if (vgic_ready(dev->kvm) || dev->kvm->arch.vgic.nr_spis)
+			ret = -EBUSY;
+		else
+			dev->kvm->arch.vgic.nr_spis =
+				val - VGIC_NR_PRIVATE_IRQS;
+
+		mutex_unlock(&dev->kvm->lock);
+
+		return ret;
+	}
+	}
+
+	return -ENXIO;
+}
+
+static int vgic_get_common_attr(struct kvm_device *dev,
+				struct kvm_device_attr *attr)
+{
+	int r = -ENXIO;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
+		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+
+		r = put_user(dev->kvm->arch.vgic.nr_spis +
+			     VGIC_NR_PRIVATE_IRQS, uaddr);
+		break;
+	}
+	}
+
+	return r;
+}
+
 static int vgic_create(struct kvm_device *dev, u32 type)
 {
 	return kvm_vgic_create(dev->kvm, type);
@@ -49,18 +109,29 @@ void kvm_register_vgic_device(unsigned long type)
 static int vgic_v2_set_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return -ENXIO;
+	int ret;
+
+	ret = vgic_set_common_attr(dev, attr);
+	return ret;
+
 }
 
 static int vgic_v2_get_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return -ENXIO;
+	int ret;
+
+	ret = vgic_get_common_attr(dev, attr);
+	return ret;
 }
 
 static int vgic_v2_has_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
+		return 0;
+	}
 	return -ENXIO;
 }
 
@@ -80,18 +151,22 @@ struct kvm_device_ops kvm_arm_vgic_v2_ops = {
 static int vgic_v3_set_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return -ENXIO;
+	return vgic_set_common_attr(dev, attr);
 }
 
 static int vgic_v3_get_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
-	return -ENXIO;
+	return vgic_get_common_attr(dev, attr);
 }
 
 static int vgic_v3_has_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
+		return 0;
+	}
 	return -ENXIO;
 }
 
-- 
2.7.3

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

* [PATCH v3 40/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

This patch implements the KVM_DEV_ARM_VGIC_GRP_CTRL group API
featuring KVM_DEV_ARM_VGIC_CTRL_INIT attribute. The vgic_init
function is not yet implemented though.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic-kvm-device.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index 05ff925..e153f12 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -23,6 +23,8 @@
 static int vgic_set_common_attr(struct kvm_device *dev,
 				struct kvm_device_attr *attr)
 {
+	int r;
+
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
 		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
@@ -55,6 +57,16 @@ static int vgic_set_common_attr(struct kvm_device *dev,
 
 		return ret;
 	}
+	case KVM_DEV_ARM_VGIC_GRP_CTRL: {
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_CTRL_INIT:
+			mutex_lock(&dev->kvm->lock);
+			r = vgic_init(dev->kvm);
+			mutex_unlock(&dev->kvm->lock);
+			return r;
+		}
+		break;
+	}
 	}
 
 	return -ENXIO;
@@ -131,6 +143,11 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
+	case KVM_DEV_ARM_VGIC_GRP_CTRL:
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_CTRL_INIT:
+			return 0;
+		}
 	}
 	return -ENXIO;
 }
@@ -166,6 +183,11 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
+	case KVM_DEV_ARM_VGIC_GRP_CTRL:
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_CTRL_INIT:
+			return 0;
+		}
 	}
 	return -ENXIO;
 }
-- 
2.7.3

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

* [PATCH v3 40/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

This patch implements the KVM_DEV_ARM_VGIC_GRP_CTRL group API
featuring KVM_DEV_ARM_VGIC_CTRL_INIT attribute. The vgic_init
function is not yet implemented though.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic-kvm-device.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index 05ff925..e153f12 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -23,6 +23,8 @@
 static int vgic_set_common_attr(struct kvm_device *dev,
 				struct kvm_device_attr *attr)
 {
+	int r;
+
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
 		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
@@ -55,6 +57,16 @@ static int vgic_set_common_attr(struct kvm_device *dev,
 
 		return ret;
 	}
+	case KVM_DEV_ARM_VGIC_GRP_CTRL: {
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_CTRL_INIT:
+			mutex_lock(&dev->kvm->lock);
+			r = vgic_init(dev->kvm);
+			mutex_unlock(&dev->kvm->lock);
+			return r;
+		}
+		break;
+	}
 	}
 
 	return -ENXIO;
@@ -131,6 +143,11 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
+	case KVM_DEV_ARM_VGIC_GRP_CTRL:
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_CTRL_INIT:
+			return 0;
+		}
 	}
 	return -ENXIO;
 }
@@ -166,6 +183,11 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
+	case KVM_DEV_ARM_VGIC_GRP_CTRL:
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_CTRL_INIT:
+			return 0;
+		}
 	}
 	return -ENXIO;
 }
-- 
2.7.3

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

* [PATCH v3 41/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

kvm_vgic_addr is used by the userspace to set the base address of
the following register regions, as seen by the guest:
- distributor(v2 and v3),
- re-distributors (v3),
- CPU interface (v2).

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h             |   2 +
 virt/kvm/arm/vgic/vgic-kvm-device.c | 112 ++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h            |   3 +
 3 files changed, 117 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 2c43eb8..73cab36 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -194,6 +194,8 @@ struct vgic_cpu {
 	u64 live_lrs;
 };
 
+int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
+
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level);
 
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index e153f12..493e941 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -16,10 +16,122 @@
 #include <linux/kvm_host.h>
 #include <kvm/arm_vgic.h>
 #include <linux/uaccess.h>
+#include <asm/kvm_mmu.h>
 #include "vgic.h"
 
 /* common helpers */
 
+static int vgic_ioaddr_overlap(struct kvm *kvm)
+{
+	phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;
+	phys_addr_t cpu = kvm->arch.vgic.vgic_cpu_base;
+
+	if (IS_VGIC_ADDR_UNDEF(dist) || IS_VGIC_ADDR_UNDEF(cpu))
+		return 0;
+	if ((dist <= cpu && dist + KVM_VGIC_V2_DIST_SIZE > cpu) ||
+	    (cpu <= dist && cpu + KVM_VGIC_V2_CPU_SIZE > dist))
+		return -EBUSY;
+	return 0;
+}
+
+static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
+			      phys_addr_t addr, phys_addr_t size)
+{
+	int ret;
+
+	if (addr & ~KVM_PHYS_MASK)
+		return -E2BIG;
+
+	if (addr & (SZ_4K - 1))
+		return -EINVAL;
+
+	if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
+		return -EEXIST;
+	if (addr + size < addr)
+		return -EINVAL;
+
+	*ioaddr = addr;
+	ret = vgic_ioaddr_overlap(kvm);
+	if (ret)
+		*ioaddr = VGIC_ADDR_UNDEF;
+
+	return ret;
+}
+
+/**
+ * kvm_vgic_addr - set or get vgic VM base addresses
+ * @kvm:   pointer to the vm struct
+ * @type:  the VGIC addr type, one of KVM_VGIC_V[23]_ADDR_TYPE_XXX
+ * @addr:  pointer to address value
+ * @write: if true set the address in the VM address space, if false read the
+ *          address
+ *
+ * Set or get the vgic base addresses for the distributor and the virtual CPU
+ * interface in the VM physical address space.  These addresses are properties
+ * of the emulated core/SoC and therefore user space initially knows this
+ * information.
+ */
+int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
+{
+	int r = 0;
+	struct vgic_dist *vgic = &kvm->arch.vgic;
+	int type_needed;
+	phys_addr_t *addr_ptr, block_size;
+	phys_addr_t alignment;
+
+	mutex_lock(&kvm->lock);
+	switch (type) {
+	case KVM_VGIC_V2_ADDR_TYPE_DIST:
+		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
+		addr_ptr = &vgic->vgic_dist_base;
+		block_size = KVM_VGIC_V2_DIST_SIZE;
+		alignment = SZ_4K;
+		break;
+	case KVM_VGIC_V2_ADDR_TYPE_CPU:
+		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
+		addr_ptr = &vgic->vgic_cpu_base;
+		block_size = KVM_VGIC_V2_CPU_SIZE;
+		alignment = SZ_4K;
+		break;
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+	case KVM_VGIC_V3_ADDR_TYPE_DIST:
+		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
+		addr_ptr = &vgic->vgic_dist_base;
+		block_size = KVM_VGIC_V3_DIST_SIZE;
+		alignment = SZ_64K;
+		break;
+	case KVM_VGIC_V3_ADDR_TYPE_REDIST:
+		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
+		addr_ptr = &vgic->vgic_redist_base;
+		block_size = KVM_VGIC_V3_REDIST_SIZE;
+		alignment = SZ_64K;
+		break;
+#endif
+	default:
+		r = -ENODEV;
+		goto out;
+	}
+
+	if (vgic->vgic_model != type_needed) {
+		r = -ENODEV;
+		goto out;
+	}
+
+	if (write) {
+		if (!IS_ALIGNED(*addr, alignment))
+			r = -EINVAL;
+		else
+			r = vgic_ioaddr_assign(kvm, addr_ptr,
+					       *addr, block_size);
+	} else {
+		*addr = *addr_ptr;
+	}
+
+out:
+	mutex_unlock(&kvm->lock);
+	return r;
+}
+
 static int vgic_set_common_attr(struct kvm_device *dev,
 				struct kvm_device_attr *attr)
 {
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index e7c66a5..c44ee01 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -19,6 +19,9 @@
 #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
 #define IMPLEMENTER_ARM		0x43b
 
+#define VGIC_ADDR_UNDEF		(-1)
+#define IS_VGIC_ADDR_UNDEF(_x)  ((_x) == VGIC_ADDR_UNDEF)
+
 #define INTERRUPT_ID_BITS_SPIS	10
 
 #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
-- 
2.7.3

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

* [PATCH v3 41/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

kvm_vgic_addr is used by the userspace to set the base address of
the following register regions, as seen by the guest:
- distributor(v2 and v3),
- re-distributors (v3),
- CPU interface (v2).

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h             |   2 +
 virt/kvm/arm/vgic/vgic-kvm-device.c | 112 ++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h            |   3 +
 3 files changed, 117 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 2c43eb8..73cab36 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -194,6 +194,8 @@ struct vgic_cpu {
 	u64 live_lrs;
 };
 
+int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
+
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level);
 
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index e153f12..493e941 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -16,10 +16,122 @@
 #include <linux/kvm_host.h>
 #include <kvm/arm_vgic.h>
 #include <linux/uaccess.h>
+#include <asm/kvm_mmu.h>
 #include "vgic.h"
 
 /* common helpers */
 
+static int vgic_ioaddr_overlap(struct kvm *kvm)
+{
+	phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;
+	phys_addr_t cpu = kvm->arch.vgic.vgic_cpu_base;
+
+	if (IS_VGIC_ADDR_UNDEF(dist) || IS_VGIC_ADDR_UNDEF(cpu))
+		return 0;
+	if ((dist <= cpu && dist + KVM_VGIC_V2_DIST_SIZE > cpu) ||
+	    (cpu <= dist && cpu + KVM_VGIC_V2_CPU_SIZE > dist))
+		return -EBUSY;
+	return 0;
+}
+
+static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
+			      phys_addr_t addr, phys_addr_t size)
+{
+	int ret;
+
+	if (addr & ~KVM_PHYS_MASK)
+		return -E2BIG;
+
+	if (addr & (SZ_4K - 1))
+		return -EINVAL;
+
+	if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
+		return -EEXIST;
+	if (addr + size < addr)
+		return -EINVAL;
+
+	*ioaddr = addr;
+	ret = vgic_ioaddr_overlap(kvm);
+	if (ret)
+		*ioaddr = VGIC_ADDR_UNDEF;
+
+	return ret;
+}
+
+/**
+ * kvm_vgic_addr - set or get vgic VM base addresses
+ * @kvm:   pointer to the vm struct
+ * @type:  the VGIC addr type, one of KVM_VGIC_V[23]_ADDR_TYPE_XXX
+ * @addr:  pointer to address value
+ * @write: if true set the address in the VM address space, if false read the
+ *          address
+ *
+ * Set or get the vgic base addresses for the distributor and the virtual CPU
+ * interface in the VM physical address space.  These addresses are properties
+ * of the emulated core/SoC and therefore user space initially knows this
+ * information.
+ */
+int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
+{
+	int r = 0;
+	struct vgic_dist *vgic = &kvm->arch.vgic;
+	int type_needed;
+	phys_addr_t *addr_ptr, block_size;
+	phys_addr_t alignment;
+
+	mutex_lock(&kvm->lock);
+	switch (type) {
+	case KVM_VGIC_V2_ADDR_TYPE_DIST:
+		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
+		addr_ptr = &vgic->vgic_dist_base;
+		block_size = KVM_VGIC_V2_DIST_SIZE;
+		alignment = SZ_4K;
+		break;
+	case KVM_VGIC_V2_ADDR_TYPE_CPU:
+		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
+		addr_ptr = &vgic->vgic_cpu_base;
+		block_size = KVM_VGIC_V2_CPU_SIZE;
+		alignment = SZ_4K;
+		break;
+#ifdef CONFIG_KVM_ARM_VGIC_V3
+	case KVM_VGIC_V3_ADDR_TYPE_DIST:
+		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
+		addr_ptr = &vgic->vgic_dist_base;
+		block_size = KVM_VGIC_V3_DIST_SIZE;
+		alignment = SZ_64K;
+		break;
+	case KVM_VGIC_V3_ADDR_TYPE_REDIST:
+		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
+		addr_ptr = &vgic->vgic_redist_base;
+		block_size = KVM_VGIC_V3_REDIST_SIZE;
+		alignment = SZ_64K;
+		break;
+#endif
+	default:
+		r = -ENODEV;
+		goto out;
+	}
+
+	if (vgic->vgic_model != type_needed) {
+		r = -ENODEV;
+		goto out;
+	}
+
+	if (write) {
+		if (!IS_ALIGNED(*addr, alignment))
+			r = -EINVAL;
+		else
+			r = vgic_ioaddr_assign(kvm, addr_ptr,
+					       *addr, block_size);
+	} else {
+		*addr = *addr_ptr;
+	}
+
+out:
+	mutex_unlock(&kvm->lock);
+	return r;
+}
+
 static int vgic_set_common_attr(struct kvm_device *dev,
 				struct kvm_device_attr *attr)
 {
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index e7c66a5..c44ee01 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -19,6 +19,9 @@
 #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
 #define IMPLEMENTER_ARM		0x43b
 
+#define VGIC_ADDR_UNDEF		(-1)
+#define IS_VGIC_ADDR_UNDEF(_x)  ((_x) == VGIC_ADDR_UNDEF)
+
 #define INTERRUPT_ID_BITS_SPIS	10
 
 #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
-- 
2.7.3

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

* [PATCH v3 42/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

This patch implements the KVM_DEV_ARM_VGIC_GRP_ADDR group which
enables to set the base address of GIC regions as seen by the guest.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic-kvm-device.c | 38 +++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index 493e941..0189c13 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -138,6 +138,17 @@ static int vgic_set_common_attr(struct kvm_device *dev,
 	int r;
 
 	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR: {
+		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+		u64 addr;
+		unsigned long type = (unsigned long)attr->attr;
+
+		if (copy_from_user(&addr, uaddr, sizeof(addr)))
+			return -EFAULT;
+
+		r = kvm_vgic_addr(dev->kvm, type, &addr, true);
+		return (r == -ENODEV) ? -ENXIO : r;
+	}
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
 		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
 		u32 val;
@@ -190,6 +201,19 @@ static int vgic_get_common_attr(struct kvm_device *dev,
 	int r = -ENXIO;
 
 	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR: {
+		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+		u64 addr;
+		unsigned long type = (unsigned long)attr->attr;
+
+		r = kvm_vgic_addr(dev->kvm, type, &addr, false);
+		if (r)
+			return (r == -ENODEV) ? -ENXIO : r;
+
+		if (copy_to_user(uaddr, &addr, sizeof(addr)))
+			return -EFAULT;
+		break;
+	}
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
 		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
 
@@ -253,6 +277,13 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
 	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR:
+		switch (attr->attr) {
+		case KVM_VGIC_V2_ADDR_TYPE_DIST:
+		case KVM_VGIC_V2_ADDR_TYPE_CPU:
+			return 0;
+		}
+		break;
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
 	case KVM_DEV_ARM_VGIC_GRP_CTRL:
@@ -293,6 +324,13 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
 	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR:
+		switch (attr->attr) {
+		case KVM_VGIC_V3_ADDR_TYPE_DIST:
+		case KVM_VGIC_V3_ADDR_TYPE_REDIST:
+			return 0;
+		}
+		break;
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
 	case KVM_DEV_ARM_VGIC_GRP_CTRL:
-- 
2.7.3

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

* [PATCH v3 42/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

This patch implements the KVM_DEV_ARM_VGIC_GRP_ADDR group which
enables to set the base address of GIC regions as seen by the guest.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic-kvm-device.c | 38 +++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index 493e941..0189c13 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -138,6 +138,17 @@ static int vgic_set_common_attr(struct kvm_device *dev,
 	int r;
 
 	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR: {
+		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+		u64 addr;
+		unsigned long type = (unsigned long)attr->attr;
+
+		if (copy_from_user(&addr, uaddr, sizeof(addr)))
+			return -EFAULT;
+
+		r = kvm_vgic_addr(dev->kvm, type, &addr, true);
+		return (r == -ENODEV) ? -ENXIO : r;
+	}
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
 		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
 		u32 val;
@@ -190,6 +201,19 @@ static int vgic_get_common_attr(struct kvm_device *dev,
 	int r = -ENXIO;
 
 	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR: {
+		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+		u64 addr;
+		unsigned long type = (unsigned long)attr->attr;
+
+		r = kvm_vgic_addr(dev->kvm, type, &addr, false);
+		if (r)
+			return (r == -ENODEV) ? -ENXIO : r;
+
+		if (copy_to_user(uaddr, &addr, sizeof(addr)))
+			return -EFAULT;
+		break;
+	}
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
 		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
 
@@ -253,6 +277,13 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
 	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR:
+		switch (attr->attr) {
+		case KVM_VGIC_V2_ADDR_TYPE_DIST:
+		case KVM_VGIC_V2_ADDR_TYPE_CPU:
+			return 0;
+		}
+		break;
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
 	case KVM_DEV_ARM_VGIC_GRP_CTRL:
@@ -293,6 +324,13 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
 	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_ADDR:
+		switch (attr->attr) {
+		case KVM_VGIC_V3_ADDR_TYPE_DIST:
+		case KVM_VGIC_V3_ADDR_TYPE_REDIST:
+			return 0;
+		}
+		break;
 	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
 		return 0;
 	case KVM_DEV_ARM_VGIC_GRP_CTRL:
-- 
2.7.3

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

* [PATCH v3 43/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

This patch implements the switches for KVM_DEV_ARM_VGIC_GRP_DIST_REGS
and KVM_DEV_ARM_VGIC_GRP_CPU_REGS API which allows the userspace to
access VGIC registers.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic-kvm-device.c | 53 +++++++++++++++++++++++++++++++++++--
 virt/kvm/arm/vgic/vgic-mmio-v2.c    | 34 ++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h            |  1 +
 3 files changed, 86 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index 0189c13..c952f6f 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -252,6 +252,21 @@ void kvm_register_vgic_device(unsigned long type)
 	}
 }
 
+/** vgic_attr_regs_access: allows user space to read/write VGIC registers
+ *
+ * @dev: kvm device handle
+ * @attr: kvm device attribute
+ * @reg: address the value is read or written
+ * @is_write: write flag
+ *
+ */
+static int vgic_attr_regs_access(struct kvm_device *dev,
+				 struct kvm_device_attr *attr,
+				 u32 *reg, bool is_write)
+{
+	return -ENXIO;
+}
+
 /* V2 ops */
 
 static int vgic_v2_set_attr(struct kvm_device *dev,
@@ -260,8 +275,23 @@ static int vgic_v2_set_attr(struct kvm_device *dev,
 	int ret;
 
 	ret = vgic_set_common_attr(dev, attr);
-	return ret;
+	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;
+
+		if (get_user(reg, uaddr))
+			return -EFAULT;
 
+		return vgic_attr_regs_access(dev, attr, &reg, true);
+	}
+	}
+
+	return -ENXIO;
 }
 
 static int vgic_v2_get_attr(struct kvm_device *dev,
@@ -270,7 +300,23 @@ static int vgic_v2_get_attr(struct kvm_device *dev,
 	int ret;
 
 	ret = vgic_get_common_attr(dev, attr);
-	return ret;
+	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 = 0;
+
+		ret = vgic_attr_regs_access(dev, attr, &reg, false);
+		if (ret)
+			return ret;
+		return put_user(reg, uaddr);
+	}
+	}
+
+	return -ENXIO;
 }
 
 static int vgic_v2_has_attr(struct kvm_device *dev,
@@ -284,6 +330,9 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
 			return 0;
 		}
 		break;
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
+		return vgic_v2_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 8006ac0..cf8fee9 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -246,3 +246,37 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
 
 	return SZ_4K;
 }
+
+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;
+
+	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+		regions = vgic_v2_dist_registers;
+		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
+		return -ENXIO;		/* TODO: describe CPU i/f regs also */
+	default:
+		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;
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index c44ee01..a4397f9 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -36,6 +36,7 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
 void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
+int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
 int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
 			     enum vgic_type);
 
-- 
2.7.3

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

* [PATCH v3 43/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

This patch implements the switches for KVM_DEV_ARM_VGIC_GRP_DIST_REGS
and KVM_DEV_ARM_VGIC_GRP_CPU_REGS API which allows the userspace to
access VGIC registers.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic-kvm-device.c | 53 +++++++++++++++++++++++++++++++++++--
 virt/kvm/arm/vgic/vgic-mmio-v2.c    | 34 ++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h            |  1 +
 3 files changed, 86 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index 0189c13..c952f6f 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -252,6 +252,21 @@ void kvm_register_vgic_device(unsigned long type)
 	}
 }
 
+/** vgic_attr_regs_access: allows user space to read/write VGIC registers
+ *
+ * @dev: kvm device handle
+ * @attr: kvm device attribute
+ * @reg: address the value is read or written
+ * @is_write: write flag
+ *
+ */
+static int vgic_attr_regs_access(struct kvm_device *dev,
+				 struct kvm_device_attr *attr,
+				 u32 *reg, bool is_write)
+{
+	return -ENXIO;
+}
+
 /* V2 ops */
 
 static int vgic_v2_set_attr(struct kvm_device *dev,
@@ -260,8 +275,23 @@ static int vgic_v2_set_attr(struct kvm_device *dev,
 	int ret;
 
 	ret = vgic_set_common_attr(dev, attr);
-	return ret;
+	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;
+
+		if (get_user(reg, uaddr))
+			return -EFAULT;
 
+		return vgic_attr_regs_access(dev, attr, &reg, true);
+	}
+	}
+
+	return -ENXIO;
 }
 
 static int vgic_v2_get_attr(struct kvm_device *dev,
@@ -270,7 +300,23 @@ static int vgic_v2_get_attr(struct kvm_device *dev,
 	int ret;
 
 	ret = vgic_get_common_attr(dev, attr);
-	return ret;
+	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 = 0;
+
+		ret = vgic_attr_regs_access(dev, attr, &reg, false);
+		if (ret)
+			return ret;
+		return put_user(reg, uaddr);
+	}
+	}
+
+	return -ENXIO;
 }
 
 static int vgic_v2_has_attr(struct kvm_device *dev,
@@ -284,6 +330,9 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
 			return 0;
 		}
 		break;
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
+		return vgic_v2_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 8006ac0..cf8fee9 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -246,3 +246,37 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
 
 	return SZ_4K;
 }
+
+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;
+
+	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+		regions = vgic_v2_dist_registers;
+		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
+		return -ENXIO;		/* TODO: describe CPU i/f regs also */
+	default:
+		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;
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index c44ee01..a4397f9 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -36,6 +36,7 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
 void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
+int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
 int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
 			     enum vgic_type);
 
-- 
2.7.3

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

* [PATCH v3 44/55] KVM: arm/arm64: vgic-new: Export register access interface
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

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

Userland can access the emulated GIC to save and restore its state
for initialization or migration purposes.
The kvm_io_bus API requires an absolute gpa, which does not fit the
KVM_DEV_ARM_VGIC_GRP_DIST_REGS user API, that only provides relative
offsets. So we provide a wrapper to plug into our MMIO framework and
find the respective register handler.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- adapt to new MMIO framework
- handle endianess explicitly

Changelog v2 .. v3:
- wrap accessor function for easier reusage later
- moved from earlier in the series

 virt/kvm/arm/vgic/vgic-mmio-v2.c | 36 ++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h         |  2 ++
 2 files changed, 38 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index cf8fee9..c453e6f 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -280,3 +280,39 @@ 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_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+			 int offset, u32 *val)
+{
+	struct vgic_io_device dev = {
+		.regions = vgic_v2_dist_registers,
+		.nr_regions = ARRAY_SIZE(vgic_v2_dist_registers),
+	};
+
+	return vgic_uaccess(vcpu, &dev, is_write, offset, val);
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index a4397f9..bc5750e 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -37,6 +37,8 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
+int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+			 int offset, u32 *val);
 int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
 			     enum vgic_type);
 
-- 
2.7.3

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

* [PATCH v3 44/55] KVM: arm/arm64: vgic-new: Export register access interface
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

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

Userland can access the emulated GIC to save and restore its state
for initialization or migration purposes.
The kvm_io_bus API requires an absolute gpa, which does not fit the
KVM_DEV_ARM_VGIC_GRP_DIST_REGS user API, that only provides relative
offsets. So we provide a wrapper to plug into our MMIO framework and
find the respective register handler.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- adapt to new MMIO framework
- handle endianess explicitly

Changelog v2 .. v3:
- wrap accessor function for easier reusage later
- moved from earlier in the series

 virt/kvm/arm/vgic/vgic-mmio-v2.c | 36 ++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h         |  2 ++
 2 files changed, 38 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index cf8fee9..c453e6f 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -280,3 +280,39 @@ 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_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+			 int offset, u32 *val)
+{
+	struct vgic_io_device dev = {
+		.regions = vgic_v2_dist_registers,
+		.nr_regions = ARRAY_SIZE(vgic_v2_dist_registers),
+	};
+
+	return vgic_uaccess(vcpu, &dev, is_write, offset, val);
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index a4397f9..bc5750e 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -37,6 +37,8 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
+int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+			 int offset, u32 *val);
 int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
 			     enum vgic_type);
 
-- 
2.7.3

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

* [PATCH v3 45/55] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Userland may want to save and restore the state of the in-kernel VGIC,
so we provide the code which takes a userland request and translate
that into calls to our MMIO framework.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic-kvm-device.c | 50 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 49 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index c952f6f..bb33af8 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -264,7 +264,55 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
 				 struct kvm_device_attr *attr,
 				 u32 *reg, bool is_write)
 {
-	return -ENXIO;
+	gpa_t addr;
+	int cpuid, ret, c;
+	struct kvm_vcpu *vcpu, *tmp_vcpu;
+
+	cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >>
+		 KVM_DEV_ARM_VGIC_CPUID_SHIFT;
+	vcpu = kvm_get_vcpu(dev->kvm, cpuid);
+	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+	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;
+	}
+
+	/*
+	 * 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;
+		}
+	}
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
+		ret = -EINVAL;
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+out:
+	mutex_unlock(&dev->kvm->lock);
+	return ret;
 }
 
 /* V2 ops */
-- 
2.7.3

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

* [PATCH v3 45/55] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

Userland may want to save and restore the state of the in-kernel VGIC,
so we provide the code which takes a userland request and translate
that into calls to our MMIO framework.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic-kvm-device.c | 50 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 49 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index c952f6f..bb33af8 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -264,7 +264,55 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
 				 struct kvm_device_attr *attr,
 				 u32 *reg, bool is_write)
 {
-	return -ENXIO;
+	gpa_t addr;
+	int cpuid, ret, c;
+	struct kvm_vcpu *vcpu, *tmp_vcpu;
+
+	cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >>
+		 KVM_DEV_ARM_VGIC_CPUID_SHIFT;
+	vcpu = kvm_get_vcpu(dev->kvm, cpuid);
+	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+	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;
+	}
+
+	/*
+	 * 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;
+		}
+	}
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
+		ret = -EINVAL;
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+out:
+	mutex_unlock(&dev->kvm->lock);
+	return ret;
 }
 
 /* V2 ops */
-- 
2.7.3

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

* [PATCH v3 46/55] KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:45   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Since the GIC CPU interface is always virtualized by the hardware,
we don't have CPU interface state information readily available in our
emulation if userland wants to save or restore it.
Fortunately the GIC hypervisor interface provides the VMCR register to
access the required virtual CPU interface bits.
Provide wrappers for GICv2 and GICv3 hosts to have access to this
register.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v2 .. v3:
- remove exported v2/v3 selector functions (as per Marc's patch)

 include/kvm/vgic/vgic.h     |  7 +++++++
 virt/kvm/arm/vgic/vgic-v2.c | 29 +++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c | 22 ++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h    | 14 ++++++++++++++
 4 files changed, 72 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 73cab36..cfc3640 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -171,6 +171,13 @@ struct vgic_v3_cpu_if {
 #endif
 };
 
+struct vgic_vmcr {
+	u32	ctlr;
+	u32	abpr;
+	u32	bpr;
+	u32	pmr;
+};
+
 struct vgic_cpu {
 	/* CPU vif control registers for world switch */
 	union {
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 4cee616..70cac63 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -176,3 +176,32 @@ void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
 {
 	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
 }
+
+void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	u32 vmcr;
+
+	vmcr  = (vmcrp->ctlr << GICH_VMCR_CTRL_SHIFT) & GICH_VMCR_CTRL_MASK;
+	vmcr |= (vmcrp->abpr << GICH_VMCR_ALIAS_BINPOINT_SHIFT) &
+		GICH_VMCR_ALIAS_BINPOINT_MASK;
+	vmcr |= (vmcrp->bpr << GICH_VMCR_BINPOINT_SHIFT) &
+		GICH_VMCR_BINPOINT_MASK;
+	vmcr |= (vmcrp->pmr << GICH_VMCR_PRIMASK_SHIFT) &
+		GICH_VMCR_PRIMASK_MASK;
+
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = vmcr;
+}
+
+void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr;
+
+	vmcrp->ctlr = (vmcr & GICH_VMCR_CTRL_MASK) >>
+			GICH_VMCR_CTRL_SHIFT;
+	vmcrp->abpr = (vmcr & GICH_VMCR_ALIAS_BINPOINT_MASK) >>
+			GICH_VMCR_ALIAS_BINPOINT_SHIFT;
+	vmcrp->bpr  = (vmcr & GICH_VMCR_BINPOINT_MASK) >>
+			GICH_VMCR_BINPOINT_SHIFT;
+	vmcrp->pmr  = (vmcr & GICH_VMCR_PRIMASK_MASK) >>
+			GICH_VMCR_PRIMASK_SHIFT;
+}
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 43d1dd7..dca52b3 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -166,3 +166,25 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
 {
 	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = 0;
 }
+
+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;
+	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;
+
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
+}
+
+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;
+	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;
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index bc5750e..5260d23 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -39,6 +39,8 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
 int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			 int offset, u32 *val);
+void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
 			     enum vgic_type);
 
@@ -48,6 +50,8 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
 void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
+void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
 #else
 static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
@@ -71,6 +75,16 @@ static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
 {
 }
 
+static inline
+void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+}
+
+static inline
+void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+}
+
 static inline int vgic_register_redist_iodevs(struct kvm *kvm,
 					      gpa_t dist_base_address)
 {
-- 
2.7.3

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

* [PATCH v3 46/55] KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors
@ 2016-05-06 10:45   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

Since the GIC CPU interface is always virtualized by the hardware,
we don't have CPU interface state information readily available in our
emulation if userland wants to save or restore it.
Fortunately the GIC hypervisor interface provides the VMCR register to
access the required virtual CPU interface bits.
Provide wrappers for GICv2 and GICv3 hosts to have access to this
register.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v2 .. v3:
- remove exported v2/v3 selector functions (as per Marc's patch)

 include/kvm/vgic/vgic.h     |  7 +++++++
 virt/kvm/arm/vgic/vgic-v2.c | 29 +++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c | 22 ++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h    | 14 ++++++++++++++
 4 files changed, 72 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 73cab36..cfc3640 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -171,6 +171,13 @@ struct vgic_v3_cpu_if {
 #endif
 };
 
+struct vgic_vmcr {
+	u32	ctlr;
+	u32	abpr;
+	u32	bpr;
+	u32	pmr;
+};
+
 struct vgic_cpu {
 	/* CPU vif control registers for world switch */
 	union {
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 4cee616..70cac63 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -176,3 +176,32 @@ void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
 {
 	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
 }
+
+void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	u32 vmcr;
+
+	vmcr  = (vmcrp->ctlr << GICH_VMCR_CTRL_SHIFT) & GICH_VMCR_CTRL_MASK;
+	vmcr |= (vmcrp->abpr << GICH_VMCR_ALIAS_BINPOINT_SHIFT) &
+		GICH_VMCR_ALIAS_BINPOINT_MASK;
+	vmcr |= (vmcrp->bpr << GICH_VMCR_BINPOINT_SHIFT) &
+		GICH_VMCR_BINPOINT_MASK;
+	vmcr |= (vmcrp->pmr << GICH_VMCR_PRIMASK_SHIFT) &
+		GICH_VMCR_PRIMASK_MASK;
+
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = vmcr;
+}
+
+void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr;
+
+	vmcrp->ctlr = (vmcr & GICH_VMCR_CTRL_MASK) >>
+			GICH_VMCR_CTRL_SHIFT;
+	vmcrp->abpr = (vmcr & GICH_VMCR_ALIAS_BINPOINT_MASK) >>
+			GICH_VMCR_ALIAS_BINPOINT_SHIFT;
+	vmcrp->bpr  = (vmcr & GICH_VMCR_BINPOINT_MASK) >>
+			GICH_VMCR_BINPOINT_SHIFT;
+	vmcrp->pmr  = (vmcr & GICH_VMCR_PRIMASK_MASK) >>
+			GICH_VMCR_PRIMASK_SHIFT;
+}
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 43d1dd7..dca52b3 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -166,3 +166,25 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
 {
 	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = 0;
 }
+
+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;
+	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;
+
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
+}
+
+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;
+	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;
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index bc5750e..5260d23 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -39,6 +39,8 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
 int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			 int offset, u32 *val);
+void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
 			     enum vgic_type);
 
@@ -48,6 +50,8 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
 void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
+void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
 #else
 static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
@@ -71,6 +75,16 @@ static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
 {
 }
 
+static inline
+void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+}
+
+static inline
+void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
+{
+}
+
 static inline int vgic_register_redist_iodevs(struct kvm *kvm,
 					      gpa_t dist_base_address)
 {
-- 
2.7.3

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

* [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:46   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:46 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Using the VMCR accessors we provide access to GIC CPU interface state
to userland by wiring it up to the existing userland interface.
[Marc: move and make VMCR accessors static, streamline MMIO handlers]

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
Changelog v2 .. v3:
- total rework, moving into vgic-mmio-v2.c
- move vmcr accessor wrapper functions into this file
- use the register description table for CPU i/f registers as well
- add RAZ/WI handling for the active priority registers
- streamline MMIO handler functions

 virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
 virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h            |   2 +
 3 files changed, 107 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index bb33af8..2122ff2 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
 
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
-		ret = -EINVAL;
+		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
 		break;
 	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
 		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index c453e6f..0060539 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -206,6 +206,84 @@ 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. */
+static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
+					   gpa_t addr, unsigned int len)
+{
+	struct vgic_vmcr vmcr;
+	u32 val;
+
+	vgic_get_vmcr(vcpu, &vmcr);
+
+	switch (addr & 0xff) {
+	case GIC_CPU_CTRL:
+		val = vmcr.ctlr;
+		break;
+	case GIC_CPU_PRIMASK:
+		val = vmcr.pmr;
+		break;
+	case GIC_CPU_BINPOINT:
+		val = vmcr.bpr;
+		break;
+	case GIC_CPU_ALIAS_BINPOINT:
+		val = vmcr.abpr;
+		break;
+	case GIC_CPU_IDENT:
+		val = ((PRODUCT_ID_KVM << 20) |
+		       (GICC_ARCH_VERSION_V2 << 16) |
+		       IMPLEMENTER_ARM);
+		break;
+	default:
+		return 0;
+	}
+
+	return extract_bytes(val, addr & 3, len);
+}
+
+static void vgic_mmio_write_vcpuif(struct kvm_vcpu *vcpu,
+				   gpa_t addr, unsigned int len,
+				   unsigned long val)
+{
+	struct vgic_vmcr vmcr;
+
+	vgic_get_vmcr(vcpu, &vmcr);
+
+	switch (addr & 0xff) {
+	case GIC_CPU_CTRL:
+		vmcr.ctlr = val;
+		break;
+	case GIC_CPU_PRIMASK:
+		vmcr.pmr = val;
+		break;
+	case GIC_CPU_BINPOINT:
+		vmcr.bpr = val;
+		break;
+	case GIC_CPU_ALIAS_BINPOINT:
+		vmcr.abpr = val;
+		break;
+	}
+
+	vgic_set_vmcr(vcpu, &vmcr);
+}
+
 static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -237,6 +315,21 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
 		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
 };
 
+static const struct vgic_register_region vgic_v2_cpu_registers[] = {
+	REGISTER_DESC_WITH_LENGTH(GIC_CPU_CTRL,
+		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+	REGISTER_DESC_WITH_LENGTH(GIC_CPU_PRIMASK,
+		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+	REGISTER_DESC_WITH_LENGTH(GIC_CPU_BINPOINT,
+		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+	REGISTER_DESC_WITH_LENGTH(GIC_CPU_ALIAS_BINPOINT,
+		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+	REGISTER_DESC_WITH_LENGTH(GIC_CPU_ACTIVEPRIO,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+	REGISTER_DESC_WITH_LENGTH(GIC_CPU_IDENT,
+		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+};
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
 {
 	dev->regions = vgic_v2_dist_registers;
@@ -306,6 +399,17 @@ static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
 	return ret;
 }
 
+int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+			  int offset, u32 *val)
+{
+	struct vgic_io_device dev = {
+		.regions = vgic_v2_cpu_registers,
+		.nr_regions = ARRAY_SIZE(vgic_v2_cpu_registers),
+	};
+
+	return vgic_uaccess(vcpu, &dev, is_write, offset, val);
+}
+
 int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			 int offset, u32 *val)
 {
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 5260d23..7a69955 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -39,6 +39,8 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
 int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			 int offset, u32 *val);
+int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+			  int offset, u32 *val);
 void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
-- 
2.7.3

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

* [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
@ 2016-05-06 10:46   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:46 UTC (permalink / raw)
  To: linux-arm-kernel

Using the VMCR accessors we provide access to GIC CPU interface state
to userland by wiring it up to the existing userland interface.
[Marc: move and make VMCR accessors static, streamline MMIO handlers]

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
Changelog v2 .. v3:
- total rework, moving into vgic-mmio-v2.c
- move vmcr accessor wrapper functions into this file
- use the register description table for CPU i/f registers as well
- add RAZ/WI handling for the active priority registers
- streamline MMIO handler functions

 virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
 virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h            |   2 +
 3 files changed, 107 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index bb33af8..2122ff2 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
 
 	switch (attr->group) {
 	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
-		ret = -EINVAL;
+		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
 		break;
 	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
 		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
index c453e6f..0060539 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
@@ -206,6 +206,84 @@ 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. */
+static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
+					   gpa_t addr, unsigned int len)
+{
+	struct vgic_vmcr vmcr;
+	u32 val;
+
+	vgic_get_vmcr(vcpu, &vmcr);
+
+	switch (addr & 0xff) {
+	case GIC_CPU_CTRL:
+		val = vmcr.ctlr;
+		break;
+	case GIC_CPU_PRIMASK:
+		val = vmcr.pmr;
+		break;
+	case GIC_CPU_BINPOINT:
+		val = vmcr.bpr;
+		break;
+	case GIC_CPU_ALIAS_BINPOINT:
+		val = vmcr.abpr;
+		break;
+	case GIC_CPU_IDENT:
+		val = ((PRODUCT_ID_KVM << 20) |
+		       (GICC_ARCH_VERSION_V2 << 16) |
+		       IMPLEMENTER_ARM);
+		break;
+	default:
+		return 0;
+	}
+
+	return extract_bytes(val, addr & 3, len);
+}
+
+static void vgic_mmio_write_vcpuif(struct kvm_vcpu *vcpu,
+				   gpa_t addr, unsigned int len,
+				   unsigned long val)
+{
+	struct vgic_vmcr vmcr;
+
+	vgic_get_vmcr(vcpu, &vmcr);
+
+	switch (addr & 0xff) {
+	case GIC_CPU_CTRL:
+		vmcr.ctlr = val;
+		break;
+	case GIC_CPU_PRIMASK:
+		vmcr.pmr = val;
+		break;
+	case GIC_CPU_BINPOINT:
+		vmcr.bpr = val;
+		break;
+	case GIC_CPU_ALIAS_BINPOINT:
+		vmcr.abpr = val;
+		break;
+	}
+
+	vgic_set_vmcr(vcpu, &vmcr);
+}
+
 static const struct vgic_register_region vgic_v2_dist_registers[] = {
 	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
 		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
@@ -237,6 +315,21 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
 		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
 };
 
+static const struct vgic_register_region vgic_v2_cpu_registers[] = {
+	REGISTER_DESC_WITH_LENGTH(GIC_CPU_CTRL,
+		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+	REGISTER_DESC_WITH_LENGTH(GIC_CPU_PRIMASK,
+		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+	REGISTER_DESC_WITH_LENGTH(GIC_CPU_BINPOINT,
+		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+	REGISTER_DESC_WITH_LENGTH(GIC_CPU_ALIAS_BINPOINT,
+		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+	REGISTER_DESC_WITH_LENGTH(GIC_CPU_ACTIVEPRIO,
+		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
+	REGISTER_DESC_WITH_LENGTH(GIC_CPU_IDENT,
+		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
+};
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
 {
 	dev->regions = vgic_v2_dist_registers;
@@ -306,6 +399,17 @@ static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
 	return ret;
 }
 
+int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+			  int offset, u32 *val)
+{
+	struct vgic_io_device dev = {
+		.regions = vgic_v2_cpu_registers,
+		.nr_regions = ARRAY_SIZE(vgic_v2_cpu_registers),
+	};
+
+	return vgic_uaccess(vcpu, &dev, is_write, offset, val);
+}
+
 int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			 int offset, u32 *val)
 {
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 5260d23..7a69955 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -39,6 +39,8 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
 int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			 int offset, u32 *val);
+int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
+			  int offset, u32 *val);
 void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
-- 
2.7.3

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

* [PATCH v3 48/55] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:46   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:46 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

Implements kvm_vgic_hyp_init and vgic_probe function.

The vgic_global struct is enriched with new fields populated
by those functions.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- rename vgic_init.c to vgic-init.c

Changelog v2 .. v3:
- include kvm/arm_vgic.h instead of kvm/vgic/vgic.h
- move ich_vtr_el2 variable into probe function

 include/kvm/vgic/vgic.h       |   1 +
 virt/kvm/arm/vgic/vgic-init.c | 122 ++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v2.c   |  90 +++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c   |  73 +++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h      |   7 +++
 5 files changed, 293 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic-init.c

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index cfc3640..d144e3d 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -202,6 +202,7 @@ struct vgic_cpu {
 };
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
+int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level);
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
new file mode 100644
index 0000000..f10997b
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/cpu.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/kvm_host.h>
+#include <kvm/arm_vgic.h>
+#include <asm/kvm_mmu.h>
+#include "vgic.h"
+
+/* GENERIC PROBE */
+
+static void vgic_init_maintenance_interrupt(void *info)
+{
+	enable_percpu_irq(kvm_vgic_global_state.maint_irq, 0);
+}
+
+static int vgic_cpu_notify(struct notifier_block *self,
+			   unsigned long action, void *cpu)
+{
+	switch (action) {
+	case CPU_STARTING:
+	case CPU_STARTING_FROZEN:
+		vgic_init_maintenance_interrupt(NULL);
+		break;
+	case CPU_DYING:
+	case CPU_DYING_FROZEN:
+		disable_percpu_irq(kvm_vgic_global_state.maint_irq);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block vgic_cpu_nb = {
+	.notifier_call = vgic_cpu_notify,
+};
+
+static irqreturn_t vgic_maintenance_handler(int irq, void *data)
+{
+	/*
+	 * We cannot rely on the vgic maintenance interrupt to be
+	 * delivered synchronously. This means we can only use it to
+	 * exit the VM, and we perform the handling of EOIed
+	 * interrupts on the exit path (see vgic_process_maintenance).
+	 */
+	return IRQ_HANDLED;
+}
+
+static const struct of_device_id vgic_ids[] = {
+	{ .compatible = "arm,cortex-a15-gic",	.data = vgic_v2_probe, },
+	{ .compatible = "arm,cortex-a7-gic",	.data = vgic_v2_probe, },
+	{ .compatible = "arm,gic-400",		.data = vgic_v2_probe, },
+	{ .compatible = "arm,gic-v3",		.data = vgic_v3_probe, },
+	{},
+};
+
+/**
+ * kvm_vgic_hyp_init: populates the kvm_vgic_global_state variable
+ * according to the host GIC model. Accordingly calls either
+ * vgic_v2/v3_probe which registers the KVM_DEVICE that can be
+ * instantiated by a guest later on .
+ */
+int kvm_vgic_hyp_init(void)
+{
+	const struct of_device_id *matched_id;
+	const int (*vgic_probe)(struct device_node *);
+	struct device_node *vgic_node;
+	int ret;
+
+	vgic_node = of_find_matching_node_and_match(NULL,
+						    vgic_ids, &matched_id);
+	if (!vgic_node) {
+		kvm_err("error: no compatible GIC node found\n");
+		return -ENODEV;
+	}
+
+	vgic_probe = matched_id->data;
+	ret = vgic_probe(vgic_node);
+	if (ret)
+		return ret;
+
+	ret = request_percpu_irq(kvm_vgic_global_state.maint_irq,
+				 vgic_maintenance_handler,
+				 "vgic", kvm_get_running_vcpus());
+	if (ret) {
+		kvm_err("Cannot register interrupt %d\n",
+			kvm_vgic_global_state.maint_irq);
+		return ret;
+	}
+
+	ret = __register_cpu_notifier(&vgic_cpu_nb);
+	if (ret) {
+		kvm_err("Cannot register vgic CPU notifier\n");
+		goto out_free_irq;
+	}
+
+	on_each_cpu(vgic_init_maintenance_interrupt, NULL, 1);
+
+	return 0;
+
+out_free_irq:
+	free_percpu_irq(kvm_vgic_global_state.maint_irq,
+			kvm_get_running_vcpus());
+	return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 70cac63..91b69a4 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -17,6 +17,11 @@
 #include <linux/irqchip/arm-gic.h>
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
+#include <kvm/arm_vgic.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/kvm_mmu.h>
 
 #include "vgic.h"
 
@@ -205,3 +210,88 @@ void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcrp->pmr  = (vmcr & GICH_VMCR_PRIMASK_MASK) >>
 			GICH_VMCR_PRIMASK_SHIFT;
 }
+
+/**
+ * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
+ * @node:	pointer to the DT node
+ *
+ * Returns 0 if a GICv2 has been found, returns an error code otherwise
+ */
+int vgic_v2_probe(struct device_node *vgic_node)
+{
+	int ret;
+	struct resource vctrl_res;
+	struct resource vcpu_res;
+
+	kvm_vgic_global_state.maint_irq = irq_of_parse_and_map(vgic_node, 0);
+	if (!kvm_vgic_global_state.maint_irq) {
+		kvm_err("error getting vgic maintenance irq from DT\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	ret = of_address_to_resource(vgic_node, 2, &vctrl_res);
+	if (ret) {
+		kvm_err("Cannot obtain GICH resource\n");
+		goto out;
+	}
+
+	kvm_vgic_global_state.vctrl_base = of_iomap(vgic_node, 2);
+	if (!kvm_vgic_global_state.vctrl_base) {
+		kvm_err("Cannot ioremap GICH\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	kvm_vgic_global_state.nr_lr =
+		readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VTR);
+	kvm_vgic_global_state.nr_lr = (kvm_vgic_global_state.nr_lr & 0x3f) + 1;
+
+	ret = create_hyp_io_mappings(kvm_vgic_global_state.vctrl_base,
+				     kvm_vgic_global_state.vctrl_base +
+					 resource_size(&vctrl_res),
+				     vctrl_res.start);
+	if (ret) {
+		kvm_err("Cannot map VCTRL into hyp\n");
+		goto out_unmap;
+	}
+
+	if (of_address_to_resource(vgic_node, 3, &vcpu_res)) {
+		kvm_err("Cannot obtain GICV resource\n");
+		ret = -ENXIO;
+		goto out_unmap;
+	}
+
+	if (!PAGE_ALIGNED(vcpu_res.start)) {
+		kvm_err("GICV physical address 0x%llx not page aligned\n",
+			(unsigned long long)vcpu_res.start);
+		ret = -ENXIO;
+		goto out_unmap;
+	}
+
+	if (!PAGE_ALIGNED(resource_size(&vcpu_res))) {
+		kvm_err("GICV size 0x%llx not a multiple of page size 0x%lx\n",
+			(unsigned long long)resource_size(&vcpu_res),
+			PAGE_SIZE);
+		ret = -ENXIO;
+		goto out_unmap;
+	}
+
+	kvm_vgic_global_state.can_emulate_gicv2 = true;
+	kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
+
+	kvm_vgic_global_state.vcpu_base = vcpu_res.start;
+
+	kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
+		 vctrl_res.start, kvm_vgic_global_state.maint_irq);
+
+	kvm_vgic_global_state.type = VGIC_V2;
+	kvm_vgic_global_state.max_gic_vcpus = VGIC_V2_MAX_CPUS;
+	goto out;
+
+out_unmap:
+	iounmap(kvm_vgic_global_state.vctrl_base);
+out:
+	of_node_put(vgic_node);
+	return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index dca52b3..48b0bb7 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -15,6 +15,12 @@
 #include <linux/irqchip/arm-gic-v3.h>
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
+#include <kvm/arm_vgic.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/kvm_mmu.h>
+#include <asm/kvm_asm.h>
 
 #include "vgic.h"
 
@@ -188,3 +194,70 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcrp->bpr  = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
 	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
 }
+
+/**
+ * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
+ * @node:	pointer to the DT node
+ *
+ * Returns 0 if a GICv3 has been found, returns an error code otherwise
+ */
+int vgic_v3_probe(struct device_node *vgic_node)
+{
+	u32 ich_vtr_el2;
+	u32 gicv_idx;
+	int ret = 0;
+	struct resource vcpu_res;
+
+	kvm_vgic_global_state.maint_irq = irq_of_parse_and_map(vgic_node, 0);
+	if (!kvm_vgic_global_state.maint_irq) {
+		kvm_err("error getting vgic maintenance irq from DT\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	ich_vtr_el2 = kvm_call_hyp(__vgic_v3_get_ich_vtr_el2);
+
+	/*
+	 * The ListRegs field is 5 bits, but there is a architectural
+	 * maximum of 16 list registers. Just ignore bit 4...
+	 */
+	kvm_vgic_global_state.nr_lr = (ich_vtr_el2 & 0xf) + 1;
+	kvm_vgic_global_state.can_emulate_gicv2 = false;
+
+	if (of_property_read_u32(vgic_node, "#redistributor-regions",
+				 &gicv_idx))
+		gicv_idx = 1;
+
+	gicv_idx += 3; /* Also skip GICD, GICC, GICH */
+	if (of_address_to_resource(vgic_node, gicv_idx, &vcpu_res)) {
+		kvm_info("GICv3: no GICV resource entry\n");
+		kvm_vgic_global_state.vcpu_base = 0;
+	} else if (!PAGE_ALIGNED(vcpu_res.start)) {
+		pr_warn("GICV physical address 0x%llx not page aligned\n",
+			(unsigned long long)vcpu_res.start);
+		kvm_vgic_global_state.vcpu_base = 0;
+	} else if (!PAGE_ALIGNED(resource_size(&vcpu_res))) {
+		pr_warn("GICV size 0x%llx not a multiple of page size 0x%lx\n",
+			(unsigned long long)resource_size(&vcpu_res),
+			PAGE_SIZE);
+		kvm_vgic_global_state.vcpu_base = 0;
+	} else {
+		kvm_vgic_global_state.vcpu_base = vcpu_res.start;
+		kvm_vgic_global_state.can_emulate_gicv2 = true;
+		kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
+	}
+	if (kvm_vgic_global_state.vcpu_base == 0)
+		kvm_info("disabling GICv2 emulation\n");
+	kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V3);
+
+	kvm_vgic_global_state.vctrl_base = NULL;
+	kvm_vgic_global_state.type = VGIC_V3;
+	kvm_vgic_global_state.max_gic_vcpus = VGIC_V3_MAX_CPUS;
+
+	kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
+		 vcpu_res.start, kvm_vgic_global_state.maint_irq);
+
+out:
+	of_node_put(vgic_node);
+	return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 7a69955..e49b1df 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -43,6 +43,7 @@ int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			  int offset, u32 *val);
 void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+int vgic_v2_probe(struct device_node *vgic_node);
 int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
 			     enum vgic_type);
 
@@ -54,6 +55,7 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
 void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+int vgic_v3_probe(struct device_node *vgic_node);
 int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
 #else
 static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
@@ -87,6 +89,11 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
 {
 }
 
+static inline int vgic_v3_probe(struct device_node *vgic_node)
+{
+	return -ENODEV;
+}
+
 static inline int vgic_register_redist_iodevs(struct kvm *kvm,
 					      gpa_t dist_base_address)
 {
-- 
2.7.3

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

* [PATCH v3 48/55] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
@ 2016-05-06 10:46   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:46 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

Implements kvm_vgic_hyp_init and vgic_probe function.

The vgic_global struct is enriched with new fields populated
by those functions.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- rename vgic_init.c to vgic-init.c

Changelog v2 .. v3:
- include kvm/arm_vgic.h instead of kvm/vgic/vgic.h
- move ich_vtr_el2 variable into probe function

 include/kvm/vgic/vgic.h       |   1 +
 virt/kvm/arm/vgic/vgic-init.c | 122 ++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v2.c   |  90 +++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c   |  73 +++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h      |   7 +++
 5 files changed, 293 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic-init.c

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index cfc3640..d144e3d 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -202,6 +202,7 @@ struct vgic_cpu {
 };
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
+int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level);
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
new file mode 100644
index 0000000..f10997b
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/cpu.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/kvm_host.h>
+#include <kvm/arm_vgic.h>
+#include <asm/kvm_mmu.h>
+#include "vgic.h"
+
+/* GENERIC PROBE */
+
+static void vgic_init_maintenance_interrupt(void *info)
+{
+	enable_percpu_irq(kvm_vgic_global_state.maint_irq, 0);
+}
+
+static int vgic_cpu_notify(struct notifier_block *self,
+			   unsigned long action, void *cpu)
+{
+	switch (action) {
+	case CPU_STARTING:
+	case CPU_STARTING_FROZEN:
+		vgic_init_maintenance_interrupt(NULL);
+		break;
+	case CPU_DYING:
+	case CPU_DYING_FROZEN:
+		disable_percpu_irq(kvm_vgic_global_state.maint_irq);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block vgic_cpu_nb = {
+	.notifier_call = vgic_cpu_notify,
+};
+
+static irqreturn_t vgic_maintenance_handler(int irq, void *data)
+{
+	/*
+	 * We cannot rely on the vgic maintenance interrupt to be
+	 * delivered synchronously. This means we can only use it to
+	 * exit the VM, and we perform the handling of EOIed
+	 * interrupts on the exit path (see vgic_process_maintenance).
+	 */
+	return IRQ_HANDLED;
+}
+
+static const struct of_device_id vgic_ids[] = {
+	{ .compatible = "arm,cortex-a15-gic",	.data = vgic_v2_probe, },
+	{ .compatible = "arm,cortex-a7-gic",	.data = vgic_v2_probe, },
+	{ .compatible = "arm,gic-400",		.data = vgic_v2_probe, },
+	{ .compatible = "arm,gic-v3",		.data = vgic_v3_probe, },
+	{},
+};
+
+/**
+ * kvm_vgic_hyp_init: populates the kvm_vgic_global_state variable
+ * according to the host GIC model. Accordingly calls either
+ * vgic_v2/v3_probe which registers the KVM_DEVICE that can be
+ * instantiated by a guest later on .
+ */
+int kvm_vgic_hyp_init(void)
+{
+	const struct of_device_id *matched_id;
+	const int (*vgic_probe)(struct device_node *);
+	struct device_node *vgic_node;
+	int ret;
+
+	vgic_node = of_find_matching_node_and_match(NULL,
+						    vgic_ids, &matched_id);
+	if (!vgic_node) {
+		kvm_err("error: no compatible GIC node found\n");
+		return -ENODEV;
+	}
+
+	vgic_probe = matched_id->data;
+	ret = vgic_probe(vgic_node);
+	if (ret)
+		return ret;
+
+	ret = request_percpu_irq(kvm_vgic_global_state.maint_irq,
+				 vgic_maintenance_handler,
+				 "vgic", kvm_get_running_vcpus());
+	if (ret) {
+		kvm_err("Cannot register interrupt %d\n",
+			kvm_vgic_global_state.maint_irq);
+		return ret;
+	}
+
+	ret = __register_cpu_notifier(&vgic_cpu_nb);
+	if (ret) {
+		kvm_err("Cannot register vgic CPU notifier\n");
+		goto out_free_irq;
+	}
+
+	on_each_cpu(vgic_init_maintenance_interrupt, NULL, 1);
+
+	return 0;
+
+out_free_irq:
+	free_percpu_irq(kvm_vgic_global_state.maint_irq,
+			kvm_get_running_vcpus());
+	return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 70cac63..91b69a4 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -17,6 +17,11 @@
 #include <linux/irqchip/arm-gic.h>
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
+#include <kvm/arm_vgic.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/kvm_mmu.h>
 
 #include "vgic.h"
 
@@ -205,3 +210,88 @@ void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcrp->pmr  = (vmcr & GICH_VMCR_PRIMASK_MASK) >>
 			GICH_VMCR_PRIMASK_SHIFT;
 }
+
+/**
+ * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
+ * @node:	pointer to the DT node
+ *
+ * Returns 0 if a GICv2 has been found, returns an error code otherwise
+ */
+int vgic_v2_probe(struct device_node *vgic_node)
+{
+	int ret;
+	struct resource vctrl_res;
+	struct resource vcpu_res;
+
+	kvm_vgic_global_state.maint_irq = irq_of_parse_and_map(vgic_node, 0);
+	if (!kvm_vgic_global_state.maint_irq) {
+		kvm_err("error getting vgic maintenance irq from DT\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	ret = of_address_to_resource(vgic_node, 2, &vctrl_res);
+	if (ret) {
+		kvm_err("Cannot obtain GICH resource\n");
+		goto out;
+	}
+
+	kvm_vgic_global_state.vctrl_base = of_iomap(vgic_node, 2);
+	if (!kvm_vgic_global_state.vctrl_base) {
+		kvm_err("Cannot ioremap GICH\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	kvm_vgic_global_state.nr_lr =
+		readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VTR);
+	kvm_vgic_global_state.nr_lr = (kvm_vgic_global_state.nr_lr & 0x3f) + 1;
+
+	ret = create_hyp_io_mappings(kvm_vgic_global_state.vctrl_base,
+				     kvm_vgic_global_state.vctrl_base +
+					 resource_size(&vctrl_res),
+				     vctrl_res.start);
+	if (ret) {
+		kvm_err("Cannot map VCTRL into hyp\n");
+		goto out_unmap;
+	}
+
+	if (of_address_to_resource(vgic_node, 3, &vcpu_res)) {
+		kvm_err("Cannot obtain GICV resource\n");
+		ret = -ENXIO;
+		goto out_unmap;
+	}
+
+	if (!PAGE_ALIGNED(vcpu_res.start)) {
+		kvm_err("GICV physical address 0x%llx not page aligned\n",
+			(unsigned long long)vcpu_res.start);
+		ret = -ENXIO;
+		goto out_unmap;
+	}
+
+	if (!PAGE_ALIGNED(resource_size(&vcpu_res))) {
+		kvm_err("GICV size 0x%llx not a multiple of page size 0x%lx\n",
+			(unsigned long long)resource_size(&vcpu_res),
+			PAGE_SIZE);
+		ret = -ENXIO;
+		goto out_unmap;
+	}
+
+	kvm_vgic_global_state.can_emulate_gicv2 = true;
+	kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
+
+	kvm_vgic_global_state.vcpu_base = vcpu_res.start;
+
+	kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
+		 vctrl_res.start, kvm_vgic_global_state.maint_irq);
+
+	kvm_vgic_global_state.type = VGIC_V2;
+	kvm_vgic_global_state.max_gic_vcpus = VGIC_V2_MAX_CPUS;
+	goto out;
+
+out_unmap:
+	iounmap(kvm_vgic_global_state.vctrl_base);
+out:
+	of_node_put(vgic_node);
+	return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index dca52b3..48b0bb7 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -15,6 +15,12 @@
 #include <linux/irqchip/arm-gic-v3.h>
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
+#include <kvm/arm_vgic.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/kvm_mmu.h>
+#include <asm/kvm_asm.h>
 
 #include "vgic.h"
 
@@ -188,3 +194,70 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcrp->bpr  = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
 	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
 }
+
+/**
+ * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
+ * @node:	pointer to the DT node
+ *
+ * Returns 0 if a GICv3 has been found, returns an error code otherwise
+ */
+int vgic_v3_probe(struct device_node *vgic_node)
+{
+	u32 ich_vtr_el2;
+	u32 gicv_idx;
+	int ret = 0;
+	struct resource vcpu_res;
+
+	kvm_vgic_global_state.maint_irq = irq_of_parse_and_map(vgic_node, 0);
+	if (!kvm_vgic_global_state.maint_irq) {
+		kvm_err("error getting vgic maintenance irq from DT\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	ich_vtr_el2 = kvm_call_hyp(__vgic_v3_get_ich_vtr_el2);
+
+	/*
+	 * The ListRegs field is 5 bits, but there is a architectural
+	 * maximum of 16 list registers. Just ignore bit 4...
+	 */
+	kvm_vgic_global_state.nr_lr = (ich_vtr_el2 & 0xf) + 1;
+	kvm_vgic_global_state.can_emulate_gicv2 = false;
+
+	if (of_property_read_u32(vgic_node, "#redistributor-regions",
+				 &gicv_idx))
+		gicv_idx = 1;
+
+	gicv_idx += 3; /* Also skip GICD, GICC, GICH */
+	if (of_address_to_resource(vgic_node, gicv_idx, &vcpu_res)) {
+		kvm_info("GICv3: no GICV resource entry\n");
+		kvm_vgic_global_state.vcpu_base = 0;
+	} else if (!PAGE_ALIGNED(vcpu_res.start)) {
+		pr_warn("GICV physical address 0x%llx not page aligned\n",
+			(unsigned long long)vcpu_res.start);
+		kvm_vgic_global_state.vcpu_base = 0;
+	} else if (!PAGE_ALIGNED(resource_size(&vcpu_res))) {
+		pr_warn("GICV size 0x%llx not a multiple of page size 0x%lx\n",
+			(unsigned long long)resource_size(&vcpu_res),
+			PAGE_SIZE);
+		kvm_vgic_global_state.vcpu_base = 0;
+	} else {
+		kvm_vgic_global_state.vcpu_base = vcpu_res.start;
+		kvm_vgic_global_state.can_emulate_gicv2 = true;
+		kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
+	}
+	if (kvm_vgic_global_state.vcpu_base == 0)
+		kvm_info("disabling GICv2 emulation\n");
+	kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V3);
+
+	kvm_vgic_global_state.vctrl_base = NULL;
+	kvm_vgic_global_state.type = VGIC_V3;
+	kvm_vgic_global_state.max_gic_vcpus = VGIC_V3_MAX_CPUS;
+
+	kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
+		 vcpu_res.start, kvm_vgic_global_state.maint_irq);
+
+out:
+	of_node_put(vgic_node);
+	return ret;
+}
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 7a69955..e49b1df 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -43,6 +43,7 @@ int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			  int offset, u32 *val);
 void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+int vgic_v2_probe(struct device_node *vgic_node);
 int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
 			     enum vgic_type);
 
@@ -54,6 +55,7 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
 void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+int vgic_v3_probe(struct device_node *vgic_node);
 int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
 #else
 static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
@@ -87,6 +89,11 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
 {
 }
 
+static inline int vgic_v3_probe(struct device_node *vgic_node)
+{
+	return -ENODEV;
+}
+
 static inline int vgic_register_redist_iodevs(struct kvm *kvm,
 					      gpa_t dist_base_address)
 {
-- 
2.7.3

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

* [PATCH v3 49/55] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:46   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:46 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

This patch implements the vgic_creation function which is
called on CREATE_IRQCHIP VM IOCTL (v2 only) or KVM_CREATE_DEVICE

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h       |  1 +
 virt/kvm/arm/vgic/vgic-init.c | 84 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 85 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index d144e3d..899b7b7 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -202,6 +202,7 @@ struct vgic_cpu {
 };
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
+int kvm_vgic_create(struct kvm *kvm, u32 type);
 int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
index f10997b..a150363 100644
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -24,6 +24,90 @@
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
+/* CREATION */
+
+/**
+ * kvm_vgic_create: triggered by the instantiation of the VGIC device by
+ * user space, either through the legacy ARM specific VM IOCTL (CREATE_IRQCHIP)
+ * or through the generic VM IOCTL, KVM_CREATE_DEVICE API.
+ * Completion can be tested by irqchip_in_kernel
+ */
+int kvm_vgic_create(struct kvm *kvm, u32 type)
+{
+	int i, vcpu_lock_idx = -1, ret;
+	struct kvm_vcpu *vcpu;
+
+	mutex_lock(&kvm->lock);
+
+	if (irqchip_in_kernel(kvm)) {
+		ret = -EEXIST;
+		goto out;
+	}
+
+	/*
+	 * This function is also called by the KVM_CREATE_IRQCHIP handler,
+	 * which had no chance yet to check the availability of the GICv2
+	 * emulation. So check this here again. KVM_CREATE_DEVICE does
+	 * the proper checks already.
+	 */
+	if (type == KVM_DEV_TYPE_ARM_VGIC_V2 &&
+		!kvm_vgic_global_state.can_emulate_gicv2) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/*
+	 * Any time a vcpu is run, vcpu_load is called which tries to grab the
+	 * vcpu->mutex.  By grabbing the vcpu->mutex of all VCPUs we ensure
+	 * that no other VCPUs are run while we create the vgic.
+	 */
+	ret = -EBUSY;
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		if (!mutex_trylock(&vcpu->mutex))
+			goto out_unlock;
+		vcpu_lock_idx = i;
+	}
+
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		if (vcpu->arch.has_run_once)
+			goto out_unlock;
+	}
+	ret = 0;
+
+	if (type == KVM_DEV_TYPE_ARM_VGIC_V2)
+		kvm->arch.max_vcpus = VGIC_V2_MAX_CPUS;
+	else
+		kvm->arch.max_vcpus = VGIC_V3_MAX_CPUS;
+
+	if (atomic_read(&kvm->online_vcpus) > kvm->arch.max_vcpus) {
+		ret = -E2BIG;
+		goto out_unlock;
+	}
+
+	kvm->arch.vgic.in_kernel = true;
+	kvm->arch.vgic.vgic_model = type;
+
+	/*
+	 * kvm_vgic_global_state.vctrl_base is set on vgic probe (kvm_arch_init)
+	 * it is stored in distributor struct for asm save/restore purpose
+	 */
+	kvm->arch.vgic.vctrl_base = kvm_vgic_global_state.vctrl_base;
+
+	kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
+	kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
+	kvm->arch.vgic.vgic_redist_base = VGIC_ADDR_UNDEF;
+
+out_unlock:
+	for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
+		vcpu = kvm_get_vcpu(kvm, vcpu_lock_idx);
+		mutex_unlock(&vcpu->mutex);
+	}
+
+out:
+	mutex_unlock(&kvm->lock);
+	return ret;
+}
+
 /* GENERIC PROBE */
 
 static void vgic_init_maintenance_interrupt(void *info)
-- 
2.7.3

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

* [PATCH v3 49/55] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create
@ 2016-05-06 10:46   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:46 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

This patch implements the vgic_creation function which is
called on CREATE_IRQCHIP VM IOCTL (v2 only) or KVM_CREATE_DEVICE

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h       |  1 +
 virt/kvm/arm/vgic/vgic-init.c | 84 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 85 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index d144e3d..899b7b7 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -202,6 +202,7 @@ struct vgic_cpu {
 };
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
+int kvm_vgic_create(struct kvm *kvm, u32 type);
 int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
index f10997b..a150363 100644
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -24,6 +24,90 @@
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
+/* CREATION */
+
+/**
+ * kvm_vgic_create: triggered by the instantiation of the VGIC device by
+ * user space, either through the legacy ARM specific VM IOCTL (CREATE_IRQCHIP)
+ * or through the generic VM IOCTL, KVM_CREATE_DEVICE API.
+ * Completion can be tested by irqchip_in_kernel
+ */
+int kvm_vgic_create(struct kvm *kvm, u32 type)
+{
+	int i, vcpu_lock_idx = -1, ret;
+	struct kvm_vcpu *vcpu;
+
+	mutex_lock(&kvm->lock);
+
+	if (irqchip_in_kernel(kvm)) {
+		ret = -EEXIST;
+		goto out;
+	}
+
+	/*
+	 * This function is also called by the KVM_CREATE_IRQCHIP handler,
+	 * which had no chance yet to check the availability of the GICv2
+	 * emulation. So check this here again. KVM_CREATE_DEVICE does
+	 * the proper checks already.
+	 */
+	if (type == KVM_DEV_TYPE_ARM_VGIC_V2 &&
+		!kvm_vgic_global_state.can_emulate_gicv2) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/*
+	 * Any time a vcpu is run, vcpu_load is called which tries to grab the
+	 * vcpu->mutex.  By grabbing the vcpu->mutex of all VCPUs we ensure
+	 * that no other VCPUs are run while we create the vgic.
+	 */
+	ret = -EBUSY;
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		if (!mutex_trylock(&vcpu->mutex))
+			goto out_unlock;
+		vcpu_lock_idx = i;
+	}
+
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		if (vcpu->arch.has_run_once)
+			goto out_unlock;
+	}
+	ret = 0;
+
+	if (type == KVM_DEV_TYPE_ARM_VGIC_V2)
+		kvm->arch.max_vcpus = VGIC_V2_MAX_CPUS;
+	else
+		kvm->arch.max_vcpus = VGIC_V3_MAX_CPUS;
+
+	if (atomic_read(&kvm->online_vcpus) > kvm->arch.max_vcpus) {
+		ret = -E2BIG;
+		goto out_unlock;
+	}
+
+	kvm->arch.vgic.in_kernel = true;
+	kvm->arch.vgic.vgic_model = type;
+
+	/*
+	 * kvm_vgic_global_state.vctrl_base is set on vgic probe (kvm_arch_init)
+	 * it is stored in distributor struct for asm save/restore purpose
+	 */
+	kvm->arch.vgic.vctrl_base = kvm_vgic_global_state.vctrl_base;
+
+	kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
+	kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
+	kvm->arch.vgic.vgic_redist_base = VGIC_ADDR_UNDEF;
+
+out_unlock:
+	for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
+		vcpu = kvm_get_vcpu(kvm, vcpu_lock_idx);
+		mutex_unlock(&vcpu->mutex);
+	}
+
+out:
+	mutex_unlock(&kvm->lock);
+	return ret;
+}
+
 /* GENERIC PROBE */
 
 static void vgic_init_maintenance_interrupt(void *info)
-- 
2.7.3

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

* [PATCH v3 50/55] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:46   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:46 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

This patch allocates and initializes the data structures used
to model the vgic distributor and virtual cpu interfaces. At that
stage the number of IRQs and number of virtual CPUs is frozen.

The following early_init functions are kept since they are called from
arm.c. However they may disappear in subsequent patches since
they are void.

vgic_[v2|v3]_enable still is stubbed at this stage.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- initialize v2/v3 default CPU affinities explicitly

Changelog v1 .. v2:
- move lazy_init() into vgic_update_irq_pending()

 include/kvm/vgic/vgic.h       |   7 +-
 virt/kvm/arm/vgic/vgic-init.c | 213 ++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v2.c   |   5 +
 virt/kvm/arm/vgic/vgic-v3.c   |   5 +
 virt/kvm/arm/vgic/vgic.c      |   4 +
 virt/kvm/arm/vgic/vgic.h      |   8 ++
 6 files changed, 241 insertions(+), 1 deletion(-)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 899b7b7..538078a 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -119,6 +119,7 @@ struct vgic_io_device {
 struct vgic_dist {
 	bool			in_kernel;
 	bool			ready;
+	bool			initialized;
 
 	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
 	u32			vgic_model;
@@ -202,7 +203,11 @@ struct vgic_cpu {
 };
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
+void kvm_vgic_early_init(struct kvm *kvm);
 int kvm_vgic_create(struct kvm *kvm, u32 type);
+void kvm_vgic_destroy(struct kvm *kvm);
+void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
+void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
 int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
@@ -211,7 +216,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
-#define vgic_initialized(k)	(false)
+#define vgic_initialized(k)	((k)->arch.vgic.initialized)
 #define vgic_ready(k)		((k)->arch.vgic.ready)
 #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
 			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
index a150363..3f9c137 100644
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -24,6 +24,42 @@
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
+/*
+ * Initialization rules: there are multiple stages to the vgic
+ * initialization, both for the distributor and the CPU interfaces.
+ *
+ * Distributor:
+ *
+ * - kvm_vgic_early_init(): initialization of static data that doesn't
+ *   depend on any sizing information or emulation type. No allocation
+ *   is allowed there.
+ *
+ * - vgic_init(): allocation and initialization of the generic data
+ *   structures that depend on sizing information (number of CPUs,
+ *   number of interrupts). Also initializes the vcpu specific data
+ *   structures. Can be executed lazily for GICv2.
+ *
+ * CPU Interface:
+ *
+ * - kvm_vgic_cpu_early_init(): initialization of static data that
+ *   doesn't depend on any sizing information or emulation type. No
+ *   allocation is allowed there.
+ */
+
+/* EARLY INIT */
+
+/*
+ * Those 2 functions should not be needed anymore but they
+ * still are called from arm.c
+ */
+void kvm_vgic_early_init(struct kvm *kvm)
+{
+}
+
+void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu)
+{
+}
+
 /* CREATION */
 
 /**
@@ -108,6 +144,183 @@ out:
 	return ret;
 }
 
+/* INIT/DESTROY */
+
+/**
+ * kvm_vgic_dist_init: initialize the dist data structures
+ * @kvm: kvm struct pointer
+ * @nr_spis: number of spis, frozen by caller
+ */
+int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
+	int i;
+
+	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
+	if (!dist->spis)
+		return  -ENOMEM;
+
+	/*
+	 * In following code we do not take the irq struct lock since
+	 * no other action on irq structs can happen while the VGIC is
+	 * not initialized yet:
+	 * injection requires (VGICV3) or does (VGIC2) initialization.
+	 * MMIO access triggers init.
+	 */
+	for (i = 0; i < nr_spis; i++) {
+		struct vgic_irq *irq = &dist->spis[i];
+
+		irq->intid = i + VGIC_NR_PRIVATE_IRQS;
+		INIT_LIST_HEAD(&irq->ap_list);
+		spin_lock_init(&irq->irq_lock);
+		irq->vcpu = NULL;
+		irq->target_vcpu = vcpu0;
+		if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
+			irq->targets = 0;
+		else
+			irq->mpidr = 0;
+	}
+	return 0;
+}
+
+/**
+ * kvm_vgic_vcpu_init: initialize the vcpu data structures and
+ * enable the VCPU interface
+ * @kvm: kvm struct pointer
+ */
+void kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	int i;
+
+	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
+	spin_lock_init(&vgic_cpu->ap_list_lock);
+
+	/*
+	 * Enable and configure all SGIs to be edge-triggered and
+	 * configure all PPIs as level-triggered.
+	 */
+	for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
+		struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
+
+		INIT_LIST_HEAD(&irq->ap_list);
+		spin_lock_init(&irq->irq_lock);
+		irq->intid = i;
+		irq->vcpu = NULL;
+		irq->target_vcpu = vcpu;
+		irq->targets = 1U << vcpu->vcpu_id;
+		if (vgic_irq_is_sgi(i)) {
+			/* SGIs */
+			irq->enabled = 1;
+			irq->config = VGIC_CONFIG_EDGE;
+		} else {
+			/* PPIs */
+			irq->config = VGIC_CONFIG_LEVEL;
+		}
+	}
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_enable(vcpu);
+	else
+		vgic_v3_enable(vcpu);
+}
+
+/*
+ * vgic_init: allocates and initializes dist and vcpu data structures
+ * depending on two dimensioning parameters:
+ * - the number of spis
+ * - the number of vcpus
+ * The function is generally called when nr_spis has been explicitly set
+ * by the guest through the KVM DEVICE API. If not nr_spis is set to 256.
+ * Completion can be tested by vgic_initialized
+ * Must be called with kvm->lock held!
+ */
+int vgic_init(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	struct kvm_vcpu *vcpu;
+	int ret = 0, i;
+
+	if (vgic_initialized(kvm))
+		return 0;
+
+	/* freeze the number of spis */
+	if (!dist->nr_spis)
+		dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;
+
+	ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
+	if (ret)
+		goto out;
+
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		kvm_vgic_vcpu_init(vcpu);
+
+	dist->initialized = true;
+out:
+	return ret;
+}
+
+static void kvm_vgic_dist_destroy(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+
+	mutex_lock(&kvm->lock);
+
+	dist->ready = false;
+	dist->initialized = false;
+
+	kfree(dist->spis);
+	kfree(dist->redist_iodevs);
+	dist->nr_spis = 0;
+
+	mutex_unlock(&kvm->lock);
+}
+
+void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+
+	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
+}
+
+void kvm_vgic_destroy(struct kvm *kvm)
+{
+	struct kvm_vcpu *vcpu;
+	int i;
+
+	kvm_vgic_dist_destroy(kvm);
+
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		kvm_vgic_vcpu_destroy(vcpu);
+}
+
+/**
+ * Lazy init only is allowed if the GIC exposed to the guest is a GICV2.
+ * GICV3 must be explicitly initialized by the guest using the
+ * KVM_DEV_ARM_VGIC_GRP_CTRL KVM_DEVICE group
+ */
+int vgic_lazy_init(struct kvm *kvm)
+{
+	int ret = 0;
+
+	if (unlikely(!vgic_initialized(kvm))) {
+		/*
+		 * We only provide the automatic initialization of the VGIC
+		 * for the legacy case of a GICv2. Any other type must
+		 * be explicitly initialized once setup with the respective
+		 * KVM device call.
+		 */
+		if (kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2)
+			return -EBUSY;
+
+		mutex_lock(&kvm->lock);
+		ret = vgic_init(kvm);
+		mutex_unlock(&kvm->lock);
+	}
+
+	return ret;
+}
+
 /* GENERIC PROBE */
 
 static void vgic_init_maintenance_interrupt(void *info)
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 91b69a4..48aa877 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -211,6 +211,11 @@ void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 			GICH_VMCR_PRIMASK_SHIFT;
 }
 
+/* not yet implemented */
+void vgic_v2_enable(struct kvm_vcpu *vcpu)
+{
+}
+
 /**
  * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
  * @node:	pointer to the DT node
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 48b0bb7..7cab5b9 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -195,6 +195,11 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
 }
 
+/* not yet implemented */
+void vgic_v3_enable(struct kvm_vcpu *vcpu)
+{
+}
+
 /**
  * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
  * @node:	pointer to the DT node
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 5355de6..068389a 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -255,6 +255,10 @@ static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
 
 	trace_vgic_update_irq_pending(cpuid, intid, level);
 
+	ret = vgic_lazy_init(kvm);
+	if (ret)
+		return ret;
+
 	vcpu = kvm_get_vcpu(kvm, cpuid);
 	if (!vcpu && intid < VGIC_NR_PRIVATE_IRQS)
 		return -EINVAL;
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index e49b1df..cad04eb 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -43,6 +43,7 @@ int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			  int offset, u32 *val);
 void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v2_enable(struct kvm_vcpu *vcpu);
 int vgic_v2_probe(struct device_node *vgic_node);
 int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
 			     enum vgic_type);
@@ -55,6 +56,7 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
 void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v3_enable(struct kvm_vcpu *vcpu);
 int vgic_v3_probe(struct device_node *vgic_node);
 int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
 #else
@@ -89,6 +91,10 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
 {
 }
 
+static inline void vgic_v3_enable(struct kvm_vcpu *vcpu)
+{
+}
+
 static inline int vgic_v3_probe(struct device_node *vgic_node)
 {
 	return -ENODEV;
@@ -102,5 +108,7 @@ static inline int vgic_register_redist_iodevs(struct kvm *kvm,
 #endif
 
 void kvm_register_vgic_device(unsigned long type);
+int vgic_lazy_init(struct kvm *kvm);
+int vgic_init(struct kvm *kvm);
 
 #endif
-- 
2.7.3


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

* [PATCH v3 50/55] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
@ 2016-05-06 10:46   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:46 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

This patch allocates and initializes the data structures used
to model the vgic distributor and virtual cpu interfaces. At that
stage the number of IRQs and number of virtual CPUs is frozen.

The following early_init functions are kept since they are called from
arm.c. However they may disappear in subsequent patches since
they are void.

vgic_[v2|v3]_enable still is stubbed at this stage.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- initialize v2/v3 default CPU affinities explicitly

Changelog v1 .. v2:
- move lazy_init() into vgic_update_irq_pending()

 include/kvm/vgic/vgic.h       |   7 +-
 virt/kvm/arm/vgic/vgic-init.c | 213 ++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v2.c   |   5 +
 virt/kvm/arm/vgic/vgic-v3.c   |   5 +
 virt/kvm/arm/vgic/vgic.c      |   4 +
 virt/kvm/arm/vgic/vgic.h      |   8 ++
 6 files changed, 241 insertions(+), 1 deletion(-)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 899b7b7..538078a 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -119,6 +119,7 @@ struct vgic_io_device {
 struct vgic_dist {
 	bool			in_kernel;
 	bool			ready;
+	bool			initialized;
 
 	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
 	u32			vgic_model;
@@ -202,7 +203,11 @@ struct vgic_cpu {
 };
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
+void kvm_vgic_early_init(struct kvm *kvm);
 int kvm_vgic_create(struct kvm *kvm, u32 type);
+void kvm_vgic_destroy(struct kvm *kvm);
+void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
+void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
 int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
@@ -211,7 +216,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
-#define vgic_initialized(k)	(false)
+#define vgic_initialized(k)	((k)->arch.vgic.initialized)
 #define vgic_ready(k)		((k)->arch.vgic.ready)
 #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
 			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
index a150363..3f9c137 100644
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -24,6 +24,42 @@
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
+/*
+ * Initialization rules: there are multiple stages to the vgic
+ * initialization, both for the distributor and the CPU interfaces.
+ *
+ * Distributor:
+ *
+ * - kvm_vgic_early_init(): initialization of static data that doesn't
+ *   depend on any sizing information or emulation type. No allocation
+ *   is allowed there.
+ *
+ * - vgic_init(): allocation and initialization of the generic data
+ *   structures that depend on sizing information (number of CPUs,
+ *   number of interrupts). Also initializes the vcpu specific data
+ *   structures. Can be executed lazily for GICv2.
+ *
+ * CPU Interface:
+ *
+ * - kvm_vgic_cpu_early_init(): initialization of static data that
+ *   doesn't depend on any sizing information or emulation type. No
+ *   allocation is allowed there.
+ */
+
+/* EARLY INIT */
+
+/*
+ * Those 2 functions should not be needed anymore but they
+ * still are called from arm.c
+ */
+void kvm_vgic_early_init(struct kvm *kvm)
+{
+}
+
+void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu)
+{
+}
+
 /* CREATION */
 
 /**
@@ -108,6 +144,183 @@ out:
 	return ret;
 }
 
+/* INIT/DESTROY */
+
+/**
+ * kvm_vgic_dist_init: initialize the dist data structures
+ * @kvm: kvm struct pointer
+ * @nr_spis: number of spis, frozen by caller
+ */
+int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
+	int i;
+
+	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
+	if (!dist->spis)
+		return  -ENOMEM;
+
+	/*
+	 * In following code we do not take the irq struct lock since
+	 * no other action on irq structs can happen while the VGIC is
+	 * not initialized yet:
+	 * injection requires (VGICV3) or does (VGIC2) initialization.
+	 * MMIO access triggers init.
+	 */
+	for (i = 0; i < nr_spis; i++) {
+		struct vgic_irq *irq = &dist->spis[i];
+
+		irq->intid = i + VGIC_NR_PRIVATE_IRQS;
+		INIT_LIST_HEAD(&irq->ap_list);
+		spin_lock_init(&irq->irq_lock);
+		irq->vcpu = NULL;
+		irq->target_vcpu = vcpu0;
+		if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
+			irq->targets = 0;
+		else
+			irq->mpidr = 0;
+	}
+	return 0;
+}
+
+/**
+ * kvm_vgic_vcpu_init: initialize the vcpu data structures and
+ * enable the VCPU interface
+ * @kvm: kvm struct pointer
+ */
+void kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	int i;
+
+	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
+	spin_lock_init(&vgic_cpu->ap_list_lock);
+
+	/*
+	 * Enable and configure all SGIs to be edge-triggered and
+	 * configure all PPIs as level-triggered.
+	 */
+	for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
+		struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
+
+		INIT_LIST_HEAD(&irq->ap_list);
+		spin_lock_init(&irq->irq_lock);
+		irq->intid = i;
+		irq->vcpu = NULL;
+		irq->target_vcpu = vcpu;
+		irq->targets = 1U << vcpu->vcpu_id;
+		if (vgic_irq_is_sgi(i)) {
+			/* SGIs */
+			irq->enabled = 1;
+			irq->config = VGIC_CONFIG_EDGE;
+		} else {
+			/* PPIs */
+			irq->config = VGIC_CONFIG_LEVEL;
+		}
+	}
+	if (kvm_vgic_global_state.type == VGIC_V2)
+		vgic_v2_enable(vcpu);
+	else
+		vgic_v3_enable(vcpu);
+}
+
+/*
+ * vgic_init: allocates and initializes dist and vcpu data structures
+ * depending on two dimensioning parameters:
+ * - the number of spis
+ * - the number of vcpus
+ * The function is generally called when nr_spis has been explicitly set
+ * by the guest through the KVM DEVICE API. If not nr_spis is set to 256.
+ * Completion can be tested by vgic_initialized
+ * Must be called with kvm->lock held!
+ */
+int vgic_init(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	struct kvm_vcpu *vcpu;
+	int ret = 0, i;
+
+	if (vgic_initialized(kvm))
+		return 0;
+
+	/* freeze the number of spis */
+	if (!dist->nr_spis)
+		dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;
+
+	ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
+	if (ret)
+		goto out;
+
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		kvm_vgic_vcpu_init(vcpu);
+
+	dist->initialized = true;
+out:
+	return ret;
+}
+
+static void kvm_vgic_dist_destroy(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+
+	mutex_lock(&kvm->lock);
+
+	dist->ready = false;
+	dist->initialized = false;
+
+	kfree(dist->spis);
+	kfree(dist->redist_iodevs);
+	dist->nr_spis = 0;
+
+	mutex_unlock(&kvm->lock);
+}
+
+void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
+{
+	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+
+	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
+}
+
+void kvm_vgic_destroy(struct kvm *kvm)
+{
+	struct kvm_vcpu *vcpu;
+	int i;
+
+	kvm_vgic_dist_destroy(kvm);
+
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		kvm_vgic_vcpu_destroy(vcpu);
+}
+
+/**
+ * Lazy init only is allowed if the GIC exposed to the guest is a GICV2.
+ * GICV3 must be explicitly initialized by the guest using the
+ * KVM_DEV_ARM_VGIC_GRP_CTRL KVM_DEVICE group
+ */
+int vgic_lazy_init(struct kvm *kvm)
+{
+	int ret = 0;
+
+	if (unlikely(!vgic_initialized(kvm))) {
+		/*
+		 * We only provide the automatic initialization of the VGIC
+		 * for the legacy case of a GICv2. Any other type must
+		 * be explicitly initialized once setup with the respective
+		 * KVM device call.
+		 */
+		if (kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2)
+			return -EBUSY;
+
+		mutex_lock(&kvm->lock);
+		ret = vgic_init(kvm);
+		mutex_unlock(&kvm->lock);
+	}
+
+	return ret;
+}
+
 /* GENERIC PROBE */
 
 static void vgic_init_maintenance_interrupt(void *info)
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 91b69a4..48aa877 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -211,6 +211,11 @@ void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 			GICH_VMCR_PRIMASK_SHIFT;
 }
 
+/* not yet implemented */
+void vgic_v2_enable(struct kvm_vcpu *vcpu)
+{
+}
+
 /**
  * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
  * @node:	pointer to the DT node
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 48b0bb7..7cab5b9 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -195,6 +195,11 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
 }
 
+/* not yet implemented */
+void vgic_v3_enable(struct kvm_vcpu *vcpu)
+{
+}
+
 /**
  * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
  * @node:	pointer to the DT node
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 5355de6..068389a 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -255,6 +255,10 @@ static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
 
 	trace_vgic_update_irq_pending(cpuid, intid, level);
 
+	ret = vgic_lazy_init(kvm);
+	if (ret)
+		return ret;
+
 	vcpu = kvm_get_vcpu(kvm, cpuid);
 	if (!vcpu && intid < VGIC_NR_PRIVATE_IRQS)
 		return -EINVAL;
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index e49b1df..cad04eb 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -43,6 +43,7 @@ int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
 			  int offset, u32 *val);
 void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v2_enable(struct kvm_vcpu *vcpu);
 int vgic_v2_probe(struct device_node *vgic_node);
 int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
 			     enum vgic_type);
@@ -55,6 +56,7 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
 void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+void vgic_v3_enable(struct kvm_vcpu *vcpu);
 int vgic_v3_probe(struct device_node *vgic_node);
 int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
 #else
@@ -89,6 +91,10 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
 {
 }
 
+static inline void vgic_v3_enable(struct kvm_vcpu *vcpu)
+{
+}
+
 static inline int vgic_v3_probe(struct device_node *vgic_node)
 {
 	return -ENODEV;
@@ -102,5 +108,7 @@ static inline int vgic_register_redist_iodevs(struct kvm *kvm,
 #endif
 
 void kvm_register_vgic_device(unsigned long type);
+int vgic_lazy_init(struct kvm *kvm);
+int vgic_init(struct kvm *kvm);
 
 #endif
-- 
2.7.3

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

* [PATCH v3 51/55] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:46   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:46 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

map_resources is the last initialization step. It is executed on
1st VCPU run. At that stage the code checks the userspace has provided
the base addresses for the relevant VGIC regions, which depend on
the type of VGIC that is exposed to the guest.

The function also forces the vgic_init if it has not been executed yet
(only allowed for VGIC v2).

for GICv2, The VGIC CPU interface is mapped onto the GIC virtual CPU
interface.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h       |  1 +
 virt/kvm/arm/vgic/vgic-init.c | 27 +++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v2.c   | 47 +++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c   | 44 ++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h      |  7 +++++++
 5 files changed, 126 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 538078a..07c3011 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -208,6 +208,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type);
 void kvm_vgic_destroy(struct kvm *kvm);
 void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
 void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
+int kvm_vgic_map_resources(struct kvm *kvm);
 int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
index 3f9c137..7fefb12 100644
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -321,6 +321,33 @@ int vgic_lazy_init(struct kvm *kvm)
 	return ret;
 }
 
+/* RESOURCE MAPPING */
+
+/**
+ * Map the MMIO regions depending on the VGIC model exposed to the guest
+ * called on the first VCPU run.
+ * Also map the virtual CPU interface into the VM.
+ * v2/v3 derivatives call vgic_init if not already done.
+ * Completion can be tested by vgic_ready
+ */
+int kvm_vgic_map_resources(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	int ret = 0;
+
+	mutex_lock(&kvm->lock);
+	if (!irqchip_in_kernel(kvm))
+		goto out;
+
+	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
+		ret = vgic_v2_map_resources(kvm);
+	else
+		ret = vgic_v3_map_resources(kvm);
+out:
+	mutex_unlock(&kvm->lock);
+	return ret;
+}
+
 /* GENERIC PROBE */
 
 static void vgic_init_maintenance_interrupt(void *info)
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 48aa877..1e411f5 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -216,6 +216,53 @@ void vgic_v2_enable(struct kvm_vcpu *vcpu)
 {
 }
 
+int vgic_v2_map_resources(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	int ret = 0;
+
+	if (vgic_ready(kvm))
+		goto out;
+
+	if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base) ||
+	    IS_VGIC_ADDR_UNDEF(dist->vgic_cpu_base)) {
+		kvm_err("Need to set vgic cpu and dist addresses first\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	/*
+	 * Initialize the vgic if this hasn't already been done on demand by
+	 * accessing the vgic state from userspace.
+	 */
+	ret = vgic_init(kvm);
+	if (ret) {
+		kvm_err("Unable to initialize VGIC dynamic data structures\n");
+		goto out;
+	}
+
+	ret = vgic_register_dist_iodev(kvm, dist->vgic_dist_base, VGIC_V2);
+	if (ret) {
+		kvm_err("Unable to register VGIC MMIO regions\n");
+		goto out;
+	}
+
+	ret = kvm_phys_addr_ioremap(kvm, dist->vgic_cpu_base,
+				    kvm_vgic_global_state.vcpu_base,
+				    KVM_VGIC_V2_CPU_SIZE, true);
+	if (ret) {
+		kvm_err("Unable to remap VGIC CPU to VCPU\n");
+		goto out;
+	}
+
+	dist->ready = true;
+
+out:
+	if (ret)
+		kvm_vgic_destroy(kvm);
+	return ret;
+}
+
 /**
  * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
  * @node:	pointer to the DT node
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 7cab5b9..4bfd42a 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -200,6 +200,50 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 {
 }
 
+int vgic_v3_map_resources(struct kvm *kvm)
+{
+	int ret = 0;
+	struct vgic_dist *dist = &kvm->arch.vgic;
+
+	if (vgic_ready(kvm))
+		goto out;
+
+	if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base) ||
+	    IS_VGIC_ADDR_UNDEF(dist->vgic_redist_base)) {
+		kvm_err("Need to set vgic distributor addresses first\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	/*
+	 * For a VGICv3 we require the userland to explicitly initialize
+	 * the VGIC before we need to use it.
+	 */
+	if (!vgic_initialized(kvm)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	ret = vgic_register_dist_iodev(kvm, dist->vgic_dist_base, VGIC_V3);
+	if (ret) {
+		kvm_err("Unable to register VGICv3 dist MMIO regions\n");
+		goto out;
+	}
+
+	ret = vgic_register_redist_iodevs(kvm, dist->vgic_redist_base);
+	if (ret) {
+		kvm_err("Unable to register VGICv3 redist MMIO regions\n");
+		goto out;
+	}
+
+	dist->ready = true;
+
+out:
+	if (ret)
+		kvm_vgic_destroy(kvm);
+	return ret;
+}
+
 /**
  * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
  * @node:	pointer to the DT node
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index cad04eb..5c7dc99 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -45,6 +45,7 @@ void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_enable(struct kvm_vcpu *vcpu);
 int vgic_v2_probe(struct device_node *vgic_node);
+int vgic_v2_map_resources(struct kvm *kvm);
 int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
 			     enum vgic_type);
 
@@ -58,6 +59,7 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_enable(struct kvm_vcpu *vcpu);
 int vgic_v3_probe(struct device_node *vgic_node);
+int vgic_v3_map_resources(struct kvm *kvm);
 int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
 #else
 static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
@@ -100,6 +102,11 @@ static inline int vgic_v3_probe(struct device_node *vgic_node)
 	return -ENODEV;
 }
 
+static inline int vgic_v3_map_resources(struct kvm *kvm)
+{
+	return -ENODEV;
+}
+
 static inline int vgic_register_redist_iodevs(struct kvm *kvm,
 					      gpa_t dist_base_address)
 {
-- 
2.7.3

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

* [PATCH v3 51/55] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources
@ 2016-05-06 10:46   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:46 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

map_resources is the last initialization step. It is executed on
1st VCPU run. At that stage the code checks the userspace has provided
the base addresses for the relevant VGIC regions, which depend on
the type of VGIC that is exposed to the guest.

The function also forces the vgic_init if it has not been executed yet
(only allowed for VGIC v2).

for GICv2, The VGIC CPU interface is mapped onto the GIC virtual CPU
interface.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/vgic/vgic.h       |  1 +
 virt/kvm/arm/vgic/vgic-init.c | 27 +++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v2.c   | 47 +++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c   | 44 ++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h      |  7 +++++++
 5 files changed, 126 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 538078a..07c3011 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -208,6 +208,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type);
 void kvm_vgic_destroy(struct kvm *kvm);
 void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
 void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
+int kvm_vgic_map_resources(struct kvm *kvm);
 int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
index 3f9c137..7fefb12 100644
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -321,6 +321,33 @@ int vgic_lazy_init(struct kvm *kvm)
 	return ret;
 }
 
+/* RESOURCE MAPPING */
+
+/**
+ * Map the MMIO regions depending on the VGIC model exposed to the guest
+ * called on the first VCPU run.
+ * Also map the virtual CPU interface into the VM.
+ * v2/v3 derivatives call vgic_init if not already done.
+ * Completion can be tested by vgic_ready
+ */
+int kvm_vgic_map_resources(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	int ret = 0;
+
+	mutex_lock(&kvm->lock);
+	if (!irqchip_in_kernel(kvm))
+		goto out;
+
+	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
+		ret = vgic_v2_map_resources(kvm);
+	else
+		ret = vgic_v3_map_resources(kvm);
+out:
+	mutex_unlock(&kvm->lock);
+	return ret;
+}
+
 /* GENERIC PROBE */
 
 static void vgic_init_maintenance_interrupt(void *info)
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 48aa877..1e411f5 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -216,6 +216,53 @@ void vgic_v2_enable(struct kvm_vcpu *vcpu)
 {
 }
 
+int vgic_v2_map_resources(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	int ret = 0;
+
+	if (vgic_ready(kvm))
+		goto out;
+
+	if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base) ||
+	    IS_VGIC_ADDR_UNDEF(dist->vgic_cpu_base)) {
+		kvm_err("Need to set vgic cpu and dist addresses first\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	/*
+	 * Initialize the vgic if this hasn't already been done on demand by
+	 * accessing the vgic state from userspace.
+	 */
+	ret = vgic_init(kvm);
+	if (ret) {
+		kvm_err("Unable to initialize VGIC dynamic data structures\n");
+		goto out;
+	}
+
+	ret = vgic_register_dist_iodev(kvm, dist->vgic_dist_base, VGIC_V2);
+	if (ret) {
+		kvm_err("Unable to register VGIC MMIO regions\n");
+		goto out;
+	}
+
+	ret = kvm_phys_addr_ioremap(kvm, dist->vgic_cpu_base,
+				    kvm_vgic_global_state.vcpu_base,
+				    KVM_VGIC_V2_CPU_SIZE, true);
+	if (ret) {
+		kvm_err("Unable to remap VGIC CPU to VCPU\n");
+		goto out;
+	}
+
+	dist->ready = true;
+
+out:
+	if (ret)
+		kvm_vgic_destroy(kvm);
+	return ret;
+}
+
 /**
  * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
  * @node:	pointer to the DT node
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 7cab5b9..4bfd42a 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -200,6 +200,50 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 {
 }
 
+int vgic_v3_map_resources(struct kvm *kvm)
+{
+	int ret = 0;
+	struct vgic_dist *dist = &kvm->arch.vgic;
+
+	if (vgic_ready(kvm))
+		goto out;
+
+	if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base) ||
+	    IS_VGIC_ADDR_UNDEF(dist->vgic_redist_base)) {
+		kvm_err("Need to set vgic distributor addresses first\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	/*
+	 * For a VGICv3 we require the userland to explicitly initialize
+	 * the VGIC before we need to use it.
+	 */
+	if (!vgic_initialized(kvm)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	ret = vgic_register_dist_iodev(kvm, dist->vgic_dist_base, VGIC_V3);
+	if (ret) {
+		kvm_err("Unable to register VGICv3 dist MMIO regions\n");
+		goto out;
+	}
+
+	ret = vgic_register_redist_iodevs(kvm, dist->vgic_redist_base);
+	if (ret) {
+		kvm_err("Unable to register VGICv3 redist MMIO regions\n");
+		goto out;
+	}
+
+	dist->ready = true;
+
+out:
+	if (ret)
+		kvm_vgic_destroy(kvm);
+	return ret;
+}
+
 /**
  * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
  * @node:	pointer to the DT node
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index cad04eb..5c7dc99 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -45,6 +45,7 @@ void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v2_enable(struct kvm_vcpu *vcpu);
 int vgic_v2_probe(struct device_node *vgic_node);
+int vgic_v2_map_resources(struct kvm *kvm);
 int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
 			     enum vgic_type);
 
@@ -58,6 +59,7 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_enable(struct kvm_vcpu *vcpu);
 int vgic_v3_probe(struct device_node *vgic_node);
+int vgic_v3_map_resources(struct kvm *kvm);
 int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
 #else
 static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
@@ -100,6 +102,11 @@ static inline int vgic_v3_probe(struct device_node *vgic_node)
 	return -ENODEV;
 }
 
+static inline int vgic_v3_map_resources(struct kvm *kvm)
+{
+	return -ENODEV;
+}
+
 static inline int vgic_register_redist_iodevs(struct kvm *kvm,
 					      gpa_t dist_base_address)
 {
-- 
2.7.3

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

* [PATCH v3 52/55] KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:46   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:46 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

From: Eric Auger <eric.auger@linaro.org>

Enable the VGIC operation by properly initialising the registers
in the hypervisor GIC interface.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic-v2.c | 11 ++++++++++-
 virt/kvm/arm/vgic/vgic-v3.c | 23 ++++++++++++++++++++++-
 2 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 1e411f5..4493593 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -211,9 +211,18 @@ void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 			GICH_VMCR_PRIMASK_SHIFT;
 }
 
-/* not yet implemented */
 void vgic_v2_enable(struct kvm_vcpu *vcpu)
 {
+	/*
+	 * By forcing VMCR to zero, the GIC will restore the binary
+	 * points to their reset values. Anything else resets to zero
+	 * anyway.
+	 */
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = 0;
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr = ~0;
+
+	/* Get the show on the road... */
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr = GICH_HCR_EN;
 }
 
 int vgic_v2_map_resources(struct kvm *kvm)
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 4bfd42a..6d7422f 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -195,9 +195,30 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
 }
 
-/* not yet implemented */
 void vgic_v3_enable(struct kvm_vcpu *vcpu)
 {
+	struct vgic_v3_cpu_if *vgic_v3 = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	/*
+	 * By forcing VMCR to zero, the GIC will restore the binary
+	 * points to their reset values. Anything else resets to zero
+	 * anyway.
+	 */
+	vgic_v3->vgic_vmcr = 0;
+	vgic_v3->vgic_elrsr = ~0;
+
+	/*
+	 * If we are emulating a GICv3, we do it in an non-GICv2-compatible
+	 * way, so we force SRE to 1 to demonstrate this to the guest.
+	 * This goes with the spec allowing the value to be RAO/WI.
+	 */
+	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
+		vgic_v3->vgic_sre = ICC_SRE_EL1_SRE;
+	else
+		vgic_v3->vgic_sre = 0;
+
+	/* Get the show on the road... */
+	vgic_v3->vgic_hcr = ICH_HCR_EN;
 }
 
 int vgic_v3_map_resources(struct kvm *kvm)
-- 
2.7.3

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

* [PATCH v3 52/55] KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable
@ 2016-05-06 10:46   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:46 UTC (permalink / raw)
  To: linux-arm-kernel

From: Eric Auger <eric.auger@linaro.org>

Enable the VGIC operation by properly initialising the registers
in the hypervisor GIC interface.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic-v2.c | 11 ++++++++++-
 virt/kvm/arm/vgic/vgic-v3.c | 23 ++++++++++++++++++++++-
 2 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 1e411f5..4493593 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -211,9 +211,18 @@ void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 			GICH_VMCR_PRIMASK_SHIFT;
 }
 
-/* not yet implemented */
 void vgic_v2_enable(struct kvm_vcpu *vcpu)
 {
+	/*
+	 * By forcing VMCR to zero, the GIC will restore the binary
+	 * points to their reset values. Anything else resets to zero
+	 * anyway.
+	 */
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = 0;
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr = ~0;
+
+	/* Get the show on the road... */
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr = GICH_HCR_EN;
 }
 
 int vgic_v2_map_resources(struct kvm *kvm)
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 4bfd42a..6d7422f 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -195,9 +195,30 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
 }
 
-/* not yet implemented */
 void vgic_v3_enable(struct kvm_vcpu *vcpu)
 {
+	struct vgic_v3_cpu_if *vgic_v3 = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	/*
+	 * By forcing VMCR to zero, the GIC will restore the binary
+	 * points to their reset values. Anything else resets to zero
+	 * anyway.
+	 */
+	vgic_v3->vgic_vmcr = 0;
+	vgic_v3->vgic_elrsr = ~0;
+
+	/*
+	 * If we are emulating a GICv3, we do it in an non-GICv2-compatible
+	 * way, so we force SRE to 1 to demonstrate this to the guest.
+	 * This goes with the spec allowing the value to be RAO/WI.
+	 */
+	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
+		vgic_v3->vgic_sre = ICC_SRE_EL1_SRE;
+	else
+		vgic_v3->vgic_sre = 0;
+
+	/* Get the show on the road... */
+	vgic_v3->vgic_hcr = ICH_HCR_EN;
 }
 
 int vgic_v3_map_resources(struct kvm *kvm)
-- 
2.7.3

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

* [PATCH v3 53/55] KVM: arm/arm64: vgic-new: Wire up irqfd injection
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:46   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:46 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Connect to the new VGIC to the irqfd framework, so that we can
inject IRQs.
GSI routing and MSI routing is not yet implemented.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic-irqfd.c | 52 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic-irqfd.c

diff --git a/virt/kvm/arm/vgic/vgic-irqfd.c b/virt/kvm/arm/vgic/vgic-irqfd.c
new file mode 100644
index 0000000..c675513
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-irqfd.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <trace/events/kvm.h>
+
+int kvm_irq_map_gsi(struct kvm *kvm,
+		    struct kvm_kernel_irq_routing_entry *entries,
+		    int gsi)
+{
+	return 0;
+}
+
+int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned int irqchip,
+			 unsigned int pin)
+{
+	return pin;
+}
+
+int kvm_set_irq(struct kvm *kvm, int irq_source_id,
+		u32 irq, int level, bool line_status)
+{
+	unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS;
+
+	trace_kvm_set_irq(irq, level, irq_source_id);
+
+	BUG_ON(!vgic_initialized(kvm));
+
+	return kvm_vgic_inject_irq(kvm, 0, spi, level);
+}
+
+/* MSI not implemented yet */
+int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
+		struct kvm *kvm, int irq_source_id,
+		int level, bool line_status)
+{
+	return 0;
+}
-- 
2.7.3

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

* [PATCH v3 53/55] KVM: arm/arm64: vgic-new: Wire up irqfd injection
@ 2016-05-06 10:46   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:46 UTC (permalink / raw)
  To: linux-arm-kernel

Connect to the new VGIC to the irqfd framework, so that we can
inject IRQs.
GSI routing and MSI routing is not yet implemented.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virt/kvm/arm/vgic/vgic-irqfd.c | 52 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)
 create mode 100644 virt/kvm/arm/vgic/vgic-irqfd.c

diff --git a/virt/kvm/arm/vgic/vgic-irqfd.c b/virt/kvm/arm/vgic/vgic-irqfd.c
new file mode 100644
index 0000000..c675513
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-irqfd.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <trace/events/kvm.h>
+
+int kvm_irq_map_gsi(struct kvm *kvm,
+		    struct kvm_kernel_irq_routing_entry *entries,
+		    int gsi)
+{
+	return 0;
+}
+
+int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned int irqchip,
+			 unsigned int pin)
+{
+	return pin;
+}
+
+int kvm_set_irq(struct kvm *kvm, int irq_source_id,
+		u32 irq, int level, bool line_status)
+{
+	unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS;
+
+	trace_kvm_set_irq(irq, level, irq_source_id);
+
+	BUG_ON(!vgic_initialized(kvm));
+
+	return kvm_vgic_inject_irq(kvm, 0, spi, level);
+}
+
+/* MSI not implemented yet */
+int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
+		struct kvm *kvm, int irq_source_id,
+		int level, bool line_status)
+{
+	return 0;
+}
-- 
2.7.3

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

* [PATCH v3 54/55] KVM: arm/arm64: vgic-new: implement mapped IRQ handling
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:46   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:46 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

We now store the mapped hardware IRQ number in our struct, so we
don't need the irq_phys_map for the new VGIC.
Implement the hardware IRQ mapping on top of the reworked arch
timer interface.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- adapt to new arch_timer mapped IRQ interface
- implement inject_mapped_irq() as a macro (since it is identical to
  the "un-mapped" IRQ implementation)

Changelog v1 .. v2:
- replace inject_mapped_irq() macro with a separate implementation,
  which only allows mapped IRQs to be injected via this interface

 include/kvm/vgic/vgic.h  |  5 +++++
 virt/kvm/arm/vgic/vgic.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 07c3011..64aca0c 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -213,6 +213,11 @@ int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level);
+int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+			       bool level);
+int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, u32 virt_irq, u32 phys_irq);
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq);
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 068389a..3f854c5 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -310,6 +310,44 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
 }
 
+int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+			       bool level)
+{
+	return vgic_update_irq_pending(kvm, cpuid, intid, level, true);
+}
+
+int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, u32 virt_irq, u32 phys_irq)
+{
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
+
+	BUG_ON(!irq);
+
+	spin_lock(&irq->irq_lock);
+
+	irq->hw = true;
+	irq->hwintid = phys_irq;
+
+	spin_unlock(&irq->irq_lock);
+
+	return 0;
+}
+
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq)
+{
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
+
+	BUG_ON(!irq);
+
+	spin_lock(&irq->irq_lock);
+
+	irq->hw = false;
+	irq->hwintid = 0;
+
+	spin_unlock(&irq->irq_lock);
+
+	return 0;
+}
+
 /**
  * vgic_prune_ap_list - Remove non-relevant interrupts from the list
  *
@@ -563,3 +601,15 @@ void vgic_kick_vcpus(struct kvm *kvm)
 			kvm_vcpu_kick(vcpu);
 	}
 }
+
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq)
+{
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
+	bool map_is_active;
+
+	spin_lock(&irq->irq_lock);
+	map_is_active = irq->hw && irq->active;
+	spin_unlock(&irq->irq_lock);
+
+	return map_is_active;
+}
-- 
2.7.3

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

* [PATCH v3 54/55] KVM: arm/arm64: vgic-new: implement mapped IRQ handling
@ 2016-05-06 10:46   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:46 UTC (permalink / raw)
  To: linux-arm-kernel

We now store the mapped hardware IRQ number in our struct, so we
don't need the irq_phys_map for the new VGIC.
Implement the hardware IRQ mapping on top of the reworked arch
timer interface.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog RFC..v1:
- adapt to new arch_timer mapped IRQ interface
- implement inject_mapped_irq() as a macro (since it is identical to
  the "un-mapped" IRQ implementation)

Changelog v1 .. v2:
- replace inject_mapped_irq() macro with a separate implementation,
  which only allows mapped IRQs to be injected via this interface

 include/kvm/vgic/vgic.h  |  5 +++++
 virt/kvm/arm/vgic/vgic.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+)

diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
index 07c3011..64aca0c 100644
--- a/include/kvm/vgic/vgic.h
+++ b/include/kvm/vgic/vgic.h
@@ -213,6 +213,11 @@ int kvm_vgic_hyp_init(void);
 
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 			bool level);
+int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+			       bool level);
+int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, u32 virt_irq, u32 phys_irq);
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq);
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 068389a..3f854c5 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -310,6 +310,44 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
 	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
 }
 
+int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
+			       bool level)
+{
+	return vgic_update_irq_pending(kvm, cpuid, intid, level, true);
+}
+
+int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, u32 virt_irq, u32 phys_irq)
+{
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
+
+	BUG_ON(!irq);
+
+	spin_lock(&irq->irq_lock);
+
+	irq->hw = true;
+	irq->hwintid = phys_irq;
+
+	spin_unlock(&irq->irq_lock);
+
+	return 0;
+}
+
+int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq)
+{
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
+
+	BUG_ON(!irq);
+
+	spin_lock(&irq->irq_lock);
+
+	irq->hw = false;
+	irq->hwintid = 0;
+
+	spin_unlock(&irq->irq_lock);
+
+	return 0;
+}
+
 /**
  * vgic_prune_ap_list - Remove non-relevant interrupts from the list
  *
@@ -563,3 +601,15 @@ void vgic_kick_vcpus(struct kvm *kvm)
 			kvm_vcpu_kick(vcpu);
 	}
 }
+
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq)
+{
+	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
+	bool map_is_active;
+
+	spin_lock(&irq->irq_lock);
+	map_is_active = irq->hw && irq->active;
+	spin_unlock(&irq->irq_lock);
+
+	return map_is_active;
+}
-- 
2.7.3

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

* [PATCH v3 55/55] KVM: arm/arm64: vgic-new: enable build
  2016-05-06 10:45 ` Andre Przywara
@ 2016-05-06 10:46   ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:46 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Now that the new VGIC implementation has reached feature parity with
the old one, add the new files to the build system and add a Kconfig
option to switch between the two versions.
We set the default to the new version to get maximum test coverage,
in case people experience problems they can switch back to the old
behaviour if needed.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- adjust the changed filenames in the Makefiles
- add vgic-mmio-v2.c and vgic-mmio-v3.c to the Makefiles

 arch/arm/kvm/Kconfig          |  7 +++++++
 arch/arm/kvm/Makefile         | 11 +++++++++++
 arch/arm64/kvm/Kconfig        |  7 +++++++
 arch/arm64/kvm/Makefile       | 12 ++++++++++++
 virt/kvm/arm/hyp/vgic-v2-sr.c |  5 +++++
 5 files changed, 42 insertions(+)

diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig
index 95a0005..02abfff 100644
--- a/arch/arm/kvm/Kconfig
+++ b/arch/arm/kvm/Kconfig
@@ -46,6 +46,13 @@ config KVM_ARM_HOST
 	---help---
 	  Provides host support for ARM processors.
 
+config KVM_NEW_VGIC
+	bool "New VGIC implementation"
+	depends on KVM
+	default y
+	---help---
+	  uses the new VGIC implementation
+
 source drivers/vhost/Kconfig
 
 endif # VIRTUALIZATION
diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
index eb1bf43..a596b58 100644
--- a/arch/arm/kvm/Makefile
+++ b/arch/arm/kvm/Makefile
@@ -21,7 +21,18 @@ obj-$(CONFIG_KVM_ARM_HOST) += hyp/
 obj-y += kvm-arm.o init.o interrupts.o
 obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
 obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o
+
+ifeq ($(CONFIG_KVM_NEW_VGIC),y)
+obj-y += $(KVM)/arm/vgic/vgic.o
+obj-y += $(KVM)/arm/vgic/vgic-init.o
+obj-y += $(KVM)/arm/vgic/vgic-irqfd.o
+obj-y += $(KVM)/arm/vgic/vgic-v2.o
+obj-y += $(KVM)/arm/vgic/vgic-mmio.o
+obj-y += $(KVM)/arm/vgic/vgic-mmio-v2.o
+obj-y += $(KVM)/arm/vgic/vgic-kvm-device.o
+else
 obj-y += $(KVM)/arm/vgic.o
 obj-y += $(KVM)/arm/vgic-v2.o
 obj-y += $(KVM)/arm/vgic-v2-emul.o
+endif
 obj-y += $(KVM)/arm/arch_timer.o
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index de7450d..3f0e1ce 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -55,6 +55,13 @@ config KVM_ARM_PMU
 	  Adds support for a virtual Performance Monitoring Unit (PMU) in
 	  virtual machines.
 
+config KVM_NEW_VGIC
+	bool "New VGIC implementation"
+	depends on KVM
+	default y
+        ---help---
+          uses the new VGIC implementation
+
 source drivers/vhost/Kconfig
 
 endif # VIRTUALIZATION
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 122cff4..a7a958c 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -20,10 +20,22 @@ kvm-$(CONFIG_KVM_ARM_HOST) += emulate.o inject_fault.o regmap.o
 kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
 kvm-$(CONFIG_KVM_ARM_HOST) += guest.o debug.o reset.o sys_regs.o sys_regs_generic_v8.o
 
+ifeq ($(CONFIG_KVM_NEW_VGIC),y)
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-init.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-irqfd.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v2.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v3.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v2.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-kvm-device.o
+else
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2-emul.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
+endif
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
 kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index caac41f..a3f12b3 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -21,7 +21,12 @@
 
 #include <asm/kvm_hyp.h>
 
+#ifdef CONFIG_KVM_NEW_VGIC
+extern struct vgic_global kvm_vgic_global_state;
+#define vgic_v2_params kvm_vgic_global_state
+#else
 extern struct vgic_params vgic_v2_params;
+#endif
 
 static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu,
 					    void __iomem *base)
-- 
2.7.3

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

* [PATCH v3 55/55] KVM: arm/arm64: vgic-new: enable build
@ 2016-05-06 10:46   ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-06 10:46 UTC (permalink / raw)
  To: linux-arm-kernel

Now that the new VGIC implementation has reached feature parity with
the old one, add the new files to the build system and add a Kconfig
option to switch between the two versions.
We set the default to the new version to get maximum test coverage,
in case people experience problems they can switch back to the old
behaviour if needed.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Changelog v1 .. v2:
- adjust the changed filenames in the Makefiles
- add vgic-mmio-v2.c and vgic-mmio-v3.c to the Makefiles

 arch/arm/kvm/Kconfig          |  7 +++++++
 arch/arm/kvm/Makefile         | 11 +++++++++++
 arch/arm64/kvm/Kconfig        |  7 +++++++
 arch/arm64/kvm/Makefile       | 12 ++++++++++++
 virt/kvm/arm/hyp/vgic-v2-sr.c |  5 +++++
 5 files changed, 42 insertions(+)

diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig
index 95a0005..02abfff 100644
--- a/arch/arm/kvm/Kconfig
+++ b/arch/arm/kvm/Kconfig
@@ -46,6 +46,13 @@ config KVM_ARM_HOST
 	---help---
 	  Provides host support for ARM processors.
 
+config KVM_NEW_VGIC
+	bool "New VGIC implementation"
+	depends on KVM
+	default y
+	---help---
+	  uses the new VGIC implementation
+
 source drivers/vhost/Kconfig
 
 endif # VIRTUALIZATION
diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
index eb1bf43..a596b58 100644
--- a/arch/arm/kvm/Makefile
+++ b/arch/arm/kvm/Makefile
@@ -21,7 +21,18 @@ obj-$(CONFIG_KVM_ARM_HOST) += hyp/
 obj-y += kvm-arm.o init.o interrupts.o
 obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
 obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o
+
+ifeq ($(CONFIG_KVM_NEW_VGIC),y)
+obj-y += $(KVM)/arm/vgic/vgic.o
+obj-y += $(KVM)/arm/vgic/vgic-init.o
+obj-y += $(KVM)/arm/vgic/vgic-irqfd.o
+obj-y += $(KVM)/arm/vgic/vgic-v2.o
+obj-y += $(KVM)/arm/vgic/vgic-mmio.o
+obj-y += $(KVM)/arm/vgic/vgic-mmio-v2.o
+obj-y += $(KVM)/arm/vgic/vgic-kvm-device.o
+else
 obj-y += $(KVM)/arm/vgic.o
 obj-y += $(KVM)/arm/vgic-v2.o
 obj-y += $(KVM)/arm/vgic-v2-emul.o
+endif
 obj-y += $(KVM)/arm/arch_timer.o
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index de7450d..3f0e1ce 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -55,6 +55,13 @@ config KVM_ARM_PMU
 	  Adds support for a virtual Performance Monitoring Unit (PMU) in
 	  virtual machines.
 
+config KVM_NEW_VGIC
+	bool "New VGIC implementation"
+	depends on KVM
+	default y
+        ---help---
+          uses the new VGIC implementation
+
 source drivers/vhost/Kconfig
 
 endif # VIRTUALIZATION
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 122cff4..a7a958c 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -20,10 +20,22 @@ kvm-$(CONFIG_KVM_ARM_HOST) += emulate.o inject_fault.o regmap.o
 kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
 kvm-$(CONFIG_KVM_ARM_HOST) += guest.o debug.o reset.o sys_regs.o sys_regs_generic_v8.o
 
+ifeq ($(CONFIG_KVM_NEW_VGIC),y)
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-init.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-irqfd.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v2.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v3.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v2.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-kvm-device.o
+else
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2-emul.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
+endif
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
 kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index caac41f..a3f12b3 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -21,7 +21,12 @@
 
 #include <asm/kvm_hyp.h>
 
+#ifdef CONFIG_KVM_NEW_VGIC
+extern struct vgic_global kvm_vgic_global_state;
+#define vgic_v2_params kvm_vgic_global_state
+#else
 extern struct vgic_params vgic_v2_params;
+#endif
 
 static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu,
 					    void __iomem *base)
-- 
2.7.3

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

* Re: [PATCH v3 19/55] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-06 19:07     ` Tom Hanson
  -1 siblings, 0 replies; 400+ messages in thread
From: Tom Hanson @ 2016-05-06 19:07 UTC (permalink / raw)
  To: Andre Przywara, Marc Zyngier, Christoffer Dall
  Cc: linux-arm-kernel, kvmarm, kvm

On 05/06/2016 04:45 AM, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
>
> As the GICv3 virtual interface registers differ from their GICv2
> siblings, we need different handlers for processing maintenance
> interrupts and reading/writing to the LRs.
> Implement the respective handler functions and connect them to
> existing code to be called if the host is using a GICv3.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - remove outdated comment about the dist_lock
> - add WARN_ON about LR_STATE not being 0 in maintenance interrupts
>
> Changelog v1 .. v2:
> - inject the IRQ priority into the list register
>
> Changelog v2 .. v3:
> - remove no longer needed irqchip/arm-gic.h inclusion
>
>   include/linux/irqchip/arm-gic-v3.h |   1 +
>   virt/kvm/arm/vgic/vgic-v3.c        | 168 +++++++++++++++++++++++++++++++++++++
>   virt/kvm/arm/vgic/vgic.c           |  25 ++++--
>   virt/kvm/arm/vgic/vgic.h           |  29 +++++++
>   4 files changed, 218 insertions(+), 5 deletions(-)
>   create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
>
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index ec938d1..35e93cf 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -275,6 +275,7 @@
>   #define ICH_LR_ACTIVE_BIT		(1ULL << 63)
>   #define ICH_LR_PHYS_ID_SHIFT		32
>   #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
> +#define ICH_LR_PRIORITY_SHIFT		48
>
>   /* These are for GICv2 emulation only */
>   #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> new file mode 100644
> index 0000000..43d1dd7
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-v3.c

...

> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	int lr;
> +
> +	/* Assumes ap_list_lock held */


If truly required that ap_list_lock already be locked, then the code should enforce it. At least in dev mode. Maybe:
          DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->ap_list_lock));

...

> +/* Requires the irq to be locked already */
> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)


Similarly, if required then the code should enforce it.
          DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));

  ...

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

* [PATCH v3 19/55] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
@ 2016-05-06 19:07     ` Tom Hanson
  0 siblings, 0 replies; 400+ messages in thread
From: Tom Hanson @ 2016-05-06 19:07 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/06/2016 04:45 AM, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
>
> As the GICv3 virtual interface registers differ from their GICv2
> siblings, we need different handlers for processing maintenance
> interrupts and reading/writing to the LRs.
> Implement the respective handler functions and connect them to
> existing code to be called if the host is using a GICv3.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - remove outdated comment about the dist_lock
> - add WARN_ON about LR_STATE not being 0 in maintenance interrupts
>
> Changelog v1 .. v2:
> - inject the IRQ priority into the list register
>
> Changelog v2 .. v3:
> - remove no longer needed irqchip/arm-gic.h inclusion
>
>   include/linux/irqchip/arm-gic-v3.h |   1 +
>   virt/kvm/arm/vgic/vgic-v3.c        | 168 +++++++++++++++++++++++++++++++++++++
>   virt/kvm/arm/vgic/vgic.c           |  25 ++++--
>   virt/kvm/arm/vgic/vgic.h           |  29 +++++++
>   4 files changed, 218 insertions(+), 5 deletions(-)
>   create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
>
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index ec938d1..35e93cf 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -275,6 +275,7 @@
>   #define ICH_LR_ACTIVE_BIT		(1ULL << 63)
>   #define ICH_LR_PHYS_ID_SHIFT		32
>   #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
> +#define ICH_LR_PRIORITY_SHIFT		48
>
>   /* These are for GICv2 emulation only */
>   #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> new file mode 100644
> index 0000000..43d1dd7
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-v3.c

...

> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	int lr;
> +
> +	/* Assumes ap_list_lock held */


If truly required that ap_list_lock already be locked, then the code should enforce it. At least in dev mode. Maybe:
          DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->ap_list_lock));

...

> +/* Requires the irq to be locked already */
> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)


Similarly, if required then the code should enforce it.
          DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));

  ...

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

* Re: [PATCH v3 32/55] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-09 17:18     ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-09 17:18 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall
  Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> Create a new file called vgic-mmio-v3.c and describe the GICv3
> distributor and redistributor registers there.
> This adds a special macro to deal with the split of SGI/PPI in the
> redistributor and SPIs in the distributor, which allows us to reuse
> the existing GICv2 handlers for those registers which are compatible.
> Also we provide a function to deal with the registration of the two
> separate redistributor frames per VCPU.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Reviewed-by: Eric Auger <eric.auger@linaro.org>
> ---
> Changelog RFC..v1:
> - adapt to new MMIO registration approach:
>   register one device for the distributor and two for each VCPU
> - implement special handling for private interrupts
> - remove empty stub functions
> - make IGROUPR return RAO
> 
> Changelog v1 .. v2:
> - adapt to new framework, introduce vgic-mmio-v3.c
> - remove userland register access functions (for now)
> - precompute .len when describing a VGIC register
> - add missed pointer incrementation on registering redist regions
> - replace _nyi stub functions with raz/wi versions
> 
> Changelog v2 .. v3:
> - replace inclusion of kvm/vgic/vgic.h with kvm/arm_vgic.h
> - add prototype and stub code for vgic_register_redist_iodevs
> - rename register struct variables _rdbase_ and _sgibase_
> 
>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.c    |   5 +
>  virt/kvm/arm/vgic/vgic-mmio.h    |   2 +
>  virt/kvm/arm/vgic/vgic.h         |   7 ++
>  4 files changed, 205 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> new file mode 100644
> index 0000000..06c7ec5
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -0,0 +1,191 @@
> +/*
> + * VGICv3 MMIO 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 <kvm/iodev.h>
> +#include <kvm/arm_vgic.h>
> +
> +#include <asm/kvm_emulate.h>
> +
> +#include "vgic.h"
> +#include "vgic-mmio.h"
> +
> +/*
> + * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
> + * redistributors, while SPIs are covered by registers in the distributor
> + * block. Trying to set private IRQs in this block gets ignored.
> + * We take some special care here to fix the calculation of the register
> + * offset.
> + */
> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, read_ops, write_ops, bpi) \
> +	{								\
> +		.reg_offset = off,					\
> +		.bits_per_irq = bpi,					\
> +		.len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8,		\
> +		.read = vgic_mmio_read_raz,				\
> +		.write = vgic_mmio_write_wi,				\
> +	}, {								\
> +		.reg_offset = off + (bpi * VGIC_NR_PRIVATE_IRQS) / 8,	\
> +		.bits_per_irq = bpi,					\
> +		.len = (bpi * (1024 - VGIC_NR_PRIVATE_IRQS)) / 8,	\
> +		.read = read_ops,					\
> +		.write = write_ops,					\
> +	}
> +
> +static const struct vgic_register_region vgic_v3_dist_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
> +	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
> +};
> +
> +static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
> +};
> +
> +static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
> +		vgic_mmio_read_config, vgic_mmio_write_config, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +};
> +
> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
> +{
> +	dev->regions = vgic_v3_dist_registers;
> +	dev->nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
> +
> +	kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
> +
> +	return SZ_64K;
> +}
> +
> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
> +{
> +	int nr_vcpus = atomic_read(&kvm->online_vcpus);
> +	struct kvm_vcpu *vcpu;
> +	struct vgic_io_device *devices, *device;
> +	int c, ret = 0;
> +
> +	devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
> +			  GFP_KERNEL);
> +	if (!devices)
> +		return -ENOMEM;
> +
> +	device = devices;
> +	kvm_for_each_vcpu(c, vcpu, kvm) {
> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
> +		device->base_addr = redist_base_address;
> +		device->regions = vgic_v3_rdbase_registers;
> +		device->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
> +		device->redist_vcpu = vcpu;
> +
> +		mutex_lock(&kvm->slots_lock);
> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> +					      redist_base_address,
> +					      SZ_64K, &device->dev);
> +		mutex_unlock(&kvm->slots_lock);
> +
> +		if (ret)
> +			break;
> +
> +		device++;
> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
> +		device->base_addr = redist_base_address + SZ_64K;
> +		device->regions = vgic_v3_sgibase_registers;
> +		device->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
> +		device->redist_vcpu = vcpu;
> +
> +		mutex_lock(&kvm->slots_lock);
> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> +					      redist_base_address + SZ_64K,
> +					      SZ_64K, &device->dev);
> +		mutex_unlock(&kvm->slots_lock);
> +		if (ret) {
> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
> +						  &devices[c * 2].dev);
> +			break;
> +		}
> +		device++;
> +		redist_base_address += 2 * SZ_64K;
> +	}

What I fail to see here is what prevents the redistributor range from
overlapping with the distributor (or any other device). The kvm IO bus
is happy with overlapping addresses, but I'm not sure at all that this
is safe.

Care to shed some light on it?

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 32/55] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
@ 2016-05-09 17:18     ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-09 17:18 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> Create a new file called vgic-mmio-v3.c and describe the GICv3
> distributor and redistributor registers there.
> This adds a special macro to deal with the split of SGI/PPI in the
> redistributor and SPIs in the distributor, which allows us to reuse
> the existing GICv2 handlers for those registers which are compatible.
> Also we provide a function to deal with the registration of the two
> separate redistributor frames per VCPU.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Reviewed-by: Eric Auger <eric.auger@linaro.org>
> ---
> Changelog RFC..v1:
> - adapt to new MMIO registration approach:
>   register one device for the distributor and two for each VCPU
> - implement special handling for private interrupts
> - remove empty stub functions
> - make IGROUPR return RAO
> 
> Changelog v1 .. v2:
> - adapt to new framework, introduce vgic-mmio-v3.c
> - remove userland register access functions (for now)
> - precompute .len when describing a VGIC register
> - add missed pointer incrementation on registering redist regions
> - replace _nyi stub functions with raz/wi versions
> 
> Changelog v2 .. v3:
> - replace inclusion of kvm/vgic/vgic.h with kvm/arm_vgic.h
> - add prototype and stub code for vgic_register_redist_iodevs
> - rename register struct variables _rdbase_ and _sgibase_
> 
>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.c    |   5 +
>  virt/kvm/arm/vgic/vgic-mmio.h    |   2 +
>  virt/kvm/arm/vgic/vgic.h         |   7 ++
>  4 files changed, 205 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> new file mode 100644
> index 0000000..06c7ec5
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -0,0 +1,191 @@
> +/*
> + * VGICv3 MMIO 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 <kvm/iodev.h>
> +#include <kvm/arm_vgic.h>
> +
> +#include <asm/kvm_emulate.h>
> +
> +#include "vgic.h"
> +#include "vgic-mmio.h"
> +
> +/*
> + * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
> + * redistributors, while SPIs are covered by registers in the distributor
> + * block. Trying to set private IRQs in this block gets ignored.
> + * We take some special care here to fix the calculation of the register
> + * offset.
> + */
> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, read_ops, write_ops, bpi) \
> +	{								\
> +		.reg_offset = off,					\
> +		.bits_per_irq = bpi,					\
> +		.len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8,		\
> +		.read = vgic_mmio_read_raz,				\
> +		.write = vgic_mmio_write_wi,				\
> +	}, {								\
> +		.reg_offset = off + (bpi * VGIC_NR_PRIVATE_IRQS) / 8,	\
> +		.bits_per_irq = bpi,					\
> +		.len = (bpi * (1024 - VGIC_NR_PRIVATE_IRQS)) / 8,	\
> +		.read = read_ops,					\
> +		.write = write_ops,					\
> +	}
> +
> +static const struct vgic_register_region vgic_v3_dist_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
> +	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
> +};
> +
> +static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
> +};
> +
> +static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
> +		vgic_mmio_read_config, vgic_mmio_write_config, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +};
> +
> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
> +{
> +	dev->regions = vgic_v3_dist_registers;
> +	dev->nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
> +
> +	kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
> +
> +	return SZ_64K;
> +}
> +
> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
> +{
> +	int nr_vcpus = atomic_read(&kvm->online_vcpus);
> +	struct kvm_vcpu *vcpu;
> +	struct vgic_io_device *devices, *device;
> +	int c, ret = 0;
> +
> +	devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
> +			  GFP_KERNEL);
> +	if (!devices)
> +		return -ENOMEM;
> +
> +	device = devices;
> +	kvm_for_each_vcpu(c, vcpu, kvm) {
> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
> +		device->base_addr = redist_base_address;
> +		device->regions = vgic_v3_rdbase_registers;
> +		device->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
> +		device->redist_vcpu = vcpu;
> +
> +		mutex_lock(&kvm->slots_lock);
> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> +					      redist_base_address,
> +					      SZ_64K, &device->dev);
> +		mutex_unlock(&kvm->slots_lock);
> +
> +		if (ret)
> +			break;
> +
> +		device++;
> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
> +		device->base_addr = redist_base_address + SZ_64K;
> +		device->regions = vgic_v3_sgibase_registers;
> +		device->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
> +		device->redist_vcpu = vcpu;
> +
> +		mutex_lock(&kvm->slots_lock);
> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> +					      redist_base_address + SZ_64K,
> +					      SZ_64K, &device->dev);
> +		mutex_unlock(&kvm->slots_lock);
> +		if (ret) {
> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
> +						  &devices[c * 2].dev);
> +			break;
> +		}
> +		device++;
> +		redist_base_address += 2 * SZ_64K;
> +	}

What I fail to see here is what prevents the redistributor range from
overlapping with the distributor (or any other device). The kvm IO bus
is happy with overlapping addresses, but I'm not sure at all that this
is safe.

Care to shed some light on it?

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
  2016-05-06 10:46   ` Andre Przywara
@ 2016-05-09 17:27     ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-09 17:27 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall
  Cc: linux-arm-kernel, kvmarm, kvm, Eric Auger

On 06/05/16 11:46, Andre Przywara wrote:
> Using the VMCR accessors we provide access to GIC CPU interface state
> to userland by wiring it up to the existing userland interface.
> [Marc: move and make VMCR accessors static, streamline MMIO handlers]
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
> Changelog v2 .. v3:
> - total rework, moving into vgic-mmio-v2.c
> - move vmcr accessor wrapper functions into this file
> - use the register description table for CPU i/f registers as well
> - add RAZ/WI handling for the active priority registers
> - streamline MMIO handler functions
> 
>  virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h            |   2 +
>  3 files changed, 107 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index bb33af8..2122ff2 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
>  
>  	switch (attr->group) {
>  	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> -		ret = -EINVAL;
> +		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
>  		break;
>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>  		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index c453e6f..0060539 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -206,6 +206,84 @@ 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. */
> +static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
> +					   gpa_t addr, unsigned int len)
> +{
> +	struct vgic_vmcr vmcr;
> +	u32 val;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +
> +	switch (addr & 0xff) {
> +	case GIC_CPU_CTRL:
> +		val = vmcr.ctlr;
> +		break;
> +	case GIC_CPU_PRIMASK:
> +		val = vmcr.pmr;
> +		break;
> +	case GIC_CPU_BINPOINT:
> +		val = vmcr.bpr;
> +		break;
> +	case GIC_CPU_ALIAS_BINPOINT:
> +		val = vmcr.abpr;
> +		break;
> +	case GIC_CPU_IDENT:
> +		val = ((PRODUCT_ID_KVM << 20) |
> +		       (GICC_ARCH_VERSION_V2 << 16) |
> +		       IMPLEMENTER_ARM);
> +		break;
> +	default:
> +		return 0;
> +	}
> +
> +	return extract_bytes(val, addr & 3, len);
> +}
> +
> +static void vgic_mmio_write_vcpuif(struct kvm_vcpu *vcpu,
> +				   gpa_t addr, unsigned int len,
> +				   unsigned long val)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +
> +	switch (addr & 0xff) {
> +	case GIC_CPU_CTRL:
> +		vmcr.ctlr = val;
> +		break;
> +	case GIC_CPU_PRIMASK:
> +		vmcr.pmr = val;
> +		break;
> +	case GIC_CPU_BINPOINT:
> +		vmcr.bpr = val;
> +		break;
> +	case GIC_CPU_ALIAS_BINPOINT:
> +		vmcr.abpr = val;
> +		break;
> +	}
> +
> +	vgic_set_vmcr(vcpu, &vmcr);
> +}
> +
>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -237,6 +315,21 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
>  };
>  
> +static const struct vgic_register_region vgic_v2_cpu_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_CTRL,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_PRIMASK,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_BINPOINT,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_ALIAS_BINPOINT,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_ACTIVEPRIO,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_IDENT,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +};
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
>  {
>  	dev->regions = vgic_v2_dist_registers;
> @@ -306,6 +399,17 @@ static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>  	return ret;
>  }
>  
> +int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +			  int offset, u32 *val)
> +{
> +	struct vgic_io_device dev = {
> +		.regions = vgic_v2_cpu_registers,
> +		.nr_regions = ARRAY_SIZE(vgic_v2_cpu_registers),
> +	};
> +
> +	return vgic_uaccess(vcpu, &dev, is_write, offset, val);
> +}
> +
>  int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			 int offset, u32 *val)
>  {

And what about this:

+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;
+
+       addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+       switch (attr->group) {
+       case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+               regions = vgic_v2_dist_registers;
+               nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
+               break;
+       case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
+               return -ENXIO;          /* TODO: describe CPU i/f regs also */
+       default:
+               return -ENXIO;
+       }

This TODO was already in the previous version. Can you please wire it
and give save/restore a chance to work?

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
@ 2016-05-09 17:27     ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-09 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/05/16 11:46, Andre Przywara wrote:
> Using the VMCR accessors we provide access to GIC CPU interface state
> to userland by wiring it up to the existing userland interface.
> [Marc: move and make VMCR accessors static, streamline MMIO handlers]
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
> Changelog v2 .. v3:
> - total rework, moving into vgic-mmio-v2.c
> - move vmcr accessor wrapper functions into this file
> - use the register description table for CPU i/f registers as well
> - add RAZ/WI handling for the active priority registers
> - streamline MMIO handler functions
> 
>  virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h            |   2 +
>  3 files changed, 107 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index bb33af8..2122ff2 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
>  
>  	switch (attr->group) {
>  	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> -		ret = -EINVAL;
> +		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
>  		break;
>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>  		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index c453e6f..0060539 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -206,6 +206,84 @@ 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. */
> +static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
> +					   gpa_t addr, unsigned int len)
> +{
> +	struct vgic_vmcr vmcr;
> +	u32 val;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +
> +	switch (addr & 0xff) {
> +	case GIC_CPU_CTRL:
> +		val = vmcr.ctlr;
> +		break;
> +	case GIC_CPU_PRIMASK:
> +		val = vmcr.pmr;
> +		break;
> +	case GIC_CPU_BINPOINT:
> +		val = vmcr.bpr;
> +		break;
> +	case GIC_CPU_ALIAS_BINPOINT:
> +		val = vmcr.abpr;
> +		break;
> +	case GIC_CPU_IDENT:
> +		val = ((PRODUCT_ID_KVM << 20) |
> +		       (GICC_ARCH_VERSION_V2 << 16) |
> +		       IMPLEMENTER_ARM);
> +		break;
> +	default:
> +		return 0;
> +	}
> +
> +	return extract_bytes(val, addr & 3, len);
> +}
> +
> +static void vgic_mmio_write_vcpuif(struct kvm_vcpu *vcpu,
> +				   gpa_t addr, unsigned int len,
> +				   unsigned long val)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +
> +	switch (addr & 0xff) {
> +	case GIC_CPU_CTRL:
> +		vmcr.ctlr = val;
> +		break;
> +	case GIC_CPU_PRIMASK:
> +		vmcr.pmr = val;
> +		break;
> +	case GIC_CPU_BINPOINT:
> +		vmcr.bpr = val;
> +		break;
> +	case GIC_CPU_ALIAS_BINPOINT:
> +		vmcr.abpr = val;
> +		break;
> +	}
> +
> +	vgic_set_vmcr(vcpu, &vmcr);
> +}
> +
>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -237,6 +315,21 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
>  };
>  
> +static const struct vgic_register_region vgic_v2_cpu_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_CTRL,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_PRIMASK,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_BINPOINT,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_ALIAS_BINPOINT,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_ACTIVEPRIO,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_IDENT,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +};
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
>  {
>  	dev->regions = vgic_v2_dist_registers;
> @@ -306,6 +399,17 @@ static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>  	return ret;
>  }
>  
> +int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +			  int offset, u32 *val)
> +{
> +	struct vgic_io_device dev = {
> +		.regions = vgic_v2_cpu_registers,
> +		.nr_regions = ARRAY_SIZE(vgic_v2_cpu_registers),
> +	};
> +
> +	return vgic_uaccess(vcpu, &dev, is_write, offset, val);
> +}
> +
>  int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			 int offset, u32 *val)
>  {

And what about this:

+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;
+
+       addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+       switch (attr->group) {
+       case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
+               regions = vgic_v2_dist_registers;
+               nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
+               break;
+       case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
+               return -ENXIO;          /* TODO: describe CPU i/f regs also */
+       default:
+               return -ENXIO;
+       }

This TODO was already in the previous version. Can you please wire it
and give save/restore a chance to work?

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 32/55] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
  2016-05-09 17:18     ` Marc Zyngier
@ 2016-05-09 17:51       ` Chalamarla, Tirumalesh
  -1 siblings, 0 replies; 400+ messages in thread
From: Chalamarla, Tirumalesh @ 2016-05-09 17:51 UTC (permalink / raw)
  To: Marc Zyngier, Andre Przywara, Christoffer Dall
  Cc: kvmarm, linux-arm-kernel, kvm






On 5/9/16, 10:18 AM, "kvmarm-bounces@lists.cs.columbia.edu on behalf of Marc Zyngier" <kvmarm-bounces@lists.cs.columbia.edu on behalf of marc.zyngier@arm.com> wrote:

>On 06/05/16 11:45, Andre Przywara wrote:
>> Create a new file called vgic-mmio-v3.c and describe the GICv3
>> distributor and redistributor registers there.
>> This adds a special macro to deal with the split of SGI/PPI in the
>> redistributor and SPIs in the distributor, which allows us to reuse
>> the existing GICv2 handlers for those registers which are compatible.
>> Also we provide a function to deal with the registration of the two
>> separate redistributor frames per VCPU.
>> 
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> Reviewed-by: Eric Auger <eric.auger@linaro.org>
>> ---
>> Changelog RFC..v1:
>> - adapt to new MMIO registration approach:
>>   register one device for the distributor and two for each VCPU
>> - implement special handling for private interrupts
>> - remove empty stub functions
>> - make IGROUPR return RAO
>> 
>> Changelog v1 .. v2:
>> - adapt to new framework, introduce vgic-mmio-v3.c
>> - remove userland register access functions (for now)
>> - precompute .len when describing a VGIC register
>> - add missed pointer incrementation on registering redist regions
>> - replace _nyi stub functions with raz/wi versions
>> 
>> Changelog v2 .. v3:
>> - replace inclusion of kvm/vgic/vgic.h with kvm/arm_vgic.h
>> - add prototype and stub code for vgic_register_redist_iodevs
>> - rename register struct variables _rdbase_ and _sgibase_
>> 
>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-mmio.c    |   5 +
>>  virt/kvm/arm/vgic/vgic-mmio.h    |   2 +
>>  virt/kvm/arm/vgic/vgic.h         |   7 ++
>>  4 files changed, 205 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
>> 
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> new file mode 100644
>> index 0000000..06c7ec5
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> @@ -0,0 +1,191 @@
>> +/*
>> + * VGICv3 MMIO 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 <kvm/iodev.h>
>> +#include <kvm/arm_vgic.h>
>> +
>> +#include <asm/kvm_emulate.h>
>> +
>> +#include "vgic.h"
>> +#include "vgic-mmio.h"
>> +
>> +/*
>> + * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
>> + * redistributors, while SPIs are covered by registers in the distributor
>> + * block. Trying to set private IRQs in this block gets ignored.
>> + * We take some special care here to fix the calculation of the register
>> + * offset.
>> + */
>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, read_ops, write_ops, bpi) \
>> +	{								\
>> +		.reg_offset = off,					\
>> +		.bits_per_irq = bpi,					\
>> +		.len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8,		\
>> +		.read = vgic_mmio_read_raz,				\
>> +		.write = vgic_mmio_write_wi,				\
>> +	}, {								\
>> +		.reg_offset = off + (bpi * VGIC_NR_PRIVATE_IRQS) / 8,	\
>> +		.bits_per_irq = bpi,					\
>> +		.len = (bpi * (1024 - VGIC_NR_PRIVATE_IRQS)) / 8,	\
>> +		.read = read_ops,					\
>> +		.write = write_ops,					\
>> +	}
>> +
>> +static const struct vgic_register_region vgic_v3_dist_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
>> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
>> +	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
>> +};
>> +
>> +static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
>> +};
>> +
>> +static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
>> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
>> +		vgic_mmio_read_config, vgic_mmio_write_config, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +};
>> +
>> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
>> +{
>> +	dev->regions = vgic_v3_dist_registers;
>> +	dev->nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
>> +
>> +	kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
>> +
>> +	return SZ_64K;
>> +}
>> +
>> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
>> +{
>> +	int nr_vcpus = atomic_read(&kvm->online_vcpus);
>> +	struct kvm_vcpu *vcpu;
>> +	struct vgic_io_device *devices, *device;
>> +	int c, ret = 0;
>> +
>> +	devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
>> +			  GFP_KERNEL);
>> +	if (!devices)
>> +		return -ENOMEM;
>> +
>> +	device = devices;
>> +	kvm_for_each_vcpu(c, vcpu, kvm) {
>> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>> +		device->base_addr = redist_base_address;
>> +		device->regions = vgic_v3_rdbase_registers;
>> +		device->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
>> +		device->redist_vcpu = vcpu;
>> +
>> +		mutex_lock(&kvm->slots_lock);
>> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> +					      redist_base_address,
>> +					      SZ_64K, &device->dev);
>> +		mutex_unlock(&kvm->slots_lock);
>> +
>> +		if (ret)
>> +			break;
>> +
>> +		device++;
>> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>> +		device->base_addr = redist_base_address + SZ_64K;
>> +		device->regions = vgic_v3_sgibase_registers;
>> +		device->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
>> +		device->redist_vcpu = vcpu;
>> +
>> +		mutex_lock(&kvm->slots_lock);
>> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> +					      redist_base_address + SZ_64K,
>> +					      SZ_64K, &device->dev);
>> +		mutex_unlock(&kvm->slots_lock);
>> +		if (ret) {
>> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> +						  &devices[c * 2].dev);
>> +			break;
>> +		}
>> +		device++;
>> +		redist_base_address += 2 * SZ_64K;
>> +	}
>
>What I fail to see here is what prevents the redistributor range from
>overlapping with the distributor (or any other device). The kvm IO bus
>is happy with overlapping addresses, but I'm not sure at all that this
>is safe.
>
>Care to shed some light on it?

Added the same question on wrong patch last week, thanks Marc. 
>
>Thanks,
>
>	M.
>-- 
>Jazz is not dead. It just smells funny...
>_______________________________________________
>kvmarm mailing list
>kvmarm@lists.cs.columbia.edu
>https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* [PATCH v3 32/55] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
@ 2016-05-09 17:51       ` Chalamarla, Tirumalesh
  0 siblings, 0 replies; 400+ messages in thread
From: Chalamarla, Tirumalesh @ 2016-05-09 17:51 UTC (permalink / raw)
  To: linux-arm-kernel






On 5/9/16, 10:18 AM, "kvmarm-bounces at lists.cs.columbia.edu on behalf of Marc Zyngier" <kvmarm-bounces at lists.cs.columbia.edu on behalf of marc.zyngier@arm.com> wrote:

>On 06/05/16 11:45, Andre Przywara wrote:
>> Create a new file called vgic-mmio-v3.c and describe the GICv3
>> distributor and redistributor registers there.
>> This adds a special macro to deal with the split of SGI/PPI in the
>> redistributor and SPIs in the distributor, which allows us to reuse
>> the existing GICv2 handlers for those registers which are compatible.
>> Also we provide a function to deal with the registration of the two
>> separate redistributor frames per VCPU.
>> 
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> Reviewed-by: Eric Auger <eric.auger@linaro.org>
>> ---
>> Changelog RFC..v1:
>> - adapt to new MMIO registration approach:
>>   register one device for the distributor and two for each VCPU
>> - implement special handling for private interrupts
>> - remove empty stub functions
>> - make IGROUPR return RAO
>> 
>> Changelog v1 .. v2:
>> - adapt to new framework, introduce vgic-mmio-v3.c
>> - remove userland register access functions (for now)
>> - precompute .len when describing a VGIC register
>> - add missed pointer incrementation on registering redist regions
>> - replace _nyi stub functions with raz/wi versions
>> 
>> Changelog v2 .. v3:
>> - replace inclusion of kvm/vgic/vgic.h with kvm/arm_vgic.h
>> - add prototype and stub code for vgic_register_redist_iodevs
>> - rename register struct variables _rdbase_ and _sgibase_
>> 
>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-mmio.c    |   5 +
>>  virt/kvm/arm/vgic/vgic-mmio.h    |   2 +
>>  virt/kvm/arm/vgic/vgic.h         |   7 ++
>>  4 files changed, 205 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
>> 
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> new file mode 100644
>> index 0000000..06c7ec5
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> @@ -0,0 +1,191 @@
>> +/*
>> + * VGICv3 MMIO 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 <kvm/iodev.h>
>> +#include <kvm/arm_vgic.h>
>> +
>> +#include <asm/kvm_emulate.h>
>> +
>> +#include "vgic.h"
>> +#include "vgic-mmio.h"
>> +
>> +/*
>> + * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
>> + * redistributors, while SPIs are covered by registers in the distributor
>> + * block. Trying to set private IRQs in this block gets ignored.
>> + * We take some special care here to fix the calculation of the register
>> + * offset.
>> + */
>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, read_ops, write_ops, bpi) \
>> +	{								\
>> +		.reg_offset = off,					\
>> +		.bits_per_irq = bpi,					\
>> +		.len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8,		\
>> +		.read = vgic_mmio_read_raz,				\
>> +		.write = vgic_mmio_write_wi,				\
>> +	}, {								\
>> +		.reg_offset = off + (bpi * VGIC_NR_PRIVATE_IRQS) / 8,	\
>> +		.bits_per_irq = bpi,					\
>> +		.len = (bpi * (1024 - VGIC_NR_PRIVATE_IRQS)) / 8,	\
>> +		.read = read_ops,					\
>> +		.write = write_ops,					\
>> +	}
>> +
>> +static const struct vgic_register_region vgic_v3_dist_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
>> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
>> +	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
>> +};
>> +
>> +static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
>> +};
>> +
>> +static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
>> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
>> +		vgic_mmio_read_config, vgic_mmio_write_config, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +};
>> +
>> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
>> +{
>> +	dev->regions = vgic_v3_dist_registers;
>> +	dev->nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
>> +
>> +	kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
>> +
>> +	return SZ_64K;
>> +}
>> +
>> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
>> +{
>> +	int nr_vcpus = atomic_read(&kvm->online_vcpus);
>> +	struct kvm_vcpu *vcpu;
>> +	struct vgic_io_device *devices, *device;
>> +	int c, ret = 0;
>> +
>> +	devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
>> +			  GFP_KERNEL);
>> +	if (!devices)
>> +		return -ENOMEM;
>> +
>> +	device = devices;
>> +	kvm_for_each_vcpu(c, vcpu, kvm) {
>> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>> +		device->base_addr = redist_base_address;
>> +		device->regions = vgic_v3_rdbase_registers;
>> +		device->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
>> +		device->redist_vcpu = vcpu;
>> +
>> +		mutex_lock(&kvm->slots_lock);
>> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> +					      redist_base_address,
>> +					      SZ_64K, &device->dev);
>> +		mutex_unlock(&kvm->slots_lock);
>> +
>> +		if (ret)
>> +			break;
>> +
>> +		device++;
>> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>> +		device->base_addr = redist_base_address + SZ_64K;
>> +		device->regions = vgic_v3_sgibase_registers;
>> +		device->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
>> +		device->redist_vcpu = vcpu;
>> +
>> +		mutex_lock(&kvm->slots_lock);
>> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> +					      redist_base_address + SZ_64K,
>> +					      SZ_64K, &device->dev);
>> +		mutex_unlock(&kvm->slots_lock);
>> +		if (ret) {
>> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> +						  &devices[c * 2].dev);
>> +			break;
>> +		}
>> +		device++;
>> +		redist_base_address += 2 * SZ_64K;
>> +	}
>
>What I fail to see here is what prevents the redistributor range from
>overlapping with the distributor (or any other device). The kvm IO bus
>is happy with overlapping addresses, but I'm not sure at all that this
>is safe.
>
>Care to shed some light on it?

Added the same question on wrong patch last week, thanks Marc. 
>
>Thanks,
>
>	M.
>-- 
>Jazz is not dead. It just smells funny...
>_______________________________________________
>kvmarm mailing list
>kvmarm at lists.cs.columbia.edu
>https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v3 06/55] KVM: arm/arm64: arch_timer: Remove irq_phys_map
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10  8:33     ` Eric Auger
  -1 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10  8:33 UTC (permalink / raw)
  To: Andre Przywara, Marc Zyngier, Christoffer Dall
  Cc: kvmarm, kvm, linux-arm-kernel

Hi Andre,
On 05/06/2016 12:45 PM, Andre Przywara wrote:
> Now that the interface between the arch timer and the VGIC does not
> require passing the irq_phys_map entry pointer anymore, let's remove
> it from the virtual arch timer and use the virtual IRQ number instead
> directly.
> The remaining pointer returned by kvm_vgic_map_phys_irq() will be
> removed in the following patch.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog v1 .. v2:
> - remove extra virt_irq member from struct, instead use irq.irq directly
> 
> Changelog v2 .. v3:
> - remove bogus validity check from kvm_vgic_unmap_phys_irq()
> 
>  include/kvm/arm_arch_timer.h |  3 ---
>  virt/kvm/arm/arch_timer.c    | 10 ++++------
>  2 files changed, 4 insertions(+), 9 deletions(-)
> 
> diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> index b651aed..a47b7de 100644
> --- a/include/kvm/arm_arch_timer.h
> +++ b/include/kvm/arm_arch_timer.h
> @@ -53,9 +53,6 @@ struct arch_timer_cpu {
>  	/* Timer IRQ */
>  	struct kvm_irq_level		irq;
>  
> -	/* VGIC mapping */
> -	struct irq_phys_map		*map;
> -
>  	/* Active IRQ state caching */
>  	bool				active_cleared_last;
>  };
> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> index 29d597d..f2cd188 100644
> --- a/virt/kvm/arm/arch_timer.c
> +++ b/virt/kvm/arm/arch_timer.c
> @@ -176,10 +176,10 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level)
>  
>  	timer->active_cleared_last = false;
>  	timer->irq.level = new_level;
> -	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->map->virt_irq,
> +	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->irq.irq,
>  				   timer->irq.level);
>  	ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id,
> -					 timer->map->virt_irq,
> +					 timer->irq.irq,
>  					 timer->irq.level);
>  	WARN_ON(ret);
>  }
> @@ -277,7 +277,7 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
>  	* exit.
>  	*/
>  	phys_active = timer->irq.level ||
> -			kvm_vgic_map_is_active(vcpu, timer->map->virt_irq);
> +			kvm_vgic_map_is_active(vcpu, timer->irq.irq);
>  
>  	/*
>  	 * We want to avoid hitting the (re)distributor as much as
> @@ -379,7 +379,6 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
>  	if (WARN_ON(IS_ERR(map)))
>  		return PTR_ERR(map);
>  
> -	timer->map = map;
>  	return 0;
>  }
>  
> @@ -522,8 +521,7 @@ void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu)
>  	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
>  
>  	timer_disarm(timer);
> -	if (timer->map)
> -		kvm_vgic_unmap_phys_irq(vcpu, timer->map->virt_irq);
> +	kvm_vgic_unmap_phys_irq(vcpu, timer->irq.irq);
Reviewed-by: Eric Auger <eric.auger@linaro.org>

Eric
>  }
>  
>  void kvm_timer_enable(struct kvm *kvm)
> 


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

* [PATCH v3 06/55] KVM: arm/arm64: arch_timer: Remove irq_phys_map
@ 2016-05-10  8:33     ` Eric Auger
  0 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10  8:33 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Andre,
On 05/06/2016 12:45 PM, Andre Przywara wrote:
> Now that the interface between the arch timer and the VGIC does not
> require passing the irq_phys_map entry pointer anymore, let's remove
> it from the virtual arch timer and use the virtual IRQ number instead
> directly.
> The remaining pointer returned by kvm_vgic_map_phys_irq() will be
> removed in the following patch.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog v1 .. v2:
> - remove extra virt_irq member from struct, instead use irq.irq directly
> 
> Changelog v2 .. v3:
> - remove bogus validity check from kvm_vgic_unmap_phys_irq()
> 
>  include/kvm/arm_arch_timer.h |  3 ---
>  virt/kvm/arm/arch_timer.c    | 10 ++++------
>  2 files changed, 4 insertions(+), 9 deletions(-)
> 
> diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> index b651aed..a47b7de 100644
> --- a/include/kvm/arm_arch_timer.h
> +++ b/include/kvm/arm_arch_timer.h
> @@ -53,9 +53,6 @@ struct arch_timer_cpu {
>  	/* Timer IRQ */
>  	struct kvm_irq_level		irq;
>  
> -	/* VGIC mapping */
> -	struct irq_phys_map		*map;
> -
>  	/* Active IRQ state caching */
>  	bool				active_cleared_last;
>  };
> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> index 29d597d..f2cd188 100644
> --- a/virt/kvm/arm/arch_timer.c
> +++ b/virt/kvm/arm/arch_timer.c
> @@ -176,10 +176,10 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level)
>  
>  	timer->active_cleared_last = false;
>  	timer->irq.level = new_level;
> -	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->map->virt_irq,
> +	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->irq.irq,
>  				   timer->irq.level);
>  	ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id,
> -					 timer->map->virt_irq,
> +					 timer->irq.irq,
>  					 timer->irq.level);
>  	WARN_ON(ret);
>  }
> @@ -277,7 +277,7 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
>  	* exit.
>  	*/
>  	phys_active = timer->irq.level ||
> -			kvm_vgic_map_is_active(vcpu, timer->map->virt_irq);
> +			kvm_vgic_map_is_active(vcpu, timer->irq.irq);
>  
>  	/*
>  	 * We want to avoid hitting the (re)distributor as much as
> @@ -379,7 +379,6 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
>  	if (WARN_ON(IS_ERR(map)))
>  		return PTR_ERR(map);
>  
> -	timer->map = map;
>  	return 0;
>  }
>  
> @@ -522,8 +521,7 @@ void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu)
>  	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
>  
>  	timer_disarm(timer);
> -	if (timer->map)
> -		kvm_vgic_unmap_phys_irq(vcpu, timer->map->virt_irq);
> +	kvm_vgic_unmap_phys_irq(vcpu, timer->irq.irq);
Reviewed-by: Eric Auger <eric.auger@linaro.org>

Eric
>  }
>  
>  void kvm_timer_enable(struct kvm *kvm)
> 

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

* Re: [PATCH v3 09/55] KVM: arm/arm64: Fix MMIO emulation data handling
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10  8:57     ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10  8:57 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall
  Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> When the kernel was handling a guest MMIO read access internally, we
> need to copy the emulation result into the run->mmio structure in order
> for the kvm_handle_mmio_return() function to pick it up and inject the
> 	result back into the guest.
> 
> Currently the only user of kvm_io_bus for ARM is the VGIC, which did
> this copying itself, so this was not causing issues so far.
> 
> But with the upcoming new vgic implementation we need this done
> properly.
> 
> Update the kvm_handle_mmio_return description and cleanup the code to
> only perform a single copying when needed.
> 
> Code and commit message inspired by Andre Przywara.
> 
> Reported-by: Andre Przywara <andre.przywara@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 09/55] KVM: arm/arm64: Fix MMIO emulation data handling
@ 2016-05-10  8:57     ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10  8:57 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> When the kernel was handling a guest MMIO read access internally, we
> need to copy the emulation result into the run->mmio structure in order
> for the kvm_handle_mmio_return() function to pick it up and inject the
> 	result back into the guest.
> 
> Currently the only user of kvm_io_bus for ARM is the VGIC, which did
> this copying itself, so this was not causing issues so far.
> 
> But with the upcoming new vgic implementation we need this done
> properly.
> 
> Update the kvm_handle_mmio_return description and cleanup the code to
> only perform a single copying when needed.
> 
> Code and commit message inspired by Andre Przywara.
> 
> Reported-by: Andre Przywara <andre.przywara@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 10/55] KVM: arm/arm64: Export mmio_read/write_bus
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10  8:59     ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10  8:59 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall
  Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Rename mmio_{read,write}_bus to kvm_mmio_{read,write}_bus and export
> them out of mmio.c.
> This will be needed later for the new VGIC implementation.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 10/55] KVM: arm/arm64: Export mmio_read/write_bus
@ 2016-05-10  8:59     ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10  8:59 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Rename mmio_{read,write}_bus to kvm_mmio_{read,write}_bus and export
> them out of mmio.c.
> This will be needed later for the new VGIC implementation.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 11/55] KVM: arm/arm64: pmu: abstract access to number of SPIs
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10  9:00     ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10  9:00 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

On 06/05/16 11:45, Andre Przywara wrote:
> Currently the PMU uses a member of the struct vgic_dist directly,
> which not only breaks abstraction, but will fail with the new VGIC.
> Abstract this access in the VGIC header file.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 11/55] KVM: arm/arm64: pmu: abstract access to number of SPIs
@ 2016-05-10  9:00     ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10  9:00 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> Currently the PMU uses a member of the struct vgic_dist directly,
> which not only breaks abstraction, but will fail with the new VGIC.
> Abstract this access in the VGIC header file.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 12/55] KVM: arm/arm64: move GICv2 emulation defines into arm-gic-v3.h
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10  9:02     ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10  9:02 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall
  Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> As (some) GICv3 hosts can emulate a GICv2, some GICv2 specific masks
> for the list register definition also apply to GICv3 LRs.
> At the moment we have those definitions in the KVM VGICv3
> implementation, so let's move them into the GICv3 header file to
> have them automatically defined.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 12/55] KVM: arm/arm64: move GICv2 emulation defines into arm-gic-v3.h
@ 2016-05-10  9:02     ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10  9:02 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> As (some) GICv3 hosts can emulate a GICv2, some GICv2 specific masks
> for the list register definition also apply to GICv3 LRs.
> At the moment we have those definitions in the KVM VGICv3
> implementation, so let's move them into the GICv3 header file to
> have them automatically defined.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 13/55] KVM: arm/arm64: vgic-new: Add data structure definitions
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10  9:05     ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10  9:05 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall
  Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Add a new header file for the new and improved GIC implementation.
> The big change is that we now have a struct vgic_irq per IRQ instead
> of spreading all the information over various bitmaps.
> 
> We include this new header conditionally from within the old header
> file for the time being to avoid touching all the users.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 13/55] KVM: arm/arm64: vgic-new: Add data structure definitions
@ 2016-05-10  9:05     ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10  9:05 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Add a new header file for the new and improved GIC implementation.
> The big change is that we now have a struct vgic_irq per IRQ instead
> of spreading all the information over various bitmaps.
> 
> We include this new header conditionally from within the old header
> file for the time being to avoid touching all the users.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 14/55] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10  9:22     ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10  9:22 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall
  Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> The new VGIC implementation centers around a struct vgic_irq instance
> per virtual IRQ.
> Provide a function to retrieve the right instance for a given IRQ
> number and (in case of private interrupts) the right VCPU.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic.c | 41 +++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h | 22 ++++++++++++++++++++++
>  2 files changed, 63 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic.c
>  create mode 100644 virt/kvm/arm/vgic/vgic.h
> 
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> new file mode 100644
> index 0000000..fb45537
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -0,0 +1,41 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +
> +#include "vgic.h"
> +
> +struct vgic_global __section(.hyp.text) kvm_vgic_global_state;

nit: this structure isn't referenced anywhere yet.

> +
> +struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> +			      u32 intid)
> +{
> +	/* SGIs and PPIs */
> +	if (intid <= VGIC_MAX_PRIVATE)
> +		return &vcpu->arch.vgic_cpu.private_irqs[intid];
> +
> +	/* SPIs */
> +	if (intid <= VGIC_MAX_SPI)
> +		return &kvm->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS];
> +
> +	/* LPIs are not yet covered */
> +	if (intid >= VGIC_MIN_LPI)
> +		return NULL;
> +
> +	WARN(1, "Looking up struct vgic_irq for reserved INTID");
> +	return NULL;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> new file mode 100644
> index 0000000..61b8d22
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -0,0 +1,22 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef __KVM_ARM_VGIC_NEW_H__
> +#define __KVM_ARM_VGIC_NEW_H__
> +
> +struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> +			      u32 intid);
> +
> +#endif
> 

Otherwise:

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 14/55] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
@ 2016-05-10  9:22     ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10  9:22 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> The new VGIC implementation centers around a struct vgic_irq instance
> per virtual IRQ.
> Provide a function to retrieve the right instance for a given IRQ
> number and (in case of private interrupts) the right VCPU.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic.c | 41 +++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h | 22 ++++++++++++++++++++++
>  2 files changed, 63 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic.c
>  create mode 100644 virt/kvm/arm/vgic/vgic.h
> 
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> new file mode 100644
> index 0000000..fb45537
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -0,0 +1,41 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +
> +#include "vgic.h"
> +
> +struct vgic_global __section(.hyp.text) kvm_vgic_global_state;

nit: this structure isn't referenced anywhere yet.

> +
> +struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> +			      u32 intid)
> +{
> +	/* SGIs and PPIs */
> +	if (intid <= VGIC_MAX_PRIVATE)
> +		return &vcpu->arch.vgic_cpu.private_irqs[intid];
> +
> +	/* SPIs */
> +	if (intid <= VGIC_MAX_SPI)
> +		return &kvm->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS];
> +
> +	/* LPIs are not yet covered */
> +	if (intid >= VGIC_MIN_LPI)
> +		return NULL;
> +
> +	WARN(1, "Looking up struct vgic_irq for reserved INTID");
> +	return NULL;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> new file mode 100644
> index 0000000..61b8d22
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -0,0 +1,22 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef __KVM_ARM_VGIC_NEW_H__
> +#define __KVM_ARM_VGIC_NEW_H__
> +
> +struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> +			      u32 intid);
> +
> +#endif
> 

Otherwise:

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 15/55] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10  9:25     ` Eric Auger
  -1 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10  9:25 UTC (permalink / raw)
  To: Andre Przywara, Marc Zyngier, Christoffer Dall
  Cc: kvmarm, kvm, linux-arm-kernel

Hi,
On 05/06/2016 12:45 PM, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Provide a vgic_queue_irq() function which decides whether a given
nit: now called vgic_queue_irq_unlock
> IRQ needs to be queued to a VCPU's ap_list.
> This should be called whenever an IRQ becomes pending or enabled,
> either as a result of userspace injection, from in-kernel emulated
> devices like the architected timer or from MMIO accesses to the
> distributor emulation.
> Also provides the necessary functions to allow userland to inject an
> IRQ to a guest.
> Since this is the first code that starts using our locking mechanism, we
> add some (hopefully) clear documentation of our locking strategy and
> requirements along with this patch.
> 
> [Andre: refactor out vgic_queue_irq_unlock()]
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - add spinlock checks protected by CONFIG_DEBUG_SPINLOCK
> - add more comments to vgic_target_oracle
> - remove BUG_ON() if IRQ is neither edge or level
> - rename vgic_queue_irq() to vgic_queue_irq_unlock()
> - simplify initial check in vgic_queue_irq_unlock()
> - extend retry loop to ask the oracle again
> - minor comment fixes
> 
> Changelog v1 .. v2:
> - move most IRQ injection code into vgic_update_irq_pending()
> 
>  include/kvm/vgic/vgic.h  |   3 +
>  virt/kvm/arm/vgic/vgic.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h |   1 +
>  3 files changed, 213 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 39933ee..2bfb42c 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -181,6 +181,9 @@ struct vgic_cpu {
>  	u64 live_lrs;
>  };
>  
> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			bool level);
> +
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>  #define vgic_initialized(k)	(false)
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index fb45537..92b78a0 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -19,8 +19,31 @@
>  
>  #include "vgic.h"
>  
> +#define CREATE_TRACE_POINTS
> +#include "../trace.h"
> +
> +#ifdef CONFIG_DEBUG_SPINLOCK
> +#define DEBUG_SPINLOCK_BUG_ON(p) BUG_ON(p)
> +#else
> +#define DEBUG_SPINLOCK_BUG_ON(p)
> +#endif
> +
>  struct vgic_global __section(.hyp.text) kvm_vgic_global_state;
>  
> +/*
> + * Locking order is always:
> + *   vgic_cpu->ap_list_lock
> + *     vgic_irq->irq_lock
> + *
> + * (that is, always take the ap_list_lock before the struct vgic_irq lock).
> + *
> + * When taking more than one ap_list_lock at the same time, always take the
> + * lowest numbered VCPU's ap_list_lock first, so:
> + *   vcpuX->vcpu_id < vcpuY->vcpu_id:
> + *     spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
> + *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
> + */
> +
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid)
>  {
> @@ -39,3 +62,189 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  	WARN(1, "Looking up struct vgic_irq for reserved INTID");
>  	return NULL;
>  }
> +
> +/**
> + * kvm_vgic_target_oracle - compute the target vcpu for an irq
> + *
> + * @irq:	The irq to route. Must be already locked.
> + *
> + * Based on the current state of the interrupt (enabled, pending,
> + * active, vcpu and target_vcpu), compute the next vcpu this should be
> + * given to. Return NULL if this shouldn't be injected at all.
> + *
> + * Requires the IRQ lock to be held.
> + */
> +static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
> +{
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
> +
> +	/* If the interrupt is active, it must stay on the current vcpu */
> +	if (irq->active)
> +		return irq->vcpu;
> +
> +	/*
> +	 * If the IRQ is not active but enabled and pending, we should direct
> +	 * it to its configured target VCPU.
> +	 */
> +	if (irq->enabled && irq->pending)
> +		return irq->target_vcpu;
> +
> +	/* If neither active nor pending and enabled, then this IRQ should not
> +	 * be queued to any VCPU.
> +	 */
> +	return NULL;
> +}
> +
> +/*
> + * Only valid injection if changing level for level-triggered IRQs or for a
> + * rising edge.
> + */
> +static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
> +{
> +	switch (irq->config) {
> +	case VGIC_CONFIG_LEVEL:
> +		return irq->line_level != level;
> +	case VGIC_CONFIG_EDGE:
> +		return level;
> +	}
> +
> +	return false;
> +}
> +
> +/*
> + * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
> + * Do the queuing if necessary, taking the right locks in the right order.
> + * Returns true when the IRQ was queued, false otherwise.
> + *
> + * Needs to be entered with the IRQ lock already held, but will return
> + * with all locks dropped.
> + */
> +bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq)
> +{
> +	struct kvm_vcpu *vcpu;
> +
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
> +
> +retry:
> +	vcpu = vgic_target_oracle(irq);
> +	if (irq->vcpu || !vcpu) {
> +		/*
> +		 * If this IRQ is already on a VCPU's ap_list, then it
> +		 * cannot be moved or modified and there is no more work for
> +		 * us to do.
> +		 *
> +		 * Otherwise, if the irq is not pending and enabled, it does
> +		 * not need to be inserted into an ap_list and there is also
> +		 * no more work for us to do.
> +		 */
> +		spin_unlock(&irq->irq_lock);
> +		return false;
> +	}
> +
> +	/*
> +	 * We must unlock the irq lock to take the ap_list_lock where
> +	 * we are going to insert this new pending interrupt.
> +	 */
> +	spin_unlock(&irq->irq_lock);
> +
> +	/* someone can do stuff here, which we re-check below */
> +
> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +	spin_lock(&irq->irq_lock);
> +
> +	/*
> +	 * Did something change behind our backs?
> +	 *
> +	 * There are two cases:
> +	 * 1) The irq became pending or active behind our backs and/or
> +	 *    the irq->vcpu field was set correspondingly when putting
> +	 *    the irq on an ap_list. Then drop the locks and return.
Don't we actually implement 3 cases here:
1) the IRQ was queued in our back
2) the IRQ was disabled/turned not pending in our back
3) someone changed the affinity?
> +	 * 2) Someone changed the affinity on this irq behind our
> +	 *    backs and we are now holding the wrong ap_list_lock.
> +	 *    Then drop the locks and try the new VCPU.
> +	 */
> +	if (irq->vcpu || !(irq->pending && irq->enabled)) {
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +		return false;
> +	}
> +
> +	if (irq->target_vcpu != vcpu) {
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +		spin_lock(&irq->irq_lock);
> +		goto retry;
> +	}
> +
> +	list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
> +	irq->vcpu = vcpu;
> +
> +	spin_unlock(&irq->irq_lock);
> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +	kvm_vcpu_kick(vcpu);
> +
> +	return true;
> +}
> +
> +static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
> +				   unsigned int intid, bool level,
> +				   bool mapped_irq)
> +{
> +	struct kvm_vcpu *vcpu;
> +	struct vgic_irq *irq;
> +	int ret;
> +
> +	trace_vgic_update_irq_pending(cpuid, intid, level);
> +
> +	vcpu = kvm_get_vcpu(kvm, cpuid);
> +	if (!vcpu && intid < VGIC_NR_PRIVATE_IRQS)
> +		return -EINVAL;
> +
> +	irq = vgic_get_irq(kvm, vcpu, intid);
> +	if (!irq)
> +		return -EINVAL;
> +
> +	if (irq->hw != mapped_irq)
> +		return -EINVAL;
> +
> +	spin_lock(&irq->irq_lock);
> +
> +	if (!vgic_validate_injection(irq, level)) {
> +		/* Nothing to see here, move along... */
> +		spin_unlock(&irq->irq_lock);
> +		return 0;
> +	}
> +
> +	if (irq->config == VGIC_CONFIG_LEVEL) {
> +		irq->line_level = level;
> +		irq->pending = level || irq->soft_pending;
> +	} else {
> +		irq->pending = true;
> +	}
> +
> +	vgic_queue_irq_unlock(kvm, irq);
> +
> +	return 0;
> +}
> +
> +/**
> + * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
> + * @kvm:     The VM structure pointer
> + * @cpuid:   The CPU for PPIs
> + * @intid:   The INTID to inject a new state to.
> + * @level:   Edge-triggered:  true:  to trigger the interrupt
> + *			      false: to ignore the call
> + *	     Level-sensitive  true:  raise the input signal
> + *			      false: lower the input signal
> + *
> + * The VGIC is not concerned with devices being active-LOW or active-HIGH for
> + * level-sensitive interrupts.  You can think of the level parameter as 1
> + * being HIGH and 0 being LOW and all devices being active-HIGH.
> + */
> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			bool level)
> +{
> +	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 61b8d22..c625767 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -18,5 +18,6 @@
>  
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
> +bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
>  
>  #endif
> 
Reviewed-by: Eric Auger <eric.auger@linaro.org>

Eric



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

* [PATCH v3 15/55] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
@ 2016-05-10  9:25     ` Eric Auger
  0 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10  9:25 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,
On 05/06/2016 12:45 PM, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Provide a vgic_queue_irq() function which decides whether a given
nit: now called vgic_queue_irq_unlock
> IRQ needs to be queued to a VCPU's ap_list.
> This should be called whenever an IRQ becomes pending or enabled,
> either as a result of userspace injection, from in-kernel emulated
> devices like the architected timer or from MMIO accesses to the
> distributor emulation.
> Also provides the necessary functions to allow userland to inject an
> IRQ to a guest.
> Since this is the first code that starts using our locking mechanism, we
> add some (hopefully) clear documentation of our locking strategy and
> requirements along with this patch.
> 
> [Andre: refactor out vgic_queue_irq_unlock()]
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - add spinlock checks protected by CONFIG_DEBUG_SPINLOCK
> - add more comments to vgic_target_oracle
> - remove BUG_ON() if IRQ is neither edge or level
> - rename vgic_queue_irq() to vgic_queue_irq_unlock()
> - simplify initial check in vgic_queue_irq_unlock()
> - extend retry loop to ask the oracle again
> - minor comment fixes
> 
> Changelog v1 .. v2:
> - move most IRQ injection code into vgic_update_irq_pending()
> 
>  include/kvm/vgic/vgic.h  |   3 +
>  virt/kvm/arm/vgic/vgic.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h |   1 +
>  3 files changed, 213 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 39933ee..2bfb42c 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -181,6 +181,9 @@ struct vgic_cpu {
>  	u64 live_lrs;
>  };
>  
> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			bool level);
> +
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>  #define vgic_initialized(k)	(false)
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index fb45537..92b78a0 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -19,8 +19,31 @@
>  
>  #include "vgic.h"
>  
> +#define CREATE_TRACE_POINTS
> +#include "../trace.h"
> +
> +#ifdef CONFIG_DEBUG_SPINLOCK
> +#define DEBUG_SPINLOCK_BUG_ON(p) BUG_ON(p)
> +#else
> +#define DEBUG_SPINLOCK_BUG_ON(p)
> +#endif
> +
>  struct vgic_global __section(.hyp.text) kvm_vgic_global_state;
>  
> +/*
> + * Locking order is always:
> + *   vgic_cpu->ap_list_lock
> + *     vgic_irq->irq_lock
> + *
> + * (that is, always take the ap_list_lock before the struct vgic_irq lock).
> + *
> + * When taking more than one ap_list_lock at the same time, always take the
> + * lowest numbered VCPU's ap_list_lock first, so:
> + *   vcpuX->vcpu_id < vcpuY->vcpu_id:
> + *     spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
> + *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
> + */
> +
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid)
>  {
> @@ -39,3 +62,189 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  	WARN(1, "Looking up struct vgic_irq for reserved INTID");
>  	return NULL;
>  }
> +
> +/**
> + * kvm_vgic_target_oracle - compute the target vcpu for an irq
> + *
> + * @irq:	The irq to route. Must be already locked.
> + *
> + * Based on the current state of the interrupt (enabled, pending,
> + * active, vcpu and target_vcpu), compute the next vcpu this should be
> + * given to. Return NULL if this shouldn't be injected at all.
> + *
> + * Requires the IRQ lock to be held.
> + */
> +static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
> +{
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
> +
> +	/* If the interrupt is active, it must stay on the current vcpu */
> +	if (irq->active)
> +		return irq->vcpu;
> +
> +	/*
> +	 * If the IRQ is not active but enabled and pending, we should direct
> +	 * it to its configured target VCPU.
> +	 */
> +	if (irq->enabled && irq->pending)
> +		return irq->target_vcpu;
> +
> +	/* If neither active nor pending and enabled, then this IRQ should not
> +	 * be queued to any VCPU.
> +	 */
> +	return NULL;
> +}
> +
> +/*
> + * Only valid injection if changing level for level-triggered IRQs or for a
> + * rising edge.
> + */
> +static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
> +{
> +	switch (irq->config) {
> +	case VGIC_CONFIG_LEVEL:
> +		return irq->line_level != level;
> +	case VGIC_CONFIG_EDGE:
> +		return level;
> +	}
> +
> +	return false;
> +}
> +
> +/*
> + * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
> + * Do the queuing if necessary, taking the right locks in the right order.
> + * Returns true when the IRQ was queued, false otherwise.
> + *
> + * Needs to be entered with the IRQ lock already held, but will return
> + * with all locks dropped.
> + */
> +bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq)
> +{
> +	struct kvm_vcpu *vcpu;
> +
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
> +
> +retry:
> +	vcpu = vgic_target_oracle(irq);
> +	if (irq->vcpu || !vcpu) {
> +		/*
> +		 * If this IRQ is already on a VCPU's ap_list, then it
> +		 * cannot be moved or modified and there is no more work for
> +		 * us to do.
> +		 *
> +		 * Otherwise, if the irq is not pending and enabled, it does
> +		 * not need to be inserted into an ap_list and there is also
> +		 * no more work for us to do.
> +		 */
> +		spin_unlock(&irq->irq_lock);
> +		return false;
> +	}
> +
> +	/*
> +	 * We must unlock the irq lock to take the ap_list_lock where
> +	 * we are going to insert this new pending interrupt.
> +	 */
> +	spin_unlock(&irq->irq_lock);
> +
> +	/* someone can do stuff here, which we re-check below */
> +
> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +	spin_lock(&irq->irq_lock);
> +
> +	/*
> +	 * Did something change behind our backs?
> +	 *
> +	 * There are two cases:
> +	 * 1) The irq became pending or active behind our backs and/or
> +	 *    the irq->vcpu field was set correspondingly when putting
> +	 *    the irq on an ap_list. Then drop the locks and return.
Don't we actually implement 3 cases here:
1) the IRQ was queued in our back
2) the IRQ was disabled/turned not pending in our back
3) someone changed the affinity?
> +	 * 2) Someone changed the affinity on this irq behind our
> +	 *    backs and we are now holding the wrong ap_list_lock.
> +	 *    Then drop the locks and try the new VCPU.
> +	 */
> +	if (irq->vcpu || !(irq->pending && irq->enabled)) {
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +		return false;
> +	}
> +
> +	if (irq->target_vcpu != vcpu) {
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +		spin_lock(&irq->irq_lock);
> +		goto retry;
> +	}
> +
> +	list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
> +	irq->vcpu = vcpu;
> +
> +	spin_unlock(&irq->irq_lock);
> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +	kvm_vcpu_kick(vcpu);
> +
> +	return true;
> +}
> +
> +static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
> +				   unsigned int intid, bool level,
> +				   bool mapped_irq)
> +{
> +	struct kvm_vcpu *vcpu;
> +	struct vgic_irq *irq;
> +	int ret;
> +
> +	trace_vgic_update_irq_pending(cpuid, intid, level);
> +
> +	vcpu = kvm_get_vcpu(kvm, cpuid);
> +	if (!vcpu && intid < VGIC_NR_PRIVATE_IRQS)
> +		return -EINVAL;
> +
> +	irq = vgic_get_irq(kvm, vcpu, intid);
> +	if (!irq)
> +		return -EINVAL;
> +
> +	if (irq->hw != mapped_irq)
> +		return -EINVAL;
> +
> +	spin_lock(&irq->irq_lock);
> +
> +	if (!vgic_validate_injection(irq, level)) {
> +		/* Nothing to see here, move along... */
> +		spin_unlock(&irq->irq_lock);
> +		return 0;
> +	}
> +
> +	if (irq->config == VGIC_CONFIG_LEVEL) {
> +		irq->line_level = level;
> +		irq->pending = level || irq->soft_pending;
> +	} else {
> +		irq->pending = true;
> +	}
> +
> +	vgic_queue_irq_unlock(kvm, irq);
> +
> +	return 0;
> +}
> +
> +/**
> + * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
> + * @kvm:     The VM structure pointer
> + * @cpuid:   The CPU for PPIs
> + * @intid:   The INTID to inject a new state to.
> + * @level:   Edge-triggered:  true:  to trigger the interrupt
> + *			      false: to ignore the call
> + *	     Level-sensitive  true:  raise the input signal
> + *			      false: lower the input signal
> + *
> + * The VGIC is not concerned with devices being active-LOW or active-HIGH for
> + * level-sensitive interrupts.  You can think of the level parameter as 1
> + * being HIGH and 0 being LOW and all devices being active-HIGH.
> + */
> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			bool level)
> +{
> +	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 61b8d22..c625767 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -18,5 +18,6 @@
>  
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
> +bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
>  
>  #endif
> 
Reviewed-by: Eric Auger <eric.auger@linaro.org>

Eric

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

* Re: [PATCH v3 16/55] KVM: arm/arm64: vgic-new: Add IRQ sorting
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10  9:29     ` Eric Auger
  -1 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10  9:29 UTC (permalink / raw)
  To: Andre Przywara, Marc Zyngier, Christoffer Dall
  Cc: kvmarm, kvm, linux-arm-kernel

On 05/06/2016 12:45 PM, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Adds the sorting function to cover the case where you have more IRQs
> to consider than you have LRs. We now consider priorities.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 57 insertions(+)
> 
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 92b78a0..4fb20fd 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -16,6 +16,7 @@
>  
>  #include <linux/kvm.h>
>  #include <linux/kvm_host.h>
> +#include <linux/list_sort.h>
>  
>  #include "vgic.h"
>  
> @@ -96,6 +97,62 @@ static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
>  }
>  
>  /*
> + * The order of items in the ap_lists defines how we'll pack things in LRs as
> + * well, the first items in the list being the first things populated in the
> + * LRs.
> + *
> + * A hard rule is that active interrupts can never be pushed out of the LRs
> + * (and therefore take priority) since we cannot reliably trap on deactivation
> + * of IRQs and therefore they have to be present in the LRs.
> + *
> + * Otherwise things should be sorted by the priority field and the GIC
> + * hardware support will take care of preemption of priority groups etc.
> + *
> + * Return negative if "a" sorts before "b", 0 to preserve order, and positive
> + * to sort "b" before "a".
> + */
> +static int vgic_irq_cmp(void *priv, struct list_head *a, struct list_head *b)
> +{
> +	struct vgic_irq *irqa = container_of(a, struct vgic_irq, ap_list);
> +	struct vgic_irq *irqb = container_of(b, struct vgic_irq, ap_list);
> +	bool penda, pendb;
> +	int ret;
> +
> +	spin_lock(&irqa->irq_lock);
> +	spin_lock(&irqb->irq_lock);
> +
> +	if (irqa->active || irqb->active) {
> +		ret = (int)irqb->active - (int)irqa->active;
> +		goto out;
> +	}
> +
> +	penda = irqa->enabled && irqa->pending;
> +	pendb = irqb->enabled && irqb->pending;
> +
> +	if (!penda || !pendb) {
> +		ret = (int)pendb - (int)penda;
> +		goto out;
> +	}
> +
> +	/* Both pending and enabled, sort by priority */
> +	ret = irqa->priority - irqb->priority;
> +out:
> +	spin_unlock(&irqb->irq_lock);
> +	spin_unlock(&irqa->irq_lock);
> +	return ret;
> +}
> +
> +/* Must be called with the ap_list_lock held */
> +static void vgic_sort_ap_list(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
> +
> +	list_sort(NULL, &vgic_cpu->ap_list_head, vgic_irq_cmp);
> +}
> +
> +/*
>   * Only valid injection if changing level for level-triggered IRQs or for a
>   * rising edge.
>   */
> 
Reviewed-by: Eric Auger <eric.auger@linaro.org>

Eric


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

* [PATCH v3 16/55] KVM: arm/arm64: vgic-new: Add IRQ sorting
@ 2016-05-10  9:29     ` Eric Auger
  0 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10  9:29 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/06/2016 12:45 PM, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Adds the sorting function to cover the case where you have more IRQs
> to consider than you have LRs. We now consider priorities.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 57 insertions(+)
> 
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 92b78a0..4fb20fd 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -16,6 +16,7 @@
>  
>  #include <linux/kvm.h>
>  #include <linux/kvm_host.h>
> +#include <linux/list_sort.h>
>  
>  #include "vgic.h"
>  
> @@ -96,6 +97,62 @@ static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
>  }
>  
>  /*
> + * The order of items in the ap_lists defines how we'll pack things in LRs as
> + * well, the first items in the list being the first things populated in the
> + * LRs.
> + *
> + * A hard rule is that active interrupts can never be pushed out of the LRs
> + * (and therefore take priority) since we cannot reliably trap on deactivation
> + * of IRQs and therefore they have to be present in the LRs.
> + *
> + * Otherwise things should be sorted by the priority field and the GIC
> + * hardware support will take care of preemption of priority groups etc.
> + *
> + * Return negative if "a" sorts before "b", 0 to preserve order, and positive
> + * to sort "b" before "a".
> + */
> +static int vgic_irq_cmp(void *priv, struct list_head *a, struct list_head *b)
> +{
> +	struct vgic_irq *irqa = container_of(a, struct vgic_irq, ap_list);
> +	struct vgic_irq *irqb = container_of(b, struct vgic_irq, ap_list);
> +	bool penda, pendb;
> +	int ret;
> +
> +	spin_lock(&irqa->irq_lock);
> +	spin_lock(&irqb->irq_lock);
> +
> +	if (irqa->active || irqb->active) {
> +		ret = (int)irqb->active - (int)irqa->active;
> +		goto out;
> +	}
> +
> +	penda = irqa->enabled && irqa->pending;
> +	pendb = irqb->enabled && irqb->pending;
> +
> +	if (!penda || !pendb) {
> +		ret = (int)pendb - (int)penda;
> +		goto out;
> +	}
> +
> +	/* Both pending and enabled, sort by priority */
> +	ret = irqa->priority - irqb->priority;
> +out:
> +	spin_unlock(&irqb->irq_lock);
> +	spin_unlock(&irqa->irq_lock);
> +	return ret;
> +}
> +
> +/* Must be called with the ap_list_lock held */
> +static void vgic_sort_ap_list(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
> +
> +	list_sort(NULL, &vgic_cpu->ap_list_head, vgic_irq_cmp);
> +}
> +
> +/*
>   * Only valid injection if changing level for level-triggered IRQs or for a
>   * rising edge.
>   */
> 
Reviewed-by: Eric Auger <eric.auger@linaro.org>

Eric

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

* Re: [PATCH v3 14/55] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10  9:35     ` Eric Auger
  -1 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10  9:35 UTC (permalink / raw)
  To: Andre Przywara, Marc Zyngier, Christoffer Dall
  Cc: linux-arm-kernel, kvmarm, kvm

On 05/06/2016 12:45 PM, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> The new VGIC implementation centers around a struct vgic_irq instance
> per virtual IRQ.
> Provide a function to retrieve the right instance for a given IRQ
> number and (in case of private interrupts) the right VCPU.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic.c | 41 +++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h | 22 ++++++++++++++++++++++
>  2 files changed, 63 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic.c
>  create mode 100644 virt/kvm/arm/vgic/vgic.h
> 
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> new file mode 100644
> index 0000000..fb45537
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -0,0 +1,41 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +
> +#include "vgic.h"
> +
> +struct vgic_global __section(.hyp.text) kvm_vgic_global_state;
> +
> +struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> +			      u32 intid)
> +{
> +	/* SGIs and PPIs */
> +	if (intid <= VGIC_MAX_PRIVATE)
> +		return &vcpu->arch.vgic_cpu.private_irqs[intid];
> +
> +	/* SPIs */
> +	if (intid <= VGIC_MAX_SPI)
> +		return &kvm->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS];
> +
> +	/* LPIs are not yet covered */
> +	if (intid >= VGIC_MIN_LPI)
> +		return NULL;
> +
> +	WARN(1, "Looking up struct vgic_irq for reserved INTID");
> +	return NULL;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> new file mode 100644
> index 0000000..61b8d22
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -0,0 +1,22 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef __KVM_ARM_VGIC_NEW_H__
> +#define __KVM_ARM_VGIC_NEW_H__
> +
> +struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> +			      u32 intid);
> +
> +#endif
> 
Reviewed-by: Eric Auger <eric.auger@linaro.org>

Eric

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

* [PATCH v3 14/55] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
@ 2016-05-10  9:35     ` Eric Auger
  0 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10  9:35 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/06/2016 12:45 PM, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> The new VGIC implementation centers around a struct vgic_irq instance
> per virtual IRQ.
> Provide a function to retrieve the right instance for a given IRQ
> number and (in case of private interrupts) the right VCPU.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic.c | 41 +++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h | 22 ++++++++++++++++++++++
>  2 files changed, 63 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic.c
>  create mode 100644 virt/kvm/arm/vgic/vgic.h
> 
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> new file mode 100644
> index 0000000..fb45537
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -0,0 +1,41 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +
> +#include "vgic.h"
> +
> +struct vgic_global __section(.hyp.text) kvm_vgic_global_state;
> +
> +struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> +			      u32 intid)
> +{
> +	/* SGIs and PPIs */
> +	if (intid <= VGIC_MAX_PRIVATE)
> +		return &vcpu->arch.vgic_cpu.private_irqs[intid];
> +
> +	/* SPIs */
> +	if (intid <= VGIC_MAX_SPI)
> +		return &kvm->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS];
> +
> +	/* LPIs are not yet covered */
> +	if (intid >= VGIC_MIN_LPI)
> +		return NULL;
> +
> +	WARN(1, "Looking up struct vgic_irq for reserved INTID");
> +	return NULL;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> new file mode 100644
> index 0000000..61b8d22
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -0,0 +1,22 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef __KVM_ARM_VGIC_NEW_H__
> +#define __KVM_ARM_VGIC_NEW_H__
> +
> +struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> +			      u32 intid);
> +
> +#endif
> 
Reviewed-by: Eric Auger <eric.auger@linaro.org>

Eric

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

* Re: [PATCH v3 15/55] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10  9:39     ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10  9:39 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall
  Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Provide a vgic_queue_irq() function which decides whether a given
> IRQ needs to be queued to a VCPU's ap_list.
> This should be called whenever an IRQ becomes pending or enabled,
> either as a result of userspace injection, from in-kernel emulated
> devices like the architected timer or from MMIO accesses to the
> distributor emulation.
> Also provides the necessary functions to allow userland to inject an
> IRQ to a guest.
> Since this is the first code that starts using our locking mechanism, we
> add some (hopefully) clear documentation of our locking strategy and
> requirements along with this patch.
> 
> [Andre: refactor out vgic_queue_irq_unlock()]
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 15/55] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
@ 2016-05-10  9:39     ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10  9:39 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Provide a vgic_queue_irq() function which decides whether a given
> IRQ needs to be queued to a VCPU's ap_list.
> This should be called whenever an IRQ becomes pending or enabled,
> either as a result of userspace injection, from in-kernel emulated
> devices like the architected timer or from MMIO accesses to the
> distributor emulation.
> Also provides the necessary functions to allow userland to inject an
> IRQ to a guest.
> Since this is the first code that starts using our locking mechanism, we
> add some (hopefully) clear documentation of our locking strategy and
> requirements along with this patch.
> 
> [Andre: refactor out vgic_queue_irq_unlock()]
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 16/55] KVM: arm/arm64: vgic-new: Add IRQ sorting
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10  9:48     ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10  9:48 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall
  Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Adds the sorting function to cover the case where you have more IRQs
> to consider than you have LRs. We now consider priorities.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 16/55] KVM: arm/arm64: vgic-new: Add IRQ sorting
@ 2016-05-10  9:48     ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10  9:48 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Adds the sorting function to cover the case where you have more IRQs
> to consider than you have LRs. We now consider priorities.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 11/55] KVM: arm/arm64: pmu: abstract access to number of SPIs
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10  9:52     ` Eric Auger
  -1 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10  9:52 UTC (permalink / raw)
  To: Andre Przywara, Marc Zyngier, Christoffer Dall
  Cc: kvmarm, linux-arm-kernel, kvm

Hi Andre,
On 05/06/2016 12:45 PM, Andre Przywara wrote:
> Currently the PMU uses a member of the struct vgic_dist directly,
> which not only breaks abstraction, but will fail with the new VGIC.
> Abstract this access in the VGIC header file.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/arm_vgic.h | 2 ++
>  virt/kvm/arm/pmu.c     | 2 +-
>  2 files changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 452bb85..c14ff77 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -347,6 +347,8 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>  #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> +#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
> +				 ((i) < (k)->arch.vgic.nr_irqs))
>  
>  int vgic_v2_probe(struct device_node *vgic_node,
>  		  const struct vgic_ops **ops,
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 575c7aa..bd2e872 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -477,7 +477,7 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
>  		 * the interrupt number is the same for all vcpus, while as an
>  		 * SPI it must be a separate number per vcpu.
>  		 */
> -		if (irq < VGIC_NR_SGIS || irq >= vcpu->kvm->arch.vgic.nr_irqs ||
> +		if (irq < VGIC_NR_SGIS || !vgic_valid_spi(vcpu->kvm, irq) ||
>  		    !irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
>  			return -EINVAL;
>  
> 
in case this is a PPI it will now return an error, right? I don't think
this is what we expect.

Cheers

Eric

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

* [PATCH v3 11/55] KVM: arm/arm64: pmu: abstract access to number of SPIs
@ 2016-05-10  9:52     ` Eric Auger
  0 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10  9:52 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Andre,
On 05/06/2016 12:45 PM, Andre Przywara wrote:
> Currently the PMU uses a member of the struct vgic_dist directly,
> which not only breaks abstraction, but will fail with the new VGIC.
> Abstract this access in the VGIC header file.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/arm_vgic.h | 2 ++
>  virt/kvm/arm/pmu.c     | 2 +-
>  2 files changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 452bb85..c14ff77 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -347,6 +347,8 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>  #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> +#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
> +				 ((i) < (k)->arch.vgic.nr_irqs))
>  
>  int vgic_v2_probe(struct device_node *vgic_node,
>  		  const struct vgic_ops **ops,
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 575c7aa..bd2e872 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -477,7 +477,7 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
>  		 * the interrupt number is the same for all vcpus, while as an
>  		 * SPI it must be a separate number per vcpu.
>  		 */
> -		if (irq < VGIC_NR_SGIS || irq >= vcpu->kvm->arch.vgic.nr_irqs ||
> +		if (irq < VGIC_NR_SGIS || !vgic_valid_spi(vcpu->kvm, irq) ||
>  		    !irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
>  			return -EINVAL;
>  
> 
in case this is a PPI it will now return an error, right? I don't think
this is what we expect.

Cheers

Eric

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

* Re: [PATCH v3 11/55] KVM: arm/arm64: pmu: abstract access to number of SPIs
  2016-05-10  9:52     ` Eric Auger
@ 2016-05-10 10:04       ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 10:04 UTC (permalink / raw)
  To: Eric Auger, Andre Przywara, Christoffer Dall
  Cc: linux-arm-kernel, kvmarm, kvm

On 10/05/16 10:52, Eric Auger wrote:
> Hi Andre,
> On 05/06/2016 12:45 PM, Andre Przywara wrote:
>> Currently the PMU uses a member of the struct vgic_dist directly,
>> which not only breaks abstraction, but will fail with the new VGIC.
>> Abstract this access in the VGIC header file.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/arm_vgic.h | 2 ++
>>  virt/kvm/arm/pmu.c     | 2 +-
>>  2 files changed, 3 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index 452bb85..c14ff77 100644
>> --- a/include/kvm/arm_vgic.h
>> +++ b/include/kvm/arm_vgic.h
>> @@ -347,6 +347,8 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
>>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>>  #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
>>  #define vgic_ready(k)		((k)->arch.vgic.ready)
>> +#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>> +				 ((i) < (k)->arch.vgic.nr_irqs))
>>  
>>  int vgic_v2_probe(struct device_node *vgic_node,
>>  		  const struct vgic_ops **ops,
>> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
>> index 575c7aa..bd2e872 100644
>> --- a/virt/kvm/arm/pmu.c
>> +++ b/virt/kvm/arm/pmu.c
>> @@ -477,7 +477,7 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
>>  		 * the interrupt number is the same for all vcpus, while as an
>>  		 * SPI it must be a separate number per vcpu.
>>  		 */
>> -		if (irq < VGIC_NR_SGIS || irq >= vcpu->kvm->arch.vgic.nr_irqs ||
>> +		if (irq < VGIC_NR_SGIS || !vgic_valid_spi(vcpu->kvm, irq) ||
>>  		    !irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
>>  			return -EINVAL;
>>  
>>
> in case this is a PPI it will now return an error, right? I don't think
> this is what we expect.

Ouch. Good catch. I missed the ! too...

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 11/55] KVM: arm/arm64: pmu: abstract access to number of SPIs
@ 2016-05-10 10:04       ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 10:04 UTC (permalink / raw)
  To: linux-arm-kernel

On 10/05/16 10:52, Eric Auger wrote:
> Hi Andre,
> On 05/06/2016 12:45 PM, Andre Przywara wrote:
>> Currently the PMU uses a member of the struct vgic_dist directly,
>> which not only breaks abstraction, but will fail with the new VGIC.
>> Abstract this access in the VGIC header file.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  include/kvm/arm_vgic.h | 2 ++
>>  virt/kvm/arm/pmu.c     | 2 +-
>>  2 files changed, 3 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index 452bb85..c14ff77 100644
>> --- a/include/kvm/arm_vgic.h
>> +++ b/include/kvm/arm_vgic.h
>> @@ -347,6 +347,8 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
>>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>>  #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
>>  #define vgic_ready(k)		((k)->arch.vgic.ready)
>> +#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>> +				 ((i) < (k)->arch.vgic.nr_irqs))
>>  
>>  int vgic_v2_probe(struct device_node *vgic_node,
>>  		  const struct vgic_ops **ops,
>> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
>> index 575c7aa..bd2e872 100644
>> --- a/virt/kvm/arm/pmu.c
>> +++ b/virt/kvm/arm/pmu.c
>> @@ -477,7 +477,7 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
>>  		 * the interrupt number is the same for all vcpus, while as an
>>  		 * SPI it must be a separate number per vcpu.
>>  		 */
>> -		if (irq < VGIC_NR_SGIS || irq >= vcpu->kvm->arch.vgic.nr_irqs ||
>> +		if (irq < VGIC_NR_SGIS || !vgic_valid_spi(vcpu->kvm, irq) ||
>>  		    !irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
>>  			return -EINVAL;
>>  
>>
> in case this is a PPI it will now return an error, right? I don't think
> this is what we expect.

Ouch. Good catch. I missed the ! too...

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 20/55] KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10 10:22     ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 10:22 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall
  Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> Tell KVM whether a particular VCPU has an IRQ that needs handling
> in the guest. This is used to decide whether a VCPU is runnable.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 20/55] KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
@ 2016-05-10 10:22     ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 10:22 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> Tell KVM whether a particular VCPU has an IRQ that needs handling
> in the guest. This is used to decide whether a VCPU is runnable.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10 10:28     ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 10:28 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

On 06/05/16 11:45, Andre Przywara wrote:
> As the enable register handlers are shared between the v2 and v3
> emulation, their implementation goes into vgic-mmio.c, to be easily
> referenced from the v3 emulation as well later.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
@ 2016-05-10 10:28     ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 10:28 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> As the enable register handlers are shared between the v2 and v3
> emulation, their implementation goes into vgic-mmio.c, to be easily
> referenced from the v3 emulation as well later.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 25/55] KVM: arm/arm64: vgic-new: Add PENDING registers handlers
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10 10:49     ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 10:49 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

On 06/05/16 11:45, Andre Przywara wrote:
> The pending register handlers are shared between the v2 and v3
> emulation, so their implementation goes into vgic-mmio.c, to be easily
> referenced from the v3 emulation as well later.
> For level triggered interrupts the real line level is unaffected by
> this write, so we keep this state separate and combine it with the
> device's level to get the actual pending state.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 25/55] KVM: arm/arm64: vgic-new: Add PENDING registers handlers
@ 2016-05-10 10:49     ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 10:49 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> The pending register handlers are shared between the v2 and v3
> emulation, so their implementation goes into vgic-mmio.c, to be easily
> referenced from the v3 emulation as well later.
> For level triggered interrupts the real line level is unaffected by
> this write, so we keep this state separate and combine it with the
> device's level to get the actual pending state.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH] KVM: arm/arm64: vgic-new: fix overlap check for device addresses
  2016-05-09 17:18     ` Marc Zyngier
@ 2016-05-10 10:58       ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-10 10:58 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

When userland sets the base addresses for the GIC register frames,
the kernel tries to make sure that the regions for the distributor and
the one for the CPU interface or the redistributors do not overlap.
Only that this check currently takes care of a GICv2 model only.
Rework the overlap check to take a GICv3 in account also.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Hi Marc,

this one goes on top of the new-vgic-v3 series.
Does this address your concerns about the overlap check?
I'd be grateful if you could apply some of your C wizardry on the first
function ;-)

Cheers,
Andre.

 virt/kvm/arm/vgic/vgic-kvm-device.c | 59 ++++++++++++++++++++++++++-----------
 1 file changed, 41 insertions(+), 18 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index 2122ff2..fcf38ef 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -21,41 +21,63 @@
 
 /* common helpers */
 
-static int vgic_ioaddr_overlap(struct kvm *kvm)
+static phys_addr_t vgic_get_existing_region(struct kvm *kvm, phys_addr_t *addr)
 {
-	phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;
-	phys_addr_t cpu = kvm->arch.vgic.vgic_cpu_base;
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	phys_addr_t cpu_addr;
+	bool is_vgicv2 = (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2);
 
-	if (IS_VGIC_ADDR_UNDEF(dist) || IS_VGIC_ADDR_UNDEF(cpu))
-		return 0;
-	if ((dist <= cpu && dist + KVM_VGIC_V2_DIST_SIZE > cpu) ||
-	    (cpu <= dist && cpu + KVM_VGIC_V2_CPU_SIZE > dist))
-		return -EBUSY;
-	return 0;
+	cpu_addr = is_vgicv2 ? dist->vgic_cpu_base : dist->vgic_redist_base;
+
+	if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base)) {
+		if (IS_VGIC_ADDR_UNDEF(cpu_addr))
+			return 0;
+
+		*addr = cpu_addr;
+		if (is_vgicv2)
+			return KVM_VGIC_V2_CPU_SIZE;
+		return atomic_read(&kvm->online_vcpus) * KVM_VGIC_V3_REDIST_SIZE;
+	}
+
+	*addr = dist->vgic_dist_base;
+	return is_vgicv2 ? KVM_VGIC_V2_DIST_SIZE : KVM_VGIC_V3_DIST_SIZE;
+}
+
+static bool vgic_ioaddr_overlap(struct kvm *kvm, phys_addr_t addr,
+				phys_addr_t size)
+{
+	phys_addr_t used_addr, used_size;
+
+	used_size = vgic_get_existing_region(kvm, &used_addr);
+	if (!used_size)
+		return false;
+
+	if (addr + size <= used_addr)
+		return false;
+
+	if (used_addr + used_size <= addr)
+		return false;
+
+	return true;
 }
 
 static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
 			      phys_addr_t addr, phys_addr_t size)
 {
-	int ret;
-
 	if (addr & ~KVM_PHYS_MASK)
 		return -E2BIG;
 
-	if (addr & (SZ_4K - 1))
-		return -EINVAL;
-
 	if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
 		return -EEXIST;
 	if (addr + size < addr)
 		return -EINVAL;
 
+	if (vgic_ioaddr_overlap(kvm, addr, size))
+		return -EBUSY;
+
 	*ioaddr = addr;
-	ret = vgic_ioaddr_overlap(kvm);
-	if (ret)
-		*ioaddr = VGIC_ADDR_UNDEF;
 
-	return ret;
+	return 0;
 }
 
 /**
@@ -104,6 +126,7 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
 		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
 		addr_ptr = &vgic->vgic_redist_base;
 		block_size = KVM_VGIC_V3_REDIST_SIZE;
+		block_size *= atomic_read(&kvm->online_vcpus);
 		alignment = SZ_64K;
 		break;
 #endif
-- 
2.7.3


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

* [PATCH] KVM: arm/arm64: vgic-new: fix overlap check for device addresses
@ 2016-05-10 10:58       ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-10 10:58 UTC (permalink / raw)
  To: linux-arm-kernel

When userland sets the base addresses for the GIC register frames,
the kernel tries to make sure that the regions for the distributor and
the one for the CPU interface or the redistributors do not overlap.
Only that this check currently takes care of a GICv2 model only.
Rework the overlap check to take a GICv3 in account also.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Hi Marc,

this one goes on top of the new-vgic-v3 series.
Does this address your concerns about the overlap check?
I'd be grateful if you could apply some of your C wizardry on the first
function ;-)

Cheers,
Andre.

 virt/kvm/arm/vgic/vgic-kvm-device.c | 59 ++++++++++++++++++++++++++-----------
 1 file changed, 41 insertions(+), 18 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index 2122ff2..fcf38ef 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -21,41 +21,63 @@
 
 /* common helpers */
 
-static int vgic_ioaddr_overlap(struct kvm *kvm)
+static phys_addr_t vgic_get_existing_region(struct kvm *kvm, phys_addr_t *addr)
 {
-	phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;
-	phys_addr_t cpu = kvm->arch.vgic.vgic_cpu_base;
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	phys_addr_t cpu_addr;
+	bool is_vgicv2 = (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2);
 
-	if (IS_VGIC_ADDR_UNDEF(dist) || IS_VGIC_ADDR_UNDEF(cpu))
-		return 0;
-	if ((dist <= cpu && dist + KVM_VGIC_V2_DIST_SIZE > cpu) ||
-	    (cpu <= dist && cpu + KVM_VGIC_V2_CPU_SIZE > dist))
-		return -EBUSY;
-	return 0;
+	cpu_addr = is_vgicv2 ? dist->vgic_cpu_base : dist->vgic_redist_base;
+
+	if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base)) {
+		if (IS_VGIC_ADDR_UNDEF(cpu_addr))
+			return 0;
+
+		*addr = cpu_addr;
+		if (is_vgicv2)
+			return KVM_VGIC_V2_CPU_SIZE;
+		return atomic_read(&kvm->online_vcpus) * KVM_VGIC_V3_REDIST_SIZE;
+	}
+
+	*addr = dist->vgic_dist_base;
+	return is_vgicv2 ? KVM_VGIC_V2_DIST_SIZE : KVM_VGIC_V3_DIST_SIZE;
+}
+
+static bool vgic_ioaddr_overlap(struct kvm *kvm, phys_addr_t addr,
+				phys_addr_t size)
+{
+	phys_addr_t used_addr, used_size;
+
+	used_size = vgic_get_existing_region(kvm, &used_addr);
+	if (!used_size)
+		return false;
+
+	if (addr + size <= used_addr)
+		return false;
+
+	if (used_addr + used_size <= addr)
+		return false;
+
+	return true;
 }
 
 static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
 			      phys_addr_t addr, phys_addr_t size)
 {
-	int ret;
-
 	if (addr & ~KVM_PHYS_MASK)
 		return -E2BIG;
 
-	if (addr & (SZ_4K - 1))
-		return -EINVAL;
-
 	if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
 		return -EEXIST;
 	if (addr + size < addr)
 		return -EINVAL;
 
+	if (vgic_ioaddr_overlap(kvm, addr, size))
+		return -EBUSY;
+
 	*ioaddr = addr;
-	ret = vgic_ioaddr_overlap(kvm);
-	if (ret)
-		*ioaddr = VGIC_ADDR_UNDEF;
 
-	return ret;
+	return 0;
 }
 
 /**
@@ -104,6 +126,7 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
 		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
 		addr_ptr = &vgic->vgic_redist_base;
 		block_size = KVM_VGIC_V3_REDIST_SIZE;
+		block_size *= atomic_read(&kvm->online_vcpus);
 		alignment = SZ_64K;
 		break;
 #endif
-- 
2.7.3

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

* Re: [PATCH v3 15/55] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10 12:08     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-10 12:08 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 06, 2016 at 11:45:28AM +0100, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Provide a vgic_queue_irq() function which decides whether a given
> IRQ needs to be queued to a VCPU's ap_list.
> This should be called whenever an IRQ becomes pending or enabled,
> either as a result of userspace injection, from in-kernel emulated
> devices like the architected timer or from MMIO accesses to the
> distributor emulation.
> Also provides the necessary functions to allow userland to inject an
> IRQ to a guest.
> Since this is the first code that starts using our locking mechanism, we
> add some (hopefully) clear documentation of our locking strategy and
> requirements along with this patch.
> 
> [Andre: refactor out vgic_queue_irq_unlock()]
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - add spinlock checks protected by CONFIG_DEBUG_SPINLOCK
> - add more comments to vgic_target_oracle
> - remove BUG_ON() if IRQ is neither edge or level
> - rename vgic_queue_irq() to vgic_queue_irq_unlock()
> - simplify initial check in vgic_queue_irq_unlock()
> - extend retry loop to ask the oracle again
> - minor comment fixes
> 
> Changelog v1 .. v2:
> - move most IRQ injection code into vgic_update_irq_pending()
> 
>  include/kvm/vgic/vgic.h  |   3 +
>  virt/kvm/arm/vgic/vgic.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h |   1 +
>  3 files changed, 213 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 39933ee..2bfb42c 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -181,6 +181,9 @@ struct vgic_cpu {
>  	u64 live_lrs;
>  };
>  
> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			bool level);
> +
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>  #define vgic_initialized(k)	(false)
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index fb45537..92b78a0 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -19,8 +19,31 @@
>  
>  #include "vgic.h"
>  
> +#define CREATE_TRACE_POINTS
> +#include "../trace.h"
> +
> +#ifdef CONFIG_DEBUG_SPINLOCK
> +#define DEBUG_SPINLOCK_BUG_ON(p) BUG_ON(p)
> +#else
> +#define DEBUG_SPINLOCK_BUG_ON(p)
> +#endif
> +
>  struct vgic_global __section(.hyp.text) kvm_vgic_global_state;
>  
> +/*
> + * Locking order is always:
> + *   vgic_cpu->ap_list_lock
> + *     vgic_irq->irq_lock
> + *
> + * (that is, always take the ap_list_lock before the struct vgic_irq lock).
> + *
> + * When taking more than one ap_list_lock at the same time, always take the
> + * lowest numbered VCPU's ap_list_lock first, so:
> + *   vcpuX->vcpu_id < vcpuY->vcpu_id:
> + *     spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
> + *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
> + */
> +
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid)
>  {
> @@ -39,3 +62,189 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  	WARN(1, "Looking up struct vgic_irq for reserved INTID");
>  	return NULL;
>  }
> +
> +/**
> + * kvm_vgic_target_oracle - compute the target vcpu for an irq
> + *
> + * @irq:	The irq to route. Must be already locked.
> + *
> + * Based on the current state of the interrupt (enabled, pending,
> + * active, vcpu and target_vcpu), compute the next vcpu this should be
> + * given to. Return NULL if this shouldn't be injected at all.
> + *
> + * Requires the IRQ lock to be held.
> + */
> +static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
> +{
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
> +
> +	/* If the interrupt is active, it must stay on the current vcpu */
> +	if (irq->active)
> +		return irq->vcpu;
> +
> +	/*
> +	 * If the IRQ is not active but enabled and pending, we should direct
> +	 * it to its configured target VCPU.
> +	 */
> +	if (irq->enabled && irq->pending)
> +		return irq->target_vcpu;
> +
> +	/* If neither active nor pending and enabled, then this IRQ should not
> +	 * be queued to any VCPU.
> +	 */
> +	return NULL;
> +}
> +
> +/*
> + * Only valid injection if changing level for level-triggered IRQs or for a
> + * rising edge.
> + */
> +static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
> +{
> +	switch (irq->config) {
> +	case VGIC_CONFIG_LEVEL:
> +		return irq->line_level != level;
> +	case VGIC_CONFIG_EDGE:
> +		return level;
> +	}
> +
> +	return false;
> +}
> +
> +/*
> + * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
> + * Do the queuing if necessary, taking the right locks in the right order.
> + * Returns true when the IRQ was queued, false otherwise.
> + *
> + * Needs to be entered with the IRQ lock already held, but will return
> + * with all locks dropped.
> + */
> +bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq)
> +{
> +	struct kvm_vcpu *vcpu;
> +
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
> +
> +retry:
> +	vcpu = vgic_target_oracle(irq);
> +	if (irq->vcpu || !vcpu) {
> +		/*
> +		 * If this IRQ is already on a VCPU's ap_list, then it
> +		 * cannot be moved or modified and there is no more work for
> +		 * us to do.
> +		 *
> +		 * Otherwise, if the irq is not pending and enabled, it does
> +		 * not need to be inserted into an ap_list and there is also
> +		 * no more work for us to do.
> +		 */
> +		spin_unlock(&irq->irq_lock);
> +		return false;
> +	}
> +
> +	/*
> +	 * We must unlock the irq lock to take the ap_list_lock where
> +	 * we are going to insert this new pending interrupt.
> +	 */
> +	spin_unlock(&irq->irq_lock);
> +
> +	/* someone can do stuff here, which we re-check below */
> +
> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +	spin_lock(&irq->irq_lock);
> +
> +	/*
> +	 * Did something change behind our backs?
> +	 *
> +	 * There are two cases:
> +	 * 1) The irq became pending or active behind our backs and/or

but you're not checking the active state below?

so did you mean 'became pending and enabled' ?

> +	 *    the irq->vcpu field was set correspondingly when putting
> +	 *    the irq on an ap_list. Then drop the locks and return.
> +	 * 2) Someone changed the affinity on this irq behind our
> +	 *    backs and we are now holding the wrong ap_list_lock.
> +	 *    Then drop the locks and try the new VCPU.
> +	 */

I thought we agreed a long time ago to change this to:

        if (unlinkely(irq->vcpu || vcpu != vgic_target_oracle(irq))) {
		spin_unlock(&irq->irq_lock);
		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
	
		spin_lock(&irq->irq_lock);
		goto retry;
	}

and get rid of two different if statements below ??

At least I don't understand why we are explicitly evaluating
!(irq->pending && irq->enabled) here, but using the oracle above?

In fact, I think if you did what I suggest above, then you can reuse
this for the active state, which frankly looks more complicated than we
had hoped for...

> +	if (irq->vcpu || !(irq->pending && irq->enabled)) {
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +		return false;
> +	}
> +
> +	if (irq->target_vcpu != vcpu) {
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +		spin_lock(&irq->irq_lock);
> +		goto retry;
> +	}
> +
> +	list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
> +	irq->vcpu = vcpu;
> +
> +	spin_unlock(&irq->irq_lock);
> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +	kvm_vcpu_kick(vcpu);
> +
> +	return true;
> +}
> +
> +static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
> +				   unsigned int intid, bool level,
> +				   bool mapped_irq)
> +{
> +	struct kvm_vcpu *vcpu;
> +	struct vgic_irq *irq;
> +	int ret;
> +
> +	trace_vgic_update_irq_pending(cpuid, intid, level);
> +
> +	vcpu = kvm_get_vcpu(kvm, cpuid);
> +	if (!vcpu && intid < VGIC_NR_PRIVATE_IRQS)
> +		return -EINVAL;
> +
> +	irq = vgic_get_irq(kvm, vcpu, intid);
> +	if (!irq)
> +		return -EINVAL;
> +
> +	if (irq->hw != mapped_irq)
> +		return -EINVAL;
> +
> +	spin_lock(&irq->irq_lock);
> +
> +	if (!vgic_validate_injection(irq, level)) {
> +		/* Nothing to see here, move along... */
> +		spin_unlock(&irq->irq_lock);
> +		return 0;
> +	}
> +
> +	if (irq->config == VGIC_CONFIG_LEVEL) {
> +		irq->line_level = level;
> +		irq->pending = level || irq->soft_pending;
> +	} else {
> +		irq->pending = true;
> +	}
> +
> +	vgic_queue_irq_unlock(kvm, irq);
> +
> +	return 0;
> +}
> +
> +/**
> + * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
> + * @kvm:     The VM structure pointer
> + * @cpuid:   The CPU for PPIs
> + * @intid:   The INTID to inject a new state to.
> + * @level:   Edge-triggered:  true:  to trigger the interrupt
> + *			      false: to ignore the call
> + *	     Level-sensitive  true:  raise the input signal
> + *			      false: lower the input signal
> + *
> + * The VGIC is not concerned with devices being active-LOW or active-HIGH for
> + * level-sensitive interrupts.  You can think of the level parameter as 1
> + * being HIGH and 0 being LOW and all devices being active-HIGH.
> + */
> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			bool level)
> +{
> +	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 61b8d22..c625767 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -18,5 +18,6 @@
>  
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
> +bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
>  
>  #endif
> -- 
> 2.7.3
> 

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

* [PATCH v3 15/55] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection
@ 2016-05-10 12:08     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-10 12:08 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:28AM +0100, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Provide a vgic_queue_irq() function which decides whether a given
> IRQ needs to be queued to a VCPU's ap_list.
> This should be called whenever an IRQ becomes pending or enabled,
> either as a result of userspace injection, from in-kernel emulated
> devices like the architected timer or from MMIO accesses to the
> distributor emulation.
> Also provides the necessary functions to allow userland to inject an
> IRQ to a guest.
> Since this is the first code that starts using our locking mechanism, we
> add some (hopefully) clear documentation of our locking strategy and
> requirements along with this patch.
> 
> [Andre: refactor out vgic_queue_irq_unlock()]
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - add spinlock checks protected by CONFIG_DEBUG_SPINLOCK
> - add more comments to vgic_target_oracle
> - remove BUG_ON() if IRQ is neither edge or level
> - rename vgic_queue_irq() to vgic_queue_irq_unlock()
> - simplify initial check in vgic_queue_irq_unlock()
> - extend retry loop to ask the oracle again
> - minor comment fixes
> 
> Changelog v1 .. v2:
> - move most IRQ injection code into vgic_update_irq_pending()
> 
>  include/kvm/vgic/vgic.h  |   3 +
>  virt/kvm/arm/vgic/vgic.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h |   1 +
>  3 files changed, 213 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 39933ee..2bfb42c 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -181,6 +181,9 @@ struct vgic_cpu {
>  	u64 live_lrs;
>  };
>  
> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			bool level);
> +
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>  #define vgic_initialized(k)	(false)
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index fb45537..92b78a0 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -19,8 +19,31 @@
>  
>  #include "vgic.h"
>  
> +#define CREATE_TRACE_POINTS
> +#include "../trace.h"
> +
> +#ifdef CONFIG_DEBUG_SPINLOCK
> +#define DEBUG_SPINLOCK_BUG_ON(p) BUG_ON(p)
> +#else
> +#define DEBUG_SPINLOCK_BUG_ON(p)
> +#endif
> +
>  struct vgic_global __section(.hyp.text) kvm_vgic_global_state;
>  
> +/*
> + * Locking order is always:
> + *   vgic_cpu->ap_list_lock
> + *     vgic_irq->irq_lock
> + *
> + * (that is, always take the ap_list_lock before the struct vgic_irq lock).
> + *
> + * When taking more than one ap_list_lock at the same time, always take the
> + * lowest numbered VCPU's ap_list_lock first, so:
> + *   vcpuX->vcpu_id < vcpuY->vcpu_id:
> + *     spin_lock(vcpuX->arch.vgic_cpu.ap_list_lock);
> + *     spin_lock(vcpuY->arch.vgic_cpu.ap_list_lock);
> + */
> +
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid)
>  {
> @@ -39,3 +62,189 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  	WARN(1, "Looking up struct vgic_irq for reserved INTID");
>  	return NULL;
>  }
> +
> +/**
> + * kvm_vgic_target_oracle - compute the target vcpu for an irq
> + *
> + * @irq:	The irq to route. Must be already locked.
> + *
> + * Based on the current state of the interrupt (enabled, pending,
> + * active, vcpu and target_vcpu), compute the next vcpu this should be
> + * given to. Return NULL if this shouldn't be injected at all.
> + *
> + * Requires the IRQ lock to be held.
> + */
> +static struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)
> +{
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
> +
> +	/* If the interrupt is active, it must stay on the current vcpu */
> +	if (irq->active)
> +		return irq->vcpu;
> +
> +	/*
> +	 * If the IRQ is not active but enabled and pending, we should direct
> +	 * it to its configured target VCPU.
> +	 */
> +	if (irq->enabled && irq->pending)
> +		return irq->target_vcpu;
> +
> +	/* If neither active nor pending and enabled, then this IRQ should not
> +	 * be queued to any VCPU.
> +	 */
> +	return NULL;
> +}
> +
> +/*
> + * Only valid injection if changing level for level-triggered IRQs or for a
> + * rising edge.
> + */
> +static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
> +{
> +	switch (irq->config) {
> +	case VGIC_CONFIG_LEVEL:
> +		return irq->line_level != level;
> +	case VGIC_CONFIG_EDGE:
> +		return level;
> +	}
> +
> +	return false;
> +}
> +
> +/*
> + * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
> + * Do the queuing if necessary, taking the right locks in the right order.
> + * Returns true when the IRQ was queued, false otherwise.
> + *
> + * Needs to be entered with the IRQ lock already held, but will return
> + * with all locks dropped.
> + */
> +bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq)
> +{
> +	struct kvm_vcpu *vcpu;
> +
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
> +
> +retry:
> +	vcpu = vgic_target_oracle(irq);
> +	if (irq->vcpu || !vcpu) {
> +		/*
> +		 * If this IRQ is already on a VCPU's ap_list, then it
> +		 * cannot be moved or modified and there is no more work for
> +		 * us to do.
> +		 *
> +		 * Otherwise, if the irq is not pending and enabled, it does
> +		 * not need to be inserted into an ap_list and there is also
> +		 * no more work for us to do.
> +		 */
> +		spin_unlock(&irq->irq_lock);
> +		return false;
> +	}
> +
> +	/*
> +	 * We must unlock the irq lock to take the ap_list_lock where
> +	 * we are going to insert this new pending interrupt.
> +	 */
> +	spin_unlock(&irq->irq_lock);
> +
> +	/* someone can do stuff here, which we re-check below */
> +
> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +	spin_lock(&irq->irq_lock);
> +
> +	/*
> +	 * Did something change behind our backs?
> +	 *
> +	 * There are two cases:
> +	 * 1) The irq became pending or active behind our backs and/or

but you're not checking the active state below?

so did you mean 'became pending and enabled' ?

> +	 *    the irq->vcpu field was set correspondingly when putting
> +	 *    the irq on an ap_list. Then drop the locks and return.
> +	 * 2) Someone changed the affinity on this irq behind our
> +	 *    backs and we are now holding the wrong ap_list_lock.
> +	 *    Then drop the locks and try the new VCPU.
> +	 */

I thought we agreed a long time ago to change this to:

        if (unlinkely(irq->vcpu || vcpu != vgic_target_oracle(irq))) {
		spin_unlock(&irq->irq_lock);
		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
	
		spin_lock(&irq->irq_lock);
		goto retry;
	}

and get rid of two different if statements below ??

At least I don't understand why we are explicitly evaluating
!(irq->pending && irq->enabled) here, but using the oracle above?

In fact, I think if you did what I suggest above, then you can reuse
this for the active state, which frankly looks more complicated than we
had hoped for...

> +	if (irq->vcpu || !(irq->pending && irq->enabled)) {
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +		return false;
> +	}
> +
> +	if (irq->target_vcpu != vcpu) {
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +		spin_lock(&irq->irq_lock);
> +		goto retry;
> +	}
> +
> +	list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
> +	irq->vcpu = vcpu;
> +
> +	spin_unlock(&irq->irq_lock);
> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +	kvm_vcpu_kick(vcpu);
> +
> +	return true;
> +}
> +
> +static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
> +				   unsigned int intid, bool level,
> +				   bool mapped_irq)
> +{
> +	struct kvm_vcpu *vcpu;
> +	struct vgic_irq *irq;
> +	int ret;
> +
> +	trace_vgic_update_irq_pending(cpuid, intid, level);
> +
> +	vcpu = kvm_get_vcpu(kvm, cpuid);
> +	if (!vcpu && intid < VGIC_NR_PRIVATE_IRQS)
> +		return -EINVAL;
> +
> +	irq = vgic_get_irq(kvm, vcpu, intid);
> +	if (!irq)
> +		return -EINVAL;
> +
> +	if (irq->hw != mapped_irq)
> +		return -EINVAL;
> +
> +	spin_lock(&irq->irq_lock);
> +
> +	if (!vgic_validate_injection(irq, level)) {
> +		/* Nothing to see here, move along... */
> +		spin_unlock(&irq->irq_lock);
> +		return 0;
> +	}
> +
> +	if (irq->config == VGIC_CONFIG_LEVEL) {
> +		irq->line_level = level;
> +		irq->pending = level || irq->soft_pending;
> +	} else {
> +		irq->pending = true;
> +	}
> +
> +	vgic_queue_irq_unlock(kvm, irq);
> +
> +	return 0;
> +}
> +
> +/**
> + * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
> + * @kvm:     The VM structure pointer
> + * @cpuid:   The CPU for PPIs
> + * @intid:   The INTID to inject a new state to.
> + * @level:   Edge-triggered:  true:  to trigger the interrupt
> + *			      false: to ignore the call
> + *	     Level-sensitive  true:  raise the input signal
> + *			      false: lower the input signal
> + *
> + * The VGIC is not concerned with devices being active-LOW or active-HIGH for
> + * level-sensitive interrupts.  You can think of the level parameter as 1
> + * being HIGH and 0 being LOW and all devices being active-HIGH.
> + */
> +int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			bool level)
> +{
> +	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 61b8d22..c625767 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -18,5 +18,6 @@
>  
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
> +bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
>  
>  #endif
> -- 
> 2.7.3
> 

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

* Re: [PATCH v3 26/55] KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10 12:09     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-10 12:09 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 06, 2016 at 11:45:39AM +0100, Andre Przywara wrote:
> The active register handlers are shared between the v2 and v3
> emulation, so their implementation goes into vgic-mmio.c, to be
> easily referenced from the v3 emulation as well later.
> Since activation/deactivation of an interrupt may happen entirely
> in the guest without it ever exiting, we need some extra logic to
> properly track the active state.
> Putting it on an ap_list on activation is similar to the normal case
> handled by vgic_queue_irq_unlock(), but differs in some details that
> make a separate implementation worthwhile.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - handling queueing in write handler
> - remove IRQ lock from read handler
> 
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c |   4 +-
>  virt/kvm/arm/vgic/vgic-mmio.c    | 120 +++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h    |  10 ++++
>  3 files changed, 132 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 4b87e0a..054b52d 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -80,9 +80,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>  		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index 4df1af7..dbf683e 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -162,6 +162,126 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
>  	}
>  }
>  
> +unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	u32 value = 0;
> +	int i;
> +
> +	/* Loop over all IRQs affected by this read */
> +	for (i = 0; i < len * 8; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (irq->active)
> +			value |= (1U << i);
> +	}
> +
> +	return extract_bytes(value, addr & 3, len);
> +}
> +
> +void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	int i;
> +
> +	for_each_set_bit(i, &val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		irq->active = false;
> +
> +		/*
> +		 * Christoffer wrote:
> +		 * The question is what to do if the vcpu for this irq is
> +		 * running and the LR there has the active bit set, then we'll
> +		 * overwrite this change when we fold the LR state back into
> +		 * the vgic_irq struct.
> +		 *
> +		 * Since I expect this to be extremely rare, one option is to
> +		 * force irq->vcpu to exit (if non-null) and then do you
> +		 * thing here after you've confirm it has exited while holding
> +		 * some lock preventing it from re-entering again.
> +		 * Slightly crazy.
> +		 *
> +		 * The alternative is to put a big fat comment nothing that
> +		 * this is non-supported bad race, and wait until someone
> +		 * submits a bug report relating to this...
> +		 */

I thought I wrote a patch for this?

> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	int i;
> +
> +	for_each_set_bit(i, &val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		/* As this is a special case, we can't use the
> +		 * vgic_queue_irq_unlock() function to put this on a VCPU.
> +		 * So deal with this here explicitly unless the IRQs was
> +		 * already active, it was on a VCPU before or there is no
> +		 * target VCPU assigned at the moment.
> +		 */
> +		if (irq->active || irq->vcpu || !irq->target_vcpu) {
> +			irq->active = true;
> +
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +retry:
> +		vcpu = irq->target_vcpu;
> +
> +		spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&irq->irq_lock);
> +
> +		/*
> +		 * Recheck after dropping the IRQ lock to see if we should
> +		 * still care about queueing it.
> +		 */
> +		if (irq->active || irq->vcpu) {
> +			irq->active = true;
> +
> +			spin_unlock(&irq->irq_lock);
> +			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +			continue;
> +		}
> +
> +		/* Did the target VCPU change while we had the lock dropped? */
> +		if (vcpu != irq->target_vcpu) {
> +			spin_unlock(&irq->irq_lock);
> +			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +			goto retry;
> +		}
> +
> +		/* Now queue the IRQ to the VCPU's ap_list. */
> +		list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
> +		irq->vcpu = vcpu;
> +
> +		irq->active = true;
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +		kvm_vcpu_kick(vcpu);

quite frankly, this looks very complicated and I really think it's worth
reusing the queue function after seeing this (sorry I haven't been able
to before).

-Christoffer

> +	}
> +}
> +
>  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 d4fc029..fa875dc 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -96,6 +96,16 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
>  			      gpa_t addr, unsigned int len,
>  			      unsigned long val);
>  
> +unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len);
> +
> +void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val);
> +
> +void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val);
>  
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
> -- 
> 2.7.3
> 

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

* [PATCH v3 26/55] KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
@ 2016-05-10 12:09     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-10 12:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:39AM +0100, Andre Przywara wrote:
> The active register handlers are shared between the v2 and v3
> emulation, so their implementation goes into vgic-mmio.c, to be
> easily referenced from the v3 emulation as well later.
> Since activation/deactivation of an interrupt may happen entirely
> in the guest without it ever exiting, we need some extra logic to
> properly track the active state.
> Putting it on an ap_list on activation is similar to the normal case
> handled by vgic_queue_irq_unlock(), but differs in some details that
> make a separate implementation worthwhile.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - handling queueing in write handler
> - remove IRQ lock from read handler
> 
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c |   4 +-
>  virt/kvm/arm/vgic/vgic-mmio.c    | 120 +++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h    |  10 ++++
>  3 files changed, 132 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 4b87e0a..054b52d 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -80,9 +80,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>  		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index 4df1af7..dbf683e 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -162,6 +162,126 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
>  	}
>  }
>  
> +unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	u32 value = 0;
> +	int i;
> +
> +	/* Loop over all IRQs affected by this read */
> +	for (i = 0; i < len * 8; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (irq->active)
> +			value |= (1U << i);
> +	}
> +
> +	return extract_bytes(value, addr & 3, len);
> +}
> +
> +void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	int i;
> +
> +	for_each_set_bit(i, &val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		irq->active = false;
> +
> +		/*
> +		 * Christoffer wrote:
> +		 * The question is what to do if the vcpu for this irq is
> +		 * running and the LR there has the active bit set, then we'll
> +		 * overwrite this change when we fold the LR state back into
> +		 * the vgic_irq struct.
> +		 *
> +		 * Since I expect this to be extremely rare, one option is to
> +		 * force irq->vcpu to exit (if non-null) and then do you
> +		 * thing here after you've confirm it has exited while holding
> +		 * some lock preventing it from re-entering again.
> +		 * Slightly crazy.
> +		 *
> +		 * The alternative is to put a big fat comment nothing that
> +		 * this is non-supported bad race, and wait until someone
> +		 * submits a bug report relating to this...
> +		 */

I thought I wrote a patch for this?

> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	int i;
> +
> +	for_each_set_bit(i, &val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		/* As this is a special case, we can't use the
> +		 * vgic_queue_irq_unlock() function to put this on a VCPU.
> +		 * So deal with this here explicitly unless the IRQs was
> +		 * already active, it was on a VCPU before or there is no
> +		 * target VCPU assigned at the moment.
> +		 */
> +		if (irq->active || irq->vcpu || !irq->target_vcpu) {
> +			irq->active = true;
> +
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +retry:
> +		vcpu = irq->target_vcpu;
> +
> +		spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&irq->irq_lock);
> +
> +		/*
> +		 * Recheck after dropping the IRQ lock to see if we should
> +		 * still care about queueing it.
> +		 */
> +		if (irq->active || irq->vcpu) {
> +			irq->active = true;
> +
> +			spin_unlock(&irq->irq_lock);
> +			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +			continue;
> +		}
> +
> +		/* Did the target VCPU change while we had the lock dropped? */
> +		if (vcpu != irq->target_vcpu) {
> +			spin_unlock(&irq->irq_lock);
> +			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +			goto retry;
> +		}
> +
> +		/* Now queue the IRQ to the VCPU's ap_list. */
> +		list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
> +		irq->vcpu = vcpu;
> +
> +		irq->active = true;
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +		kvm_vcpu_kick(vcpu);

quite frankly, this looks very complicated and I really think it's worth
reusing the queue function after seeing this (sorry I haven't been able
to before).

-Christoffer

> +	}
> +}
> +
>  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 d4fc029..fa875dc 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -96,6 +96,16 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
>  			      gpa_t addr, unsigned int len,
>  			      unsigned long val);
>  
> +unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len);
> +
> +void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val);
> +
> +void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val);
>  
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
> -- 
> 2.7.3
> 

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

* Re: [PATCH v3 26/55] KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10 12:14     ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 12:14 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall
  Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> The active register handlers are shared between the v2 and v3
> emulation, so their implementation goes into vgic-mmio.c, to be
> easily referenced from the v3 emulation as well later.
> Since activation/deactivation of an interrupt may happen entirely
> in the guest without it ever exiting, we need some extra logic to
> properly track the active state.
> Putting it on an ap_list on activation is similar to the normal case
> handled by vgic_queue_irq_unlock(), but differs in some details that
> make a separate implementation worthwhile.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - handling queueing in write handler
> - remove IRQ lock from read handler
> 
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c |   4 +-
>  virt/kvm/arm/vgic/vgic-mmio.c    | 120 +++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h    |  10 ++++
>  3 files changed, 132 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 4b87e0a..054b52d 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -80,9 +80,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>  		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index 4df1af7..dbf683e 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -162,6 +162,126 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
>  	}
>  }
>  
> +unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	u32 value = 0;
> +	int i;
> +
> +	/* Loop over all IRQs affected by this read */
> +	for (i = 0; i < len * 8; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (irq->active)
> +			value |= (1U << i);
> +	}
> +
> +	return extract_bytes(value, addr & 3, len);
> +}
> +
> +void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	int i;
> +
> +	for_each_set_bit(i, &val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		irq->active = false;
> +
> +		/*
> +		 * Christoffer wrote:
> +		 * The question is what to do if the vcpu for this irq is
> +		 * running and the LR there has the active bit set, then we'll
> +		 * overwrite this change when we fold the LR state back into
> +		 * the vgic_irq struct.
> +		 *
> +		 * Since I expect this to be extremely rare, one option is to
> +		 * force irq->vcpu to exit (if non-null) and then do you
> +		 * thing here after you've confirm it has exited while holding
> +		 * some lock preventing it from re-entering again.
> +		 * Slightly crazy.
> +		 *
> +		 * The alternative is to put a big fat comment nothing that
> +		 * this is non-supported bad race, and wait until someone
> +		 * submits a bug report relating to this...
> +		 */

Don't we have a patch by Christoffer that addresses this exact issue?

> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	int i;
> +
> +	for_each_set_bit(i, &val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		/* As this is a special case, we can't use the
> +		 * vgic_queue_irq_unlock() function to put this on a VCPU.
> +		 * So deal with this here explicitly unless the IRQs was
> +		 * already active, it was on a VCPU before or there is no
> +		 * target VCPU assigned at the moment.
> +		 */
> +		if (irq->active || irq->vcpu || !irq->target_vcpu) {
> +			irq->active = true;
> +
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +retry:
> +		vcpu = irq->target_vcpu;
> +
> +		spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&irq->irq_lock);
> +
> +		/*
> +		 * Recheck after dropping the IRQ lock to see if we should
> +		 * still care about queueing it.
> +		 */
> +		if (irq->active || irq->vcpu) {
> +			irq->active = true;
> +
> +			spin_unlock(&irq->irq_lock);
> +			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +			continue;
> +		}
> +
> +		/* Did the target VCPU change while we had the lock dropped? */
> +		if (vcpu != irq->target_vcpu) {
> +			spin_unlock(&irq->irq_lock);
> +			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +			goto retry;
> +		}
> +
> +		/* Now queue the IRQ to the VCPU's ap_list. */
> +		list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
> +		irq->vcpu = vcpu;
> +
> +		irq->active = true;
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +		kvm_vcpu_kick(vcpu);
> +	}

This is annoyingly close to vgic_queue_irq_unlock()... Maybe switching
this to some form of preprocessor template. Or not.

> +}
> +
>  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 d4fc029..fa875dc 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -96,6 +96,16 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
>  			      gpa_t addr, unsigned int len,
>  			      unsigned long val);
>  
> +unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len);
> +
> +void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val);
> +
> +void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val);
>  
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
> 

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 26/55] KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
@ 2016-05-10 12:14     ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 12:14 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> The active register handlers are shared between the v2 and v3
> emulation, so their implementation goes into vgic-mmio.c, to be
> easily referenced from the v3 emulation as well later.
> Since activation/deactivation of an interrupt may happen entirely
> in the guest without it ever exiting, we need some extra logic to
> properly track the active state.
> Putting it on an ap_list on activation is similar to the normal case
> handled by vgic_queue_irq_unlock(), but differs in some details that
> make a separate implementation worthwhile.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - handling queueing in write handler
> - remove IRQ lock from read handler
> 
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c |   4 +-
>  virt/kvm/arm/vgic/vgic-mmio.c    | 120 +++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h    |  10 ++++
>  3 files changed, 132 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 4b87e0a..054b52d 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -80,9 +80,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>  		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index 4df1af7..dbf683e 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -162,6 +162,126 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
>  	}
>  }
>  
> +unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	u32 value = 0;
> +	int i;
> +
> +	/* Loop over all IRQs affected by this read */
> +	for (i = 0; i < len * 8; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (irq->active)
> +			value |= (1U << i);
> +	}
> +
> +	return extract_bytes(value, addr & 3, len);
> +}
> +
> +void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	int i;
> +
> +	for_each_set_bit(i, &val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		irq->active = false;
> +
> +		/*
> +		 * Christoffer wrote:
> +		 * The question is what to do if the vcpu for this irq is
> +		 * running and the LR there has the active bit set, then we'll
> +		 * overwrite this change when we fold the LR state back into
> +		 * the vgic_irq struct.
> +		 *
> +		 * Since I expect this to be extremely rare, one option is to
> +		 * force irq->vcpu to exit (if non-null) and then do you
> +		 * thing here after you've confirm it has exited while holding
> +		 * some lock preventing it from re-entering again.
> +		 * Slightly crazy.
> +		 *
> +		 * The alternative is to put a big fat comment nothing that
> +		 * this is non-supported bad race, and wait until someone
> +		 * submits a bug report relating to this...
> +		 */

Don't we have a patch by Christoffer that addresses this exact issue?

> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	int i;
> +
> +	for_each_set_bit(i, &val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		/* As this is a special case, we can't use the
> +		 * vgic_queue_irq_unlock() function to put this on a VCPU.
> +		 * So deal with this here explicitly unless the IRQs was
> +		 * already active, it was on a VCPU before or there is no
> +		 * target VCPU assigned at the moment.
> +		 */
> +		if (irq->active || irq->vcpu || !irq->target_vcpu) {
> +			irq->active = true;
> +
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +retry:
> +		vcpu = irq->target_vcpu;
> +
> +		spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&irq->irq_lock);
> +
> +		/*
> +		 * Recheck after dropping the IRQ lock to see if we should
> +		 * still care about queueing it.
> +		 */
> +		if (irq->active || irq->vcpu) {
> +			irq->active = true;
> +
> +			spin_unlock(&irq->irq_lock);
> +			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +			continue;
> +		}
> +
> +		/* Did the target VCPU change while we had the lock dropped? */
> +		if (vcpu != irq->target_vcpu) {
> +			spin_unlock(&irq->irq_lock);
> +			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +			goto retry;
> +		}
> +
> +		/* Now queue the IRQ to the VCPU's ap_list. */
> +		list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
> +		irq->vcpu = vcpu;
> +
> +		irq->active = true;
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +
> +		kvm_vcpu_kick(vcpu);
> +	}

This is annoyingly close to vgic_queue_irq_unlock()... Maybe switching
this to some form of preprocessor template. Or not.

> +}
> +
>  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 d4fc029..fa875dc 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -96,6 +96,16 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
>  			      gpa_t addr, unsigned int len,
>  			      unsigned long val);
>  
> +unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len);
> +
> +void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val);
> +
> +void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val);
>  
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
> 

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 26/55] KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
  2016-05-10 12:14     ` Marc Zyngier
@ 2016-05-10 13:04       ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-10 13:04 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Hi Marc,

On 10/05/16 13:14, Marc Zyngier wrote:
> On 06/05/16 11:45, Andre Przywara wrote:
>> The active register handlers are shared between the v2 and v3
>> emulation, so their implementation goes into vgic-mmio.c, to be
>> easily referenced from the v3 emulation as well later.
>> Since activation/deactivation of an interrupt may happen entirely
>> in the guest without it ever exiting, we need some extra logic to
>> properly track the active state.
>> Putting it on an ap_list on activation is similar to the normal case
>> handled by vgic_queue_irq_unlock(), but differs in some details that
>> make a separate implementation worthwhile.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - handling queueing in write handler
>> - remove IRQ lock from read handler
>>
>> Changelog v1 .. v2:
>> - adapt to new MMIO framework
>>
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |   4 +-
>>  virt/kvm/arm/vgic/vgic-mmio.c    | 120 +++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-mmio.h    |  10 ++++
>>  3 files changed, 132 insertions(+), 2 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index 4b87e0a..054b52d 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -80,9 +80,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>>  		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>> index 4df1af7..dbf683e 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>> @@ -162,6 +162,126 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
>>  	}
>>  }
>>  
>> +unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
>> +				    gpa_t addr, unsigned int len)
>> +{
>> +	u32 intid = (addr & 0x7f) * 8;
>> +	u32 value = 0;
>> +	int i;
>> +
>> +	/* Loop over all IRQs affected by this read */
>> +	for (i = 0; i < len * 8; i++) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		if (irq->active)
>> +			value |= (1U << i);
>> +	}
>> +
>> +	return extract_bytes(value, addr & 3, len);
>> +}
>> +
>> +void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
>> +			     gpa_t addr, unsigned int len,
>> +			     unsigned long val)
>> +{
>> +	u32 intid = (addr & 0x7f) * 8;
>> +	int i;
>> +
>> +	for_each_set_bit(i, &val, len * 8) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		irq->active = false;
>> +
>> +		/*
>> +		 * Christoffer wrote:
>> +		 * The question is what to do if the vcpu for this irq is
>> +		 * running and the LR there has the active bit set, then we'll
>> +		 * overwrite this change when we fold the LR state back into
>> +		 * the vgic_irq struct.
>> +		 *
>> +		 * Since I expect this to be extremely rare, one option is to
>> +		 * force irq->vcpu to exit (if non-null) and then do you
>> +		 * thing here after you've confirm it has exited while holding
>> +		 * some lock preventing it from re-entering again.
>> +		 * Slightly crazy.
>> +		 *
>> +		 * The alternative is to put a big fat comment nothing that
>> +		 * this is non-supported bad race, and wait until someone
>> +		 * submits a bug report relating to this...
>> +		 */
> 
> Don't we have a patch by Christoffer that addresses this exact issue?

Yes, and if I am not mistaken you said last week that we put this patch
and the firmware-independent probing on top of the queue, so I didn't
merge it.

>> +
>> +		spin_unlock(&irq->irq_lock);
>> +	}
>> +}
>> +
>> +void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
>> +			     gpa_t addr, unsigned int len,
>> +			     unsigned long val)
>> +{
>> +	u32 intid = (addr & 0x7f) * 8;
>> +	int i;
>> +
>> +	for_each_set_bit(i, &val, len * 8) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		/* As this is a special case, we can't use the
>> +		 * vgic_queue_irq_unlock() function to put this on a VCPU.
>> +		 * So deal with this here explicitly unless the IRQs was
>> +		 * already active, it was on a VCPU before or there is no
>> +		 * target VCPU assigned at the moment.
>> +		 */
>> +		if (irq->active || irq->vcpu || !irq->target_vcpu) {
>> +			irq->active = true;
>> +
>> +			spin_unlock(&irq->irq_lock);
>> +			continue;
>> +		}
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +retry:
>> +		vcpu = irq->target_vcpu;
>> +
>> +		spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		/*
>> +		 * Recheck after dropping the IRQ lock to see if we should
>> +		 * still care about queueing it.
>> +		 */
>> +		if (irq->active || irq->vcpu) {
>> +			irq->active = true;
>> +
>> +			spin_unlock(&irq->irq_lock);
>> +			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +
>> +			continue;
>> +		}
>> +
>> +		/* Did the target VCPU change while we had the lock dropped? */
>> +		if (vcpu != irq->target_vcpu) {
>> +			spin_unlock(&irq->irq_lock);
>> +			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +
>> +			goto retry;
>> +		}
>> +
>> +		/* Now queue the IRQ to the VCPU's ap_list. */
>> +		list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
>> +		irq->vcpu = vcpu;
>> +
>> +		irq->active = true;
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +
>> +		kvm_vcpu_kick(vcpu);
>> +	}
> 
> This is annoyingly close to vgic_queue_irq_unlock()... Maybe switching
> this to some form of preprocessor template. Or not.

I think we had this discussion with Christoffer before. There are subtle
differences and the impression was that unifying the two would make them
basically unreadable because of all this special handling.
Not sure if the preprocessor would help here.

Cheers,
Andre.

> 
>> +}
>> +
>>  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 d4fc029..fa875dc 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.h
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
>> @@ -96,6 +96,16 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
>>  			      gpa_t addr, unsigned int len,
>>  			      unsigned long val);
>>  
>> +unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
>> +				    gpa_t addr, unsigned int len);
>> +
>> +void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
>> +			     gpa_t addr, unsigned int len,
>> +			     unsigned long val);
>> +
>> +void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
>> +			     gpa_t addr, unsigned int len,
>> +			     unsigned long val);
>>  
>>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>>  
>>
> 
> Thanks,
> 
> 	M.
> 

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

* [PATCH v3 26/55] KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
@ 2016-05-10 13:04       ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-10 13:04 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marc,

On 10/05/16 13:14, Marc Zyngier wrote:
> On 06/05/16 11:45, Andre Przywara wrote:
>> The active register handlers are shared between the v2 and v3
>> emulation, so their implementation goes into vgic-mmio.c, to be
>> easily referenced from the v3 emulation as well later.
>> Since activation/deactivation of an interrupt may happen entirely
>> in the guest without it ever exiting, we need some extra logic to
>> properly track the active state.
>> Putting it on an ap_list on activation is similar to the normal case
>> handled by vgic_queue_irq_unlock(), but differs in some details that
>> make a separate implementation worthwhile.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - handling queueing in write handler
>> - remove IRQ lock from read handler
>>
>> Changelog v1 .. v2:
>> - adapt to new MMIO framework
>>
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |   4 +-
>>  virt/kvm/arm/vgic/vgic-mmio.c    | 120 +++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-mmio.h    |  10 ++++
>>  3 files changed, 132 insertions(+), 2 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index 4b87e0a..054b52d 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -80,9 +80,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>>  		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>> index 4df1af7..dbf683e 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>> @@ -162,6 +162,126 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
>>  	}
>>  }
>>  
>> +unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
>> +				    gpa_t addr, unsigned int len)
>> +{
>> +	u32 intid = (addr & 0x7f) * 8;
>> +	u32 value = 0;
>> +	int i;
>> +
>> +	/* Loop over all IRQs affected by this read */
>> +	for (i = 0; i < len * 8; i++) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		if (irq->active)
>> +			value |= (1U << i);
>> +	}
>> +
>> +	return extract_bytes(value, addr & 3, len);
>> +}
>> +
>> +void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
>> +			     gpa_t addr, unsigned int len,
>> +			     unsigned long val)
>> +{
>> +	u32 intid = (addr & 0x7f) * 8;
>> +	int i;
>> +
>> +	for_each_set_bit(i, &val, len * 8) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		irq->active = false;
>> +
>> +		/*
>> +		 * Christoffer wrote:
>> +		 * The question is what to do if the vcpu for this irq is
>> +		 * running and the LR there has the active bit set, then we'll
>> +		 * overwrite this change when we fold the LR state back into
>> +		 * the vgic_irq struct.
>> +		 *
>> +		 * Since I expect this to be extremely rare, one option is to
>> +		 * force irq->vcpu to exit (if non-null) and then do you
>> +		 * thing here after you've confirm it has exited while holding
>> +		 * some lock preventing it from re-entering again.
>> +		 * Slightly crazy.
>> +		 *
>> +		 * The alternative is to put a big fat comment nothing that
>> +		 * this is non-supported bad race, and wait until someone
>> +		 * submits a bug report relating to this...
>> +		 */
> 
> Don't we have a patch by Christoffer that addresses this exact issue?

Yes, and if I am not mistaken you said last week that we put this patch
and the firmware-independent probing on top of the queue, so I didn't
merge it.

>> +
>> +		spin_unlock(&irq->irq_lock);
>> +	}
>> +}
>> +
>> +void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
>> +			     gpa_t addr, unsigned int len,
>> +			     unsigned long val)
>> +{
>> +	u32 intid = (addr & 0x7f) * 8;
>> +	int i;
>> +
>> +	for_each_set_bit(i, &val, len * 8) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		/* As this is a special case, we can't use the
>> +		 * vgic_queue_irq_unlock() function to put this on a VCPU.
>> +		 * So deal with this here explicitly unless the IRQs was
>> +		 * already active, it was on a VCPU before or there is no
>> +		 * target VCPU assigned at the moment.
>> +		 */
>> +		if (irq->active || irq->vcpu || !irq->target_vcpu) {
>> +			irq->active = true;
>> +
>> +			spin_unlock(&irq->irq_lock);
>> +			continue;
>> +		}
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +retry:
>> +		vcpu = irq->target_vcpu;
>> +
>> +		spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		/*
>> +		 * Recheck after dropping the IRQ lock to see if we should
>> +		 * still care about queueing it.
>> +		 */
>> +		if (irq->active || irq->vcpu) {
>> +			irq->active = true;
>> +
>> +			spin_unlock(&irq->irq_lock);
>> +			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +
>> +			continue;
>> +		}
>> +
>> +		/* Did the target VCPU change while we had the lock dropped? */
>> +		if (vcpu != irq->target_vcpu) {
>> +			spin_unlock(&irq->irq_lock);
>> +			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +
>> +			goto retry;
>> +		}
>> +
>> +		/* Now queue the IRQ to the VCPU's ap_list. */
>> +		list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
>> +		irq->vcpu = vcpu;
>> +
>> +		irq->active = true;
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
>> +
>> +		kvm_vcpu_kick(vcpu);
>> +	}
> 
> This is annoyingly close to vgic_queue_irq_unlock()... Maybe switching
> this to some form of preprocessor template. Or not.

I think we had this discussion with Christoffer before. There are subtle
differences and the impression was that unifying the two would make them
basically unreadable because of all this special handling.
Not sure if the preprocessor would help here.

Cheers,
Andre.

> 
>> +}
>> +
>>  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 d4fc029..fa875dc 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.h
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
>> @@ -96,6 +96,16 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
>>  			      gpa_t addr, unsigned int len,
>>  			      unsigned long val);
>>  
>> +unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
>> +				    gpa_t addr, unsigned int len);
>> +
>> +void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
>> +			     gpa_t addr, unsigned int len,
>> +			     unsigned long val);
>> +
>> +void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
>> +			     gpa_t addr, unsigned int len,
>> +			     unsigned long val);
>>  
>>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>>  
>>
> 
> Thanks,
> 
> 	M.
> 

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

* Re: [PATCH v3 17/55] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10 13:11     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-10 13:11 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:45:30AM +0100, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Implement the framework for syncing IRQs between our emulation and
> the list registers, which represent the guest's view of IRQs.
> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
> which gets called on guest entry and exit.
> The code talking to the actual GICv2/v3 hardware is added in the
> following patches.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---

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

> Changelog RFC..v1:
> - split out vgic_clear_lr() from vgic_populate_lr()
> - rename vgic_populate_lrs() to vgic_flush_lr_state()
> - clean all LRs when the distributor is disabled
> - use list_del() instead of list_del_init()
> - add comments to explain the direction of sync/flush_hwstate
> - remove unneeded BUG_ON(in_interrupt()
> 
> Changelog v2 .. v3:
> - remove bogus v2 specific rebase leftovers
> 
>  include/kvm/vgic/vgic.h  |   4 +
>  virt/kvm/arm/vgic/vgic.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h |   2 +
>  3 files changed, 199 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 2bfb42c..5fae4a9 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -190,6 +190,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>  
> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
> +
>  /**
>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>   *
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 4fb20fd..c6f8b9b 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -305,3 +305,196 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  {
>  	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
>  }
> +
> +/**
> + * vgic_prune_ap_list - Remove non-relevant interrupts from the list
> + *
> + * @vcpu: The VCPU pointer
> + *
> + * Go over the list of "interesting" interrupts, and prune those that we
> + * won't have to consider in the near future.
> + */
> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq, *tmp;
> +
> +retry:
> +	spin_lock(&vgic_cpu->ap_list_lock);
> +
> +	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
> +		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		BUG_ON(vcpu != irq->vcpu);
> +
> +		target_vcpu = vgic_target_oracle(irq);
> +
> +		if (!target_vcpu) {
> +			/*
> +			 * We don't need to process this interrupt any
> +			 * further, move it off the list.
> +			 */
> +			list_del(&irq->ap_list);
> +			irq->vcpu = NULL;
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		if (target_vcpu == vcpu) {
> +			/* We're on the right CPU */
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		/* This interrupt looks like it has to be migrated. */
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vgic_cpu->ap_list_lock);
> +
> +		/*
> +		 * Ensure locking order by always locking the smallest
> +		 * ID first.
> +		 */
> +		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
> +			vcpuA = vcpu;
> +			vcpuB = target_vcpu;
> +		} else {
> +			vcpuA = target_vcpu;
> +			vcpuB = vcpu;
> +		}
> +
> +		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&irq->irq_lock);
> +
> +		/*
> +		 * If the affinity has been preserved, move the
> +		 * interrupt around. Otherwise, it means things have
> +		 * changed while the interrupt was unlocked, and we
> +		 * need to replay this.
> +		 *
> +		 * In all cases, we cannot trust the list not to have
> +		 * changed, so we restart from the beginning.
> +		 */
> +		if (target_vcpu == vgic_target_oracle(irq)) {
> +			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
> +
> +			list_del(&irq->ap_list);
> +			irq->vcpu = target_vcpu;
> +			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		goto retry;
> +	}
> +
> +	spin_unlock(&vgic_cpu->ap_list_lock);
> +}
> +
> +static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +/* Requires the ap_list_lock and the irq_lock to be held. */
> +static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
> +				    struct vgic_irq *irq, int lr)
> +{
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
> +}
> +
> +static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
> +{
> +}
> +
> +static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +		/* GICv2 SGIs can count for more than one... */
> +		if (vgic_irq_is_sgi(irq->intid) && irq->source)
> +			count += hweight8(irq->source);
> +		else
> +			count++;
> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return count;
> +}
> +
> +/* Requires the VCPU's ap_list_lock to be held. */
> +static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
> +
> +	if (unlikely(!vcpu->kvm->arch.vgic.enabled))
> +		goto out_clean;
> +
> +	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
> +		vgic_set_underflow(vcpu);
> +		vgic_sort_ap_list(vcpu);
> +	}
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +
> +		if (unlikely(vgic_target_oracle(irq) != vcpu))
> +			goto next;
> +
> +		/*
> +		 * If we get an SGI with multiple sources, try to get
> +		 * them in all at once.
> +		 */
> +		do {
> +			vgic_populate_lr(vcpu, irq, count++);
> +		} while (irq->source && count < kvm_vgic_global_state.nr_lr);
> +
> +next:
> +		spin_unlock(&irq->irq_lock);
> +
> +		if (count == kvm_vgic_global_state.nr_lr)
> +			break;
> +	}
> +
> +out_clean:
> +	vcpu->arch.vgic_cpu.used_lrs = count;
> +
> +	/* Nuke remaining LRs */
> +	for ( ; count < kvm_vgic_global_state.nr_lr; count++)
> +		vgic_clear_lr(vcpu, count);
> +}
> +
> +/* Sync back the hardware VGIC state into our emulation after a guest's run. */
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	vgic_process_maintenance_interrupt(vcpu);
> +	vgic_fold_lr_state(vcpu);
> +	vgic_prune_ap_list(vcpu);
> +}
> +
> +/* Flush our emulation state into the GIC hardware before entering the guest. */
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +	vgic_flush_lr_state(vcpu);
> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index c625767..29b96b9 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -16,6 +16,8 @@
>  #ifndef __KVM_ARM_VGIC_NEW_H__
>  #define __KVM_ARM_VGIC_NEW_H__
>  
> +#define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
> +
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
> -- 
> 2.7.3
> 

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

* [PATCH v3 17/55] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
@ 2016-05-10 13:11     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-10 13:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:30AM +0100, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Implement the framework for syncing IRQs between our emulation and
> the list registers, which represent the guest's view of IRQs.
> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
> which gets called on guest entry and exit.
> The code talking to the actual GICv2/v3 hardware is added in the
> following patches.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---

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

> Changelog RFC..v1:
> - split out vgic_clear_lr() from vgic_populate_lr()
> - rename vgic_populate_lrs() to vgic_flush_lr_state()
> - clean all LRs when the distributor is disabled
> - use list_del() instead of list_del_init()
> - add comments to explain the direction of sync/flush_hwstate
> - remove unneeded BUG_ON(in_interrupt()
> 
> Changelog v2 .. v3:
> - remove bogus v2 specific rebase leftovers
> 
>  include/kvm/vgic/vgic.h  |   4 +
>  virt/kvm/arm/vgic/vgic.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h |   2 +
>  3 files changed, 199 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 2bfb42c..5fae4a9 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -190,6 +190,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>  
> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
> +
>  /**
>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>   *
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 4fb20fd..c6f8b9b 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -305,3 +305,196 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  {
>  	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
>  }
> +
> +/**
> + * vgic_prune_ap_list - Remove non-relevant interrupts from the list
> + *
> + * @vcpu: The VCPU pointer
> + *
> + * Go over the list of "interesting" interrupts, and prune those that we
> + * won't have to consider in the near future.
> + */
> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq, *tmp;
> +
> +retry:
> +	spin_lock(&vgic_cpu->ap_list_lock);
> +
> +	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
> +		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		BUG_ON(vcpu != irq->vcpu);
> +
> +		target_vcpu = vgic_target_oracle(irq);
> +
> +		if (!target_vcpu) {
> +			/*
> +			 * We don't need to process this interrupt any
> +			 * further, move it off the list.
> +			 */
> +			list_del(&irq->ap_list);
> +			irq->vcpu = NULL;
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		if (target_vcpu == vcpu) {
> +			/* We're on the right CPU */
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		/* This interrupt looks like it has to be migrated. */
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vgic_cpu->ap_list_lock);
> +
> +		/*
> +		 * Ensure locking order by always locking the smallest
> +		 * ID first.
> +		 */
> +		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
> +			vcpuA = vcpu;
> +			vcpuB = target_vcpu;
> +		} else {
> +			vcpuA = target_vcpu;
> +			vcpuB = vcpu;
> +		}
> +
> +		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&irq->irq_lock);
> +
> +		/*
> +		 * If the affinity has been preserved, move the
> +		 * interrupt around. Otherwise, it means things have
> +		 * changed while the interrupt was unlocked, and we
> +		 * need to replay this.
> +		 *
> +		 * In all cases, we cannot trust the list not to have
> +		 * changed, so we restart from the beginning.
> +		 */
> +		if (target_vcpu == vgic_target_oracle(irq)) {
> +			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
> +
> +			list_del(&irq->ap_list);
> +			irq->vcpu = target_vcpu;
> +			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		goto retry;
> +	}
> +
> +	spin_unlock(&vgic_cpu->ap_list_lock);
> +}
> +
> +static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +/* Requires the ap_list_lock and the irq_lock to be held. */
> +static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
> +				    struct vgic_irq *irq, int lr)
> +{
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
> +}
> +
> +static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
> +{
> +}
> +
> +static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +		/* GICv2 SGIs can count for more than one... */
> +		if (vgic_irq_is_sgi(irq->intid) && irq->source)
> +			count += hweight8(irq->source);
> +		else
> +			count++;
> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return count;
> +}
> +
> +/* Requires the VCPU's ap_list_lock to be held. */
> +static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
> +
> +	if (unlikely(!vcpu->kvm->arch.vgic.enabled))
> +		goto out_clean;
> +
> +	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
> +		vgic_set_underflow(vcpu);
> +		vgic_sort_ap_list(vcpu);
> +	}
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +
> +		if (unlikely(vgic_target_oracle(irq) != vcpu))
> +			goto next;
> +
> +		/*
> +		 * If we get an SGI with multiple sources, try to get
> +		 * them in all at once.
> +		 */
> +		do {
> +			vgic_populate_lr(vcpu, irq, count++);
> +		} while (irq->source && count < kvm_vgic_global_state.nr_lr);
> +
> +next:
> +		spin_unlock(&irq->irq_lock);
> +
> +		if (count == kvm_vgic_global_state.nr_lr)
> +			break;
> +	}
> +
> +out_clean:
> +	vcpu->arch.vgic_cpu.used_lrs = count;
> +
> +	/* Nuke remaining LRs */
> +	for ( ; count < kvm_vgic_global_state.nr_lr; count++)
> +		vgic_clear_lr(vcpu, count);
> +}
> +
> +/* Sync back the hardware VGIC state into our emulation after a guest's run. */
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	vgic_process_maintenance_interrupt(vcpu);
> +	vgic_fold_lr_state(vcpu);
> +	vgic_prune_ap_list(vcpu);
> +}
> +
> +/* Flush our emulation state into the GIC hardware before entering the guest. */
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +	vgic_flush_lr_state(vcpu);
> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index c625767..29b96b9 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -16,6 +16,8 @@
>  #ifndef __KVM_ARM_VGIC_NEW_H__
>  #define __KVM_ARM_VGIC_NEW_H__
>  
> +#define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
> +
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
> -- 
> 2.7.3
> 

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

* Re: [PATCH v3 26/55] KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
  2016-05-10 13:04       ` Andre Przywara
@ 2016-05-10 13:12         ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-10 13:12 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Tue, May 10, 2016 at 02:04:32PM +0100, Andre Przywara wrote:
> Hi Marc,
> 
> On 10/05/16 13:14, Marc Zyngier wrote:
> > On 06/05/16 11:45, Andre Przywara wrote:
> >> The active register handlers are shared between the v2 and v3
> >> emulation, so their implementation goes into vgic-mmio.c, to be
> >> easily referenced from the v3 emulation as well later.
> >> Since activation/deactivation of an interrupt may happen entirely
> >> in the guest without it ever exiting, we need some extra logic to
> >> properly track the active state.
> >> Putting it on an ap_list on activation is similar to the normal case
> >> handled by vgic_queue_irq_unlock(), but differs in some details that
> >> make a separate implementation worthwhile.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changelog RFC..v1:
> >> - handling queueing in write handler
> >> - remove IRQ lock from read handler
> >>
> >> Changelog v1 .. v2:
> >> - adapt to new MMIO framework
> >>
> >>  virt/kvm/arm/vgic/vgic-mmio-v2.c |   4 +-
> >>  virt/kvm/arm/vgic/vgic-mmio.c    | 120 +++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic-mmio.h    |  10 ++++
> >>  3 files changed, 132 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> index 4b87e0a..054b52d 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> @@ -80,9 +80,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> >>  		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
> >> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
> >> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
> >>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> >> index 4df1af7..dbf683e 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> >> @@ -162,6 +162,126 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
> >>  	}
> >>  }
> >>  
> >> +unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
> >> +				    gpa_t addr, unsigned int len)
> >> +{
> >> +	u32 intid = (addr & 0x7f) * 8;
> >> +	u32 value = 0;
> >> +	int i;
> >> +
> >> +	/* Loop over all IRQs affected by this read */
> >> +	for (i = 0; i < len * 8; i++) {
> >> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +		if (irq->active)
> >> +			value |= (1U << i);
> >> +	}
> >> +
> >> +	return extract_bytes(value, addr & 3, len);
> >> +}
> >> +
> >> +void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
> >> +			     gpa_t addr, unsigned int len,
> >> +			     unsigned long val)
> >> +{
> >> +	u32 intid = (addr & 0x7f) * 8;
> >> +	int i;
> >> +
> >> +	for_each_set_bit(i, &val, len * 8) {
> >> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +		spin_lock(&irq->irq_lock);
> >> +
> >> +		irq->active = false;
> >> +
> >> +		/*
> >> +		 * Christoffer wrote:
> >> +		 * The question is what to do if the vcpu for this irq is
> >> +		 * running and the LR there has the active bit set, then we'll
> >> +		 * overwrite this change when we fold the LR state back into
> >> +		 * the vgic_irq struct.
> >> +		 *
> >> +		 * Since I expect this to be extremely rare, one option is to
> >> +		 * force irq->vcpu to exit (if non-null) and then do you
> >> +		 * thing here after you've confirm it has exited while holding
> >> +		 * some lock preventing it from re-entering again.
> >> +		 * Slightly crazy.
> >> +		 *
> >> +		 * The alternative is to put a big fat comment nothing that
> >> +		 * this is non-supported bad race, and wait until someone
> >> +		 * submits a bug report relating to this...
> >> +		 */
> > 
> > Don't we have a patch by Christoffer that addresses this exact issue?
> 
> Yes, and if I am not mistaken you said last week that we put this patch
> and the firmware-independent probing on top of the queue, so I didn't
> merge it.
> 
> >> +
> >> +		spin_unlock(&irq->irq_lock);
> >> +	}
> >> +}
> >> +
> >> +void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
> >> +			     gpa_t addr, unsigned int len,
> >> +			     unsigned long val)
> >> +{
> >> +	u32 intid = (addr & 0x7f) * 8;
> >> +	int i;
> >> +
> >> +	for_each_set_bit(i, &val, len * 8) {
> >> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +		spin_lock(&irq->irq_lock);
> >> +
> >> +		/* As this is a special case, we can't use the
> >> +		 * vgic_queue_irq_unlock() function to put this on a VCPU.
> >> +		 * So deal with this here explicitly unless the IRQs was
> >> +		 * already active, it was on a VCPU before or there is no
> >> +		 * target VCPU assigned at the moment.
> >> +		 */
> >> +		if (irq->active || irq->vcpu || !irq->target_vcpu) {
> >> +			irq->active = true;
> >> +
> >> +			spin_unlock(&irq->irq_lock);
> >> +			continue;
> >> +		}
> >> +
> >> +		spin_unlock(&irq->irq_lock);
> >> +retry:
> >> +		vcpu = irq->target_vcpu;
> >> +
> >> +		spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >> +		spin_lock(&irq->irq_lock);
> >> +
> >> +		/*
> >> +		 * Recheck after dropping the IRQ lock to see if we should
> >> +		 * still care about queueing it.
> >> +		 */
> >> +		if (irq->active || irq->vcpu) {
> >> +			irq->active = true;
> >> +
> >> +			spin_unlock(&irq->irq_lock);
> >> +			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >> +
> >> +			continue;
> >> +		}
> >> +
> >> +		/* Did the target VCPU change while we had the lock dropped? */
> >> +		if (vcpu != irq->target_vcpu) {
> >> +			spin_unlock(&irq->irq_lock);
> >> +			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >> +
> >> +			goto retry;
> >> +		}
> >> +
> >> +		/* Now queue the IRQ to the VCPU's ap_list. */
> >> +		list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
> >> +		irq->vcpu = vcpu;
> >> +
> >> +		irq->active = true;
> >> +
> >> +		spin_unlock(&irq->irq_lock);
> >> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >> +
> >> +		kvm_vcpu_kick(vcpu);
> >> +	}
> > 
> > This is annoyingly close to vgic_queue_irq_unlock()... Maybe switching
> > this to some form of preprocessor template. Or not.
> 
> I think we had this discussion with Christoffer before. There are subtle
> differences and the impression was that unifying the two would make them
> basically unreadable because of all this special handling.
> Not sure if the preprocessor would help here.
> 
If we changed the queue function slightly as I suggested, I haven't been
able to come up with a case were we can't do:

spin_lock(&irq->irq_lock);
vgic_queue_irq_unlock(irq);

but I need to look at it more carefully.

-Christoffer

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

* [PATCH v3 26/55] KVM: arm/arm64: vgic-new: Add ACTIVE registers handlers
@ 2016-05-10 13:12         ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-10 13:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 10, 2016 at 02:04:32PM +0100, Andre Przywara wrote:
> Hi Marc,
> 
> On 10/05/16 13:14, Marc Zyngier wrote:
> > On 06/05/16 11:45, Andre Przywara wrote:
> >> The active register handlers are shared between the v2 and v3
> >> emulation, so their implementation goes into vgic-mmio.c, to be
> >> easily referenced from the v3 emulation as well later.
> >> Since activation/deactivation of an interrupt may happen entirely
> >> in the guest without it ever exiting, we need some extra logic to
> >> properly track the active state.
> >> Putting it on an ap_list on activation is similar to the normal case
> >> handled by vgic_queue_irq_unlock(), but differs in some details that
> >> make a separate implementation worthwhile.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changelog RFC..v1:
> >> - handling queueing in write handler
> >> - remove IRQ lock from read handler
> >>
> >> Changelog v1 .. v2:
> >> - adapt to new MMIO framework
> >>
> >>  virt/kvm/arm/vgic/vgic-mmio-v2.c |   4 +-
> >>  virt/kvm/arm/vgic/vgic-mmio.c    | 120 +++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic-mmio.h    |  10 ++++
> >>  3 files changed, 132 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> index 4b87e0a..054b52d 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> @@ -80,9 +80,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> >>  		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
> >> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
> >> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
> >>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> >> index 4df1af7..dbf683e 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> >> @@ -162,6 +162,126 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
> >>  	}
> >>  }
> >>  
> >> +unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
> >> +				    gpa_t addr, unsigned int len)
> >> +{
> >> +	u32 intid = (addr & 0x7f) * 8;
> >> +	u32 value = 0;
> >> +	int i;
> >> +
> >> +	/* Loop over all IRQs affected by this read */
> >> +	for (i = 0; i < len * 8; i++) {
> >> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +		if (irq->active)
> >> +			value |= (1U << i);
> >> +	}
> >> +
> >> +	return extract_bytes(value, addr & 3, len);
> >> +}
> >> +
> >> +void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
> >> +			     gpa_t addr, unsigned int len,
> >> +			     unsigned long val)
> >> +{
> >> +	u32 intid = (addr & 0x7f) * 8;
> >> +	int i;
> >> +
> >> +	for_each_set_bit(i, &val, len * 8) {
> >> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +		spin_lock(&irq->irq_lock);
> >> +
> >> +		irq->active = false;
> >> +
> >> +		/*
> >> +		 * Christoffer wrote:
> >> +		 * The question is what to do if the vcpu for this irq is
> >> +		 * running and the LR there has the active bit set, then we'll
> >> +		 * overwrite this change when we fold the LR state back into
> >> +		 * the vgic_irq struct.
> >> +		 *
> >> +		 * Since I expect this to be extremely rare, one option is to
> >> +		 * force irq->vcpu to exit (if non-null) and then do you
> >> +		 * thing here after you've confirm it has exited while holding
> >> +		 * some lock preventing it from re-entering again.
> >> +		 * Slightly crazy.
> >> +		 *
> >> +		 * The alternative is to put a big fat comment nothing that
> >> +		 * this is non-supported bad race, and wait until someone
> >> +		 * submits a bug report relating to this...
> >> +		 */
> > 
> > Don't we have a patch by Christoffer that addresses this exact issue?
> 
> Yes, and if I am not mistaken you said last week that we put this patch
> and the firmware-independent probing on top of the queue, so I didn't
> merge it.
> 
> >> +
> >> +		spin_unlock(&irq->irq_lock);
> >> +	}
> >> +}
> >> +
> >> +void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
> >> +			     gpa_t addr, unsigned int len,
> >> +			     unsigned long val)
> >> +{
> >> +	u32 intid = (addr & 0x7f) * 8;
> >> +	int i;
> >> +
> >> +	for_each_set_bit(i, &val, len * 8) {
> >> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +		spin_lock(&irq->irq_lock);
> >> +
> >> +		/* As this is a special case, we can't use the
> >> +		 * vgic_queue_irq_unlock() function to put this on a VCPU.
> >> +		 * So deal with this here explicitly unless the IRQs was
> >> +		 * already active, it was on a VCPU before or there is no
> >> +		 * target VCPU assigned at the moment.
> >> +		 */
> >> +		if (irq->active || irq->vcpu || !irq->target_vcpu) {
> >> +			irq->active = true;
> >> +
> >> +			spin_unlock(&irq->irq_lock);
> >> +			continue;
> >> +		}
> >> +
> >> +		spin_unlock(&irq->irq_lock);
> >> +retry:
> >> +		vcpu = irq->target_vcpu;
> >> +
> >> +		spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >> +		spin_lock(&irq->irq_lock);
> >> +
> >> +		/*
> >> +		 * Recheck after dropping the IRQ lock to see if we should
> >> +		 * still care about queueing it.
> >> +		 */
> >> +		if (irq->active || irq->vcpu) {
> >> +			irq->active = true;
> >> +
> >> +			spin_unlock(&irq->irq_lock);
> >> +			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >> +
> >> +			continue;
> >> +		}
> >> +
> >> +		/* Did the target VCPU change while we had the lock dropped? */
> >> +		if (vcpu != irq->target_vcpu) {
> >> +			spin_unlock(&irq->irq_lock);
> >> +			spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >> +
> >> +			goto retry;
> >> +		}
> >> +
> >> +		/* Now queue the IRQ to the VCPU's ap_list. */
> >> +		list_add_tail(&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head);
> >> +		irq->vcpu = vcpu;
> >> +
> >> +		irq->active = true;
> >> +
> >> +		spin_unlock(&irq->irq_lock);
> >> +		spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> >> +
> >> +		kvm_vcpu_kick(vcpu);
> >> +	}
> > 
> > This is annoyingly close to vgic_queue_irq_unlock()... Maybe switching
> > this to some form of preprocessor template. Or not.
> 
> I think we had this discussion with Christoffer before. There are subtle
> differences and the impression was that unifying the two would make them
> basically unreadable because of all this special handling.
> Not sure if the preprocessor would help here.
> 
If we changed the queue function slightly as I suggested, I haven't been
able to come up with a case were we can't do:

spin_lock(&irq->irq_lock);
vgic_queue_irq_unlock(irq);

but I need to look at it more carefully.

-Christoffer

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

* Re: [PATCH] KVM: arm/arm64: vgic-new: fix overlap check for device addresses
  2016-05-10 10:58       ` Andre Przywara
@ 2016-05-10 13:16         ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 13:16 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

On 10/05/16 11:58, Andre Przywara wrote:
> When userland sets the base addresses for the GIC register frames,
> the kernel tries to make sure that the regions for the distributor and
> the one for the CPU interface or the redistributors do not overlap.
> Only that this check currently takes care of a GICv2 model only.
> Rework the overlap check to take a GICv3 in account also.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Hi Marc,
> 
> this one goes on top of the new-vgic-v3 series.
> Does this address your concerns about the overlap check?
> I'd be grateful if you could apply some of your C wizardry on the first
> function ;-)
> 
> Cheers,
> Andre.
> 
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 59 ++++++++++++++++++++++++++-----------
>  1 file changed, 41 insertions(+), 18 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index 2122ff2..fcf38ef 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -21,41 +21,63 @@
>  
>  /* common helpers */
>  
> -static int vgic_ioaddr_overlap(struct kvm *kvm)
> +static phys_addr_t vgic_get_existing_region(struct kvm *kvm, phys_addr_t *addr)
>  {
> -	phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;
> -	phys_addr_t cpu = kvm->arch.vgic.vgic_cpu_base;
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	phys_addr_t cpu_addr;
> +	bool is_vgicv2 = (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2);
>  
> -	if (IS_VGIC_ADDR_UNDEF(dist) || IS_VGIC_ADDR_UNDEF(cpu))
> -		return 0;
> -	if ((dist <= cpu && dist + KVM_VGIC_V2_DIST_SIZE > cpu) ||
> -	    (cpu <= dist && cpu + KVM_VGIC_V2_CPU_SIZE > dist))
> -		return -EBUSY;
> -	return 0;
> +	cpu_addr = is_vgicv2 ? dist->vgic_cpu_base : dist->vgic_redist_base;
> +
> +	if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base)) {
> +		if (IS_VGIC_ADDR_UNDEF(cpu_addr))
> +			return 0;
> +
> +		*addr = cpu_addr;
> +		if (is_vgicv2)
> +			return KVM_VGIC_V2_CPU_SIZE;
> +		return atomic_read(&kvm->online_vcpus) * KVM_VGIC_V3_REDIST_SIZE;
> +	}
> +
> +	*addr = dist->vgic_dist_base;
> +	return is_vgicv2 ? KVM_VGIC_V2_DIST_SIZE : KVM_VGIC_V3_DIST_SIZE;
> +}
> +
> +static bool vgic_ioaddr_overlap(struct kvm *kvm, phys_addr_t addr,
> +				phys_addr_t size)
> +{
> +	phys_addr_t used_addr, used_size;
> +
> +	used_size = vgic_get_existing_region(kvm, &used_addr);
> +	if (!used_size)
> +		return false;
> +
> +	if (addr + size <= used_addr)
> +		return false;
> +
> +	if (used_addr + used_size <= addr)
> +		return false;
> +
> +	return true;
>  }
>  
>  static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
>  			      phys_addr_t addr, phys_addr_t size)
>  {
> -	int ret;
> -
>  	if (addr & ~KVM_PHYS_MASK)
>  		return -E2BIG;
>  
> -	if (addr & (SZ_4K - 1))
> -		return -EINVAL;
> -
>  	if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
>  		return -EEXIST;
>  	if (addr + size < addr)
>  		return -EINVAL;
>  
> +	if (vgic_ioaddr_overlap(kvm, addr, size))
> +		return -EBUSY;
> +
>  	*ioaddr = addr;
> -	ret = vgic_ioaddr_overlap(kvm);
> -	if (ret)
> -		*ioaddr = VGIC_ADDR_UNDEF;
>  
> -	return ret;
> +	return 0;
>  }
>  
>  /**
> @@ -104,6 +126,7 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
>  		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
>  		addr_ptr = &vgic->vgic_redist_base;
>  		block_size = KVM_VGIC_V3_REDIST_SIZE;
> +		block_size *= atomic_read(&kvm->online_vcpus);

What guarantees that the vcpus have been created already? AFAIU, you can
perfectly create the VM, then the GIC, and then the vcpus. So this would
be perfectly be allowed to be zero.

Or did I miss something?

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH] KVM: arm/arm64: vgic-new: fix overlap check for device addresses
@ 2016-05-10 13:16         ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 13:16 UTC (permalink / raw)
  To: linux-arm-kernel

On 10/05/16 11:58, Andre Przywara wrote:
> When userland sets the base addresses for the GIC register frames,
> the kernel tries to make sure that the regions for the distributor and
> the one for the CPU interface or the redistributors do not overlap.
> Only that this check currently takes care of a GICv2 model only.
> Rework the overlap check to take a GICv3 in account also.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Hi Marc,
> 
> this one goes on top of the new-vgic-v3 series.
> Does this address your concerns about the overlap check?
> I'd be grateful if you could apply some of your C wizardry on the first
> function ;-)
> 
> Cheers,
> Andre.
> 
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 59 ++++++++++++++++++++++++++-----------
>  1 file changed, 41 insertions(+), 18 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index 2122ff2..fcf38ef 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -21,41 +21,63 @@
>  
>  /* common helpers */
>  
> -static int vgic_ioaddr_overlap(struct kvm *kvm)
> +static phys_addr_t vgic_get_existing_region(struct kvm *kvm, phys_addr_t *addr)
>  {
> -	phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;
> -	phys_addr_t cpu = kvm->arch.vgic.vgic_cpu_base;
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	phys_addr_t cpu_addr;
> +	bool is_vgicv2 = (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2);
>  
> -	if (IS_VGIC_ADDR_UNDEF(dist) || IS_VGIC_ADDR_UNDEF(cpu))
> -		return 0;
> -	if ((dist <= cpu && dist + KVM_VGIC_V2_DIST_SIZE > cpu) ||
> -	    (cpu <= dist && cpu + KVM_VGIC_V2_CPU_SIZE > dist))
> -		return -EBUSY;
> -	return 0;
> +	cpu_addr = is_vgicv2 ? dist->vgic_cpu_base : dist->vgic_redist_base;
> +
> +	if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base)) {
> +		if (IS_VGIC_ADDR_UNDEF(cpu_addr))
> +			return 0;
> +
> +		*addr = cpu_addr;
> +		if (is_vgicv2)
> +			return KVM_VGIC_V2_CPU_SIZE;
> +		return atomic_read(&kvm->online_vcpus) * KVM_VGIC_V3_REDIST_SIZE;
> +	}
> +
> +	*addr = dist->vgic_dist_base;
> +	return is_vgicv2 ? KVM_VGIC_V2_DIST_SIZE : KVM_VGIC_V3_DIST_SIZE;
> +}
> +
> +static bool vgic_ioaddr_overlap(struct kvm *kvm, phys_addr_t addr,
> +				phys_addr_t size)
> +{
> +	phys_addr_t used_addr, used_size;
> +
> +	used_size = vgic_get_existing_region(kvm, &used_addr);
> +	if (!used_size)
> +		return false;
> +
> +	if (addr + size <= used_addr)
> +		return false;
> +
> +	if (used_addr + used_size <= addr)
> +		return false;
> +
> +	return true;
>  }
>  
>  static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
>  			      phys_addr_t addr, phys_addr_t size)
>  {
> -	int ret;
> -
>  	if (addr & ~KVM_PHYS_MASK)
>  		return -E2BIG;
>  
> -	if (addr & (SZ_4K - 1))
> -		return -EINVAL;
> -
>  	if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
>  		return -EEXIST;
>  	if (addr + size < addr)
>  		return -EINVAL;
>  
> +	if (vgic_ioaddr_overlap(kvm, addr, size))
> +		return -EBUSY;
> +
>  	*ioaddr = addr;
> -	ret = vgic_ioaddr_overlap(kvm);
> -	if (ret)
> -		*ioaddr = VGIC_ADDR_UNDEF;
>  
> -	return ret;
> +	return 0;
>  }
>  
>  /**
> @@ -104,6 +126,7 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
>  		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
>  		addr_ptr = &vgic->vgic_redist_base;
>  		block_size = KVM_VGIC_V3_REDIST_SIZE;
> +		block_size *= atomic_read(&kvm->online_vcpus);

What guarantees that the vcpus have been created already? AFAIU, you can
perfectly create the VM, then the GIC, and then the vcpus. So this would
be perfectly be allowed to be zero.

Or did I miss something?

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10 13:30     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-10 13:30 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:45:31AM +0100, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Processing maintenance interrupts and accessing the list registers
> are dependent on the host's GIC version.
> Introduce vgic-v2.c to contain GICv2 specific functions.
> Implement the GICv2 specific code for syncing the emulation state
> into the VGIC registers.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - remove explicit LR_STATE clearing on maintenance interrupt handling
> - improve documentation for vgic_v2_populate_lr()
> - remove WARN_ON on non-edge IRQs in maintenance interrupts
> - simplify multi-CPU source SGI handling
> 
> Changelog v1 .. v2:
> - inject the IRQ priority into the list register
> 
> Changelog v2 .. v3:
> - cleanup diff containing rebase artifacts
> 
>  include/linux/irqchip/arm-gic.h |   1 +
>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>  4 files changed, 191 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
> 
> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> index 9c94026..be0d26f 100644
> --- a/include/linux/irqchip/arm-gic.h
> +++ b/include/linux/irqchip/arm-gic.h
> @@ -76,6 +76,7 @@
>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
> +#define GICH_LR_PRIORITY_SHIFT		23
>  #define GICH_LR_STATE			(3 << 28)
>  #define GICH_LR_PENDING_BIT		(1 << 28)
>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> new file mode 100644
> index 0000000..4cee616
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -0,0 +1,178 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/irqchip/arm-gic.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +
> +#include "vgic.h"
> +
> +/*
> + * Call this function to convert a u64 value to an unsigned long * bitmask
> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
> + *
> + * Warning: Calling this function may modify *val.
> + */
> +static unsigned long *u64_to_bitmask(u64 *val)
> +{
> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
> +	*val = (*val >> 32) | (*val << 32);
> +#endif
> +	return (unsigned long *)val;
> +}
> +
> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +
> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
> +		u64 eisr = cpuif->vgic_eisr;
> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
> +		int lr;
> +
> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
> +
> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
> +
> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> +					     intid - VGIC_NR_PRIVATE_IRQS);
> +

why do we need to do this?  I cannot find any consumers of this info
after we've left the hyp code.

Also, I think I offered a comment about why we would potentially need
this in the first place.  This is the famous race where hardware doesn't
guarantee consistency between the MISR and ELRSR right?

> +			cpuif->vgic_elrsr |= 1ULL << lr;
> +		}
> +	}
> +
> +	/* check and disable underflow maintenance IRQ */
> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
> +
> +	/*
> +	 * In the next iterations of the vcpu loop, if we sync the
> +	 * vgic state after flushing it, but before entering the guest
> +	 * (this happens for pending signals and vmid rollovers), then
> +	 * make sure we don't pick up any old maintenance interrupts
> +	 * here.
> +	 */
> +	cpuif->vgic_eisr = 0;
> +}
> +
> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +
> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
> +}
> +
> +/*
> + * transfer the content of the LRs back into the corresponding ap_list:
> + * - active bit is transferred as is
> + * - pending bit is
> + *   - transferred as is in case of edge sensitive IRQs
> + *   - set to the line-level (resample time) for level sensitive IRQs
> + */
> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +	int lr;
> +
> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> +		u32 val = cpuif->vgic_lr[lr];
> +		u32 intid = val & GICH_LR_VIRTUALID;
> +		struct vgic_irq *irq;
> +
> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		/* Always preserve the active bit */
> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
> +
> +		/* Edge is the only case where we preserve the pending bit */
> +		if (irq->config == VGIC_CONFIG_EDGE &&
> +		    (val & GICH_LR_PENDING_BIT)) {
> +			irq->pending = true;
> +
> +			if (vgic_irq_is_sgi(intid)) {
> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> +
> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> +				irq->source |= (1 << cpuid);
> +			}
> +		}
> +
> +		/* Clear soft pending state when level IRQs have been acked */
> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> +		    !(val & GICH_LR_PENDING_BIT)) {
> +			irq->soft_pending = false;
> +			irq->pending = irq->line_level;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +/*
> + * Populates the particular LR with the state of a given IRQ:
> + * - for an edge sensitive IRQ the pending state is cleared in struct vgic_irq
> + * - for a level sensitive IRQ the pending state value is unchanged;
> + *   it is dictated directly by the input level
> + *
> + * If @irq describes an SGI with multiple sources, we choose the
> + * lowest-numbered source VCPU and clear that bit in the source bitmap.
> + *
> + * The irq_lock must be held by the caller.
> + */
> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> +{
> +	u32 val = irq->intid;
> +
> +	if (irq->pending) {
> +		val |= GICH_LR_PENDING_BIT;
> +
> +		if (irq->config == VGIC_CONFIG_EDGE)
> +			irq->pending = false;
> +
> +		if (vgic_irq_is_sgi(irq->intid)) {
> +			u32 src = ffs(irq->source);
> +
> +			BUG_ON(!src);
> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> +			irq->source &= ~(1 << (src - 1));
> +			if (irq->source)
> +				irq->pending = true;
> +		}
> +	}
> +
> +	if (irq->active)
> +		val |= GICH_LR_ACTIVE_BIT;
> +
> +	if (irq->hw) {
> +		val |= GICH_LR_HW;
> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
> +	} else {
> +		if (irq->config == VGIC_CONFIG_LEVEL)
> +			val |= GICH_LR_EOI;
> +	}
> +
> +	/* The GICv2 LR only holds five bits of priority. */
> +	val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
> +
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
> +}
> +
> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
> +{
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index c6f8b9b..68d885c 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -397,10 +397,12 @@ retry:
>  
>  static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>  {
> +	vgic_v2_process_maintenance(vcpu);
>  }
>  
>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>  {
> +	vgic_v2_fold_lr_state(vcpu);
>  }
>  
>  /* Requires the ap_list_lock and the irq_lock to be held. */
> @@ -409,14 +411,18 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>  {
>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
> +
> +	vgic_v2_populate_lr(vcpu, irq, lr);
>  }
>  
>  static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
>  {
> +	vgic_v2_clear_lr(vcpu, lr);
>  }
>  
>  static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>  {
> +	vgic_v2_set_underflow(vcpu);
>  }
>  
>  static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 29b96b9..0db490e 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -22,4 +22,10 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
>  
> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
> +
>  #endif
> -- 
> 2.7.3
> 

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

* [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
@ 2016-05-10 13:30     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-10 13:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:31AM +0100, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Processing maintenance interrupts and accessing the list registers
> are dependent on the host's GIC version.
> Introduce vgic-v2.c to contain GICv2 specific functions.
> Implement the GICv2 specific code for syncing the emulation state
> into the VGIC registers.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - remove explicit LR_STATE clearing on maintenance interrupt handling
> - improve documentation for vgic_v2_populate_lr()
> - remove WARN_ON on non-edge IRQs in maintenance interrupts
> - simplify multi-CPU source SGI handling
> 
> Changelog v1 .. v2:
> - inject the IRQ priority into the list register
> 
> Changelog v2 .. v3:
> - cleanup diff containing rebase artifacts
> 
>  include/linux/irqchip/arm-gic.h |   1 +
>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>  4 files changed, 191 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
> 
> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> index 9c94026..be0d26f 100644
> --- a/include/linux/irqchip/arm-gic.h
> +++ b/include/linux/irqchip/arm-gic.h
> @@ -76,6 +76,7 @@
>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
> +#define GICH_LR_PRIORITY_SHIFT		23
>  #define GICH_LR_STATE			(3 << 28)
>  #define GICH_LR_PENDING_BIT		(1 << 28)
>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> new file mode 100644
> index 0000000..4cee616
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -0,0 +1,178 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/irqchip/arm-gic.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +
> +#include "vgic.h"
> +
> +/*
> + * Call this function to convert a u64 value to an unsigned long * bitmask
> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
> + *
> + * Warning: Calling this function may modify *val.
> + */
> +static unsigned long *u64_to_bitmask(u64 *val)
> +{
> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
> +	*val = (*val >> 32) | (*val << 32);
> +#endif
> +	return (unsigned long *)val;
> +}
> +
> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +
> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
> +		u64 eisr = cpuif->vgic_eisr;
> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
> +		int lr;
> +
> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
> +
> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
> +
> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> +					     intid - VGIC_NR_PRIVATE_IRQS);
> +

why do we need to do this?  I cannot find any consumers of this info
after we've left the hyp code.

Also, I think I offered a comment about why we would potentially need
this in the first place.  This is the famous race where hardware doesn't
guarantee consistency between the MISR and ELRSR right?

> +			cpuif->vgic_elrsr |= 1ULL << lr;
> +		}
> +	}
> +
> +	/* check and disable underflow maintenance IRQ */
> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
> +
> +	/*
> +	 * In the next iterations of the vcpu loop, if we sync the
> +	 * vgic state after flushing it, but before entering the guest
> +	 * (this happens for pending signals and vmid rollovers), then
> +	 * make sure we don't pick up any old maintenance interrupts
> +	 * here.
> +	 */
> +	cpuif->vgic_eisr = 0;
> +}
> +
> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +
> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
> +}
> +
> +/*
> + * transfer the content of the LRs back into the corresponding ap_list:
> + * - active bit is transferred as is
> + * - pending bit is
> + *   - transferred as is in case of edge sensitive IRQs
> + *   - set to the line-level (resample time) for level sensitive IRQs
> + */
> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +	int lr;
> +
> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> +		u32 val = cpuif->vgic_lr[lr];
> +		u32 intid = val & GICH_LR_VIRTUALID;
> +		struct vgic_irq *irq;
> +
> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		/* Always preserve the active bit */
> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
> +
> +		/* Edge is the only case where we preserve the pending bit */
> +		if (irq->config == VGIC_CONFIG_EDGE &&
> +		    (val & GICH_LR_PENDING_BIT)) {
> +			irq->pending = true;
> +
> +			if (vgic_irq_is_sgi(intid)) {
> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> +
> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> +				irq->source |= (1 << cpuid);
> +			}
> +		}
> +
> +		/* Clear soft pending state when level IRQs have been acked */
> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> +		    !(val & GICH_LR_PENDING_BIT)) {
> +			irq->soft_pending = false;
> +			irq->pending = irq->line_level;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +/*
> + * Populates the particular LR with the state of a given IRQ:
> + * - for an edge sensitive IRQ the pending state is cleared in struct vgic_irq
> + * - for a level sensitive IRQ the pending state value is unchanged;
> + *   it is dictated directly by the input level
> + *
> + * If @irq describes an SGI with multiple sources, we choose the
> + * lowest-numbered source VCPU and clear that bit in the source bitmap.
> + *
> + * The irq_lock must be held by the caller.
> + */
> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> +{
> +	u32 val = irq->intid;
> +
> +	if (irq->pending) {
> +		val |= GICH_LR_PENDING_BIT;
> +
> +		if (irq->config == VGIC_CONFIG_EDGE)
> +			irq->pending = false;
> +
> +		if (vgic_irq_is_sgi(irq->intid)) {
> +			u32 src = ffs(irq->source);
> +
> +			BUG_ON(!src);
> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> +			irq->source &= ~(1 << (src - 1));
> +			if (irq->source)
> +				irq->pending = true;
> +		}
> +	}
> +
> +	if (irq->active)
> +		val |= GICH_LR_ACTIVE_BIT;
> +
> +	if (irq->hw) {
> +		val |= GICH_LR_HW;
> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
> +	} else {
> +		if (irq->config == VGIC_CONFIG_LEVEL)
> +			val |= GICH_LR_EOI;
> +	}
> +
> +	/* The GICv2 LR only holds five bits of priority. */
> +	val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
> +
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
> +}
> +
> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
> +{
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index c6f8b9b..68d885c 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -397,10 +397,12 @@ retry:
>  
>  static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>  {
> +	vgic_v2_process_maintenance(vcpu);
>  }
>  
>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>  {
> +	vgic_v2_fold_lr_state(vcpu);
>  }
>  
>  /* Requires the ap_list_lock and the irq_lock to be held. */
> @@ -409,14 +411,18 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>  {
>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
> +
> +	vgic_v2_populate_lr(vcpu, irq, lr);
>  }
>  
>  static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
>  {
> +	vgic_v2_clear_lr(vcpu, lr);
>  }
>  
>  static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>  {
> +	vgic_v2_set_underflow(vcpu);
>  }
>  
>  static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 29b96b9..0db490e 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -22,4 +22,10 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
>  
> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
> +
>  #endif
> -- 
> 2.7.3
> 

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

* Re: [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
  2016-05-10 13:30     ` Christoffer Dall
@ 2016-05-10 13:42       ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 13:42 UTC (permalink / raw)
  To: Christoffer Dall, Andre Przywara
  Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

On 10/05/16 14:30, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:31AM +0100, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Processing maintenance interrupts and accessing the list registers
>> are dependent on the host's GIC version.
>> Introduce vgic-v2.c to contain GICv2 specific functions.
>> Implement the GICv2 specific code for syncing the emulation state
>> into the VGIC registers.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - remove explicit LR_STATE clearing on maintenance interrupt handling
>> - improve documentation for vgic_v2_populate_lr()
>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
>> - simplify multi-CPU source SGI handling
>>
>> Changelog v1 .. v2:
>> - inject the IRQ priority into the list register
>>
>> Changelog v2 .. v3:
>> - cleanup diff containing rebase artifacts
>>
>>  include/linux/irqchip/arm-gic.h |   1 +
>>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>>  4 files changed, 191 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>>
>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>> index 9c94026..be0d26f 100644
>> --- a/include/linux/irqchip/arm-gic.h
>> +++ b/include/linux/irqchip/arm-gic.h
>> @@ -76,6 +76,7 @@
>>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
>> +#define GICH_LR_PRIORITY_SHIFT		23
>>  #define GICH_LR_STATE			(3 << 28)
>>  #define GICH_LR_PENDING_BIT		(1 << 28)
>>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>> new file mode 100644
>> index 0000000..4cee616
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>> @@ -0,0 +1,178 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/irqchip/arm-gic.h>
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +
>> +#include "vgic.h"
>> +
>> +/*
>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>> + *
>> + * Warning: Calling this function may modify *val.
>> + */
>> +static unsigned long *u64_to_bitmask(u64 *val)
>> +{
>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>> +	*val = (*val >> 32) | (*val << 32);
>> +#endif
>> +	return (unsigned long *)val;
>> +}
>> +
>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +
>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>> +		u64 eisr = cpuif->vgic_eisr;
>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>> +		int lr;
>> +
>> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
>> +
>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
>> +
>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>> +
> 
> why do we need to do this?  I cannot find any consumers of this info
> after we've left the hyp code.

I believe that's for vhost and irqfd. Or am I misreading your question?

> Also, I think I offered a comment about why we would potentially need
> this in the first place.  This is the famous race where hardware doesn't
> guarantee consistency between the MISR and ELRSR right?

That's the one (except it is between EISR and ELRSR). I don't have your
initial comment at hand, but would something like the following do?

			/*
			 * The maintenance interrupt may not have had a
			 * chance to update ELRSR, so let's mark the LRs
			 * presents in EISR as empty.
			 */
> 
>> +			cpuif->vgic_elrsr |= 1ULL << lr;
>> +		}
>> +	}

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
@ 2016-05-10 13:42       ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 13:42 UTC (permalink / raw)
  To: linux-arm-kernel

On 10/05/16 14:30, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:31AM +0100, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Processing maintenance interrupts and accessing the list registers
>> are dependent on the host's GIC version.
>> Introduce vgic-v2.c to contain GICv2 specific functions.
>> Implement the GICv2 specific code for syncing the emulation state
>> into the VGIC registers.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - remove explicit LR_STATE clearing on maintenance interrupt handling
>> - improve documentation for vgic_v2_populate_lr()
>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
>> - simplify multi-CPU source SGI handling
>>
>> Changelog v1 .. v2:
>> - inject the IRQ priority into the list register
>>
>> Changelog v2 .. v3:
>> - cleanup diff containing rebase artifacts
>>
>>  include/linux/irqchip/arm-gic.h |   1 +
>>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>>  4 files changed, 191 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>>
>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>> index 9c94026..be0d26f 100644
>> --- a/include/linux/irqchip/arm-gic.h
>> +++ b/include/linux/irqchip/arm-gic.h
>> @@ -76,6 +76,7 @@
>>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
>> +#define GICH_LR_PRIORITY_SHIFT		23
>>  #define GICH_LR_STATE			(3 << 28)
>>  #define GICH_LR_PENDING_BIT		(1 << 28)
>>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>> new file mode 100644
>> index 0000000..4cee616
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>> @@ -0,0 +1,178 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/irqchip/arm-gic.h>
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +
>> +#include "vgic.h"
>> +
>> +/*
>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>> + *
>> + * Warning: Calling this function may modify *val.
>> + */
>> +static unsigned long *u64_to_bitmask(u64 *val)
>> +{
>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>> +	*val = (*val >> 32) | (*val << 32);
>> +#endif
>> +	return (unsigned long *)val;
>> +}
>> +
>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +
>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>> +		u64 eisr = cpuif->vgic_eisr;
>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>> +		int lr;
>> +
>> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
>> +
>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
>> +
>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>> +
> 
> why do we need to do this?  I cannot find any consumers of this info
> after we've left the hyp code.

I believe that's for vhost and irqfd. Or am I misreading your question?

> Also, I think I offered a comment about why we would potentially need
> this in the first place.  This is the famous race where hardware doesn't
> guarantee consistency between the MISR and ELRSR right?

That's the one (except it is between EISR and ELRSR). I don't have your
initial comment at hand, but would something like the following do?

			/*
			 * The maintenance interrupt may not have had a
			 * chance to update ELRSR, so let's mark the LRs
			 * presents in EISR as empty.
			 */
> 
>> +			cpuif->vgic_elrsr |= 1ULL << lr;
>> +		}
>> +	}

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
  2016-05-10 13:42       ` Marc Zyngier
@ 2016-05-10 13:49         ` Eric Auger
  -1 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10 13:49 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall, Andre Przywara
  Cc: kvmarm, kvm, linux-arm-kernel

On 05/10/2016 03:42 PM, Marc Zyngier wrote:
> On 10/05/16 14:30, Christoffer Dall wrote:
>> On Fri, May 06, 2016 at 11:45:31AM +0100, Andre Przywara wrote:
>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>
>>> Processing maintenance interrupts and accessing the list registers
>>> are dependent on the host's GIC version.
>>> Introduce vgic-v2.c to contain GICv2 specific functions.
>>> Implement the GICv2 specific code for syncing the emulation state
>>> into the VGIC registers.
>>>
>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>> Changelog RFC..v1:
>>> - remove explicit LR_STATE clearing on maintenance interrupt handling
>>> - improve documentation for vgic_v2_populate_lr()
>>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
>>> - simplify multi-CPU source SGI handling
>>>
>>> Changelog v1 .. v2:
>>> - inject the IRQ priority into the list register
>>>
>>> Changelog v2 .. v3:
>>> - cleanup diff containing rebase artifacts
>>>
>>>  include/linux/irqchip/arm-gic.h |   1 +
>>>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>>>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>>>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>>>  4 files changed, 191 insertions(+)
>>>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>>>
>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>>> index 9c94026..be0d26f 100644
>>> --- a/include/linux/irqchip/arm-gic.h
>>> +++ b/include/linux/irqchip/arm-gic.h
>>> @@ -76,6 +76,7 @@
>>>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>>>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>>>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
>>> +#define GICH_LR_PRIORITY_SHIFT		23
>>>  #define GICH_LR_STATE			(3 << 28)
>>>  #define GICH_LR_PENDING_BIT		(1 << 28)
>>>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
>>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>>> new file mode 100644
>>> index 0000000..4cee616
>>> --- /dev/null
>>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>>> @@ -0,0 +1,178 @@
>>> +/*
>>> + * Copyright (C) 2015, 2016 ARM Ltd.
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + * GNU General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU General Public License
>>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>> + */
>>> +
>>> +#include <linux/irqchip/arm-gic.h>
>>> +#include <linux/kvm.h>
>>> +#include <linux/kvm_host.h>
>>> +
>>> +#include "vgic.h"
>>> +
>>> +/*
>>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>>> + *
>>> + * Warning: Calling this function may modify *val.
>>> + */
>>> +static unsigned long *u64_to_bitmask(u64 *val)
>>> +{
>>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>>> +	*val = (*val >> 32) | (*val << 32);
>>> +#endif
>>> +	return (unsigned long *)val;
>>> +}
>>> +
>>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>>> +{
>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>> +
>>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>>> +		u64 eisr = cpuif->vgic_eisr;
>>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>>> +		int lr;
>>> +
>>> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
>>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
>>> +
>>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
>>> +
>>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>>> +
>>
>> why do we need to do this?  I cannot find any consumers of this info
>> after we've left the hyp code.
> 
> I believe that's for vhost and irqfd. Or am I misreading your question?
Yes that's for irqfd. It triggers the resamplerfd which then "VFIO
unmasks" the IRQ

Eric
> 
>> Also, I think I offered a comment about why we would potentially need
>> this in the first place.  This is the famous race where hardware doesn't
>> guarantee consistency between the MISR and ELRSR right?
> 
> That's the one (except it is between EISR and ELRSR). I don't have your
> initial comment at hand, but would something like the following do?
> 
> 			/*
> 			 * The maintenance interrupt may not have had a
> 			 * chance to update ELRSR, so let's mark the LRs
> 			 * presents in EISR as empty.
> 			 */
>>
>>> +			cpuif->vgic_elrsr |= 1ULL << lr;
>>> +		}
>>> +	}
> 
> Thanks,
> 
> 	M.
> 


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

* [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
@ 2016-05-10 13:49         ` Eric Auger
  0 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10 13:49 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/10/2016 03:42 PM, Marc Zyngier wrote:
> On 10/05/16 14:30, Christoffer Dall wrote:
>> On Fri, May 06, 2016 at 11:45:31AM +0100, Andre Przywara wrote:
>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>
>>> Processing maintenance interrupts and accessing the list registers
>>> are dependent on the host's GIC version.
>>> Introduce vgic-v2.c to contain GICv2 specific functions.
>>> Implement the GICv2 specific code for syncing the emulation state
>>> into the VGIC registers.
>>>
>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>> Changelog RFC..v1:
>>> - remove explicit LR_STATE clearing on maintenance interrupt handling
>>> - improve documentation for vgic_v2_populate_lr()
>>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
>>> - simplify multi-CPU source SGI handling
>>>
>>> Changelog v1 .. v2:
>>> - inject the IRQ priority into the list register
>>>
>>> Changelog v2 .. v3:
>>> - cleanup diff containing rebase artifacts
>>>
>>>  include/linux/irqchip/arm-gic.h |   1 +
>>>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>>>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>>>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>>>  4 files changed, 191 insertions(+)
>>>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>>>
>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>>> index 9c94026..be0d26f 100644
>>> --- a/include/linux/irqchip/arm-gic.h
>>> +++ b/include/linux/irqchip/arm-gic.h
>>> @@ -76,6 +76,7 @@
>>>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>>>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>>>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
>>> +#define GICH_LR_PRIORITY_SHIFT		23
>>>  #define GICH_LR_STATE			(3 << 28)
>>>  #define GICH_LR_PENDING_BIT		(1 << 28)
>>>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
>>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>>> new file mode 100644
>>> index 0000000..4cee616
>>> --- /dev/null
>>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>>> @@ -0,0 +1,178 @@
>>> +/*
>>> + * Copyright (C) 2015, 2016 ARM Ltd.
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + * GNU General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU General Public License
>>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>> + */
>>> +
>>> +#include <linux/irqchip/arm-gic.h>
>>> +#include <linux/kvm.h>
>>> +#include <linux/kvm_host.h>
>>> +
>>> +#include "vgic.h"
>>> +
>>> +/*
>>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>>> + *
>>> + * Warning: Calling this function may modify *val.
>>> + */
>>> +static unsigned long *u64_to_bitmask(u64 *val)
>>> +{
>>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>>> +	*val = (*val >> 32) | (*val << 32);
>>> +#endif
>>> +	return (unsigned long *)val;
>>> +}
>>> +
>>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>>> +{
>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>> +
>>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>>> +		u64 eisr = cpuif->vgic_eisr;
>>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>>> +		int lr;
>>> +
>>> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
>>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
>>> +
>>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
>>> +
>>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>>> +
>>
>> why do we need to do this?  I cannot find any consumers of this info
>> after we've left the hyp code.
> 
> I believe that's for vhost and irqfd. Or am I misreading your question?
Yes that's for irqfd. It triggers the resamplerfd which then "VFIO
unmasks" the IRQ

Eric
> 
>> Also, I think I offered a comment about why we would potentially need
>> this in the first place.  This is the famous race where hardware doesn't
>> guarantee consistency between the MISR and ELRSR right?
> 
> That's the one (except it is between EISR and ELRSR). I don't have your
> initial comment at hand, but would something like the following do?
> 
> 			/*
> 			 * The maintenance interrupt may not have had a
> 			 * chance to update ELRSR, so let's mark the LRs
> 			 * presents in EISR as empty.
> 			 */
>>
>>> +			cpuif->vgic_elrsr |= 1ULL << lr;
>>> +		}
>>> +	}
> 
> Thanks,
> 
> 	M.
> 

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

* Re: [PATCH v3 17/55] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10 13:53     ` Eric Auger
  -1 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10 13:53 UTC (permalink / raw)
  To: Andre Przywara, Marc Zyngier, Christoffer Dall
  Cc: kvmarm, linux-arm-kernel, kvm

On 05/06/2016 12:45 PM, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Implement the framework for syncing IRQs between our emulation and
> the list registers, which represent the guest's view of IRQs.
> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
> which gets called on guest entry and exit.
> The code talking to the actual GICv2/v3 hardware is added in the
> following patches.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - split out vgic_clear_lr() from vgic_populate_lr()
> - rename vgic_populate_lrs() to vgic_flush_lr_state()
> - clean all LRs when the distributor is disabled
> - use list_del() instead of list_del_init()
> - add comments to explain the direction of sync/flush_hwstate
> - remove unneeded BUG_ON(in_interrupt()
> 
> Changelog v2 .. v3:
> - remove bogus v2 specific rebase leftovers
> 
>  include/kvm/vgic/vgic.h  |   4 +
>  virt/kvm/arm/vgic/vgic.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h |   2 +
>  3 files changed, 199 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 2bfb42c..5fae4a9 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -190,6 +190,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>  
> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
> +
>  /**
>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>   *
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 4fb20fd..c6f8b9b 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -305,3 +305,196 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  {
>  	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
>  }
> +
> +/**
> + * vgic_prune_ap_list - Remove non-relevant interrupts from the list
> + *
> + * @vcpu: The VCPU pointer
> + *
> + * Go over the list of "interesting" interrupts, and prune those that we
> + * won't have to consider in the near future.
> + */
> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq, *tmp;
> +
> +retry:
> +	spin_lock(&vgic_cpu->ap_list_lock);
> +
> +	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
> +		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		BUG_ON(vcpu != irq->vcpu);
> +
> +		target_vcpu = vgic_target_oracle(irq);
> +
> +		if (!target_vcpu) {
> +			/*
> +			 * We don't need to process this interrupt any
> +			 * further, move it off the list.
> +			 */
> +			list_del(&irq->ap_list);
> +			irq->vcpu = NULL;
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		if (target_vcpu == vcpu) {
> +			/* We're on the right CPU */
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		/* This interrupt looks like it has to be migrated. */
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vgic_cpu->ap_list_lock);
> +
> +		/*
> +		 * Ensure locking order by always locking the smallest
> +		 * ID first.
> +		 */
> +		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
> +			vcpuA = vcpu;
> +			vcpuB = target_vcpu;
> +		} else {
> +			vcpuA = target_vcpu;
> +			vcpuB = vcpu;
> +		}
> +
> +		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&irq->irq_lock);
> +
> +		/*
> +		 * If the affinity has been preserved, move the
> +		 * interrupt around. Otherwise, it means things have
> +		 * changed while the interrupt was unlocked, and we
> +		 * need to replay this.
> +		 *
> +		 * In all cases, we cannot trust the list not to have
> +		 * changed, so we restart from the beginning.
> +		 */
> +		if (target_vcpu == vgic_target_oracle(irq)) {
> +			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
> +
> +			list_del(&irq->ap_list);
> +			irq->vcpu = target_vcpu;
> +			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		goto retry;
> +	}
> +
> +	spin_unlock(&vgic_cpu->ap_list_lock);
> +}
> +
> +static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +/* Requires the ap_list_lock and the irq_lock to be held. */
> +static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
> +				    struct vgic_irq *irq, int lr)
> +{
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
> +}
> +
> +static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
> +{
> +}
> +
> +static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +}
> +

nit: we may add a comment for compute_ap_list_depth, saying
vgic_cpu->ap_list_lock must be held

Besides Reviewed-by: Eric Auger <eric.auger@linaro.org>

Eric
> +static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +		/* GICv2 SGIs can count for more than one... */
> +		if (vgic_irq_is_sgi(irq->intid) && irq->source)
> +			count += hweight8(irq->source);
> +		else
> +			count++;
> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return count;
> +}
> +
> +/* Requires the VCPU's ap_list_lock to be held. */
> +static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
> +
> +	if (unlikely(!vcpu->kvm->arch.vgic.enabled))
> +		goto out_clean;
> +
> +	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
> +		vgic_set_underflow(vcpu);
> +		vgic_sort_ap_list(vcpu);
> +	}
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +
> +		if (unlikely(vgic_target_oracle(irq) != vcpu))
> +			goto next;
> +
> +		/*
> +		 * If we get an SGI with multiple sources, try to get
> +		 * them in all at once.
> +		 */
> +		do {
> +			vgic_populate_lr(vcpu, irq, count++);
> +		} while (irq->source && count < kvm_vgic_global_state.nr_lr);
> +
> +next:
> +		spin_unlock(&irq->irq_lock);
> +
> +		if (count == kvm_vgic_global_state.nr_lr)
> +			break;
> +	}
> +
> +out_clean:
> +	vcpu->arch.vgic_cpu.used_lrs = count;
> +
> +	/* Nuke remaining LRs */
> +	for ( ; count < kvm_vgic_global_state.nr_lr; count++)
> +		vgic_clear_lr(vcpu, count);
> +}
> +
> +/* Sync back the hardware VGIC state into our emulation after a guest's run. */
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	vgic_process_maintenance_interrupt(vcpu);
> +	vgic_fold_lr_state(vcpu);
> +	vgic_prune_ap_list(vcpu);
> +}
> +
> +/* Flush our emulation state into the GIC hardware before entering the guest. */
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +	vgic_flush_lr_state(vcpu);
> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index c625767..29b96b9 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -16,6 +16,8 @@
>  #ifndef __KVM_ARM_VGIC_NEW_H__
>  #define __KVM_ARM_VGIC_NEW_H__
>  
> +#define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
> +
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
> 

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

* [PATCH v3 17/55] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
@ 2016-05-10 13:53     ` Eric Auger
  0 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10 13:53 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/06/2016 12:45 PM, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Implement the framework for syncing IRQs between our emulation and
> the list registers, which represent the guest's view of IRQs.
> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
> which gets called on guest entry and exit.
> The code talking to the actual GICv2/v3 hardware is added in the
> following patches.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - split out vgic_clear_lr() from vgic_populate_lr()
> - rename vgic_populate_lrs() to vgic_flush_lr_state()
> - clean all LRs when the distributor is disabled
> - use list_del() instead of list_del_init()
> - add comments to explain the direction of sync/flush_hwstate
> - remove unneeded BUG_ON(in_interrupt()
> 
> Changelog v2 .. v3:
> - remove bogus v2 specific rebase leftovers
> 
>  include/kvm/vgic/vgic.h  |   4 +
>  virt/kvm/arm/vgic/vgic.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h |   2 +
>  3 files changed, 199 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 2bfb42c..5fae4a9 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -190,6 +190,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>  
> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
> +
>  /**
>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>   *
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 4fb20fd..c6f8b9b 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -305,3 +305,196 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  {
>  	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
>  }
> +
> +/**
> + * vgic_prune_ap_list - Remove non-relevant interrupts from the list
> + *
> + * @vcpu: The VCPU pointer
> + *
> + * Go over the list of "interesting" interrupts, and prune those that we
> + * won't have to consider in the near future.
> + */
> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq, *tmp;
> +
> +retry:
> +	spin_lock(&vgic_cpu->ap_list_lock);
> +
> +	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
> +		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		BUG_ON(vcpu != irq->vcpu);
> +
> +		target_vcpu = vgic_target_oracle(irq);
> +
> +		if (!target_vcpu) {
> +			/*
> +			 * We don't need to process this interrupt any
> +			 * further, move it off the list.
> +			 */
> +			list_del(&irq->ap_list);
> +			irq->vcpu = NULL;
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		if (target_vcpu == vcpu) {
> +			/* We're on the right CPU */
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		/* This interrupt looks like it has to be migrated. */
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vgic_cpu->ap_list_lock);
> +
> +		/*
> +		 * Ensure locking order by always locking the smallest
> +		 * ID first.
> +		 */
> +		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
> +			vcpuA = vcpu;
> +			vcpuB = target_vcpu;
> +		} else {
> +			vcpuA = target_vcpu;
> +			vcpuB = vcpu;
> +		}
> +
> +		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&irq->irq_lock);
> +
> +		/*
> +		 * If the affinity has been preserved, move the
> +		 * interrupt around. Otherwise, it means things have
> +		 * changed while the interrupt was unlocked, and we
> +		 * need to replay this.
> +		 *
> +		 * In all cases, we cannot trust the list not to have
> +		 * changed, so we restart from the beginning.
> +		 */
> +		if (target_vcpu == vgic_target_oracle(irq)) {
> +			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
> +
> +			list_del(&irq->ap_list);
> +			irq->vcpu = target_vcpu;
> +			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		goto retry;
> +	}
> +
> +	spin_unlock(&vgic_cpu->ap_list_lock);
> +}
> +
> +static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +/* Requires the ap_list_lock and the irq_lock to be held. */
> +static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
> +				    struct vgic_irq *irq, int lr)
> +{
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
> +}
> +
> +static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
> +{
> +}
> +
> +static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +}
> +

nit: we may add a comment for compute_ap_list_depth, saying
vgic_cpu->ap_list_lock must be held

Besides Reviewed-by: Eric Auger <eric.auger@linaro.org>

Eric
> +static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +		/* GICv2 SGIs can count for more than one... */
> +		if (vgic_irq_is_sgi(irq->intid) && irq->source)
> +			count += hweight8(irq->source);
> +		else
> +			count++;
> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return count;
> +}
> +
> +/* Requires the VCPU's ap_list_lock to be held. */
> +static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
> +
> +	if (unlikely(!vcpu->kvm->arch.vgic.enabled))
> +		goto out_clean;
> +
> +	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
> +		vgic_set_underflow(vcpu);
> +		vgic_sort_ap_list(vcpu);
> +	}
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +
> +		if (unlikely(vgic_target_oracle(irq) != vcpu))
> +			goto next;
> +
> +		/*
> +		 * If we get an SGI with multiple sources, try to get
> +		 * them in all at once.
> +		 */
> +		do {
> +			vgic_populate_lr(vcpu, irq, count++);
> +		} while (irq->source && count < kvm_vgic_global_state.nr_lr);
> +
> +next:
> +		spin_unlock(&irq->irq_lock);
> +
> +		if (count == kvm_vgic_global_state.nr_lr)
> +			break;
> +	}
> +
> +out_clean:
> +	vcpu->arch.vgic_cpu.used_lrs = count;
> +
> +	/* Nuke remaining LRs */
> +	for ( ; count < kvm_vgic_global_state.nr_lr; count++)
> +		vgic_clear_lr(vcpu, count);
> +}
> +
> +/* Sync back the hardware VGIC state into our emulation after a guest's run. */
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	vgic_process_maintenance_interrupt(vcpu);
> +	vgic_fold_lr_state(vcpu);
> +	vgic_prune_ap_list(vcpu);
> +}
> +
> +/* Flush our emulation state into the GIC hardware before entering the guest. */
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +	vgic_flush_lr_state(vcpu);
> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index c625767..29b96b9 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -16,6 +16,8 @@
>  #ifndef __KVM_ARM_VGIC_NEW_H__
>  #define __KVM_ARM_VGIC_NEW_H__
>  
> +#define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
> +
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
> 

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

* Re: [PATCH v3 19/55] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10 14:04     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-10 14:04 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:45:32AM +0100, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> As the GICv3 virtual interface registers differ from their GICv2
> siblings, we need different handlers for processing maintenance
> interrupts and reading/writing to the LRs.
> Implement the respective handler functions and connect them to
> existing code to be called if the host is using a GICv3.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - remove outdated comment about the dist_lock
> - add WARN_ON about LR_STATE not being 0 in maintenance interrupts
> 
> Changelog v1 .. v2:
> - inject the IRQ priority into the list register
> 
> Changelog v2 .. v3:
> - remove no longer needed irqchip/arm-gic.h inclusion
> 
>  include/linux/irqchip/arm-gic-v3.h |   1 +
>  virt/kvm/arm/vgic/vgic-v3.c        | 168 +++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.c           |  25 ++++--
>  virt/kvm/arm/vgic/vgic.h           |  29 +++++++
>  4 files changed, 218 insertions(+), 5 deletions(-)
>  create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index ec938d1..35e93cf 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -275,6 +275,7 @@
>  #define ICH_LR_ACTIVE_BIT		(1ULL << 63)
>  #define ICH_LR_PHYS_ID_SHIFT		32
>  #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
> +#define ICH_LR_PRIORITY_SHIFT		48
>  
>  /* These are for GICv2 emulation only */
>  #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> new file mode 100644
> index 0000000..43d1dd7
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -0,0 +1,168 @@
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/irqchip/arm-gic-v3.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +
> +#include "vgic.h"
> +
> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +
> +	if (cpuif->vgic_misr & ICH_MISR_EOI) {
> +		unsigned long eisr_bmap = cpuif->vgic_eisr;
> +		int lr;
> +
> +		for_each_set_bit(lr, &eisr_bmap, kvm_vgic_global_state.nr_lr) {
> +			u32 intid;
> +			u64 val = cpuif->vgic_lr[lr];
> +
> +			if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +				intid = val & ICH_LR_VIRTUAL_ID_MASK;
> +			else
> +				intid = val & GICH_LR_VIRTUALID;
> +
> +			WARN_ON(cpuif->vgic_lr[lr] & ICH_LR_STATE);
> +
> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> +					     intid - VGIC_NR_PRIVATE_IRQS);
> +

same question as on the last patch

> +			cpuif->vgic_elrsr |= 1ULL << lr;
> +		}
> +
> +		/*
> +		 * In the next iterations of the vcpu loop, if we sync
> +		 * the vgic state after flushing it, but before
> +		 * entering the guest (this happens for pending
> +		 * signals and vmid rollovers), then make sure we
> +		 * don't pick up any old maintenance interrupts here.
> +		 */
> +		cpuif->vgic_eisr = 0;
> +	}
> +
> +	cpuif->vgic_hcr &= ~ICH_HCR_UIE;
> +}
> +
> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +
> +	cpuif->vgic_hcr |= ICH_HCR_UIE;
> +}
> +
> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	int lr;
> +
> +	/* Assumes ap_list_lock held */
> +
> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> +		u64 val = cpuif->vgic_lr[lr];
> +		u32 intid;
> +		struct vgic_irq *irq;
> +
> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +			intid = val & ICH_LR_VIRTUAL_ID_MASK;
> +		else
> +			intid = val & GICH_LR_VIRTUALID;
> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		/* Always preserve the active bit */
> +		irq->active = !!(val & ICH_LR_ACTIVE_BIT);
> +
> +		/* Edge is the only case where we preserve the pending bit */
> +		if (irq->config == VGIC_CONFIG_EDGE &&
> +		    (val & ICH_LR_PENDING_BIT)) {
> +			irq->pending = true;
> +
> +			if (vgic_irq_is_sgi(intid) &&
> +			    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> +
> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> +				irq->source |= (1 << cpuid);
> +			}
> +		}
> +
> +		/* Clear soft pending state when level irqs have been acked */
> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> +		    !(val & ICH_LR_PENDING_BIT)) {
> +			irq->soft_pending = false;
> +			irq->pending = irq->line_level;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +/* Requires the irq to be locked already */
> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> +{
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	u64 val = irq->intid;
> +
> +	if (irq->pending) {
> +		val |= ICH_LR_PENDING_BIT;
> +
> +		if (irq->config == VGIC_CONFIG_EDGE)
> +			irq->pending = false;
> +
> +		if (vgic_irq_is_sgi(irq->intid) &&
> +		    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> +			u32 src = ffs(irq->source);
> +
> +			BUG_ON(!src);
> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> +			irq->source &= ~(1 << (src - 1));
> +			if (irq->source)
> +				irq->pending = true;
> +		}
> +	}
> +
> +	if (irq->active)
> +		val |= ICH_LR_ACTIVE_BIT;
> +
> +	if (irq->hw) {
> +		val |= ICH_LR_HW;
> +		val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
> +	} else {
> +		if (irq->config == VGIC_CONFIG_LEVEL)
> +			val |= ICH_LR_EOI;
> +	}
> +
> +	/*
> +	 * Currently all guest IRQs are Group1, as Group0 would result
> +	 * in a FIQ in the guest, which it wouldn't expect.

I still don't like or understand this comment.  This should simply say
that we're making a gross assumption about all interrupts being group1
here.

> +	 * Eventually we want to make this configurable, so we may
> +	 * revisit this in the future.
> +	 */
> +	if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +		val |= ICH_LR_GROUP;
> +
> +	val |= (u64)irq->priority << ICH_LR_PRIORITY_SHIFT;
> +
> +	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = val;
> +}
> +
> +void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
> +{
> +	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = 0;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 68d885c..64d5b45 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -397,12 +397,18 @@ retry:
>  
>  static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>  {
> -	vgic_v2_process_maintenance(vcpu);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_process_maintenance(vcpu);
> +	else
> +		vgic_v3_process_maintenance(vcpu);
>  }
>  
>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>  {
> -	vgic_v2_fold_lr_state(vcpu);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_fold_lr_state(vcpu);
> +	else
> +		vgic_v3_fold_lr_state(vcpu);
>  }
>  
>  /* Requires the ap_list_lock and the irq_lock to be held. */
> @@ -412,17 +418,26 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
>  
> -	vgic_v2_populate_lr(vcpu, irq, lr);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_populate_lr(vcpu, irq, lr);
> +	else
> +		vgic_v3_populate_lr(vcpu, irq, lr);
>  }
>  
>  static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
>  {
> -	vgic_v2_clear_lr(vcpu, lr);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_clear_lr(vcpu, lr);
> +	else
> +		vgic_v3_clear_lr(vcpu, lr);
>  }
>  
>  static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>  {
> -	vgic_v2_set_underflow(vcpu);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_set_underflow(vcpu);
> +	else
> +		vgic_v3_set_underflow(vcpu);
>  }
>  
>  static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 0db490e..81b1a20 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -28,4 +28,33 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
>  void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>  
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
> +void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
> +#else
> +static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static inline void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static inline void vgic_v3_populate_lr(struct kvm_vcpu *vcpu,
> +				       struct vgic_irq *irq, int lr)
> +{
> +}
> +
> +static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
> +{
> +}
> +
> +static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +}
> +#endif
> +
>  #endif
> -- 
> 2.7.3
> 

Otherwise:

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

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

* [PATCH v3 19/55] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
@ 2016-05-10 14:04     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-10 14:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:32AM +0100, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> As the GICv3 virtual interface registers differ from their GICv2
> siblings, we need different handlers for processing maintenance
> interrupts and reading/writing to the LRs.
> Implement the respective handler functions and connect them to
> existing code to be called if the host is using a GICv3.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - remove outdated comment about the dist_lock
> - add WARN_ON about LR_STATE not being 0 in maintenance interrupts
> 
> Changelog v1 .. v2:
> - inject the IRQ priority into the list register
> 
> Changelog v2 .. v3:
> - remove no longer needed irqchip/arm-gic.h inclusion
> 
>  include/linux/irqchip/arm-gic-v3.h |   1 +
>  virt/kvm/arm/vgic/vgic-v3.c        | 168 +++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.c           |  25 ++++--
>  virt/kvm/arm/vgic/vgic.h           |  29 +++++++
>  4 files changed, 218 insertions(+), 5 deletions(-)
>  create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index ec938d1..35e93cf 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -275,6 +275,7 @@
>  #define ICH_LR_ACTIVE_BIT		(1ULL << 63)
>  #define ICH_LR_PHYS_ID_SHIFT		32
>  #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
> +#define ICH_LR_PRIORITY_SHIFT		48
>  
>  /* These are for GICv2 emulation only */
>  #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> new file mode 100644
> index 0000000..43d1dd7
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -0,0 +1,168 @@
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/irqchip/arm-gic-v3.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +
> +#include "vgic.h"
> +
> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +
> +	if (cpuif->vgic_misr & ICH_MISR_EOI) {
> +		unsigned long eisr_bmap = cpuif->vgic_eisr;
> +		int lr;
> +
> +		for_each_set_bit(lr, &eisr_bmap, kvm_vgic_global_state.nr_lr) {
> +			u32 intid;
> +			u64 val = cpuif->vgic_lr[lr];
> +
> +			if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +				intid = val & ICH_LR_VIRTUAL_ID_MASK;
> +			else
> +				intid = val & GICH_LR_VIRTUALID;
> +
> +			WARN_ON(cpuif->vgic_lr[lr] & ICH_LR_STATE);
> +
> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> +					     intid - VGIC_NR_PRIVATE_IRQS);
> +

same question as on the last patch

> +			cpuif->vgic_elrsr |= 1ULL << lr;
> +		}
> +
> +		/*
> +		 * In the next iterations of the vcpu loop, if we sync
> +		 * the vgic state after flushing it, but before
> +		 * entering the guest (this happens for pending
> +		 * signals and vmid rollovers), then make sure we
> +		 * don't pick up any old maintenance interrupts here.
> +		 */
> +		cpuif->vgic_eisr = 0;
> +	}
> +
> +	cpuif->vgic_hcr &= ~ICH_HCR_UIE;
> +}
> +
> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +
> +	cpuif->vgic_hcr |= ICH_HCR_UIE;
> +}
> +
> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	int lr;
> +
> +	/* Assumes ap_list_lock held */
> +
> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> +		u64 val = cpuif->vgic_lr[lr];
> +		u32 intid;
> +		struct vgic_irq *irq;
> +
> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +			intid = val & ICH_LR_VIRTUAL_ID_MASK;
> +		else
> +			intid = val & GICH_LR_VIRTUALID;
> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		/* Always preserve the active bit */
> +		irq->active = !!(val & ICH_LR_ACTIVE_BIT);
> +
> +		/* Edge is the only case where we preserve the pending bit */
> +		if (irq->config == VGIC_CONFIG_EDGE &&
> +		    (val & ICH_LR_PENDING_BIT)) {
> +			irq->pending = true;
> +
> +			if (vgic_irq_is_sgi(intid) &&
> +			    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> +
> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> +				irq->source |= (1 << cpuid);
> +			}
> +		}
> +
> +		/* Clear soft pending state when level irqs have been acked */
> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> +		    !(val & ICH_LR_PENDING_BIT)) {
> +			irq->soft_pending = false;
> +			irq->pending = irq->line_level;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +/* Requires the irq to be locked already */
> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> +{
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	u64 val = irq->intid;
> +
> +	if (irq->pending) {
> +		val |= ICH_LR_PENDING_BIT;
> +
> +		if (irq->config == VGIC_CONFIG_EDGE)
> +			irq->pending = false;
> +
> +		if (vgic_irq_is_sgi(irq->intid) &&
> +		    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> +			u32 src = ffs(irq->source);
> +
> +			BUG_ON(!src);
> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> +			irq->source &= ~(1 << (src - 1));
> +			if (irq->source)
> +				irq->pending = true;
> +		}
> +	}
> +
> +	if (irq->active)
> +		val |= ICH_LR_ACTIVE_BIT;
> +
> +	if (irq->hw) {
> +		val |= ICH_LR_HW;
> +		val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
> +	} else {
> +		if (irq->config == VGIC_CONFIG_LEVEL)
> +			val |= ICH_LR_EOI;
> +	}
> +
> +	/*
> +	 * Currently all guest IRQs are Group1, as Group0 would result
> +	 * in a FIQ in the guest, which it wouldn't expect.

I still don't like or understand this comment.  This should simply say
that we're making a gross assumption about all interrupts being group1
here.

> +	 * Eventually we want to make this configurable, so we may
> +	 * revisit this in the future.
> +	 */
> +	if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +		val |= ICH_LR_GROUP;
> +
> +	val |= (u64)irq->priority << ICH_LR_PRIORITY_SHIFT;
> +
> +	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = val;
> +}
> +
> +void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
> +{
> +	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = 0;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 68d885c..64d5b45 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -397,12 +397,18 @@ retry:
>  
>  static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>  {
> -	vgic_v2_process_maintenance(vcpu);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_process_maintenance(vcpu);
> +	else
> +		vgic_v3_process_maintenance(vcpu);
>  }
>  
>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>  {
> -	vgic_v2_fold_lr_state(vcpu);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_fold_lr_state(vcpu);
> +	else
> +		vgic_v3_fold_lr_state(vcpu);
>  }
>  
>  /* Requires the ap_list_lock and the irq_lock to be held. */
> @@ -412,17 +418,26 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
>  
> -	vgic_v2_populate_lr(vcpu, irq, lr);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_populate_lr(vcpu, irq, lr);
> +	else
> +		vgic_v3_populate_lr(vcpu, irq, lr);
>  }
>  
>  static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
>  {
> -	vgic_v2_clear_lr(vcpu, lr);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_clear_lr(vcpu, lr);
> +	else
> +		vgic_v3_clear_lr(vcpu, lr);
>  }
>  
>  static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>  {
> -	vgic_v2_set_underflow(vcpu);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_set_underflow(vcpu);
> +	else
> +		vgic_v3_set_underflow(vcpu);
>  }
>  
>  static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 0db490e..81b1a20 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -28,4 +28,33 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
>  void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>  
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
> +void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
> +#else
> +static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static inline void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static inline void vgic_v3_populate_lr(struct kvm_vcpu *vcpu,
> +				       struct vgic_irq *irq, int lr)
> +{
> +}
> +
> +static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
> +{
> +}
> +
> +static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +}
> +#endif
> +
>  #endif
> -- 
> 2.7.3
> 

Otherwise:

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

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

* Re: [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10 14:10     ` Eric Auger
  -1 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10 14:10 UTC (permalink / raw)
  To: Andre Przywara, Marc Zyngier, Christoffer Dall
  Cc: kvmarm, kvm, linux-arm-kernel

On 05/06/2016 12:45 PM, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Processing maintenance interrupts and accessing the list registers
> are dependent on the host's GIC version.
> Introduce vgic-v2.c to contain GICv2 specific functions.
> Implement the GICv2 specific code for syncing the emulation state
> into the VGIC registers.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - remove explicit LR_STATE clearing on maintenance interrupt handling
> - improve documentation for vgic_v2_populate_lr()
> - remove WARN_ON on non-edge IRQs in maintenance interrupts
> - simplify multi-CPU source SGI handling
> 
> Changelog v1 .. v2:
> - inject the IRQ priority into the list register
> 
> Changelog v2 .. v3:
> - cleanup diff containing rebase artifacts
> 
>  include/linux/irqchip/arm-gic.h |   1 +
>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>  4 files changed, 191 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
> 
> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> index 9c94026..be0d26f 100644
> --- a/include/linux/irqchip/arm-gic.h
> +++ b/include/linux/irqchip/arm-gic.h
> @@ -76,6 +76,7 @@
>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
> +#define GICH_LR_PRIORITY_SHIFT		23
>  #define GICH_LR_STATE			(3 << 28)
>  #define GICH_LR_PENDING_BIT		(1 << 28)
>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> new file mode 100644
> index 0000000..4cee616
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -0,0 +1,178 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/irqchip/arm-gic.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +
> +#include "vgic.h"
> +
> +/*
> + * Call this function to convert a u64 value to an unsigned long * bitmask
> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
> + *
> + * Warning: Calling this function may modify *val.
> + */
> +static unsigned long *u64_to_bitmask(u64 *val)
> +{
> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
> +	*val = (*val >> 32) | (*val << 32);
> +#endif
> +	return (unsigned long *)val;
> +}
> +
> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +
> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
> +		u64 eisr = cpuif->vgic_eisr;
> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
> +		int lr;
> +
> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
Didn't we say we could use vcpu->arch.vgic_cpu.used_lrs here?
> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
> +
> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
> +
> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> +					     intid - VGIC_NR_PRIVATE_IRQS);
> +
> +			cpuif->vgic_elrsr |= 1ULL << lr;
> +		}
> +	}
> +
> +	/* check and disable underflow maintenance IRQ */
check?

Besides
Reviewed-by: Eric Auger <eric.auger@linaro.org>

Eric
> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
> +
> +	/*
> +	 * In the next iterations of the vcpu loop, if we sync the
> +	 * vgic state after flushing it, but before entering the guest
> +	 * (this happens for pending signals and vmid rollovers), then
> +	 * make sure we don't pick up any old maintenance interrupts
> +	 * here.
> +	 */
> +	cpuif->vgic_eisr = 0;
> +}
> +
> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +
> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
> +}
> +
> +/*
> + * transfer the content of the LRs back into the corresponding ap_list:
> + * - active bit is transferred as is
> + * - pending bit is
> + *   - transferred as is in case of edge sensitive IRQs
> + *   - set to the line-level (resample time) for level sensitive IRQs
> + */
> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +	int lr;
> +
> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> +		u32 val = cpuif->vgic_lr[lr];
> +		u32 intid = val & GICH_LR_VIRTUALID;
> +		struct vgic_irq *irq;
> +
> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		/* Always preserve the active bit */
> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
> +
> +		/* Edge is the only case where we preserve the pending bit */
> +		if (irq->config == VGIC_CONFIG_EDGE &&
> +		    (val & GICH_LR_PENDING_BIT)) {
> +			irq->pending = true;
> +
> +			if (vgic_irq_is_sgi(intid)) {
> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> +
> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> +				irq->source |= (1 << cpuid);
> +			}
> +		}
> +
> +		/* Clear soft pending state when level IRQs have been acked */
> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> +		    !(val & GICH_LR_PENDING_BIT)) {
> +			irq->soft_pending = false;
> +			irq->pending = irq->line_level;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +/*
> + * Populates the particular LR with the state of a given IRQ:
> + * - for an edge sensitive IRQ the pending state is cleared in struct vgic_irq
> + * - for a level sensitive IRQ the pending state value is unchanged;
> + *   it is dictated directly by the input level
> + *
> + * If @irq describes an SGI with multiple sources, we choose the
> + * lowest-numbered source VCPU and clear that bit in the source bitmap.
> + *
> + * The irq_lock must be held by the caller.
> + */
> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> +{
> +	u32 val = irq->intid;
> +
> +	if (irq->pending) {
> +		val |= GICH_LR_PENDING_BIT;
> +
> +		if (irq->config == VGIC_CONFIG_EDGE)
> +			irq->pending = false;
> +
> +		if (vgic_irq_is_sgi(irq->intid)) {
> +			u32 src = ffs(irq->source);
> +
> +			BUG_ON(!src);
> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> +			irq->source &= ~(1 << (src - 1));
> +			if (irq->source)
> +				irq->pending = true;
> +		}
> +	}
> +
> +	if (irq->active)
> +		val |= GICH_LR_ACTIVE_BIT;
> +
> +	if (irq->hw) {
> +		val |= GICH_LR_HW;
> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
> +	} else {
> +		if (irq->config == VGIC_CONFIG_LEVEL)
> +			val |= GICH_LR_EOI;
> +	}
> +
> +	/* The GICv2 LR only holds five bits of priority. */
> +	val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
> +
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
> +}
> +
> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
> +{
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index c6f8b9b..68d885c 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -397,10 +397,12 @@ retry:
>  
>  static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>  {
> +	vgic_v2_process_maintenance(vcpu);
>  }
>  
>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>  {
> +	vgic_v2_fold_lr_state(vcpu);
>  }
>  
>  /* Requires the ap_list_lock and the irq_lock to be held. */
> @@ -409,14 +411,18 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>  {
>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
> +
> +	vgic_v2_populate_lr(vcpu, irq, lr);
>  }
>  
>  static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
>  {
> +	vgic_v2_clear_lr(vcpu, lr);
>  }
>  
>  static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>  {
> +	vgic_v2_set_underflow(vcpu);
>  }
>  
>  static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 29b96b9..0db490e 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -22,4 +22,10 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
>  
> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
> +
>  #endif
> 


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

* [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
@ 2016-05-10 14:10     ` Eric Auger
  0 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10 14:10 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/06/2016 12:45 PM, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Processing maintenance interrupts and accessing the list registers
> are dependent on the host's GIC version.
> Introduce vgic-v2.c to contain GICv2 specific functions.
> Implement the GICv2 specific code for syncing the emulation state
> into the VGIC registers.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - remove explicit LR_STATE clearing on maintenance interrupt handling
> - improve documentation for vgic_v2_populate_lr()
> - remove WARN_ON on non-edge IRQs in maintenance interrupts
> - simplify multi-CPU source SGI handling
> 
> Changelog v1 .. v2:
> - inject the IRQ priority into the list register
> 
> Changelog v2 .. v3:
> - cleanup diff containing rebase artifacts
> 
>  include/linux/irqchip/arm-gic.h |   1 +
>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>  4 files changed, 191 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
> 
> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> index 9c94026..be0d26f 100644
> --- a/include/linux/irqchip/arm-gic.h
> +++ b/include/linux/irqchip/arm-gic.h
> @@ -76,6 +76,7 @@
>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
> +#define GICH_LR_PRIORITY_SHIFT		23
>  #define GICH_LR_STATE			(3 << 28)
>  #define GICH_LR_PENDING_BIT		(1 << 28)
>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> new file mode 100644
> index 0000000..4cee616
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -0,0 +1,178 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/irqchip/arm-gic.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +
> +#include "vgic.h"
> +
> +/*
> + * Call this function to convert a u64 value to an unsigned long * bitmask
> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
> + *
> + * Warning: Calling this function may modify *val.
> + */
> +static unsigned long *u64_to_bitmask(u64 *val)
> +{
> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
> +	*val = (*val >> 32) | (*val << 32);
> +#endif
> +	return (unsigned long *)val;
> +}
> +
> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +
> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
> +		u64 eisr = cpuif->vgic_eisr;
> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
> +		int lr;
> +
> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
Didn't we say we could use vcpu->arch.vgic_cpu.used_lrs here?
> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
> +
> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
> +
> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> +					     intid - VGIC_NR_PRIVATE_IRQS);
> +
> +			cpuif->vgic_elrsr |= 1ULL << lr;
> +		}
> +	}
> +
> +	/* check and disable underflow maintenance IRQ */
check?

Besides
Reviewed-by: Eric Auger <eric.auger@linaro.org>

Eric
> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
> +
> +	/*
> +	 * In the next iterations of the vcpu loop, if we sync the
> +	 * vgic state after flushing it, but before entering the guest
> +	 * (this happens for pending signals and vmid rollovers), then
> +	 * make sure we don't pick up any old maintenance interrupts
> +	 * here.
> +	 */
> +	cpuif->vgic_eisr = 0;
> +}
> +
> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +
> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
> +}
> +
> +/*
> + * transfer the content of the LRs back into the corresponding ap_list:
> + * - active bit is transferred as is
> + * - pending bit is
> + *   - transferred as is in case of edge sensitive IRQs
> + *   - set to the line-level (resample time) for level sensitive IRQs
> + */
> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> +	int lr;
> +
> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> +		u32 val = cpuif->vgic_lr[lr];
> +		u32 intid = val & GICH_LR_VIRTUALID;
> +		struct vgic_irq *irq;
> +
> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		/* Always preserve the active bit */
> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
> +
> +		/* Edge is the only case where we preserve the pending bit */
> +		if (irq->config == VGIC_CONFIG_EDGE &&
> +		    (val & GICH_LR_PENDING_BIT)) {
> +			irq->pending = true;
> +
> +			if (vgic_irq_is_sgi(intid)) {
> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> +
> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> +				irq->source |= (1 << cpuid);
> +			}
> +		}
> +
> +		/* Clear soft pending state when level IRQs have been acked */
> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> +		    !(val & GICH_LR_PENDING_BIT)) {
> +			irq->soft_pending = false;
> +			irq->pending = irq->line_level;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +/*
> + * Populates the particular LR with the state of a given IRQ:
> + * - for an edge sensitive IRQ the pending state is cleared in struct vgic_irq
> + * - for a level sensitive IRQ the pending state value is unchanged;
> + *   it is dictated directly by the input level
> + *
> + * If @irq describes an SGI with multiple sources, we choose the
> + * lowest-numbered source VCPU and clear that bit in the source bitmap.
> + *
> + * The irq_lock must be held by the caller.
> + */
> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> +{
> +	u32 val = irq->intid;
> +
> +	if (irq->pending) {
> +		val |= GICH_LR_PENDING_BIT;
> +
> +		if (irq->config == VGIC_CONFIG_EDGE)
> +			irq->pending = false;
> +
> +		if (vgic_irq_is_sgi(irq->intid)) {
> +			u32 src = ffs(irq->source);
> +
> +			BUG_ON(!src);
> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> +			irq->source &= ~(1 << (src - 1));
> +			if (irq->source)
> +				irq->pending = true;
> +		}
> +	}
> +
> +	if (irq->active)
> +		val |= GICH_LR_ACTIVE_BIT;
> +
> +	if (irq->hw) {
> +		val |= GICH_LR_HW;
> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
> +	} else {
> +		if (irq->config == VGIC_CONFIG_LEVEL)
> +			val |= GICH_LR_EOI;
> +	}
> +
> +	/* The GICv2 LR only holds five bits of priority. */
> +	val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
> +
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
> +}
> +
> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
> +{
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index c6f8b9b..68d885c 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -397,10 +397,12 @@ retry:
>  
>  static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>  {
> +	vgic_v2_process_maintenance(vcpu);
>  }
>  
>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>  {
> +	vgic_v2_fold_lr_state(vcpu);
>  }
>  
>  /* Requires the ap_list_lock and the irq_lock to be held. */
> @@ -409,14 +411,18 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>  {
>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
> +
> +	vgic_v2_populate_lr(vcpu, irq, lr);
>  }
>  
>  static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
>  {
> +	vgic_v2_clear_lr(vcpu, lr);
>  }
>  
>  static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>  {
> +	vgic_v2_set_underflow(vcpu);
>  }
>  
>  static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 29b96b9..0db490e 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -22,4 +22,10 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
>  
> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
> +
>  #endif
> 

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

* Re: [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
  2016-05-10 13:42       ` Marc Zyngier
@ 2016-05-10 14:11         ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-10 14:11 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: Andre Przywara, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Tue, May 10, 2016 at 02:42:02PM +0100, Marc Zyngier wrote:
> On 10/05/16 14:30, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:31AM +0100, Andre Przywara wrote:
> >> From: Marc Zyngier <marc.zyngier@arm.com>
> >>
> >> Processing maintenance interrupts and accessing the list registers
> >> are dependent on the host's GIC version.
> >> Introduce vgic-v2.c to contain GICv2 specific functions.
> >> Implement the GICv2 specific code for syncing the emulation state
> >> into the VGIC registers.
> >>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changelog RFC..v1:
> >> - remove explicit LR_STATE clearing on maintenance interrupt handling
> >> - improve documentation for vgic_v2_populate_lr()
> >> - remove WARN_ON on non-edge IRQs in maintenance interrupts
> >> - simplify multi-CPU source SGI handling
> >>
> >> Changelog v1 .. v2:
> >> - inject the IRQ priority into the list register
> >>
> >> Changelog v2 .. v3:
> >> - cleanup diff containing rebase artifacts
> >>
> >>  include/linux/irqchip/arm-gic.h |   1 +
> >>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic.c        |   6 ++
> >>  virt/kvm/arm/vgic/vgic.h        |   6 ++
> >>  4 files changed, 191 insertions(+)
> >>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
> >>
> >> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> >> index 9c94026..be0d26f 100644
> >> --- a/include/linux/irqchip/arm-gic.h
> >> +++ b/include/linux/irqchip/arm-gic.h
> >> @@ -76,6 +76,7 @@
> >>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
> >>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
> >>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
> >> +#define GICH_LR_PRIORITY_SHIFT		23
> >>  #define GICH_LR_STATE			(3 << 28)
> >>  #define GICH_LR_PENDING_BIT		(1 << 28)
> >>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
> >> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> >> new file mode 100644
> >> index 0000000..4cee616
> >> --- /dev/null
> >> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> >> @@ -0,0 +1,178 @@
> >> +/*
> >> + * Copyright (C) 2015, 2016 ARM Ltd.
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License version 2 as
> >> + * published by the Free Software Foundation.
> >> + *
> >> + * This program is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >> + * GNU General Public License for more details.
> >> + *
> >> + * You should have received a copy of the GNU General Public License
> >> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> >> + */
> >> +
> >> +#include <linux/irqchip/arm-gic.h>
> >> +#include <linux/kvm.h>
> >> +#include <linux/kvm_host.h>
> >> +
> >> +#include "vgic.h"
> >> +
> >> +/*
> >> + * Call this function to convert a u64 value to an unsigned long * bitmask
> >> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
> >> + *
> >> + * Warning: Calling this function may modify *val.
> >> + */
> >> +static unsigned long *u64_to_bitmask(u64 *val)
> >> +{
> >> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
> >> +	*val = (*val >> 32) | (*val << 32);
> >> +#endif
> >> +	return (unsigned long *)val;
> >> +}
> >> +
> >> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> >> +
> >> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
> >> +		u64 eisr = cpuif->vgic_eisr;
> >> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
> >> +		int lr;
> >> +
> >> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
> >> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
> >> +
> >> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
> >> +
> >> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> >> +					     intid - VGIC_NR_PRIVATE_IRQS);
> >> +
> > 
> > why do we need to do this?  I cannot find any consumers of this info
> > after we've left the hyp code.
> 
> I believe that's for vhost and irqfd. Or am I misreading your question?
> 

I meant the setting of the bits in vgic_elrsr (sorry, badly placed
comment)...

> > Also, I think I offered a comment about why we would potentially need
> > this in the first place.  This is the famous race where hardware doesn't
> > guarantee consistency between the MISR and ELRSR right?
> 
> That's the one (except it is between EISR and ELRSR). I don't have your
> initial comment at hand, but would something like the following do?
> 
> 			/*
> 			 * The maintenance interrupt may not have had a
> 			 * chance to update ELRSR, so let's mark the LRs
> 			 * presents in EISR as empty.
> 			 */
> > 
> >> +			cpuif->vgic_elrsr |= 1ULL << lr;

so, why are we doing this?

> >> +		}
> >> +	}
> 
> Thanks,
> 
> 	M.
> -- 
> Jazz is not dead. It just smells funny...

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

* [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
@ 2016-05-10 14:11         ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-10 14:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 10, 2016 at 02:42:02PM +0100, Marc Zyngier wrote:
> On 10/05/16 14:30, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:31AM +0100, Andre Przywara wrote:
> >> From: Marc Zyngier <marc.zyngier@arm.com>
> >>
> >> Processing maintenance interrupts and accessing the list registers
> >> are dependent on the host's GIC version.
> >> Introduce vgic-v2.c to contain GICv2 specific functions.
> >> Implement the GICv2 specific code for syncing the emulation state
> >> into the VGIC registers.
> >>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changelog RFC..v1:
> >> - remove explicit LR_STATE clearing on maintenance interrupt handling
> >> - improve documentation for vgic_v2_populate_lr()
> >> - remove WARN_ON on non-edge IRQs in maintenance interrupts
> >> - simplify multi-CPU source SGI handling
> >>
> >> Changelog v1 .. v2:
> >> - inject the IRQ priority into the list register
> >>
> >> Changelog v2 .. v3:
> >> - cleanup diff containing rebase artifacts
> >>
> >>  include/linux/irqchip/arm-gic.h |   1 +
> >>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic.c        |   6 ++
> >>  virt/kvm/arm/vgic/vgic.h        |   6 ++
> >>  4 files changed, 191 insertions(+)
> >>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
> >>
> >> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> >> index 9c94026..be0d26f 100644
> >> --- a/include/linux/irqchip/arm-gic.h
> >> +++ b/include/linux/irqchip/arm-gic.h
> >> @@ -76,6 +76,7 @@
> >>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
> >>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
> >>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
> >> +#define GICH_LR_PRIORITY_SHIFT		23
> >>  #define GICH_LR_STATE			(3 << 28)
> >>  #define GICH_LR_PENDING_BIT		(1 << 28)
> >>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
> >> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> >> new file mode 100644
> >> index 0000000..4cee616
> >> --- /dev/null
> >> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> >> @@ -0,0 +1,178 @@
> >> +/*
> >> + * Copyright (C) 2015, 2016 ARM Ltd.
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License version 2 as
> >> + * published by the Free Software Foundation.
> >> + *
> >> + * This program is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >> + * GNU General Public License for more details.
> >> + *
> >> + * You should have received a copy of the GNU General Public License
> >> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> >> + */
> >> +
> >> +#include <linux/irqchip/arm-gic.h>
> >> +#include <linux/kvm.h>
> >> +#include <linux/kvm_host.h>
> >> +
> >> +#include "vgic.h"
> >> +
> >> +/*
> >> + * Call this function to convert a u64 value to an unsigned long * bitmask
> >> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
> >> + *
> >> + * Warning: Calling this function may modify *val.
> >> + */
> >> +static unsigned long *u64_to_bitmask(u64 *val)
> >> +{
> >> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
> >> +	*val = (*val >> 32) | (*val << 32);
> >> +#endif
> >> +	return (unsigned long *)val;
> >> +}
> >> +
> >> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> >> +
> >> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
> >> +		u64 eisr = cpuif->vgic_eisr;
> >> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
> >> +		int lr;
> >> +
> >> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
> >> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
> >> +
> >> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
> >> +
> >> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> >> +					     intid - VGIC_NR_PRIVATE_IRQS);
> >> +
> > 
> > why do we need to do this?  I cannot find any consumers of this info
> > after we've left the hyp code.
> 
> I believe that's for vhost and irqfd. Or am I misreading your question?
> 

I meant the setting of the bits in vgic_elrsr (sorry, badly placed
comment)...

> > Also, I think I offered a comment about why we would potentially need
> > this in the first place.  This is the famous race where hardware doesn't
> > guarantee consistency between the MISR and ELRSR right?
> 
> That's the one (except it is between EISR and ELRSR). I don't have your
> initial comment at hand, but would something like the following do?
> 
> 			/*
> 			 * The maintenance interrupt may not have had a
> 			 * chance to update ELRSR, so let's mark the LRs
> 			 * presents in EISR as empty.
> 			 */
> > 
> >> +			cpuif->vgic_elrsr |= 1ULL << lr;

so, why are we doing this?

> >> +		}
> >> +	}
> 
> Thanks,
> 
> 	M.
> -- 
> Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 19/55] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
  2016-05-10 14:04     ` Christoffer Dall
@ 2016-05-10 14:15       ` Peter Maydell
  -1 siblings, 0 replies; 400+ messages in thread
From: Peter Maydell @ 2016-05-10 14:15 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andre Przywara, Marc Zyngier, arm-mail-list, kvmarm, kvm-devel

On 10 May 2016 at 15:04, Christoffer Dall <christoffer.dall@linaro.org> wrote:
> On Fri, May 06, 2016 at 11:45:32AM +0100, Andre Przywara wrote:
>> +     /*
>> +      * Currently all guest IRQs are Group1, as Group0 would result
>> +      * in a FIQ in the guest, which it wouldn't expect.
>
> I still don't like or understand this comment.  This should simply say
> that we're making a gross assumption about all interrupts being group1
> here.

It's not really an assumption so much as it's a missing feature (aka bug):
there's no reason the vGIC shouldn't support group 0 interrupts. We
just get away with only supporting group 1 because Linux guests
happen to only use group 1 interrupts. If/when the vGIC gains support
for group0 interrupts, then it should reset with interrupts configured
in group0 by default.

>> +      * Eventually we want to make this configurable, so we may
>> +      * revisit this in the future.
>> +      */

The only reason to make it configurable is to work around a guest
kernel bug whereby Linux assumes that all interrupts start out
in Group1. Marc sent out a patch earlier today that fixes that bug:
 https://lkml.org/lkml/2016/5/10/297
Depending on how long it takes you to fix this missing vgic feature,
such kernels may all be long-forgotten, in which case you can
get away without the config option :-)

thanks
-- PMM

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

* [PATCH v3 19/55] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
@ 2016-05-10 14:15       ` Peter Maydell
  0 siblings, 0 replies; 400+ messages in thread
From: Peter Maydell @ 2016-05-10 14:15 UTC (permalink / raw)
  To: linux-arm-kernel

On 10 May 2016 at 15:04, Christoffer Dall <christoffer.dall@linaro.org> wrote:
> On Fri, May 06, 2016 at 11:45:32AM +0100, Andre Przywara wrote:
>> +     /*
>> +      * Currently all guest IRQs are Group1, as Group0 would result
>> +      * in a FIQ in the guest, which it wouldn't expect.
>
> I still don't like or understand this comment.  This should simply say
> that we're making a gross assumption about all interrupts being group1
> here.

It's not really an assumption so much as it's a missing feature (aka bug):
there's no reason the vGIC shouldn't support group 0 interrupts. We
just get away with only supporting group 1 because Linux guests
happen to only use group 1 interrupts. If/when the vGIC gains support
for group0 interrupts, then it should reset with interrupts configured
in group0 by default.

>> +      * Eventually we want to make this configurable, so we may
>> +      * revisit this in the future.
>> +      */

The only reason to make it configurable is to work around a guest
kernel bug whereby Linux assumes that all interrupts start out
in Group1. Marc sent out a patch earlier today that fixes that bug:
 https://lkml.org/lkml/2016/5/10/297
Depending on how long it takes you to fix this missing vgic feature,
such kernels may all be long-forgotten, in which case you can
get away without the config option :-)

thanks
-- PMM

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

* Re: [PATCH v3 20/55] KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10 14:18     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-10 14:18 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 06, 2016 at 11:45:33AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> Tell KVM whether a particular VCPU has an IRQ that needs handling
> in the guest. This is used to decide whether a VCPU is runnable.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

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

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

* [PATCH v3 20/55] KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq
@ 2016-05-10 14:18     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-10 14:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:33AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> Tell KVM whether a particular VCPU has an IRQ that needs handling
> in the guest. This is used to decide whether a VCPU is runnable.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

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

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

* Re: [PATCH v3 19/55] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
  2016-05-10 14:15       ` Peter Maydell
@ 2016-05-10 14:22         ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 14:22 UTC (permalink / raw)
  To: Peter Maydell, Christoffer Dall
  Cc: Andre Przywara, arm-mail-list, kvmarm, kvm-devel

On 10/05/16 15:15, Peter Maydell wrote:
> On 10 May 2016 at 15:04, Christoffer Dall <christoffer.dall@linaro.org> wrote:
>> On Fri, May 06, 2016 at 11:45:32AM +0100, Andre Przywara wrote:
>>> +     /*
>>> +      * Currently all guest IRQs are Group1, as Group0 would result
>>> +      * in a FIQ in the guest, which it wouldn't expect.
>>
>> I still don't like or understand this comment.  This should simply say
>> that we're making a gross assumption about all interrupts being group1
>> here.
> 
> It's not really an assumption so much as it's a missing feature (aka bug):
> there's no reason the vGIC shouldn't support group 0 interrupts. We
> just get away with only supporting group 1 because Linux guests
> happen to only use group 1 interrupts. If/when the vGIC gains support
> for group0 interrupts, then it should reset with interrupts configured
> in group0 by default.
> 
>>> +      * Eventually we want to make this configurable, so we may
>>> +      * revisit this in the future.
>>> +      */
> 
> The only reason to make it configurable is to work around a guest
> kernel bug whereby Linux assumes that all interrupts start out
> in Group1. Marc sent out a patch earlier today that fixes that bug:
>  https://lkml.org/lkml/2016/5/10/297
> Depending on how long it takes you to fix this missing vgic feature,
> such kernels may all be long-forgotten, in which case you can
> get away without the config option :-)

I've CC'd stable for this particular patch, so hopefully we won't have
to make it configurable as people will diligently update their
kernels... I also have a patch for handling both groups in KVM, but I'll
hold onto it until we have something we agree on for the bulk of the code.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 19/55] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
@ 2016-05-10 14:22         ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 14:22 UTC (permalink / raw)
  To: linux-arm-kernel

On 10/05/16 15:15, Peter Maydell wrote:
> On 10 May 2016 at 15:04, Christoffer Dall <christoffer.dall@linaro.org> wrote:
>> On Fri, May 06, 2016 at 11:45:32AM +0100, Andre Przywara wrote:
>>> +     /*
>>> +      * Currently all guest IRQs are Group1, as Group0 would result
>>> +      * in a FIQ in the guest, which it wouldn't expect.
>>
>> I still don't like or understand this comment.  This should simply say
>> that we're making a gross assumption about all interrupts being group1
>> here.
> 
> It's not really an assumption so much as it's a missing feature (aka bug):
> there's no reason the vGIC shouldn't support group 0 interrupts. We
> just get away with only supporting group 1 because Linux guests
> happen to only use group 1 interrupts. If/when the vGIC gains support
> for group0 interrupts, then it should reset with interrupts configured
> in group0 by default.
> 
>>> +      * Eventually we want to make this configurable, so we may
>>> +      * revisit this in the future.
>>> +      */
> 
> The only reason to make it configurable is to work around a guest
> kernel bug whereby Linux assumes that all interrupts start out
> in Group1. Marc sent out a patch earlier today that fixes that bug:
>  https://lkml.org/lkml/2016/5/10/297
> Depending on how long it takes you to fix this missing vgic feature,
> such kernels may all be long-forgotten, in which case you can
> get away without the config option :-)

I've CC'd stable for this particular patch, so hopefully we won't have
to make it configurable as people will diligently update their
kernels... I also have a patch for handling both groups in KVM, but I'll
hold onto it until we have something we agree on for the bulk of the code.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
  2016-05-10 14:11         ` Christoffer Dall
@ 2016-05-10 14:35           ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 14:35 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andre Przywara, Eric Auger, kvmarm, kvm, linux-arm-kernel

On 10/05/16 15:11, Christoffer Dall wrote:
> On Tue, May 10, 2016 at 02:42:02PM +0100, Marc Zyngier wrote:
>> On 10/05/16 14:30, Christoffer Dall wrote:
>>> On Fri, May 06, 2016 at 11:45:31AM +0100, Andre Przywara wrote:
>>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>>
>>>> Processing maintenance interrupts and accessing the list registers
>>>> are dependent on the host's GIC version.
>>>> Introduce vgic-v2.c to contain GICv2 specific functions.
>>>> Implement the GICv2 specific code for syncing the emulation state
>>>> into the VGIC registers.
>>>>
>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>> Changelog RFC..v1:
>>>> - remove explicit LR_STATE clearing on maintenance interrupt handling
>>>> - improve documentation for vgic_v2_populate_lr()
>>>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
>>>> - simplify multi-CPU source SGI handling
>>>>
>>>> Changelog v1 .. v2:
>>>> - inject the IRQ priority into the list register
>>>>
>>>> Changelog v2 .. v3:
>>>> - cleanup diff containing rebase artifacts
>>>>
>>>>  include/linux/irqchip/arm-gic.h |   1 +
>>>>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>>>>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>>>>  4 files changed, 191 insertions(+)
>>>>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>>>>
>>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>>>> index 9c94026..be0d26f 100644
>>>> --- a/include/linux/irqchip/arm-gic.h
>>>> +++ b/include/linux/irqchip/arm-gic.h
>>>> @@ -76,6 +76,7 @@
>>>>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>>>>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>>>>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
>>>> +#define GICH_LR_PRIORITY_SHIFT		23
>>>>  #define GICH_LR_STATE			(3 << 28)
>>>>  #define GICH_LR_PENDING_BIT		(1 << 28)
>>>>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
>>>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>>>> new file mode 100644
>>>> index 0000000..4cee616
>>>> --- /dev/null
>>>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>>>> @@ -0,0 +1,178 @@
>>>> +/*
>>>> + * Copyright (C) 2015, 2016 ARM Ltd.
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify
>>>> + * it under the terms of the GNU General Public License version 2 as
>>>> + * published by the Free Software Foundation.
>>>> + *
>>>> + * This program is distributed in the hope that it will be useful,
>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>> + * GNU General Public License for more details.
>>>> + *
>>>> + * You should have received a copy of the GNU General Public License
>>>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>>> + */
>>>> +
>>>> +#include <linux/irqchip/arm-gic.h>
>>>> +#include <linux/kvm.h>
>>>> +#include <linux/kvm_host.h>
>>>> +
>>>> +#include "vgic.h"
>>>> +
>>>> +/*
>>>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>>>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>>>> + *
>>>> + * Warning: Calling this function may modify *val.
>>>> + */
>>>> +static unsigned long *u64_to_bitmask(u64 *val)
>>>> +{
>>>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>>>> +	*val = (*val >> 32) | (*val << 32);
>>>> +#endif
>>>> +	return (unsigned long *)val;
>>>> +}
>>>> +
>>>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>>> +
>>>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>>>> +		u64 eisr = cpuif->vgic_eisr;
>>>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>>>> +		int lr;
>>>> +
>>>> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
>>>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
>>>> +
>>>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
>>>> +
>>>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>>>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>>>> +
>>>
>>> why do we need to do this?  I cannot find any consumers of this info
>>> after we've left the hyp code.
>>
>> I believe that's for vhost and irqfd. Or am I misreading your question?
>>
> 
> I meant the setting of the bits in vgic_elrsr (sorry, badly placed
> comment)...
> 
>>> Also, I think I offered a comment about why we would potentially need
>>> this in the first place.  This is the famous race where hardware doesn't
>>> guarantee consistency between the MISR and ELRSR right?
>>
>> That's the one (except it is between EISR and ELRSR). I don't have your
>> initial comment at hand, but would something like the following do?
>>
>> 			/*
>> 			 * The maintenance interrupt may not have had a
>> 			 * chance to update ELRSR, so let's mark the LRs
>> 			 * presents in EISR as empty.
>> 			 */
>>>
>>>> +			cpuif->vgic_elrsr |= 1ULL << lr;
> 
> so, why are we doing this?

Ah! I finally see what you mean: we don't reuse LRs at all with the new code
base, so knowing which LR is empty is irrelevant. In which case, something
like that should be done:

diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index e88b5aa..5a8f4d4 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -52,8 +52,6 @@ void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
 
 			kvm_notify_acked_irq(vcpu->kvm, 0,
 					     intid - VGIC_NR_PRIVATE_IRQS);
-
-			cpuif->vgic_elrsr |= 1ULL << lr;
 		}
 	}
 
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 53f7847..4102f0f 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -43,8 +43,6 @@ void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
 
 			kvm_notify_acked_irq(vcpu->kvm, 0,
 					     intid - VGIC_NR_PRIVATE_IRQS);
-
-			cpuif->vgic_elrsr |= 1ULL << lr;
 		}
 
 		/*

I'll give it a spin, just to be safe.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
@ 2016-05-10 14:35           ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 14:35 UTC (permalink / raw)
  To: linux-arm-kernel

On 10/05/16 15:11, Christoffer Dall wrote:
> On Tue, May 10, 2016 at 02:42:02PM +0100, Marc Zyngier wrote:
>> On 10/05/16 14:30, Christoffer Dall wrote:
>>> On Fri, May 06, 2016 at 11:45:31AM +0100, Andre Przywara wrote:
>>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>>
>>>> Processing maintenance interrupts and accessing the list registers
>>>> are dependent on the host's GIC version.
>>>> Introduce vgic-v2.c to contain GICv2 specific functions.
>>>> Implement the GICv2 specific code for syncing the emulation state
>>>> into the VGIC registers.
>>>>
>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>> Changelog RFC..v1:
>>>> - remove explicit LR_STATE clearing on maintenance interrupt handling
>>>> - improve documentation for vgic_v2_populate_lr()
>>>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
>>>> - simplify multi-CPU source SGI handling
>>>>
>>>> Changelog v1 .. v2:
>>>> - inject the IRQ priority into the list register
>>>>
>>>> Changelog v2 .. v3:
>>>> - cleanup diff containing rebase artifacts
>>>>
>>>>  include/linux/irqchip/arm-gic.h |   1 +
>>>>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>>>>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>>>>  4 files changed, 191 insertions(+)
>>>>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>>>>
>>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>>>> index 9c94026..be0d26f 100644
>>>> --- a/include/linux/irqchip/arm-gic.h
>>>> +++ b/include/linux/irqchip/arm-gic.h
>>>> @@ -76,6 +76,7 @@
>>>>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>>>>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>>>>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
>>>> +#define GICH_LR_PRIORITY_SHIFT		23
>>>>  #define GICH_LR_STATE			(3 << 28)
>>>>  #define GICH_LR_PENDING_BIT		(1 << 28)
>>>>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
>>>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>>>> new file mode 100644
>>>> index 0000000..4cee616
>>>> --- /dev/null
>>>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>>>> @@ -0,0 +1,178 @@
>>>> +/*
>>>> + * Copyright (C) 2015, 2016 ARM Ltd.
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify
>>>> + * it under the terms of the GNU General Public License version 2 as
>>>> + * published by the Free Software Foundation.
>>>> + *
>>>> + * This program is distributed in the hope that it will be useful,
>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>> + * GNU General Public License for more details.
>>>> + *
>>>> + * You should have received a copy of the GNU General Public License
>>>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>>> + */
>>>> +
>>>> +#include <linux/irqchip/arm-gic.h>
>>>> +#include <linux/kvm.h>
>>>> +#include <linux/kvm_host.h>
>>>> +
>>>> +#include "vgic.h"
>>>> +
>>>> +/*
>>>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>>>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>>>> + *
>>>> + * Warning: Calling this function may modify *val.
>>>> + */
>>>> +static unsigned long *u64_to_bitmask(u64 *val)
>>>> +{
>>>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>>>> +	*val = (*val >> 32) | (*val << 32);
>>>> +#endif
>>>> +	return (unsigned long *)val;
>>>> +}
>>>> +
>>>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>>> +
>>>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>>>> +		u64 eisr = cpuif->vgic_eisr;
>>>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>>>> +		int lr;
>>>> +
>>>> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
>>>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
>>>> +
>>>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
>>>> +
>>>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>>>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>>>> +
>>>
>>> why do we need to do this?  I cannot find any consumers of this info
>>> after we've left the hyp code.
>>
>> I believe that's for vhost and irqfd. Or am I misreading your question?
>>
> 
> I meant the setting of the bits in vgic_elrsr (sorry, badly placed
> comment)...
> 
>>> Also, I think I offered a comment about why we would potentially need
>>> this in the first place.  This is the famous race where hardware doesn't
>>> guarantee consistency between the MISR and ELRSR right?
>>
>> That's the one (except it is between EISR and ELRSR). I don't have your
>> initial comment at hand, but would something like the following do?
>>
>> 			/*
>> 			 * The maintenance interrupt may not have had a
>> 			 * chance to update ELRSR, so let's mark the LRs
>> 			 * presents in EISR as empty.
>> 			 */
>>>
>>>> +			cpuif->vgic_elrsr |= 1ULL << lr;
> 
> so, why are we doing this?

Ah! I finally see what you mean: we don't reuse LRs at all with the new code
base, so knowing which LR is empty is irrelevant. In which case, something
like that should be done:

diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index e88b5aa..5a8f4d4 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -52,8 +52,6 @@ void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
 
 			kvm_notify_acked_irq(vcpu->kvm, 0,
 					     intid - VGIC_NR_PRIVATE_IRQS);
-
-			cpuif->vgic_elrsr |= 1ULL << lr;
 		}
 	}
 
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 53f7847..4102f0f 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -43,8 +43,6 @@ void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
 
 			kvm_notify_acked_irq(vcpu->kvm, 0,
 					     intid - VGIC_NR_PRIVATE_IRQS);
-
-			cpuif->vgic_elrsr |= 1ULL << lr;
 		}
 
 		/*

I'll give it a spin, just to be safe.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3a] KVM: arm/arm64: pmu: abstract access to number of SPIs
  2016-05-10  9:52     ` Eric Auger
@ 2016-05-10 14:35       ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-10 14:35 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall, Eric Auger; +Cc: kvmarm, kvm, linux-arm-kernel

Currently the PMU uses a member of the struct vgic_dist directly,
which not only breaks abstraction, but will fail with the new VGIC.
Abstract this access in the VGIC header file.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Hi Eric, Marc,

as this if-statement was quite confusing (it wasn't even the negation
that was wrong), I rewrote it a bit to be more readable.
This one works now with PPIs (after fixing kvmtool).

Does that make sense?

Cheers,
Andre.

 include/kvm/arm_vgic.h |  2 ++
 virt/kvm/arm/pmu.c     | 19 +++++++++++--------
 2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 6a98e05..d406f8e 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -351,6 +351,8 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
 #define vgic_ready(k)		((k)->arch.vgic.ready)
+#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
+				 ((i) < (k)->arch.vgic.nr_irqs))
 
 int vgic_v2_probe(struct device_node *vgic_node,
 		  const struct vgic_ops **ops,
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 575c7aa..6ab9d6b 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -436,6 +436,11 @@ static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
+/*
+ * For one VM the interrupt type must be same for each vcpu.
+ * As a PPI, the interrupt number is the same for all vcpus,
+ * while as an SPI it must be a separate number per vcpu.
+ */
 static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi)
 {
 	int i;
@@ -457,6 +462,7 @@ static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi)
 	return true;
 }
 
+#define irq_is_ppi(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)
 
 int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
 {
@@ -471,14 +477,11 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
 		if (get_user(irq, uaddr))
 			return -EFAULT;
 
-		/*
-		 * The PMU overflow interrupt could be a PPI or SPI, but for one
-		 * VM the interrupt type must be same for each vcpu. As a PPI,
-		 * the interrupt number is the same for all vcpus, while as an
-		 * SPI it must be a separate number per vcpu.
-		 */
-		if (irq < VGIC_NR_SGIS || irq >= vcpu->kvm->arch.vgic.nr_irqs ||
-		    !irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
+		/* The PMU overflow interrupt can be a PPI or a valid SPI. */
+		if (!(irq_is_ppi(irq) || vgic_valid_spi(vcpu->kvm, irq)))
+			return -EINVAL;
+
+		if (!irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
 			return -EINVAL;
 
 		if (kvm_arm_pmu_irq_initialized(vcpu))
-- 
2.7.3


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

* [PATCH v3a] KVM: arm/arm64: pmu: abstract access to number of SPIs
@ 2016-05-10 14:35       ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-10 14:35 UTC (permalink / raw)
  To: linux-arm-kernel

Currently the PMU uses a member of the struct vgic_dist directly,
which not only breaks abstraction, but will fail with the new VGIC.
Abstract this access in the VGIC header file.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Hi Eric, Marc,

as this if-statement was quite confusing (it wasn't even the negation
that was wrong), I rewrote it a bit to be more readable.
This one works now with PPIs (after fixing kvmtool).

Does that make sense?

Cheers,
Andre.

 include/kvm/arm_vgic.h |  2 ++
 virt/kvm/arm/pmu.c     | 19 +++++++++++--------
 2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 6a98e05..d406f8e 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -351,6 +351,8 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
 #define vgic_ready(k)		((k)->arch.vgic.ready)
+#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
+				 ((i) < (k)->arch.vgic.nr_irqs))
 
 int vgic_v2_probe(struct device_node *vgic_node,
 		  const struct vgic_ops **ops,
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 575c7aa..6ab9d6b 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -436,6 +436,11 @@ static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
+/*
+ * For one VM the interrupt type must be same for each vcpu.
+ * As a PPI, the interrupt number is the same for all vcpus,
+ * while as an SPI it must be a separate number per vcpu.
+ */
 static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi)
 {
 	int i;
@@ -457,6 +462,7 @@ static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi)
 	return true;
 }
 
+#define irq_is_ppi(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)
 
 int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
 {
@@ -471,14 +477,11 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
 		if (get_user(irq, uaddr))
 			return -EFAULT;
 
-		/*
-		 * The PMU overflow interrupt could be a PPI or SPI, but for one
-		 * VM the interrupt type must be same for each vcpu. As a PPI,
-		 * the interrupt number is the same for all vcpus, while as an
-		 * SPI it must be a separate number per vcpu.
-		 */
-		if (irq < VGIC_NR_SGIS || irq >= vcpu->kvm->arch.vgic.nr_irqs ||
-		    !irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
+		/* The PMU overflow interrupt can be a PPI or a valid SPI. */
+		if (!(irq_is_ppi(irq) || vgic_valid_spi(vcpu->kvm, irq)))
+			return -EINVAL;
+
+		if (!irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
 			return -EINVAL;
 
 		if (kvm_arm_pmu_irq_initialized(vcpu))
-- 
2.7.3

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

* Re: [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
  2016-05-10 14:35           ` Marc Zyngier
@ 2016-05-10 14:45             ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 14:45 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: linux-arm-kernel, Andre Przywara, kvmarm, kvm

On 10/05/16 15:35, Marc Zyngier wrote:
> On 10/05/16 15:11, Christoffer Dall wrote:
>> On Tue, May 10, 2016 at 02:42:02PM +0100, Marc Zyngier wrote:
>>> On 10/05/16 14:30, Christoffer Dall wrote:
>>>> On Fri, May 06, 2016 at 11:45:31AM +0100, Andre Przywara wrote:
>>>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>>>
>>>>> Processing maintenance interrupts and accessing the list registers
>>>>> are dependent on the host's GIC version.
>>>>> Introduce vgic-v2.c to contain GICv2 specific functions.
>>>>> Implement the GICv2 specific code for syncing the emulation state
>>>>> into the VGIC registers.
>>>>>
>>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>> ---
>>>>> Changelog RFC..v1:
>>>>> - remove explicit LR_STATE clearing on maintenance interrupt handling
>>>>> - improve documentation for vgic_v2_populate_lr()
>>>>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
>>>>> - simplify multi-CPU source SGI handling
>>>>>
>>>>> Changelog v1 .. v2:
>>>>> - inject the IRQ priority into the list register
>>>>>
>>>>> Changelog v2 .. v3:
>>>>> - cleanup diff containing rebase artifacts
>>>>>
>>>>>  include/linux/irqchip/arm-gic.h |   1 +
>>>>>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>>>>>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>>>>>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>>>>>  4 files changed, 191 insertions(+)
>>>>>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>>>>>
>>>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>>>>> index 9c94026..be0d26f 100644
>>>>> --- a/include/linux/irqchip/arm-gic.h
>>>>> +++ b/include/linux/irqchip/arm-gic.h
>>>>> @@ -76,6 +76,7 @@
>>>>>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>>>>>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>>>>>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
>>>>> +#define GICH_LR_PRIORITY_SHIFT		23
>>>>>  #define GICH_LR_STATE			(3 << 28)
>>>>>  #define GICH_LR_PENDING_BIT		(1 << 28)
>>>>>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
>>>>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>>>>> new file mode 100644
>>>>> index 0000000..4cee616
>>>>> --- /dev/null
>>>>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>>>>> @@ -0,0 +1,178 @@
>>>>> +/*
>>>>> + * Copyright (C) 2015, 2016 ARM Ltd.
>>>>> + *
>>>>> + * This program is free software; you can redistribute it and/or modify
>>>>> + * it under the terms of the GNU General Public License version 2 as
>>>>> + * published by the Free Software Foundation.
>>>>> + *
>>>>> + * This program is distributed in the hope that it will be useful,
>>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>>> + * GNU General Public License for more details.
>>>>> + *
>>>>> + * You should have received a copy of the GNU General Public License
>>>>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>>>> + */
>>>>> +
>>>>> +#include <linux/irqchip/arm-gic.h>
>>>>> +#include <linux/kvm.h>
>>>>> +#include <linux/kvm_host.h>
>>>>> +
>>>>> +#include "vgic.h"
>>>>> +
>>>>> +/*
>>>>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>>>>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>>>>> + *
>>>>> + * Warning: Calling this function may modify *val.
>>>>> + */
>>>>> +static unsigned long *u64_to_bitmask(u64 *val)
>>>>> +{
>>>>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>>>>> +	*val = (*val >> 32) | (*val << 32);
>>>>> +#endif
>>>>> +	return (unsigned long *)val;
>>>>> +}
>>>>> +
>>>>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>>>>> +{
>>>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>>>> +
>>>>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>>>>> +		u64 eisr = cpuif->vgic_eisr;
>>>>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>>>>> +		int lr;
>>>>> +
>>>>> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
>>>>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
>>>>> +
>>>>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
>>>>> +
>>>>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>>>>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>>>>> +
>>>>
>>>> why do we need to do this?  I cannot find any consumers of this info
>>>> after we've left the hyp code.
>>>
>>> I believe that's for vhost and irqfd. Or am I misreading your question?
>>>
>>
>> I meant the setting of the bits in vgic_elrsr (sorry, badly placed
>> comment)...
>>
>>>> Also, I think I offered a comment about why we would potentially need
>>>> this in the first place.  This is the famous race where hardware doesn't
>>>> guarantee consistency between the MISR and ELRSR right?
>>>
>>> That's the one (except it is between EISR and ELRSR). I don't have your
>>> initial comment at hand, but would something like the following do?
>>>
>>> 			/*
>>> 			 * The maintenance interrupt may not have had a
>>> 			 * chance to update ELRSR, so let's mark the LRs
>>> 			 * presents in EISR as empty.
>>> 			 */
>>>>
>>>>> +			cpuif->vgic_elrsr |= 1ULL << lr;
>>
>> so, why are we doing this?
> 
> Ah! I finally see what you mean: we don't reuse LRs at all with the new code
> base, so knowing which LR is empty is irrelevant. In which case, something
> like that should be done:
> 
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index e88b5aa..5a8f4d4 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -52,8 +52,6 @@ void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>  
>  			kvm_notify_acked_irq(vcpu->kvm, 0,
>  					     intid - VGIC_NR_PRIVATE_IRQS);
> -
> -			cpuif->vgic_elrsr |= 1ULL << lr;
>  		}
>  	}
>  
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 53f7847..4102f0f 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -43,8 +43,6 @@ void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
>  
>  			kvm_notify_acked_irq(vcpu->kvm, 0,
>  					     intid - VGIC_NR_PRIVATE_IRQS);
> -
> -			cpuif->vgic_elrsr |= 1ULL << lr;
>  		}
>  
>  		/*
> 
> I'll give it a spin, just to be safe.

Seems OK on GICv2, and this of course leads to some more possible
cleanups or optimizations (I think we can get to a state where we
completely disregards ELRSR). I'll have a look.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
@ 2016-05-10 14:45             ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 14:45 UTC (permalink / raw)
  To: linux-arm-kernel

On 10/05/16 15:35, Marc Zyngier wrote:
> On 10/05/16 15:11, Christoffer Dall wrote:
>> On Tue, May 10, 2016 at 02:42:02PM +0100, Marc Zyngier wrote:
>>> On 10/05/16 14:30, Christoffer Dall wrote:
>>>> On Fri, May 06, 2016 at 11:45:31AM +0100, Andre Przywara wrote:
>>>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>>>
>>>>> Processing maintenance interrupts and accessing the list registers
>>>>> are dependent on the host's GIC version.
>>>>> Introduce vgic-v2.c to contain GICv2 specific functions.
>>>>> Implement the GICv2 specific code for syncing the emulation state
>>>>> into the VGIC registers.
>>>>>
>>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>> ---
>>>>> Changelog RFC..v1:
>>>>> - remove explicit LR_STATE clearing on maintenance interrupt handling
>>>>> - improve documentation for vgic_v2_populate_lr()
>>>>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
>>>>> - simplify multi-CPU source SGI handling
>>>>>
>>>>> Changelog v1 .. v2:
>>>>> - inject the IRQ priority into the list register
>>>>>
>>>>> Changelog v2 .. v3:
>>>>> - cleanup diff containing rebase artifacts
>>>>>
>>>>>  include/linux/irqchip/arm-gic.h |   1 +
>>>>>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>>>>>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>>>>>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>>>>>  4 files changed, 191 insertions(+)
>>>>>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>>>>>
>>>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>>>>> index 9c94026..be0d26f 100644
>>>>> --- a/include/linux/irqchip/arm-gic.h
>>>>> +++ b/include/linux/irqchip/arm-gic.h
>>>>> @@ -76,6 +76,7 @@
>>>>>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>>>>>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>>>>>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
>>>>> +#define GICH_LR_PRIORITY_SHIFT		23
>>>>>  #define GICH_LR_STATE			(3 << 28)
>>>>>  #define GICH_LR_PENDING_BIT		(1 << 28)
>>>>>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
>>>>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>>>>> new file mode 100644
>>>>> index 0000000..4cee616
>>>>> --- /dev/null
>>>>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>>>>> @@ -0,0 +1,178 @@
>>>>> +/*
>>>>> + * Copyright (C) 2015, 2016 ARM Ltd.
>>>>> + *
>>>>> + * This program is free software; you can redistribute it and/or modify
>>>>> + * it under the terms of the GNU General Public License version 2 as
>>>>> + * published by the Free Software Foundation.
>>>>> + *
>>>>> + * This program is distributed in the hope that it will be useful,
>>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>>> + * GNU General Public License for more details.
>>>>> + *
>>>>> + * You should have received a copy of the GNU General Public License
>>>>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>>>> + */
>>>>> +
>>>>> +#include <linux/irqchip/arm-gic.h>
>>>>> +#include <linux/kvm.h>
>>>>> +#include <linux/kvm_host.h>
>>>>> +
>>>>> +#include "vgic.h"
>>>>> +
>>>>> +/*
>>>>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>>>>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>>>>> + *
>>>>> + * Warning: Calling this function may modify *val.
>>>>> + */
>>>>> +static unsigned long *u64_to_bitmask(u64 *val)
>>>>> +{
>>>>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>>>>> +	*val = (*val >> 32) | (*val << 32);
>>>>> +#endif
>>>>> +	return (unsigned long *)val;
>>>>> +}
>>>>> +
>>>>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>>>>> +{
>>>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>>>> +
>>>>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>>>>> +		u64 eisr = cpuif->vgic_eisr;
>>>>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>>>>> +		int lr;
>>>>> +
>>>>> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
>>>>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
>>>>> +
>>>>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
>>>>> +
>>>>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>>>>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>>>>> +
>>>>
>>>> why do we need to do this?  I cannot find any consumers of this info
>>>> after we've left the hyp code.
>>>
>>> I believe that's for vhost and irqfd. Or am I misreading your question?
>>>
>>
>> I meant the setting of the bits in vgic_elrsr (sorry, badly placed
>> comment)...
>>
>>>> Also, I think I offered a comment about why we would potentially need
>>>> this in the first place.  This is the famous race where hardware doesn't
>>>> guarantee consistency between the MISR and ELRSR right?
>>>
>>> That's the one (except it is between EISR and ELRSR). I don't have your
>>> initial comment at hand, but would something like the following do?
>>>
>>> 			/*
>>> 			 * The maintenance interrupt may not have had a
>>> 			 * chance to update ELRSR, so let's mark the LRs
>>> 			 * presents in EISR as empty.
>>> 			 */
>>>>
>>>>> +			cpuif->vgic_elrsr |= 1ULL << lr;
>>
>> so, why are we doing this?
> 
> Ah! I finally see what you mean: we don't reuse LRs at all with the new code
> base, so knowing which LR is empty is irrelevant. In which case, something
> like that should be done:
> 
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index e88b5aa..5a8f4d4 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -52,8 +52,6 @@ void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>  
>  			kvm_notify_acked_irq(vcpu->kvm, 0,
>  					     intid - VGIC_NR_PRIVATE_IRQS);
> -
> -			cpuif->vgic_elrsr |= 1ULL << lr;
>  		}
>  	}
>  
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 53f7847..4102f0f 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -43,8 +43,6 @@ void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
>  
>  			kvm_notify_acked_irq(vcpu->kvm, 0,
>  					     intid - VGIC_NR_PRIVATE_IRQS);
> -
> -			cpuif->vgic_elrsr |= 1ULL << lr;
>  		}
>  
>  		/*
> 
> I'll give it a spin, just to be safe.

Seems OK on GICv2, and this of course leads to some more possible
cleanups or optimizations (I think we can get to a state where we
completely disregards ELRSR). I'll have a look.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3a] KVM: arm/arm64: pmu: abstract access to number of SPIs
  2016-05-10 14:35       ` Andre Przywara
@ 2016-05-10 14:58         ` Andrew Jones
  -1 siblings, 0 replies; 400+ messages in thread
From: Andrew Jones @ 2016-05-10 14:58 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Marc Zyngier, Christoffer Dall, Eric Auger, kvmarm, kvm,
	linux-arm-kernel

On Tue, May 10, 2016 at 03:35:06PM +0100, Andre Przywara wrote:
> Currently the PMU uses a member of the struct vgic_dist directly,
> which not only breaks abstraction, but will fail with the new VGIC.
> Abstract this access in the VGIC header file.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Hi Eric, Marc,
> 
> as this if-statement was quite confusing (it wasn't even the negation
> that was wrong), I rewrote it a bit to be more readable.
> This one works now with PPIs (after fixing kvmtool).
> 
> Does that make sense?
> 
> Cheers,
> Andre.
> 
>  include/kvm/arm_vgic.h |  2 ++
>  virt/kvm/arm/pmu.c     | 19 +++++++++++--------
>  2 files changed, 13 insertions(+), 8 deletions(-)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 6a98e05..d406f8e 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -351,6 +351,8 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>  #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> +#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
> +				 ((i) < (k)->arch.vgic.nr_irqs))
>  
>  int vgic_v2_probe(struct device_node *vgic_node,
>  		  const struct vgic_ops **ops,
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 575c7aa..6ab9d6b 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -436,6 +436,11 @@ static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
>  	return 0;
>  }
>  
> +/*
> + * For one VM the interrupt type must be same for each vcpu.
> + * As a PPI, the interrupt number is the same for all vcpus,
> + * while as an SPI it must be a separate number per vcpu.
> + */
>  static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi)

While at it, I'd change this function name to have 'pmu' in it. It's
just a static function, but without pmu in it it looks a bit confusing
now to check the irq is [a valid] spi or ppi number, and then to call
the generically named 'irq_is_valid' on it as well.

Thanks,
drew

>  {
>  	int i;
> @@ -457,6 +462,7 @@ static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi)
>  	return true;
>  }
>  
> +#define irq_is_ppi(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)
>  
>  int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
>  {
> @@ -471,14 +477,11 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
>  		if (get_user(irq, uaddr))
>  			return -EFAULT;
>  
> -		/*
> -		 * The PMU overflow interrupt could be a PPI or SPI, but for one
> -		 * VM the interrupt type must be same for each vcpu. As a PPI,
> -		 * the interrupt number is the same for all vcpus, while as an
> -		 * SPI it must be a separate number per vcpu.
> -		 */
> -		if (irq < VGIC_NR_SGIS || irq >= vcpu->kvm->arch.vgic.nr_irqs ||
> -		    !irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
> +		/* The PMU overflow interrupt can be a PPI or a valid SPI. */
> +		if (!(irq_is_ppi(irq) || vgic_valid_spi(vcpu->kvm, irq)))
> +			return -EINVAL;
> +
> +		if (!irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
>  			return -EINVAL;
>  
>  		if (kvm_arm_pmu_irq_initialized(vcpu))
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v3a] KVM: arm/arm64: pmu: abstract access to number of SPIs
@ 2016-05-10 14:58         ` Andrew Jones
  0 siblings, 0 replies; 400+ messages in thread
From: Andrew Jones @ 2016-05-10 14:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 10, 2016 at 03:35:06PM +0100, Andre Przywara wrote:
> Currently the PMU uses a member of the struct vgic_dist directly,
> which not only breaks abstraction, but will fail with the new VGIC.
> Abstract this access in the VGIC header file.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Hi Eric, Marc,
> 
> as this if-statement was quite confusing (it wasn't even the negation
> that was wrong), I rewrote it a bit to be more readable.
> This one works now with PPIs (after fixing kvmtool).
> 
> Does that make sense?
> 
> Cheers,
> Andre.
> 
>  include/kvm/arm_vgic.h |  2 ++
>  virt/kvm/arm/pmu.c     | 19 +++++++++++--------
>  2 files changed, 13 insertions(+), 8 deletions(-)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 6a98e05..d406f8e 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -351,6 +351,8 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>  #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> +#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
> +				 ((i) < (k)->arch.vgic.nr_irqs))
>  
>  int vgic_v2_probe(struct device_node *vgic_node,
>  		  const struct vgic_ops **ops,
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 575c7aa..6ab9d6b 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -436,6 +436,11 @@ static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
>  	return 0;
>  }
>  
> +/*
> + * For one VM the interrupt type must be same for each vcpu.
> + * As a PPI, the interrupt number is the same for all vcpus,
> + * while as an SPI it must be a separate number per vcpu.
> + */
>  static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi)

While at it, I'd change this function name to have 'pmu' in it. It's
just a static function, but without pmu in it it looks a bit confusing
now to check the irq is [a valid] spi or ppi number, and then to call
the generically named 'irq_is_valid' on it as well.

Thanks,
drew

>  {
>  	int i;
> @@ -457,6 +462,7 @@ static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi)
>  	return true;
>  }
>  
> +#define irq_is_ppi(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)
>  
>  int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
>  {
> @@ -471,14 +477,11 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
>  		if (get_user(irq, uaddr))
>  			return -EFAULT;
>  
> -		/*
> -		 * The PMU overflow interrupt could be a PPI or SPI, but for one
> -		 * VM the interrupt type must be same for each vcpu. As a PPI,
> -		 * the interrupt number is the same for all vcpus, while as an
> -		 * SPI it must be a separate number per vcpu.
> -		 */
> -		if (irq < VGIC_NR_SGIS || irq >= vcpu->kvm->arch.vgic.nr_irqs ||
> -		    !irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
> +		/* The PMU overflow interrupt can be a PPI or a valid SPI. */
> +		if (!(irq_is_ppi(irq) || vgic_valid_spi(vcpu->kvm, irq)))
> +			return -EINVAL;
> +
> +		if (!irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
>  			return -EINVAL;
>  
>  		if (kvm_arm_pmu_irq_initialized(vcpu))
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v3 17/55] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10 15:20     ` Eric Auger
  -1 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10 15:20 UTC (permalink / raw)
  To: Andre Przywara, Marc Zyngier, Christoffer Dall
  Cc: kvmarm, linux-arm-kernel, kvm

On 05/06/2016 12:45 PM, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Implement the framework for syncing IRQs between our emulation and
> the list registers, which represent the guest's view of IRQs.
> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
> which gets called on guest entry and exit.
> The code talking to the actual GICv2/v3 hardware is added in the
> following patches.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - split out vgic_clear_lr() from vgic_populate_lr()
> - rename vgic_populate_lrs() to vgic_flush_lr_state()
> - clean all LRs when the distributor is disabled
> - use list_del() instead of list_del_init()
> - add comments to explain the direction of sync/flush_hwstate
> - remove unneeded BUG_ON(in_interrupt()
> 
> Changelog v2 .. v3:
> - remove bogus v2 specific rebase leftovers
> 
>  include/kvm/vgic/vgic.h  |   4 +
>  virt/kvm/arm/vgic/vgic.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h |   2 +
>  3 files changed, 199 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 2bfb42c..5fae4a9 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -190,6 +190,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>  
> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
> +
>  /**
>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>   *
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 4fb20fd..c6f8b9b 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -305,3 +305,196 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  {
>  	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
>  }
> +
> +/**
> + * vgic_prune_ap_list - Remove non-relevant interrupts from the list
> + *
> + * @vcpu: The VCPU pointer
> + *
> + * Go over the list of "interesting" interrupts, and prune those that we
> + * won't have to consider in the near future.
> + */
> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq, *tmp;
> +
> +retry:
> +	spin_lock(&vgic_cpu->ap_list_lock);
> +
> +	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
> +		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		BUG_ON(vcpu != irq->vcpu);
> +
> +		target_vcpu = vgic_target_oracle(irq);
> +
> +		if (!target_vcpu) {
> +			/*
> +			 * We don't need to process this interrupt any
> +			 * further, move it off the list.
> +			 */
> +			list_del(&irq->ap_list);
> +			irq->vcpu = NULL;
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		if (target_vcpu == vcpu) {
> +			/* We're on the right CPU */
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		/* This interrupt looks like it has to be migrated. */
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vgic_cpu->ap_list_lock);
> +
> +		/*
> +		 * Ensure locking order by always locking the smallest
> +		 * ID first.
> +		 */
> +		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
> +			vcpuA = vcpu;
> +			vcpuB = target_vcpu;
> +		} else {
> +			vcpuA = target_vcpu;
> +			vcpuB = vcpu;
> +		}
> +
> +		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&irq->irq_lock);
> +
> +		/*
> +		 * If the affinity has been preserved, move the
> +		 * interrupt around. Otherwise, it means things have
> +		 * changed while the interrupt was unlocked, and we
> +		 * need to replay this.
> +		 *
> +		 * In all cases, we cannot trust the list not to have
> +		 * changed, so we restart from the beginning.
> +		 */
> +		if (target_vcpu == vgic_target_oracle(irq)) {
> +			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
> +
> +			list_del(&irq->ap_list);
> +			irq->vcpu = target_vcpu;
> +			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		goto retry;
> +	}
> +
> +	spin_unlock(&vgic_cpu->ap_list_lock);
> +}
> +
> +static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +/* Requires the ap_list_lock and the irq_lock to be held. */
why is it needed to hold the ap_list lock here?
> +static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
> +				    struct vgic_irq *irq, int lr)
> +{
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
?

Eric
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
> +}
> +
> +static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
> +{
> +}
> +
> +static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +		/* GICv2 SGIs can count for more than one... */
> +		if (vgic_irq_is_sgi(irq->intid) && irq->source)
> +			count += hweight8(irq->source);
> +		else
> +			count++;
> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return count;
> +}
> +
> +/* Requires the VCPU's ap_list_lock to be held. */
> +static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
> +
> +	if (unlikely(!vcpu->kvm->arch.vgic.enabled))
> +		goto out_clean;
> +
> +	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
> +		vgic_set_underflow(vcpu);
> +		vgic_sort_ap_list(vcpu);
> +	}
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +
> +		if (unlikely(vgic_target_oracle(irq) != vcpu))
> +			goto next;
> +
> +		/*
> +		 * If we get an SGI with multiple sources, try to get
> +		 * them in all at once.
> +		 */
> +		do {
> +			vgic_populate_lr(vcpu, irq, count++);
> +		} while (irq->source && count < kvm_vgic_global_state.nr_lr);
> +
> +next:
> +		spin_unlock(&irq->irq_lock);
> +
> +		if (count == kvm_vgic_global_state.nr_lr)
> +			break;
> +	}
> +
> +out_clean:
> +	vcpu->arch.vgic_cpu.used_lrs = count;
> +
> +	/* Nuke remaining LRs */
> +	for ( ; count < kvm_vgic_global_state.nr_lr; count++)
> +		vgic_clear_lr(vcpu, count);
> +}
> +
> +/* Sync back the hardware VGIC state into our emulation after a guest's run. */
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	vgic_process_maintenance_interrupt(vcpu);
> +	vgic_fold_lr_state(vcpu);
> +	vgic_prune_ap_list(vcpu);
> +}
> +
> +/* Flush our emulation state into the GIC hardware before entering the guest. */
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +	vgic_flush_lr_state(vcpu);
> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index c625767..29b96b9 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -16,6 +16,8 @@
>  #ifndef __KVM_ARM_VGIC_NEW_H__
>  #define __KVM_ARM_VGIC_NEW_H__
>  
> +#define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
> +
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
> 

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

* [PATCH v3 17/55] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
@ 2016-05-10 15:20     ` Eric Auger
  0 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10 15:20 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/06/2016 12:45 PM, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Implement the framework for syncing IRQs between our emulation and
> the list registers, which represent the guest's view of IRQs.
> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
> which gets called on guest entry and exit.
> The code talking to the actual GICv2/v3 hardware is added in the
> following patches.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - split out vgic_clear_lr() from vgic_populate_lr()
> - rename vgic_populate_lrs() to vgic_flush_lr_state()
> - clean all LRs when the distributor is disabled
> - use list_del() instead of list_del_init()
> - add comments to explain the direction of sync/flush_hwstate
> - remove unneeded BUG_ON(in_interrupt()
> 
> Changelog v2 .. v3:
> - remove bogus v2 specific rebase leftovers
> 
>  include/kvm/vgic/vgic.h  |   4 +
>  virt/kvm/arm/vgic/vgic.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h |   2 +
>  3 files changed, 199 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 2bfb42c..5fae4a9 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -190,6 +190,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>  
> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
> +
>  /**
>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>   *
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 4fb20fd..c6f8b9b 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -305,3 +305,196 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  {
>  	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
>  }
> +
> +/**
> + * vgic_prune_ap_list - Remove non-relevant interrupts from the list
> + *
> + * @vcpu: The VCPU pointer
> + *
> + * Go over the list of "interesting" interrupts, and prune those that we
> + * won't have to consider in the near future.
> + */
> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq, *tmp;
> +
> +retry:
> +	spin_lock(&vgic_cpu->ap_list_lock);
> +
> +	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
> +		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		BUG_ON(vcpu != irq->vcpu);
> +
> +		target_vcpu = vgic_target_oracle(irq);
> +
> +		if (!target_vcpu) {
> +			/*
> +			 * We don't need to process this interrupt any
> +			 * further, move it off the list.
> +			 */
> +			list_del(&irq->ap_list);
> +			irq->vcpu = NULL;
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		if (target_vcpu == vcpu) {
> +			/* We're on the right CPU */
> +			spin_unlock(&irq->irq_lock);
> +			continue;
> +		}
> +
> +		/* This interrupt looks like it has to be migrated. */
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vgic_cpu->ap_list_lock);
> +
> +		/*
> +		 * Ensure locking order by always locking the smallest
> +		 * ID first.
> +		 */
> +		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
> +			vcpuA = vcpu;
> +			vcpuB = target_vcpu;
> +		} else {
> +			vcpuA = target_vcpu;
> +			vcpuB = vcpu;
> +		}
> +
> +		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_lock(&irq->irq_lock);
> +
> +		/*
> +		 * If the affinity has been preserved, move the
> +		 * interrupt around. Otherwise, it means things have
> +		 * changed while the interrupt was unlocked, and we
> +		 * need to replay this.
> +		 *
> +		 * In all cases, we cannot trust the list not to have
> +		 * changed, so we restart from the beginning.
> +		 */
> +		if (target_vcpu == vgic_target_oracle(irq)) {
> +			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
> +
> +			list_del(&irq->ap_list);
> +			irq->vcpu = target_vcpu;
> +			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
> +		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
> +		goto retry;
> +	}
> +
> +	spin_unlock(&vgic_cpu->ap_list_lock);
> +}
> +
> +static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +/* Requires the ap_list_lock and the irq_lock to be held. */
why is it needed to hold the ap_list lock here?
> +static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
> +				    struct vgic_irq *irq, int lr)
> +{
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
?

Eric
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
> +}
> +
> +static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
> +{
> +}
> +
> +static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +		/* GICv2 SGIs can count for more than one... */
> +		if (vgic_irq_is_sgi(irq->intid) && irq->source)
> +			count += hweight8(irq->source);
> +		else
> +			count++;
> +		spin_unlock(&irq->irq_lock);
> +	}
> +	return count;
> +}
> +
> +/* Requires the VCPU's ap_list_lock to be held. */
> +static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
> +
> +	if (unlikely(!vcpu->kvm->arch.vgic.enabled))
> +		goto out_clean;
> +
> +	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
> +		vgic_set_underflow(vcpu);
> +		vgic_sort_ap_list(vcpu);
> +	}
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +
> +		if (unlikely(vgic_target_oracle(irq) != vcpu))
> +			goto next;
> +
> +		/*
> +		 * If we get an SGI with multiple sources, try to get
> +		 * them in all at once.
> +		 */
> +		do {
> +			vgic_populate_lr(vcpu, irq, count++);
> +		} while (irq->source && count < kvm_vgic_global_state.nr_lr);
> +
> +next:
> +		spin_unlock(&irq->irq_lock);
> +
> +		if (count == kvm_vgic_global_state.nr_lr)
> +			break;
> +	}
> +
> +out_clean:
> +	vcpu->arch.vgic_cpu.used_lrs = count;
> +
> +	/* Nuke remaining LRs */
> +	for ( ; count < kvm_vgic_global_state.nr_lr; count++)
> +		vgic_clear_lr(vcpu, count);
> +}
> +
> +/* Sync back the hardware VGIC state into our emulation after a guest's run. */
> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	vgic_process_maintenance_interrupt(vcpu);
> +	vgic_fold_lr_state(vcpu);
> +	vgic_prune_ap_list(vcpu);
> +}
> +
> +/* Flush our emulation state into the GIC hardware before entering the guest. */
> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +	vgic_flush_lr_state(vcpu);
> +	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index c625767..29b96b9 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -16,6 +16,8 @@
>  #ifndef __KVM_ARM_VGIC_NEW_H__
>  #define __KVM_ARM_VGIC_NEW_H__
>  
> +#define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
> +
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
> 

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

* Re: [PATCH v3a] KVM: arm/arm64: pmu: abstract access to number of SPIs
  2016-05-10 14:35       ` Andre Przywara
@ 2016-05-10 15:22         ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 15:22 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall, Eric Auger
  Cc: kvmarm, kvm, linux-arm-kernel

On 10/05/16 15:35, Andre Przywara wrote:
> Currently the PMU uses a member of the struct vgic_dist directly,
> which not only breaks abstraction, but will fail with the new VGIC.
> Abstract this access in the VGIC header file.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Hi Eric, Marc,
> 
> as this if-statement was quite confusing (it wasn't even the negation
> that was wrong), I rewrote it a bit to be more readable.
> This one works now with PPIs (after fixing kvmtool).
> 
> Does that make sense?
> 
> Cheers,
> Andre.
> 
>  include/kvm/arm_vgic.h |  2 ++
>  virt/kvm/arm/pmu.c     | 19 +++++++++++--------
>  2 files changed, 13 insertions(+), 8 deletions(-)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 6a98e05..d406f8e 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -351,6 +351,8 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>  #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> +#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
> +				 ((i) < (k)->arch.vgic.nr_irqs))
>  
>  int vgic_v2_probe(struct device_node *vgic_node,
>  		  const struct vgic_ops **ops,
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 575c7aa..6ab9d6b 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -436,6 +436,11 @@ static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
>  	return 0;
>  }
>  
> +/*
> + * For one VM the interrupt type must be same for each vcpu.
> + * As a PPI, the interrupt number is the same for all vcpus,
> + * while as an SPI it must be a separate number per vcpu.
> + */
>  static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi)
>  {
>  	int i;
> @@ -457,6 +462,7 @@ static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi)
>  	return true;
>  }
>  
> +#define irq_is_ppi(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)

You might as well move this to the VGIC code.

>  
>  int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
>  {
> @@ -471,14 +477,11 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
>  		if (get_user(irq, uaddr))
>  			return -EFAULT;
>  
> -		/*
> -		 * The PMU overflow interrupt could be a PPI or SPI, but for one
> -		 * VM the interrupt type must be same for each vcpu. As a PPI,
> -		 * the interrupt number is the same for all vcpus, while as an
> -		 * SPI it must be a separate number per vcpu.
> -		 */
> -		if (irq < VGIC_NR_SGIS || irq >= vcpu->kvm->arch.vgic.nr_irqs ||
> -		    !irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
> +		/* The PMU overflow interrupt can be a PPI or a valid SPI. */
> +		if (!(irq_is_ppi(irq) || vgic_valid_spi(vcpu->kvm, irq)))
> +			return -EINVAL;
> +
> +		if (!irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))

Why do we need to pass this boolean as a parameter? You could rewrite
irq_is_valid() to generate the is_ppi boolean by itself.

>  			return -EINVAL;
>  
>  		if (kvm_arm_pmu_irq_initialized(vcpu))
> 

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3a] KVM: arm/arm64: pmu: abstract access to number of SPIs
@ 2016-05-10 15:22         ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 15:22 UTC (permalink / raw)
  To: linux-arm-kernel

On 10/05/16 15:35, Andre Przywara wrote:
> Currently the PMU uses a member of the struct vgic_dist directly,
> which not only breaks abstraction, but will fail with the new VGIC.
> Abstract this access in the VGIC header file.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Hi Eric, Marc,
> 
> as this if-statement was quite confusing (it wasn't even the negation
> that was wrong), I rewrote it a bit to be more readable.
> This one works now with PPIs (after fixing kvmtool).
> 
> Does that make sense?
> 
> Cheers,
> Andre.
> 
>  include/kvm/arm_vgic.h |  2 ++
>  virt/kvm/arm/pmu.c     | 19 +++++++++++--------
>  2 files changed, 13 insertions(+), 8 deletions(-)
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 6a98e05..d406f8e 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -351,6 +351,8 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>  #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
> +#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
> +				 ((i) < (k)->arch.vgic.nr_irqs))
>  
>  int vgic_v2_probe(struct device_node *vgic_node,
>  		  const struct vgic_ops **ops,
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 575c7aa..6ab9d6b 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -436,6 +436,11 @@ static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
>  	return 0;
>  }
>  
> +/*
> + * For one VM the interrupt type must be same for each vcpu.
> + * As a PPI, the interrupt number is the same for all vcpus,
> + * while as an SPI it must be a separate number per vcpu.
> + */
>  static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi)
>  {
>  	int i;
> @@ -457,6 +462,7 @@ static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi)
>  	return true;
>  }
>  
> +#define irq_is_ppi(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)

You might as well move this to the VGIC code.

>  
>  int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
>  {
> @@ -471,14 +477,11 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
>  		if (get_user(irq, uaddr))
>  			return -EFAULT;
>  
> -		/*
> -		 * The PMU overflow interrupt could be a PPI or SPI, but for one
> -		 * VM the interrupt type must be same for each vcpu. As a PPI,
> -		 * the interrupt number is the same for all vcpus, while as an
> -		 * SPI it must be a separate number per vcpu.
> -		 */
> -		if (irq < VGIC_NR_SGIS || irq >= vcpu->kvm->arch.vgic.nr_irqs ||
> -		    !irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
> +		/* The PMU overflow interrupt can be a PPI or a valid SPI. */
> +		if (!(irq_is_ppi(irq) || vgic_valid_spi(vcpu->kvm, irq)))
> +			return -EINVAL;
> +
> +		if (!irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))

Why do we need to pass this boolean as a parameter? You could rewrite
irq_is_valid() to generate the is_ppi boolean by itself.

>  			return -EINVAL;
>  
>  		if (kvm_arm_pmu_irq_initialized(vcpu))
> 

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 19/55] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-10 15:28     ` Eric Auger
  -1 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10 15:28 UTC (permalink / raw)
  To: Andre Przywara, Marc Zyngier, Christoffer Dall
  Cc: kvmarm, kvm, linux-arm-kernel

On 05/06/2016 12:45 PM, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> As the GICv3 virtual interface registers differ from their GICv2
> siblings, we need different handlers for processing maintenance
> interrupts and reading/writing to the LRs.
> Implement the respective handler functions and connect them to
> existing code to be called if the host is using a GICv3.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - remove outdated comment about the dist_lock
> - add WARN_ON about LR_STATE not being 0 in maintenance interrupts
> 
> Changelog v1 .. v2:
> - inject the IRQ priority into the list register
> 
> Changelog v2 .. v3:
> - remove no longer needed irqchip/arm-gic.h inclusion
> 
>  include/linux/irqchip/arm-gic-v3.h |   1 +
>  virt/kvm/arm/vgic/vgic-v3.c        | 168 +++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.c           |  25 ++++--
>  virt/kvm/arm/vgic/vgic.h           |  29 +++++++
>  4 files changed, 218 insertions(+), 5 deletions(-)
>  create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index ec938d1..35e93cf 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -275,6 +275,7 @@
>  #define ICH_LR_ACTIVE_BIT		(1ULL << 63)
>  #define ICH_LR_PHYS_ID_SHIFT		32
>  #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
> +#define ICH_LR_PRIORITY_SHIFT		48
>  
>  /* These are for GICv2 emulation only */
>  #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> new file mode 100644
> index 0000000..43d1dd7
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -0,0 +1,168 @@
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/irqchip/arm-gic-v3.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +
> +#include "vgic.h"
> +
> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +
> +	if (cpuif->vgic_misr & ICH_MISR_EOI) {
> +		unsigned long eisr_bmap = cpuif->vgic_eisr;
> +		int lr;
> +
> +		for_each_set_bit(lr, &eisr_bmap, kvm_vgic_global_state.nr_lr) {
used_lrs?
> +			u32 intid;
> +			u64 val = cpuif->vgic_lr[lr];
> +
> +			if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +				intid = val & ICH_LR_VIRTUAL_ID_MASK;
> +			else
> +				intid = val & GICH_LR_VIRTUALID;
> +
> +			WARN_ON(cpuif->vgic_lr[lr] & ICH_LR_STATE);
> +
> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> +					     intid - VGIC_NR_PRIVATE_IRQS);
> +
> +			cpuif->vgic_elrsr |= 1ULL << lr;
> +		}
> +
> +		/*
> +		 * In the next iterations of the vcpu loop, if we sync
> +		 * the vgic state after flushing it, but before
> +		 * entering the guest (this happens for pending
> +		 * signals and vmid rollovers), then make sure we
> +		 * don't pick up any old maintenance interrupts here.
> +		 */
> +		cpuif->vgic_eisr = 0;
> +	}
> +
> +	cpuif->vgic_hcr &= ~ICH_HCR_UIE;
> +}
> +
> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +
> +	cpuif->vgic_hcr |= ICH_HCR_UIE;
> +}
> +
> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	int lr;
> +
> +	/* Assumes ap_list_lock held */
I don't think there is such requirement and failed finding the lock held.

Besides Reviewed-by: Eric Auger <eric.auger@linaro.org>

Eric
> +
> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> +		u64 val = cpuif->vgic_lr[lr];
> +		u32 intid;
> +		struct vgic_irq *irq;
> +
> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +			intid = val & ICH_LR_VIRTUAL_ID_MASK;
> +		else
> +			intid = val & GICH_LR_VIRTUALID;
> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		/* Always preserve the active bit */
> +		irq->active = !!(val & ICH_LR_ACTIVE_BIT);
> +
> +		/* Edge is the only case where we preserve the pending bit */
> +		if (irq->config == VGIC_CONFIG_EDGE &&
> +		    (val & ICH_LR_PENDING_BIT)) {
> +			irq->pending = true;
> +
> +			if (vgic_irq_is_sgi(intid) &&
> +			    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> +
> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> +				irq->source |= (1 << cpuid);
> +			}
> +		}
> +
> +		/* Clear soft pending state when level irqs have been acked */
> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> +		    !(val & ICH_LR_PENDING_BIT)) {
> +			irq->soft_pending = false;
> +			irq->pending = irq->line_level;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +/* Requires the irq to be locked already */
> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> +{
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	u64 val = irq->intid;
> +
> +	if (irq->pending) {
> +		val |= ICH_LR_PENDING_BIT;
> +
> +		if (irq->config == VGIC_CONFIG_EDGE)
> +			irq->pending = false;
> +
> +		if (vgic_irq_is_sgi(irq->intid) &&
> +		    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> +			u32 src = ffs(irq->source);
> +
> +			BUG_ON(!src);
> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> +			irq->source &= ~(1 << (src - 1));
> +			if (irq->source)
> +				irq->pending = true;
> +		}
> +	}
> +
> +	if (irq->active)
> +		val |= ICH_LR_ACTIVE_BIT;
> +
> +	if (irq->hw) {
> +		val |= ICH_LR_HW;
> +		val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
> +	} else {
> +		if (irq->config == VGIC_CONFIG_LEVEL)
> +			val |= ICH_LR_EOI;
> +	}
> +
> +	/*
> +	 * Currently all guest IRQs are Group1, as Group0 would result
> +	 * in a FIQ in the guest, which it wouldn't expect.
> +	 * Eventually we want to make this configurable, so we may
> +	 * revisit this in the future.
> +	 */
> +	if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +		val |= ICH_LR_GROUP;
> +
> +	val |= (u64)irq->priority << ICH_LR_PRIORITY_SHIFT;
> +
> +	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = val;
> +}
> +
> +void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
> +{
> +	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = 0;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 68d885c..64d5b45 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -397,12 +397,18 @@ retry:
>  
>  static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>  {
> -	vgic_v2_process_maintenance(vcpu);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_process_maintenance(vcpu);
> +	else
> +		vgic_v3_process_maintenance(vcpu);
>  }
>  
>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>  {
> -	vgic_v2_fold_lr_state(vcpu);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_fold_lr_state(vcpu);
> +	else
> +		vgic_v3_fold_lr_state(vcpu);
>  }
>  
>  /* Requires the ap_list_lock and the irq_lock to be held. */
> @@ -412,17 +418,26 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
>  
> -	vgic_v2_populate_lr(vcpu, irq, lr);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_populate_lr(vcpu, irq, lr);
> +	else
> +		vgic_v3_populate_lr(vcpu, irq, lr);
>  }
>  
>  static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
>  {
> -	vgic_v2_clear_lr(vcpu, lr);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_clear_lr(vcpu, lr);
> +	else
> +		vgic_v3_clear_lr(vcpu, lr);
>  }
>  
>  static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>  {
> -	vgic_v2_set_underflow(vcpu);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_set_underflow(vcpu);
> +	else
> +		vgic_v3_set_underflow(vcpu);
>  }
>  
>  static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 0db490e..81b1a20 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -28,4 +28,33 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
>  void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>  
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
> +void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
> +#else
> +static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static inline void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static inline void vgic_v3_populate_lr(struct kvm_vcpu *vcpu,
> +				       struct vgic_irq *irq, int lr)
> +{
> +}
> +
> +static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
> +{
> +}
> +
> +static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +}
> +#endif
> +
>  #endif
> 


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

* [PATCH v3 19/55] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
@ 2016-05-10 15:28     ` Eric Auger
  0 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-10 15:28 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/06/2016 12:45 PM, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> As the GICv3 virtual interface registers differ from their GICv2
> siblings, we need different handlers for processing maintenance
> interrupts and reading/writing to the LRs.
> Implement the respective handler functions and connect them to
> existing code to be called if the host is using a GICv3.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - remove outdated comment about the dist_lock
> - add WARN_ON about LR_STATE not being 0 in maintenance interrupts
> 
> Changelog v1 .. v2:
> - inject the IRQ priority into the list register
> 
> Changelog v2 .. v3:
> - remove no longer needed irqchip/arm-gic.h inclusion
> 
>  include/linux/irqchip/arm-gic-v3.h |   1 +
>  virt/kvm/arm/vgic/vgic-v3.c        | 168 +++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.c           |  25 ++++--
>  virt/kvm/arm/vgic/vgic.h           |  29 +++++++
>  4 files changed, 218 insertions(+), 5 deletions(-)
>  create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index ec938d1..35e93cf 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -275,6 +275,7 @@
>  #define ICH_LR_ACTIVE_BIT		(1ULL << 63)
>  #define ICH_LR_PHYS_ID_SHIFT		32
>  #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
> +#define ICH_LR_PRIORITY_SHIFT		48
>  
>  /* These are for GICv2 emulation only */
>  #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> new file mode 100644
> index 0000000..43d1dd7
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -0,0 +1,168 @@
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/irqchip/arm-gic-v3.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +
> +#include "vgic.h"
> +
> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +
> +	if (cpuif->vgic_misr & ICH_MISR_EOI) {
> +		unsigned long eisr_bmap = cpuif->vgic_eisr;
> +		int lr;
> +
> +		for_each_set_bit(lr, &eisr_bmap, kvm_vgic_global_state.nr_lr) {
used_lrs?
> +			u32 intid;
> +			u64 val = cpuif->vgic_lr[lr];
> +
> +			if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +				intid = val & ICH_LR_VIRTUAL_ID_MASK;
> +			else
> +				intid = val & GICH_LR_VIRTUALID;
> +
> +			WARN_ON(cpuif->vgic_lr[lr] & ICH_LR_STATE);
> +
> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> +					     intid - VGIC_NR_PRIVATE_IRQS);
> +
> +			cpuif->vgic_elrsr |= 1ULL << lr;
> +		}
> +
> +		/*
> +		 * In the next iterations of the vcpu loop, if we sync
> +		 * the vgic state after flushing it, but before
> +		 * entering the guest (this happens for pending
> +		 * signals and vmid rollovers), then make sure we
> +		 * don't pick up any old maintenance interrupts here.
> +		 */
> +		cpuif->vgic_eisr = 0;
> +	}
> +
> +	cpuif->vgic_hcr &= ~ICH_HCR_UIE;
> +}
> +
> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +
> +	cpuif->vgic_hcr |= ICH_HCR_UIE;
> +}
> +
> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	int lr;
> +
> +	/* Assumes ap_list_lock held */
I don't think there is such requirement and failed finding the lock held.

Besides Reviewed-by: Eric Auger <eric.auger@linaro.org>

Eric
> +
> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
> +		u64 val = cpuif->vgic_lr[lr];
> +		u32 intid;
> +		struct vgic_irq *irq;
> +
> +		if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +			intid = val & ICH_LR_VIRTUAL_ID_MASK;
> +		else
> +			intid = val & GICH_LR_VIRTUALID;
> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		/* Always preserve the active bit */
> +		irq->active = !!(val & ICH_LR_ACTIVE_BIT);
> +
> +		/* Edge is the only case where we preserve the pending bit */
> +		if (irq->config == VGIC_CONFIG_EDGE &&
> +		    (val & ICH_LR_PENDING_BIT)) {
> +			irq->pending = true;
> +
> +			if (vgic_irq_is_sgi(intid) &&
> +			    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
> +
> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
> +				irq->source |= (1 << cpuid);
> +			}
> +		}
> +
> +		/* Clear soft pending state when level irqs have been acked */
> +		if (irq->config == VGIC_CONFIG_LEVEL &&
> +		    !(val & ICH_LR_PENDING_BIT)) {
> +			irq->soft_pending = false;
> +			irq->pending = irq->line_level;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +/* Requires the irq to be locked already */
> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> +{
> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
> +	u64 val = irq->intid;
> +
> +	if (irq->pending) {
> +		val |= ICH_LR_PENDING_BIT;
> +
> +		if (irq->config == VGIC_CONFIG_EDGE)
> +			irq->pending = false;
> +
> +		if (vgic_irq_is_sgi(irq->intid) &&
> +		    model == KVM_DEV_TYPE_ARM_VGIC_V2) {
> +			u32 src = ffs(irq->source);
> +
> +			BUG_ON(!src);
> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
> +			irq->source &= ~(1 << (src - 1));
> +			if (irq->source)
> +				irq->pending = true;
> +		}
> +	}
> +
> +	if (irq->active)
> +		val |= ICH_LR_ACTIVE_BIT;
> +
> +	if (irq->hw) {
> +		val |= ICH_LR_HW;
> +		val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
> +	} else {
> +		if (irq->config == VGIC_CONFIG_LEVEL)
> +			val |= ICH_LR_EOI;
> +	}
> +
> +	/*
> +	 * Currently all guest IRQs are Group1, as Group0 would result
> +	 * in a FIQ in the guest, which it wouldn't expect.
> +	 * Eventually we want to make this configurable, so we may
> +	 * revisit this in the future.
> +	 */
> +	if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +		val |= ICH_LR_GROUP;
> +
> +	val |= (u64)irq->priority << ICH_LR_PRIORITY_SHIFT;
> +
> +	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = val;
> +}
> +
> +void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
> +{
> +	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = 0;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 68d885c..64d5b45 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -397,12 +397,18 @@ retry:
>  
>  static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>  {
> -	vgic_v2_process_maintenance(vcpu);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_process_maintenance(vcpu);
> +	else
> +		vgic_v3_process_maintenance(vcpu);
>  }
>  
>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>  {
> -	vgic_v2_fold_lr_state(vcpu);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_fold_lr_state(vcpu);
> +	else
> +		vgic_v3_fold_lr_state(vcpu);
>  }
>  
>  /* Requires the ap_list_lock and the irq_lock to be held. */
> @@ -412,17 +418,26 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
>  
> -	vgic_v2_populate_lr(vcpu, irq, lr);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_populate_lr(vcpu, irq, lr);
> +	else
> +		vgic_v3_populate_lr(vcpu, irq, lr);
>  }
>  
>  static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
>  {
> -	vgic_v2_clear_lr(vcpu, lr);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_clear_lr(vcpu, lr);
> +	else
> +		vgic_v3_clear_lr(vcpu, lr);
>  }
>  
>  static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>  {
> -	vgic_v2_set_underflow(vcpu);
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_set_underflow(vcpu);
> +	else
> +		vgic_v3_set_underflow(vcpu);
>  }
>  
>  static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 0db490e..81b1a20 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -28,4 +28,33 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
>  void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>  
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
> +void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
> +void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
> +#else
> +static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static inline void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> +{
> +}
> +
> +static inline void vgic_v3_populate_lr(struct kvm_vcpu *vcpu,
> +				       struct vgic_irq *irq, int lr)
> +{
> +}
> +
> +static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
> +{
> +}
> +
> +static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> +{
> +}
> +#endif
> +
>  #endif
> 

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

* [PATCH v2] KVM: arm/arm64: vgic-new: fix overlap check for device addresses
  2016-05-10 13:16         ` Marc Zyngier
@ 2016-05-10 17:18           ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-10 17:18 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

When userland sets the base addresses for the GIC register frames,
the kernel tries to make sure that the regions for the distributor and
the one for the CPU interface or the redistributors do not overlap.
Currently this check only works properly for GICv2.
For a GICv3 we need the number of VCPUs to compute the size of the
redistributor region, which we only know for sure at init time.
So move the overlap check from kvm_vgic_addr() to the model specific
map_resources() implementation.
This also allows us to simplify the existing checking code a bit.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Hi,

so another rework, now hopefully really covering GICv3 properly.
For consistency I also moved the GICv2 check to init time. This is
a slightly different behaviour, but shouldn't make a difference, as
the init call can fail as well - for instance if no addresses have been
set up at all.

Cheers,
Andre.

 virt/kvm/arm/vgic/vgic-kvm-device.c | 50 ++++++++-----------------------------
 virt/kvm/arm/vgic/vgic-v2.c         | 22 ++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c         | 27 ++++++++++++++++++++
 3 files changed, 60 insertions(+), 39 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index 2122ff2..9e736a7 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -19,43 +19,19 @@
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
-/* common helpers */
-
-static int vgic_ioaddr_overlap(struct kvm *kvm)
-{
-	phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;
-	phys_addr_t cpu = kvm->arch.vgic.vgic_cpu_base;
-
-	if (IS_VGIC_ADDR_UNDEF(dist) || IS_VGIC_ADDR_UNDEF(cpu))
-		return 0;
-	if ((dist <= cpu && dist + KVM_VGIC_V2_DIST_SIZE > cpu) ||
-	    (cpu <= dist && cpu + KVM_VGIC_V2_CPU_SIZE > dist))
-		return -EBUSY;
-	return 0;
-}
-
-static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
-			      phys_addr_t addr, phys_addr_t size)
+static int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
+			     phys_addr_t addr, phys_addr_t alignment)
 {
-	int ret;
-
 	if (addr & ~KVM_PHYS_MASK)
 		return -E2BIG;
 
-	if (addr & (SZ_4K - 1))
+	if (!IS_ALIGNED(addr, alignment))
 		return -EINVAL;
 
 	if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
 		return -EEXIST;
-	if (addr + size < addr)
-		return -EINVAL;
-
-	*ioaddr = addr;
-	ret = vgic_ioaddr_overlap(kvm);
-	if (ret)
-		*ioaddr = VGIC_ADDR_UNDEF;
 
-	return ret;
+	return 0;
 }
 
 /**
@@ -70,40 +46,38 @@ static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
  * interface in the VM physical address space.  These addresses are properties
  * of the emulated core/SoC and therefore user space initially knows this
  * information.
+ * Check them for sanity (alignment, double assignment). We can't check for
+ * overlapping regions in case of a virtual GICv3 here, since we don't know
+ * the number of VCPUs yet, so we defer this check to map_resources().
  */
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
 {
 	int r = 0;
 	struct vgic_dist *vgic = &kvm->arch.vgic;
 	int type_needed;
-	phys_addr_t *addr_ptr, block_size;
-	phys_addr_t alignment;
+	phys_addr_t *addr_ptr, alignment;
 
 	mutex_lock(&kvm->lock);
 	switch (type) {
 	case KVM_VGIC_V2_ADDR_TYPE_DIST:
 		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
 		addr_ptr = &vgic->vgic_dist_base;
-		block_size = KVM_VGIC_V2_DIST_SIZE;
 		alignment = SZ_4K;
 		break;
 	case KVM_VGIC_V2_ADDR_TYPE_CPU:
 		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
 		addr_ptr = &vgic->vgic_cpu_base;
-		block_size = KVM_VGIC_V2_CPU_SIZE;
 		alignment = SZ_4K;
 		break;
 #ifdef CONFIG_KVM_ARM_VGIC_V3
 	case KVM_VGIC_V3_ADDR_TYPE_DIST:
 		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
 		addr_ptr = &vgic->vgic_dist_base;
-		block_size = KVM_VGIC_V3_DIST_SIZE;
 		alignment = SZ_64K;
 		break;
 	case KVM_VGIC_V3_ADDR_TYPE_REDIST:
 		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
 		addr_ptr = &vgic->vgic_redist_base;
-		block_size = KVM_VGIC_V3_REDIST_SIZE;
 		alignment = SZ_64K;
 		break;
 #endif
@@ -118,11 +92,9 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
 	}
 
 	if (write) {
-		if (!IS_ALIGNED(*addr, alignment))
-			r = -EINVAL;
-		else
-			r = vgic_ioaddr_assign(kvm, addr_ptr,
-					       *addr, block_size);
+		r = vgic_check_ioaddr(kvm, addr_ptr, *addr, alignment);
+		if (!r)
+			*addr_ptr = *addr;
 	} else {
 		*addr = *addr_ptr;
 	}
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 4493593..fe6e3bd 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -225,6 +225,22 @@ void vgic_v2_enable(struct kvm_vcpu *vcpu)
 	vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr = GICH_HCR_EN;
 }
 
+/* check for overlapping regions and for regions crossing the end of memory */
+static bool vgic_check_addresses(gpa_t dist_base, gpa_t cpu_base)
+{
+	if (dist_base + KVM_VGIC_V2_DIST_SIZE < dist_base)
+		return false;
+	if (cpu_base + KVM_VGIC_V2_CPU_SIZE < cpu_base)
+		return false;
+
+	if (dist_base + KVM_VGIC_V2_DIST_SIZE <= cpu_base)
+		return true;
+	if (cpu_base + KVM_VGIC_V2_CPU_SIZE <= dist_base)
+		return true;
+
+	return false;
+}
+
 int vgic_v2_map_resources(struct kvm *kvm)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
@@ -240,6 +256,12 @@ int vgic_v2_map_resources(struct kvm *kvm)
 		goto out;
 	}
 
+	if (!vgic_check_addresses(dist->vgic_dist_base, dist->vgic_cpu_base)) {
+		kvm_err("VGIC CPU and dist frames overlap\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
 	/*
 	 * Initialize the vgic if this hasn't already been done on demand by
 	 * accessing the vgic state from userspace.
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 6d7422f..fa444a7 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -221,6 +221,27 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 	vgic_v3->vgic_hcr = ICH_HCR_EN;
 }
 
+/* check for overlapping regions and for regions crossing the end of memory */
+static bool vgic_check_addresses(struct kvm *kvm)
+{
+	struct vgic_dist *d = &kvm->arch.vgic;
+	gpa_t redist_size = KVM_VGIC_V3_REDIST_SIZE;
+
+	redist_size *= atomic_read(&kvm->online_vcpus);
+
+	if (d->vgic_dist_base + KVM_VGIC_V3_DIST_SIZE < d->vgic_dist_base)
+		return false;
+	if (d->vgic_redist_base + redist_size < d->vgic_redist_base)
+		return false;
+
+	if (d->vgic_dist_base + KVM_VGIC_V3_DIST_SIZE <= d->vgic_redist_base)
+		return true;
+	if (d->vgic_redist_base + redist_size <= d->vgic_dist_base)
+		return true;
+
+	return false;
+}
+
 int vgic_v3_map_resources(struct kvm *kvm)
 {
 	int ret = 0;
@@ -236,6 +257,12 @@ int vgic_v3_map_resources(struct kvm *kvm)
 		goto out;
 	}
 
+	if (!vgic_check_addresses(kvm)) {
+		kvm_err("VGIC redist and dist frames overlap\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
 	/*
 	 * For a VGICv3 we require the userland to explicitly initialize
 	 * the VGIC before we need to use it.
-- 
2.7.3


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

* [PATCH v2] KVM: arm/arm64: vgic-new: fix overlap check for device addresses
@ 2016-05-10 17:18           ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-10 17:18 UTC (permalink / raw)
  To: linux-arm-kernel

When userland sets the base addresses for the GIC register frames,
the kernel tries to make sure that the regions for the distributor and
the one for the CPU interface or the redistributors do not overlap.
Currently this check only works properly for GICv2.
For a GICv3 we need the number of VCPUs to compute the size of the
redistributor region, which we only know for sure at init time.
So move the overlap check from kvm_vgic_addr() to the model specific
map_resources() implementation.
This also allows us to simplify the existing checking code a bit.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Hi,

so another rework, now hopefully really covering GICv3 properly.
For consistency I also moved the GICv2 check to init time. This is
a slightly different behaviour, but shouldn't make a difference, as
the init call can fail as well - for instance if no addresses have been
set up at all.

Cheers,
Andre.

 virt/kvm/arm/vgic/vgic-kvm-device.c | 50 ++++++++-----------------------------
 virt/kvm/arm/vgic/vgic-v2.c         | 22 ++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c         | 27 ++++++++++++++++++++
 3 files changed, 60 insertions(+), 39 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index 2122ff2..9e736a7 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -19,43 +19,19 @@
 #include <asm/kvm_mmu.h>
 #include "vgic.h"
 
-/* common helpers */
-
-static int vgic_ioaddr_overlap(struct kvm *kvm)
-{
-	phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;
-	phys_addr_t cpu = kvm->arch.vgic.vgic_cpu_base;
-
-	if (IS_VGIC_ADDR_UNDEF(dist) || IS_VGIC_ADDR_UNDEF(cpu))
-		return 0;
-	if ((dist <= cpu && dist + KVM_VGIC_V2_DIST_SIZE > cpu) ||
-	    (cpu <= dist && cpu + KVM_VGIC_V2_CPU_SIZE > dist))
-		return -EBUSY;
-	return 0;
-}
-
-static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
-			      phys_addr_t addr, phys_addr_t size)
+static int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
+			     phys_addr_t addr, phys_addr_t alignment)
 {
-	int ret;
-
 	if (addr & ~KVM_PHYS_MASK)
 		return -E2BIG;
 
-	if (addr & (SZ_4K - 1))
+	if (!IS_ALIGNED(addr, alignment))
 		return -EINVAL;
 
 	if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
 		return -EEXIST;
-	if (addr + size < addr)
-		return -EINVAL;
-
-	*ioaddr = addr;
-	ret = vgic_ioaddr_overlap(kvm);
-	if (ret)
-		*ioaddr = VGIC_ADDR_UNDEF;
 
-	return ret;
+	return 0;
 }
 
 /**
@@ -70,40 +46,38 @@ static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
  * interface in the VM physical address space.  These addresses are properties
  * of the emulated core/SoC and therefore user space initially knows this
  * information.
+ * Check them for sanity (alignment, double assignment). We can't check for
+ * overlapping regions in case of a virtual GICv3 here, since we don't know
+ * the number of VCPUs yet, so we defer this check to map_resources().
  */
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
 {
 	int r = 0;
 	struct vgic_dist *vgic = &kvm->arch.vgic;
 	int type_needed;
-	phys_addr_t *addr_ptr, block_size;
-	phys_addr_t alignment;
+	phys_addr_t *addr_ptr, alignment;
 
 	mutex_lock(&kvm->lock);
 	switch (type) {
 	case KVM_VGIC_V2_ADDR_TYPE_DIST:
 		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
 		addr_ptr = &vgic->vgic_dist_base;
-		block_size = KVM_VGIC_V2_DIST_SIZE;
 		alignment = SZ_4K;
 		break;
 	case KVM_VGIC_V2_ADDR_TYPE_CPU:
 		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
 		addr_ptr = &vgic->vgic_cpu_base;
-		block_size = KVM_VGIC_V2_CPU_SIZE;
 		alignment = SZ_4K;
 		break;
 #ifdef CONFIG_KVM_ARM_VGIC_V3
 	case KVM_VGIC_V3_ADDR_TYPE_DIST:
 		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
 		addr_ptr = &vgic->vgic_dist_base;
-		block_size = KVM_VGIC_V3_DIST_SIZE;
 		alignment = SZ_64K;
 		break;
 	case KVM_VGIC_V3_ADDR_TYPE_REDIST:
 		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
 		addr_ptr = &vgic->vgic_redist_base;
-		block_size = KVM_VGIC_V3_REDIST_SIZE;
 		alignment = SZ_64K;
 		break;
 #endif
@@ -118,11 +92,9 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
 	}
 
 	if (write) {
-		if (!IS_ALIGNED(*addr, alignment))
-			r = -EINVAL;
-		else
-			r = vgic_ioaddr_assign(kvm, addr_ptr,
-					       *addr, block_size);
+		r = vgic_check_ioaddr(kvm, addr_ptr, *addr, alignment);
+		if (!r)
+			*addr_ptr = *addr;
 	} else {
 		*addr = *addr_ptr;
 	}
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 4493593..fe6e3bd 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -225,6 +225,22 @@ void vgic_v2_enable(struct kvm_vcpu *vcpu)
 	vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr = GICH_HCR_EN;
 }
 
+/* check for overlapping regions and for regions crossing the end of memory */
+static bool vgic_check_addresses(gpa_t dist_base, gpa_t cpu_base)
+{
+	if (dist_base + KVM_VGIC_V2_DIST_SIZE < dist_base)
+		return false;
+	if (cpu_base + KVM_VGIC_V2_CPU_SIZE < cpu_base)
+		return false;
+
+	if (dist_base + KVM_VGIC_V2_DIST_SIZE <= cpu_base)
+		return true;
+	if (cpu_base + KVM_VGIC_V2_CPU_SIZE <= dist_base)
+		return true;
+
+	return false;
+}
+
 int vgic_v2_map_resources(struct kvm *kvm)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
@@ -240,6 +256,12 @@ int vgic_v2_map_resources(struct kvm *kvm)
 		goto out;
 	}
 
+	if (!vgic_check_addresses(dist->vgic_dist_base, dist->vgic_cpu_base)) {
+		kvm_err("VGIC CPU and dist frames overlap\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
 	/*
 	 * Initialize the vgic if this hasn't already been done on demand by
 	 * accessing the vgic state from userspace.
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 6d7422f..fa444a7 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -221,6 +221,27 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 	vgic_v3->vgic_hcr = ICH_HCR_EN;
 }
 
+/* check for overlapping regions and for regions crossing the end of memory */
+static bool vgic_check_addresses(struct kvm *kvm)
+{
+	struct vgic_dist *d = &kvm->arch.vgic;
+	gpa_t redist_size = KVM_VGIC_V3_REDIST_SIZE;
+
+	redist_size *= atomic_read(&kvm->online_vcpus);
+
+	if (d->vgic_dist_base + KVM_VGIC_V3_DIST_SIZE < d->vgic_dist_base)
+		return false;
+	if (d->vgic_redist_base + redist_size < d->vgic_redist_base)
+		return false;
+
+	if (d->vgic_dist_base + KVM_VGIC_V3_DIST_SIZE <= d->vgic_redist_base)
+		return true;
+	if (d->vgic_redist_base + redist_size <= d->vgic_dist_base)
+		return true;
+
+	return false;
+}
+
 int vgic_v3_map_resources(struct kvm *kvm)
 {
 	int ret = 0;
@@ -236,6 +257,12 @@ int vgic_v3_map_resources(struct kvm *kvm)
 		goto out;
 	}
 
+	if (!vgic_check_addresses(kvm)) {
+		kvm_err("VGIC redist and dist frames overlap\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
 	/*
 	 * For a VGICv3 we require the userland to explicitly initialize
 	 * the VGIC before we need to use it.
-- 
2.7.3

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

* Re: [PATCH v3 17/55] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
  2016-05-10 15:20     ` Eric Auger
@ 2016-05-10 17:32       ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 17:32 UTC (permalink / raw)
  To: Eric Auger, Andre Przywara, Christoffer Dall
  Cc: linux-arm-kernel, kvmarm, kvm

On 10/05/16 16:20, Eric Auger wrote:
> On 05/06/2016 12:45 PM, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Implement the framework for syncing IRQs between our emulation and
>> the list registers, which represent the guest's view of IRQs.
>> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
>> which gets called on guest entry and exit.
>> The code talking to the actual GICv2/v3 hardware is added in the
>> following patches.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - split out vgic_clear_lr() from vgic_populate_lr()
>> - rename vgic_populate_lrs() to vgic_flush_lr_state()
>> - clean all LRs when the distributor is disabled
>> - use list_del() instead of list_del_init()
>> - add comments to explain the direction of sync/flush_hwstate
>> - remove unneeded BUG_ON(in_interrupt()
>>
>> Changelog v2 .. v3:
>> - remove bogus v2 specific rebase leftovers
>>
>>  include/kvm/vgic/vgic.h  |   4 +
>>  virt/kvm/arm/vgic/vgic.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.h |   2 +
>>  3 files changed, 199 insertions(+)
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index 2bfb42c..5fae4a9 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -190,6 +190,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>>  
>> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
>> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
>> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
>> +
>>  /**
>>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>>   *
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index 4fb20fd..c6f8b9b 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -305,3 +305,196 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  {
>>  	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
>>  }
>> +
>> +/**
>> + * vgic_prune_ap_list - Remove non-relevant interrupts from the list
>> + *
>> + * @vcpu: The VCPU pointer
>> + *
>> + * Go over the list of "interesting" interrupts, and prune those that we
>> + * won't have to consider in the near future.
>> + */
>> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	struct vgic_irq *irq, *tmp;
>> +
>> +retry:
>> +	spin_lock(&vgic_cpu->ap_list_lock);
>> +
>> +	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
>> +		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		BUG_ON(vcpu != irq->vcpu);
>> +
>> +		target_vcpu = vgic_target_oracle(irq);
>> +
>> +		if (!target_vcpu) {
>> +			/*
>> +			 * We don't need to process this interrupt any
>> +			 * further, move it off the list.
>> +			 */
>> +			list_del(&irq->ap_list);
>> +			irq->vcpu = NULL;
>> +			spin_unlock(&irq->irq_lock);
>> +			continue;
>> +		}
>> +
>> +		if (target_vcpu == vcpu) {
>> +			/* We're on the right CPU */
>> +			spin_unlock(&irq->irq_lock);
>> +			continue;
>> +		}
>> +
>> +		/* This interrupt looks like it has to be migrated. */
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +		spin_unlock(&vgic_cpu->ap_list_lock);
>> +
>> +		/*
>> +		 * Ensure locking order by always locking the smallest
>> +		 * ID first.
>> +		 */
>> +		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
>> +			vcpuA = vcpu;
>> +			vcpuB = target_vcpu;
>> +		} else {
>> +			vcpuA = target_vcpu;
>> +			vcpuB = vcpu;
>> +		}
>> +
>> +		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
>> +		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		/*
>> +		 * If the affinity has been preserved, move the
>> +		 * interrupt around. Otherwise, it means things have
>> +		 * changed while the interrupt was unlocked, and we
>> +		 * need to replay this.
>> +		 *
>> +		 * In all cases, we cannot trust the list not to have
>> +		 * changed, so we restart from the beginning.
>> +		 */
>> +		if (target_vcpu == vgic_target_oracle(irq)) {
>> +			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
>> +
>> +			list_del(&irq->ap_list);
>> +			irq->vcpu = target_vcpu;
>> +			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
>> +		}
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
>> +		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
>> +		goto retry;
>> +	}
>> +
>> +	spin_unlock(&vgic_cpu->ap_list_lock);
>> +}
>> +
>> +static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>> +{
>> +}
>> +
>> +static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +}
>> +
>> +/* Requires the ap_list_lock and the irq_lock to be held. */
> why is it needed to hold the ap_list lock here?
>> +static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>> +				    struct vgic_irq *irq, int lr)
>> +{
>> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
> ?

Only the irq lock needs to be held for this particular function. It is
vgic_flush_lr_state that requires the ap_list lock to be held, as it is
iterating over all the interrupts for that particular vcpu.

Andre, can you please amend the comment and drop that assertion?

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 17/55] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
@ 2016-05-10 17:32       ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 17:32 UTC (permalink / raw)
  To: linux-arm-kernel

On 10/05/16 16:20, Eric Auger wrote:
> On 05/06/2016 12:45 PM, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Implement the framework for syncing IRQs between our emulation and
>> the list registers, which represent the guest's view of IRQs.
>> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
>> which gets called on guest entry and exit.
>> The code talking to the actual GICv2/v3 hardware is added in the
>> following patches.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - split out vgic_clear_lr() from vgic_populate_lr()
>> - rename vgic_populate_lrs() to vgic_flush_lr_state()
>> - clean all LRs when the distributor is disabled
>> - use list_del() instead of list_del_init()
>> - add comments to explain the direction of sync/flush_hwstate
>> - remove unneeded BUG_ON(in_interrupt()
>>
>> Changelog v2 .. v3:
>> - remove bogus v2 specific rebase leftovers
>>
>>  include/kvm/vgic/vgic.h  |   4 +
>>  virt/kvm/arm/vgic/vgic.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.h |   2 +
>>  3 files changed, 199 insertions(+)
>>
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> index 2bfb42c..5fae4a9 100644
>> --- a/include/kvm/vgic/vgic.h
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -190,6 +190,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
>>  
>> +bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
>> +void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
>> +void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
>> +
>>  /**
>>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>>   *
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index 4fb20fd..c6f8b9b 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -305,3 +305,196 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>>  {
>>  	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
>>  }
>> +
>> +/**
>> + * vgic_prune_ap_list - Remove non-relevant interrupts from the list
>> + *
>> + * @vcpu: The VCPU pointer
>> + *
>> + * Go over the list of "interesting" interrupts, and prune those that we
>> + * won't have to consider in the near future.
>> + */
>> +static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	struct vgic_irq *irq, *tmp;
>> +
>> +retry:
>> +	spin_lock(&vgic_cpu->ap_list_lock);
>> +
>> +	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
>> +		struct kvm_vcpu *target_vcpu, *vcpuA, *vcpuB;
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		BUG_ON(vcpu != irq->vcpu);
>> +
>> +		target_vcpu = vgic_target_oracle(irq);
>> +
>> +		if (!target_vcpu) {
>> +			/*
>> +			 * We don't need to process this interrupt any
>> +			 * further, move it off the list.
>> +			 */
>> +			list_del(&irq->ap_list);
>> +			irq->vcpu = NULL;
>> +			spin_unlock(&irq->irq_lock);
>> +			continue;
>> +		}
>> +
>> +		if (target_vcpu == vcpu) {
>> +			/* We're on the right CPU */
>> +			spin_unlock(&irq->irq_lock);
>> +			continue;
>> +		}
>> +
>> +		/* This interrupt looks like it has to be migrated. */
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +		spin_unlock(&vgic_cpu->ap_list_lock);
>> +
>> +		/*
>> +		 * Ensure locking order by always locking the smallest
>> +		 * ID first.
>> +		 */
>> +		if (vcpu->vcpu_id < target_vcpu->vcpu_id) {
>> +			vcpuA = vcpu;
>> +			vcpuB = target_vcpu;
>> +		} else {
>> +			vcpuA = target_vcpu;
>> +			vcpuB = vcpu;
>> +		}
>> +
>> +		spin_lock(&vcpuA->arch.vgic_cpu.ap_list_lock);
>> +		spin_lock(&vcpuB->arch.vgic_cpu.ap_list_lock);
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		/*
>> +		 * If the affinity has been preserved, move the
>> +		 * interrupt around. Otherwise, it means things have
>> +		 * changed while the interrupt was unlocked, and we
>> +		 * need to replay this.
>> +		 *
>> +		 * In all cases, we cannot trust the list not to have
>> +		 * changed, so we restart from the beginning.
>> +		 */
>> +		if (target_vcpu == vgic_target_oracle(irq)) {
>> +			struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;
>> +
>> +			list_del(&irq->ap_list);
>> +			irq->vcpu = target_vcpu;
>> +			list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
>> +		}
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +		spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
>> +		spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
>> +		goto retry;
>> +	}
>> +
>> +	spin_unlock(&vgic_cpu->ap_list_lock);
>> +}
>> +
>> +static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>> +{
>> +}
>> +
>> +static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +}
>> +
>> +/* Requires the ap_list_lock and the irq_lock to be held. */
> why is it needed to hold the ap_list lock here?
>> +static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>> +				    struct vgic_irq *irq, int lr)
>> +{
>> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
> ?

Only the irq lock needs to be held for this particular function. It is
vgic_flush_lr_state that requires the ap_list lock to be held, as it is
iterating over all the interrupts for that particular vcpu.

Andre, can you please amend the comment and drop that assertion?

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 19/55] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
  2016-05-10 15:28     ` Eric Auger
@ 2016-05-10 17:35       ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 17:35 UTC (permalink / raw)
  To: Eric Auger, Andre Przywara, Christoffer Dall
  Cc: kvmarm, kvm, linux-arm-kernel

On 10/05/16 16:28, Eric Auger wrote:
> On 05/06/2016 12:45 PM, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> As the GICv3 virtual interface registers differ from their GICv2
>> siblings, we need different handlers for processing maintenance
>> interrupts and reading/writing to the LRs.
>> Implement the respective handler functions and connect them to
>> existing code to be called if the host is using a GICv3.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - remove outdated comment about the dist_lock
>> - add WARN_ON about LR_STATE not being 0 in maintenance interrupts
>>
>> Changelog v1 .. v2:
>> - inject the IRQ priority into the list register
>>
>> Changelog v2 .. v3:
>> - remove no longer needed irqchip/arm-gic.h inclusion
>>
>>  include/linux/irqchip/arm-gic-v3.h |   1 +
>>  virt/kvm/arm/vgic/vgic-v3.c        | 168 +++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.c           |  25 ++++--
>>  virt/kvm/arm/vgic/vgic.h           |  29 +++++++
>>  4 files changed, 218 insertions(+), 5 deletions(-)
>>  create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
>>
>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
>> index ec938d1..35e93cf 100644
>> --- a/include/linux/irqchip/arm-gic-v3.h
>> +++ b/include/linux/irqchip/arm-gic-v3.h
>> @@ -275,6 +275,7 @@
>>  #define ICH_LR_ACTIVE_BIT		(1ULL << 63)
>>  #define ICH_LR_PHYS_ID_SHIFT		32
>>  #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
>> +#define ICH_LR_PRIORITY_SHIFT		48
>>  
>>  /* These are for GICv2 emulation only */
>>  #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>> new file mode 100644
>> index 0000000..43d1dd7
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>> @@ -0,0 +1,168 @@
>> +/*
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/irqchip/arm-gic-v3.h>
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +
>> +#include "vgic.h"
>> +
>> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
>> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
>> +
>> +	if (cpuif->vgic_misr & ICH_MISR_EOI) {
>> +		unsigned long eisr_bmap = cpuif->vgic_eisr;
>> +		int lr;
>> +
>> +		for_each_set_bit(lr, &eisr_bmap, kvm_vgic_global_state.nr_lr) {
> used_lrs?

Indeed.

>> +			u32 intid;
>> +			u64 val = cpuif->vgic_lr[lr];
>> +
>> +			if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
>> +				intid = val & ICH_LR_VIRTUAL_ID_MASK;
>> +			else
>> +				intid = val & GICH_LR_VIRTUALID;
>> +
>> +			WARN_ON(cpuif->vgic_lr[lr] & ICH_LR_STATE);
>> +
>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>> +
>> +			cpuif->vgic_elrsr |= 1ULL << lr;
>> +		}
>> +
>> +		/*
>> +		 * In the next iterations of the vcpu loop, if we sync
>> +		 * the vgic state after flushing it, but before
>> +		 * entering the guest (this happens for pending
>> +		 * signals and vmid rollovers), then make sure we
>> +		 * don't pick up any old maintenance interrupts here.
>> +		 */
>> +		cpuif->vgic_eisr = 0;
>> +	}
>> +
>> +	cpuif->vgic_hcr &= ~ICH_HCR_UIE;
>> +}
>> +
>> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
>> +
>> +	cpuif->vgic_hcr |= ICH_HCR_UIE;
>> +}
>> +
>> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
>> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
>> +	int lr;
>> +
>> +	/* Assumes ap_list_lock held */
> I don't think there is such requirement and failed finding the lock held.

This looks like a leftover from a previous version. Folding the state is
done on a per-irq basis, and doesn't require to parse the ap_list.

> Besides Reviewed-by: Eric Auger <eric.auger@linaro.org>

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 19/55] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
@ 2016-05-10 17:35       ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-10 17:35 UTC (permalink / raw)
  To: linux-arm-kernel

On 10/05/16 16:28, Eric Auger wrote:
> On 05/06/2016 12:45 PM, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> As the GICv3 virtual interface registers differ from their GICv2
>> siblings, we need different handlers for processing maintenance
>> interrupts and reading/writing to the LRs.
>> Implement the respective handler functions and connect them to
>> existing code to be called if the host is using a GICv3.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - remove outdated comment about the dist_lock
>> - add WARN_ON about LR_STATE not being 0 in maintenance interrupts
>>
>> Changelog v1 .. v2:
>> - inject the IRQ priority into the list register
>>
>> Changelog v2 .. v3:
>> - remove no longer needed irqchip/arm-gic.h inclusion
>>
>>  include/linux/irqchip/arm-gic-v3.h |   1 +
>>  virt/kvm/arm/vgic/vgic-v3.c        | 168 +++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.c           |  25 ++++--
>>  virt/kvm/arm/vgic/vgic.h           |  29 +++++++
>>  4 files changed, 218 insertions(+), 5 deletions(-)
>>  create mode 100644 virt/kvm/arm/vgic/vgic-v3.c
>>
>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
>> index ec938d1..35e93cf 100644
>> --- a/include/linux/irqchip/arm-gic-v3.h
>> +++ b/include/linux/irqchip/arm-gic-v3.h
>> @@ -275,6 +275,7 @@
>>  #define ICH_LR_ACTIVE_BIT		(1ULL << 63)
>>  #define ICH_LR_PHYS_ID_SHIFT		32
>>  #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
>> +#define ICH_LR_PRIORITY_SHIFT		48
>>  
>>  /* These are for GICv2 emulation only */
>>  #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>> new file mode 100644
>> index 0000000..43d1dd7
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>> @@ -0,0 +1,168 @@
>> +/*
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/irqchip/arm-gic-v3.h>
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +
>> +#include "vgic.h"
>> +
>> +void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
>> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
>> +
>> +	if (cpuif->vgic_misr & ICH_MISR_EOI) {
>> +		unsigned long eisr_bmap = cpuif->vgic_eisr;
>> +		int lr;
>> +
>> +		for_each_set_bit(lr, &eisr_bmap, kvm_vgic_global_state.nr_lr) {
> used_lrs?

Indeed.

>> +			u32 intid;
>> +			u64 val = cpuif->vgic_lr[lr];
>> +
>> +			if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
>> +				intid = val & ICH_LR_VIRTUAL_ID_MASK;
>> +			else
>> +				intid = val & GICH_LR_VIRTUALID;
>> +
>> +			WARN_ON(cpuif->vgic_lr[lr] & ICH_LR_STATE);
>> +
>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>> +
>> +			cpuif->vgic_elrsr |= 1ULL << lr;
>> +		}
>> +
>> +		/*
>> +		 * In the next iterations of the vcpu loop, if we sync
>> +		 * the vgic state after flushing it, but before
>> +		 * entering the guest (this happens for pending
>> +		 * signals and vmid rollovers), then make sure we
>> +		 * don't pick up any old maintenance interrupts here.
>> +		 */
>> +		cpuif->vgic_eisr = 0;
>> +	}
>> +
>> +	cpuif->vgic_hcr &= ~ICH_HCR_UIE;
>> +}
>> +
>> +void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
>> +
>> +	cpuif->vgic_hcr |= ICH_HCR_UIE;
>> +}
>> +
>> +void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
>> +	u32 model = vcpu->kvm->arch.vgic.vgic_model;
>> +	int lr;
>> +
>> +	/* Assumes ap_list_lock held */
> I don't think there is such requirement and failed finding the lock held.

This looks like a leftover from a previous version. Folding the state is
done on a per-irq basis, and doesn't require to parse the ap_list.

> Besides Reviewed-by: Eric Auger <eric.auger@linaro.org>

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
  2016-05-09 17:27     ` Marc Zyngier
@ 2016-05-11  8:24       ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11  8:24 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Hi,

On 09/05/16 18:27, Marc Zyngier wrote:
> On 06/05/16 11:46, Andre Przywara wrote:
>> Using the VMCR accessors we provide access to GIC CPU interface state
>> to userland by wiring it up to the existing userland interface.
>> [Marc: move and make VMCR accessors static, streamline MMIO handlers]
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>> Changelog v2 .. v3:
>> - total rework, moving into vgic-mmio-v2.c
>> - move vmcr accessor wrapper functions into this file
>> - use the register description table for CPU i/f registers as well
>> - add RAZ/WI handling for the active priority registers
>> - streamline MMIO handler functions
>>
>>  virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.h            |   2 +
>>  3 files changed, 107 insertions(+), 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> index bb33af8..2122ff2 100644
>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> @@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
>>  
>>  	switch (attr->group) {
>>  	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
>> -		ret = -EINVAL;
>> +		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
>>  		break;
>>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>>  		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index c453e6f..0060539 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -206,6 +206,84 @@ 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. */
>> +static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
>> +					   gpa_t addr, unsigned int len)
>> +{
>> +	struct vgic_vmcr vmcr;
>> +	u32 val;
>> +
>> +	vgic_get_vmcr(vcpu, &vmcr);
>> +
>> +	switch (addr & 0xff) {
>> +	case GIC_CPU_CTRL:
>> +		val = vmcr.ctlr;
>> +		break;
>> +	case GIC_CPU_PRIMASK:
>> +		val = vmcr.pmr;
>> +		break;
>> +	case GIC_CPU_BINPOINT:
>> +		val = vmcr.bpr;
>> +		break;
>> +	case GIC_CPU_ALIAS_BINPOINT:
>> +		val = vmcr.abpr;
>> +		break;
>> +	case GIC_CPU_IDENT:
>> +		val = ((PRODUCT_ID_KVM << 20) |
>> +		       (GICC_ARCH_VERSION_V2 << 16) |
>> +		       IMPLEMENTER_ARM);
>> +		break;
>> +	default:
>> +		return 0;
>> +	}
>> +
>> +	return extract_bytes(val, addr & 3, len);
>> +}
>> +
>> +static void vgic_mmio_write_vcpuif(struct kvm_vcpu *vcpu,
>> +				   gpa_t addr, unsigned int len,
>> +				   unsigned long val)
>> +{
>> +	struct vgic_vmcr vmcr;
>> +
>> +	vgic_get_vmcr(vcpu, &vmcr);
>> +
>> +	switch (addr & 0xff) {
>> +	case GIC_CPU_CTRL:
>> +		vmcr.ctlr = val;
>> +		break;
>> +	case GIC_CPU_PRIMASK:
>> +		vmcr.pmr = val;
>> +		break;
>> +	case GIC_CPU_BINPOINT:
>> +		vmcr.bpr = val;
>> +		break;
>> +	case GIC_CPU_ALIAS_BINPOINT:
>> +		vmcr.abpr = val;
>> +		break;
>> +	}
>> +
>> +	vgic_set_vmcr(vcpu, &vmcr);
>> +}
>> +
>>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>> @@ -237,6 +315,21 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>  		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
>>  };
>>  
>> +static const struct vgic_register_region vgic_v2_cpu_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_CTRL,
>> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_PRIMASK,
>> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_BINPOINT,
>> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_ALIAS_BINPOINT,
>> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_ACTIVEPRIO,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_IDENT,
>> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
>> +};
>> +
>>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
>>  {
>>  	dev->regions = vgic_v2_dist_registers;
>> @@ -306,6 +399,17 @@ static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>>  	return ret;
>>  }
>>  
>> +int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>> +			  int offset, u32 *val)
>> +{
>> +	struct vgic_io_device dev = {
>> +		.regions = vgic_v2_cpu_registers,
>> +		.nr_regions = ARRAY_SIZE(vgic_v2_cpu_registers),
>> +	};
>> +
>> +	return vgic_uaccess(vcpu, &dev, is_write, offset, val);
>> +}
>> +
>>  int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>  			 int offset, u32 *val)
>>  {
> 
> And what about this:
> 
> +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;
> +
> +       addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
> +
> +       switch (attr->group) {
> +       case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> +               regions = vgic_v2_dist_registers;
> +               nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
> +               break;
> +       case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> +               return -ENXIO;          /* TODO: describe CPU i/f regs also */
> +       default:
> +               return -ENXIO;
> +       }
> 
> This TODO was already in the previous version. Can you please wire it
> and give save/restore a chance to work?

Oh dear, thanks for spotting this. It _was_ in my fix patch, but got
lost during the rebase. Will fix it.

Cheers,
Andre.

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

* [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
@ 2016-05-11  8:24       ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11  8:24 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 09/05/16 18:27, Marc Zyngier wrote:
> On 06/05/16 11:46, Andre Przywara wrote:
>> Using the VMCR accessors we provide access to GIC CPU interface state
>> to userland by wiring it up to the existing userland interface.
>> [Marc: move and make VMCR accessors static, streamline MMIO handlers]
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>> Changelog v2 .. v3:
>> - total rework, moving into vgic-mmio-v2.c
>> - move vmcr accessor wrapper functions into this file
>> - use the register description table for CPU i/f registers as well
>> - add RAZ/WI handling for the active priority registers
>> - streamline MMIO handler functions
>>
>>  virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.h            |   2 +
>>  3 files changed, 107 insertions(+), 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> index bb33af8..2122ff2 100644
>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> @@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
>>  
>>  	switch (attr->group) {
>>  	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
>> -		ret = -EINVAL;
>> +		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
>>  		break;
>>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>>  		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index c453e6f..0060539 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -206,6 +206,84 @@ 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. */
>> +static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
>> +					   gpa_t addr, unsigned int len)
>> +{
>> +	struct vgic_vmcr vmcr;
>> +	u32 val;
>> +
>> +	vgic_get_vmcr(vcpu, &vmcr);
>> +
>> +	switch (addr & 0xff) {
>> +	case GIC_CPU_CTRL:
>> +		val = vmcr.ctlr;
>> +		break;
>> +	case GIC_CPU_PRIMASK:
>> +		val = vmcr.pmr;
>> +		break;
>> +	case GIC_CPU_BINPOINT:
>> +		val = vmcr.bpr;
>> +		break;
>> +	case GIC_CPU_ALIAS_BINPOINT:
>> +		val = vmcr.abpr;
>> +		break;
>> +	case GIC_CPU_IDENT:
>> +		val = ((PRODUCT_ID_KVM << 20) |
>> +		       (GICC_ARCH_VERSION_V2 << 16) |
>> +		       IMPLEMENTER_ARM);
>> +		break;
>> +	default:
>> +		return 0;
>> +	}
>> +
>> +	return extract_bytes(val, addr & 3, len);
>> +}
>> +
>> +static void vgic_mmio_write_vcpuif(struct kvm_vcpu *vcpu,
>> +				   gpa_t addr, unsigned int len,
>> +				   unsigned long val)
>> +{
>> +	struct vgic_vmcr vmcr;
>> +
>> +	vgic_get_vmcr(vcpu, &vmcr);
>> +
>> +	switch (addr & 0xff) {
>> +	case GIC_CPU_CTRL:
>> +		vmcr.ctlr = val;
>> +		break;
>> +	case GIC_CPU_PRIMASK:
>> +		vmcr.pmr = val;
>> +		break;
>> +	case GIC_CPU_BINPOINT:
>> +		vmcr.bpr = val;
>> +		break;
>> +	case GIC_CPU_ALIAS_BINPOINT:
>> +		vmcr.abpr = val;
>> +		break;
>> +	}
>> +
>> +	vgic_set_vmcr(vcpu, &vmcr);
>> +}
>> +
>>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>> @@ -237,6 +315,21 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>  		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
>>  };
>>  
>> +static const struct vgic_register_region vgic_v2_cpu_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_CTRL,
>> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_PRIMASK,
>> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_BINPOINT,
>> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_ALIAS_BINPOINT,
>> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_ACTIVEPRIO,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
>> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_IDENT,
>> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
>> +};
>> +
>>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
>>  {
>>  	dev->regions = vgic_v2_dist_registers;
>> @@ -306,6 +399,17 @@ static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>>  	return ret;
>>  }
>>  
>> +int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>> +			  int offset, u32 *val)
>> +{
>> +	struct vgic_io_device dev = {
>> +		.regions = vgic_v2_cpu_registers,
>> +		.nr_regions = ARRAY_SIZE(vgic_v2_cpu_registers),
>> +	};
>> +
>> +	return vgic_uaccess(vcpu, &dev, is_write, offset, val);
>> +}
>> +
>>  int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>>  			 int offset, u32 *val)
>>  {
> 
> And what about this:
> 
> +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;
> +
> +       addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
> +
> +       switch (attr->group) {
> +       case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> +               regions = vgic_v2_dist_registers;
> +               nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
> +               break;
> +       case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> +               return -ENXIO;          /* TODO: describe CPU i/f regs also */
> +       default:
> +               return -ENXIO;
> +       }
> 
> This TODO was already in the previous version. Can you please wire it
> and give save/restore a chance to work?

Oh dear, thanks for spotting this. It _was_ in my fix patch, but got
lost during the rebase. Will fix it.

Cheers,
Andre.

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

* Re: [PATCH v3 14/55] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
  2016-05-10  9:22     ` Marc Zyngier
@ 2016-05-11  9:20       ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11  9:20 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Hi,

On 10/05/16 10:22, Marc Zyngier wrote:
> On 06/05/16 11:45, Andre Przywara wrote:
>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>
>> The new VGIC implementation centers around a struct vgic_irq instance
>> per virtual IRQ.
>> Provide a function to retrieve the right instance for a given IRQ
>> number and (in case of private interrupts) the right VCPU.
>>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic.c | 41 +++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.h | 22 ++++++++++++++++++++++
>>  2 files changed, 63 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic.c
>>  create mode 100644 virt/kvm/arm/vgic/vgic.h
>>
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> new file mode 100644
>> index 0000000..fb45537
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -0,0 +1,41 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +
>> +#include "vgic.h"
>> +
>> +struct vgic_global __section(.hyp.text) kvm_vgic_global_state;
> 
> nit: this structure isn't referenced anywhere yet.

I see it actually been used in the previous patch, but we only introduce
the header file here. This is one example of why we decided to not
enable compilation early. If you don't mind, I keep it in here.

Thanks for the ACK.

Cheers,
Andre.

>> +
>> +struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> +			      u32 intid)
>> +{
>> +	/* SGIs and PPIs */
>> +	if (intid <= VGIC_MAX_PRIVATE)
>> +		return &vcpu->arch.vgic_cpu.private_irqs[intid];
>> +
>> +	/* SPIs */
>> +	if (intid <= VGIC_MAX_SPI)
>> +		return &kvm->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS];
>> +
>> +	/* LPIs are not yet covered */
>> +	if (intid >= VGIC_MIN_LPI)
>> +		return NULL;
>> +
>> +	WARN(1, "Looking up struct vgic_irq for reserved INTID");
>> +	return NULL;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> new file mode 100644
>> index 0000000..61b8d22
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -0,0 +1,22 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +#ifndef __KVM_ARM_VGIC_NEW_H__
>> +#define __KVM_ARM_VGIC_NEW_H__
>> +
>> +struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> +			      u32 intid);
>> +
>> +#endif
>>
> 
> Otherwise:
> 
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> 
> 	M.
> 

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

* [PATCH v3 14/55] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance
@ 2016-05-11  9:20       ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11  9:20 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 10/05/16 10:22, Marc Zyngier wrote:
> On 06/05/16 11:45, Andre Przywara wrote:
>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>
>> The new VGIC implementation centers around a struct vgic_irq instance
>> per virtual IRQ.
>> Provide a function to retrieve the right instance for a given IRQ
>> number and (in case of private interrupts) the right VCPU.
>>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic.c | 41 +++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.h | 22 ++++++++++++++++++++++
>>  2 files changed, 63 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic.c
>>  create mode 100644 virt/kvm/arm/vgic/vgic.h
>>
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> new file mode 100644
>> index 0000000..fb45537
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -0,0 +1,41 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +
>> +#include "vgic.h"
>> +
>> +struct vgic_global __section(.hyp.text) kvm_vgic_global_state;
> 
> nit: this structure isn't referenced anywhere yet.

I see it actually been used in the previous patch, but we only introduce
the header file here. This is one example of why we decided to not
enable compilation early. If you don't mind, I keep it in here.

Thanks for the ACK.

Cheers,
Andre.

>> +
>> +struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> +			      u32 intid)
>> +{
>> +	/* SGIs and PPIs */
>> +	if (intid <= VGIC_MAX_PRIVATE)
>> +		return &vcpu->arch.vgic_cpu.private_irqs[intid];
>> +
>> +	/* SPIs */
>> +	if (intid <= VGIC_MAX_SPI)
>> +		return &kvm->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS];
>> +
>> +	/* LPIs are not yet covered */
>> +	if (intid >= VGIC_MIN_LPI)
>> +		return NULL;
>> +
>> +	WARN(1, "Looking up struct vgic_irq for reserved INTID");
>> +	return NULL;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> new file mode 100644
>> index 0000000..61b8d22
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -0,0 +1,22 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +#ifndef __KVM_ARM_VGIC_NEW_H__
>> +#define __KVM_ARM_VGIC_NEW_H__
>> +
>> +struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> +			      u32 intid);
>> +
>> +#endif
>>
> 
> Otherwise:
> 
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> 
> 	M.
> 

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

* Re: [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
  2016-05-10 14:45             ` Marc Zyngier
@ 2016-05-11  9:38               ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11  9:38 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: Andre Przywara, kvmarm, linux-arm-kernel, kvm

On Tue, May 10, 2016 at 03:45:20PM +0100, Marc Zyngier wrote:
> On 10/05/16 15:35, Marc Zyngier wrote:
> > On 10/05/16 15:11, Christoffer Dall wrote:
> >> On Tue, May 10, 2016 at 02:42:02PM +0100, Marc Zyngier wrote:
> >>> On 10/05/16 14:30, Christoffer Dall wrote:
> >>>> On Fri, May 06, 2016 at 11:45:31AM +0100, Andre Przywara wrote:
> >>>>> From: Marc Zyngier <marc.zyngier@arm.com>
> >>>>>
> >>>>> Processing maintenance interrupts and accessing the list registers
> >>>>> are dependent on the host's GIC version.
> >>>>> Introduce vgic-v2.c to contain GICv2 specific functions.
> >>>>> Implement the GICv2 specific code for syncing the emulation state
> >>>>> into the VGIC registers.
> >>>>>
> >>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >>>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> >>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>>>> ---
> >>>>> Changelog RFC..v1:
> >>>>> - remove explicit LR_STATE clearing on maintenance interrupt handling
> >>>>> - improve documentation for vgic_v2_populate_lr()
> >>>>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
> >>>>> - simplify multi-CPU source SGI handling
> >>>>>
> >>>>> Changelog v1 .. v2:
> >>>>> - inject the IRQ priority into the list register
> >>>>>
> >>>>> Changelog v2 .. v3:
> >>>>> - cleanup diff containing rebase artifacts
> >>>>>
> >>>>>  include/linux/irqchip/arm-gic.h |   1 +
> >>>>>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
> >>>>>  virt/kvm/arm/vgic/vgic.c        |   6 ++
> >>>>>  virt/kvm/arm/vgic/vgic.h        |   6 ++
> >>>>>  4 files changed, 191 insertions(+)
> >>>>>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
> >>>>>
> >>>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> >>>>> index 9c94026..be0d26f 100644
> >>>>> --- a/include/linux/irqchip/arm-gic.h
> >>>>> +++ b/include/linux/irqchip/arm-gic.h
> >>>>> @@ -76,6 +76,7 @@
> >>>>>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
> >>>>>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
> >>>>>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
> >>>>> +#define GICH_LR_PRIORITY_SHIFT		23
> >>>>>  #define GICH_LR_STATE			(3 << 28)
> >>>>>  #define GICH_LR_PENDING_BIT		(1 << 28)
> >>>>>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
> >>>>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> >>>>> new file mode 100644
> >>>>> index 0000000..4cee616
> >>>>> --- /dev/null
> >>>>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> >>>>> @@ -0,0 +1,178 @@
> >>>>> +/*
> >>>>> + * Copyright (C) 2015, 2016 ARM Ltd.
> >>>>> + *
> >>>>> + * This program is free software; you can redistribute it and/or modify
> >>>>> + * it under the terms of the GNU General Public License version 2 as
> >>>>> + * published by the Free Software Foundation.
> >>>>> + *
> >>>>> + * This program is distributed in the hope that it will be useful,
> >>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >>>>> + * GNU General Public License for more details.
> >>>>> + *
> >>>>> + * You should have received a copy of the GNU General Public License
> >>>>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> >>>>> + */
> >>>>> +
> >>>>> +#include <linux/irqchip/arm-gic.h>
> >>>>> +#include <linux/kvm.h>
> >>>>> +#include <linux/kvm_host.h>
> >>>>> +
> >>>>> +#include "vgic.h"
> >>>>> +
> >>>>> +/*
> >>>>> + * Call this function to convert a u64 value to an unsigned long * bitmask
> >>>>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
> >>>>> + *
> >>>>> + * Warning: Calling this function may modify *val.
> >>>>> + */
> >>>>> +static unsigned long *u64_to_bitmask(u64 *val)
> >>>>> +{
> >>>>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
> >>>>> +	*val = (*val >> 32) | (*val << 32);
> >>>>> +#endif
> >>>>> +	return (unsigned long *)val;
> >>>>> +}
> >>>>> +
> >>>>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> >>>>> +{
> >>>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> >>>>> +
> >>>>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
> >>>>> +		u64 eisr = cpuif->vgic_eisr;
> >>>>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
> >>>>> +		int lr;
> >>>>> +
> >>>>> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
> >>>>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
> >>>>> +
> >>>>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
> >>>>> +
> >>>>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> >>>>> +					     intid - VGIC_NR_PRIVATE_IRQS);
> >>>>> +
> >>>>
> >>>> why do we need to do this?  I cannot find any consumers of this info
> >>>> after we've left the hyp code.
> >>>
> >>> I believe that's for vhost and irqfd. Or am I misreading your question?
> >>>
> >>
> >> I meant the setting of the bits in vgic_elrsr (sorry, badly placed
> >> comment)...
> >>
> >>>> Also, I think I offered a comment about why we would potentially need
> >>>> this in the first place.  This is the famous race where hardware doesn't
> >>>> guarantee consistency between the MISR and ELRSR right?
> >>>
> >>> That's the one (except it is between EISR and ELRSR). I don't have your
> >>> initial comment at hand, but would something like the following do?
> >>>
> >>> 			/*
> >>> 			 * The maintenance interrupt may not have had a
> >>> 			 * chance to update ELRSR, so let's mark the LRs
> >>> 			 * presents in EISR as empty.
> >>> 			 */
> >>>>
> >>>>> +			cpuif->vgic_elrsr |= 1ULL << lr;
> >>
> >> so, why are we doing this?
> > 
> > Ah! I finally see what you mean: we don't reuse LRs at all with the new code
> > base, so knowing which LR is empty is irrelevant. In which case, something
> > like that should be done:
> > 
> > diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> > index e88b5aa..5a8f4d4 100644
> > --- a/virt/kvm/arm/vgic/vgic-v2.c
> > +++ b/virt/kvm/arm/vgic/vgic-v2.c
> > @@ -52,8 +52,6 @@ void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> >  
> >  			kvm_notify_acked_irq(vcpu->kvm, 0,
> >  					     intid - VGIC_NR_PRIVATE_IRQS);
> > -
> > -			cpuif->vgic_elrsr |= 1ULL << lr;
> >  		}
> >  	}
> >  
> > diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> > index 53f7847..4102f0f 100644
> > --- a/virt/kvm/arm/vgic/vgic-v3.c
> > +++ b/virt/kvm/arm/vgic/vgic-v3.c
> > @@ -43,8 +43,6 @@ void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> >  
> >  			kvm_notify_acked_irq(vcpu->kvm, 0,
> >  					     intid - VGIC_NR_PRIVATE_IRQS);
> > -
> > -			cpuif->vgic_elrsr |= 1ULL << lr;
> >  		}
> >  
> >  		/*
> > 
> > I'll give it a spin, just to be safe.
> 
> Seems OK on GICv2, and this of course leads to some more possible
> cleanups or optimizations (I think we can get to a state where we
> completely disregards ELRSR). I'll have a look.
> 
should be possible.  Eventually I was thinking if we really need EISR as
well?  Could we not deduct that if we have an incative LR from a struct
vgic_irq that is CONFIG_LEVEL where we wrote the LR to either
pending/active on entry, then an EOI has happened and we should signal
the kvm_notify_acked_irq()...

-Christoffer

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

* [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
@ 2016-05-11  9:38               ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11  9:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 10, 2016 at 03:45:20PM +0100, Marc Zyngier wrote:
> On 10/05/16 15:35, Marc Zyngier wrote:
> > On 10/05/16 15:11, Christoffer Dall wrote:
> >> On Tue, May 10, 2016 at 02:42:02PM +0100, Marc Zyngier wrote:
> >>> On 10/05/16 14:30, Christoffer Dall wrote:
> >>>> On Fri, May 06, 2016 at 11:45:31AM +0100, Andre Przywara wrote:
> >>>>> From: Marc Zyngier <marc.zyngier@arm.com>
> >>>>>
> >>>>> Processing maintenance interrupts and accessing the list registers
> >>>>> are dependent on the host's GIC version.
> >>>>> Introduce vgic-v2.c to contain GICv2 specific functions.
> >>>>> Implement the GICv2 specific code for syncing the emulation state
> >>>>> into the VGIC registers.
> >>>>>
> >>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >>>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> >>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>>>> ---
> >>>>> Changelog RFC..v1:
> >>>>> - remove explicit LR_STATE clearing on maintenance interrupt handling
> >>>>> - improve documentation for vgic_v2_populate_lr()
> >>>>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
> >>>>> - simplify multi-CPU source SGI handling
> >>>>>
> >>>>> Changelog v1 .. v2:
> >>>>> - inject the IRQ priority into the list register
> >>>>>
> >>>>> Changelog v2 .. v3:
> >>>>> - cleanup diff containing rebase artifacts
> >>>>>
> >>>>>  include/linux/irqchip/arm-gic.h |   1 +
> >>>>>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
> >>>>>  virt/kvm/arm/vgic/vgic.c        |   6 ++
> >>>>>  virt/kvm/arm/vgic/vgic.h        |   6 ++
> >>>>>  4 files changed, 191 insertions(+)
> >>>>>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
> >>>>>
> >>>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> >>>>> index 9c94026..be0d26f 100644
> >>>>> --- a/include/linux/irqchip/arm-gic.h
> >>>>> +++ b/include/linux/irqchip/arm-gic.h
> >>>>> @@ -76,6 +76,7 @@
> >>>>>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
> >>>>>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
> >>>>>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
> >>>>> +#define GICH_LR_PRIORITY_SHIFT		23
> >>>>>  #define GICH_LR_STATE			(3 << 28)
> >>>>>  #define GICH_LR_PENDING_BIT		(1 << 28)
> >>>>>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
> >>>>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> >>>>> new file mode 100644
> >>>>> index 0000000..4cee616
> >>>>> --- /dev/null
> >>>>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> >>>>> @@ -0,0 +1,178 @@
> >>>>> +/*
> >>>>> + * Copyright (C) 2015, 2016 ARM Ltd.
> >>>>> + *
> >>>>> + * This program is free software; you can redistribute it and/or modify
> >>>>> + * it under the terms of the GNU General Public License version 2 as
> >>>>> + * published by the Free Software Foundation.
> >>>>> + *
> >>>>> + * This program is distributed in the hope that it will be useful,
> >>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >>>>> + * GNU General Public License for more details.
> >>>>> + *
> >>>>> + * You should have received a copy of the GNU General Public License
> >>>>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> >>>>> + */
> >>>>> +
> >>>>> +#include <linux/irqchip/arm-gic.h>
> >>>>> +#include <linux/kvm.h>
> >>>>> +#include <linux/kvm_host.h>
> >>>>> +
> >>>>> +#include "vgic.h"
> >>>>> +
> >>>>> +/*
> >>>>> + * Call this function to convert a u64 value to an unsigned long * bitmask
> >>>>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
> >>>>> + *
> >>>>> + * Warning: Calling this function may modify *val.
> >>>>> + */
> >>>>> +static unsigned long *u64_to_bitmask(u64 *val)
> >>>>> +{
> >>>>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
> >>>>> +	*val = (*val >> 32) | (*val << 32);
> >>>>> +#endif
> >>>>> +	return (unsigned long *)val;
> >>>>> +}
> >>>>> +
> >>>>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> >>>>> +{
> >>>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> >>>>> +
> >>>>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
> >>>>> +		u64 eisr = cpuif->vgic_eisr;
> >>>>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
> >>>>> +		int lr;
> >>>>> +
> >>>>> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
> >>>>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
> >>>>> +
> >>>>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
> >>>>> +
> >>>>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> >>>>> +					     intid - VGIC_NR_PRIVATE_IRQS);
> >>>>> +
> >>>>
> >>>> why do we need to do this?  I cannot find any consumers of this info
> >>>> after we've left the hyp code.
> >>>
> >>> I believe that's for vhost and irqfd. Or am I misreading your question?
> >>>
> >>
> >> I meant the setting of the bits in vgic_elrsr (sorry, badly placed
> >> comment)...
> >>
> >>>> Also, I think I offered a comment about why we would potentially need
> >>>> this in the first place.  This is the famous race where hardware doesn't
> >>>> guarantee consistency between the MISR and ELRSR right?
> >>>
> >>> That's the one (except it is between EISR and ELRSR). I don't have your
> >>> initial comment at hand, but would something like the following do?
> >>>
> >>> 			/*
> >>> 			 * The maintenance interrupt may not have had a
> >>> 			 * chance to update ELRSR, so let's mark the LRs
> >>> 			 * presents in EISR as empty.
> >>> 			 */
> >>>>
> >>>>> +			cpuif->vgic_elrsr |= 1ULL << lr;
> >>
> >> so, why are we doing this?
> > 
> > Ah! I finally see what you mean: we don't reuse LRs at all with the new code
> > base, so knowing which LR is empty is irrelevant. In which case, something
> > like that should be done:
> > 
> > diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> > index e88b5aa..5a8f4d4 100644
> > --- a/virt/kvm/arm/vgic/vgic-v2.c
> > +++ b/virt/kvm/arm/vgic/vgic-v2.c
> > @@ -52,8 +52,6 @@ void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> >  
> >  			kvm_notify_acked_irq(vcpu->kvm, 0,
> >  					     intid - VGIC_NR_PRIVATE_IRQS);
> > -
> > -			cpuif->vgic_elrsr |= 1ULL << lr;
> >  		}
> >  	}
> >  
> > diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> > index 53f7847..4102f0f 100644
> > --- a/virt/kvm/arm/vgic/vgic-v3.c
> > +++ b/virt/kvm/arm/vgic/vgic-v3.c
> > @@ -43,8 +43,6 @@ void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> >  
> >  			kvm_notify_acked_irq(vcpu->kvm, 0,
> >  					     intid - VGIC_NR_PRIVATE_IRQS);
> > -
> > -			cpuif->vgic_elrsr |= 1ULL << lr;
> >  		}
> >  
> >  		/*
> > 
> > I'll give it a spin, just to be safe.
> 
> Seems OK on GICv2, and this of course leads to some more possible
> cleanups or optimizations (I think we can get to a state where we
> completely disregards ELRSR). I'll have a look.
> 
should be possible.  Eventually I was thinking if we really need EISR as
well?  Could we not deduct that if we have an incative LR from a struct
vgic_irq that is CONFIG_LEVEL where we wrote the LR to either
pending/active on entry, then an EOI has happened and we should signal
the kvm_notify_acked_irq()...

-Christoffer

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

* Re: [PATCH v3 19/55] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
  2016-05-10 14:15       ` Peter Maydell
@ 2016-05-11  9:39         ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11  9:39 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Marc Zyngier, Andre Przywara, kvmarm, arm-mail-list, kvm-devel

On Tue, May 10, 2016 at 03:15:12PM +0100, Peter Maydell wrote:
> On 10 May 2016 at 15:04, Christoffer Dall <christoffer.dall@linaro.org> wrote:
> > On Fri, May 06, 2016 at 11:45:32AM +0100, Andre Przywara wrote:
> >> +     /*
> >> +      * Currently all guest IRQs are Group1, as Group0 would result
> >> +      * in a FIQ in the guest, which it wouldn't expect.
> >
> > I still don't like or understand this comment.  This should simply say
> > that we're making a gross assumption about all interrupts being group1
> > here.
> 
> It's not really an assumption so much as it's a missing feature (aka bug):
> there's no reason the vGIC shouldn't support group 0 interrupts. We
> just get away with only supporting group 1 because Linux guests
> happen to only use group 1 interrupts. If/when the vGIC gains support
> for group0 interrupts, then it should reset with interrupts configured
> in group0 by default.
> 
> >> +      * Eventually we want to make this configurable, so we may
> >> +      * revisit this in the future.
> >> +      */
> 
> The only reason to make it configurable is to work around a guest
> kernel bug whereby Linux assumes that all interrupts start out
> in Group1. Marc sent out a patch earlier today that fixes that bug:
>  https://lkml.org/lkml/2016/5/10/297
> Depending on how long it takes you to fix this missing vgic feature,
> such kernels may all be long-forgotten, in which case you can
> get away without the config option :-)
> 
Agreed with all of the above.  My nit here is simply that if we don't
implement grouping support now, then it's just a gross hack, and we
should just state that until we fix it properly.

-Christoffer

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

* [PATCH v3 19/55] KVM: arm/arm64: vgic-new: Add GICv3 world switch backend
@ 2016-05-11  9:39         ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11  9:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 10, 2016 at 03:15:12PM +0100, Peter Maydell wrote:
> On 10 May 2016 at 15:04, Christoffer Dall <christoffer.dall@linaro.org> wrote:
> > On Fri, May 06, 2016 at 11:45:32AM +0100, Andre Przywara wrote:
> >> +     /*
> >> +      * Currently all guest IRQs are Group1, as Group0 would result
> >> +      * in a FIQ in the guest, which it wouldn't expect.
> >
> > I still don't like or understand this comment.  This should simply say
> > that we're making a gross assumption about all interrupts being group1
> > here.
> 
> It's not really an assumption so much as it's a missing feature (aka bug):
> there's no reason the vGIC shouldn't support group 0 interrupts. We
> just get away with only supporting group 1 because Linux guests
> happen to only use group 1 interrupts. If/when the vGIC gains support
> for group0 interrupts, then it should reset with interrupts configured
> in group0 by default.
> 
> >> +      * Eventually we want to make this configurable, so we may
> >> +      * revisit this in the future.
> >> +      */
> 
> The only reason to make it configurable is to work around a guest
> kernel bug whereby Linux assumes that all interrupts start out
> in Group1. Marc sent out a patch earlier today that fixes that bug:
>  https://lkml.org/lkml/2016/5/10/297
> Depending on how long it takes you to fix this missing vgic feature,
> such kernels may all be long-forgotten, in which case you can
> get away without the config option :-)
> 
Agreed with all of the above.  My nit here is simply that if we don't
implement grouping support now, then it's just a gross hack, and we
should just state that until we fix it properly.

-Christoffer

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

* Re: [PATCH v3 21/55] KVM: arm/arm64: vgic-new: Add MMIO handling framework
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-11  9:46     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11  9:46 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 06, 2016 at 11:45:34AM +0100, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Add an MMIO handling framework to the VGIC emulation:
> Each register is described by its offset, size (or number of bits per
> IRQ, if applicable) and the read/write handler functions. We provide
> initialization macros to describe each GIC register later easily.
> 
> Separate dispatch functions for read and write accesses are connected
> to the kvm_io_bus framework and binary-search for the responsible
> register handler based on the offset address within the region.
> We convert the incoming data (referenced by a pointer) to the host's
> endianess and use pass-by-value to hand the data over to the actual
> handler functions.
> 
> The register handler prototype and the endianess conversion are
> courtesy of Christoffer Dall.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - rework MMIO dispatching to use only one kvm_io_bus device
> - document purpose of register region macros
> - rename "this" parameter to "dev"
> - change IGROUPR to be RAO (returning 1 => Group1 IRQs)
> 
> Changelog v1 .. v2:
> * MASSIVE rework:
> - store register_region pointer in kvm_io_bus linked struct
> - replace write_mask_xxx functions with extract_bytes() implementation
> - change handler functions' prototypes to take and return unsigned long
> - use binary search to find matching register handler
> - convert endianess of input data in dispatch_mmio_xxx functions
> - improve readability of register initializer macros
> - remove any GICv2/GICv3 specific functions from vgic-mmio.c
> - rename file from vgic_mmio.c to vgic-mmio.c
> 
> Changelog v2 .. v3:
> - replace inclusion of vgic/vgic.h with arm_vgic.h
> 
>  include/kvm/vgic/vgic.h       |  13 ++++
>  virt/kvm/arm/vgic/vgic-mmio.c | 171 ++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h |  77 +++++++++++++++++++
>  3 files changed, 261 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio.c
>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio.h
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 2615205..4ec1270 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -106,6 +106,16 @@ struct vgic_irq {
>  	enum vgic_irq_config config;	/* Level or edge */
>  };
>  
> +struct vgic_register_region;
> +
> +struct vgic_io_device {
> +	gpa_t base_addr;
> +	struct kvm_vcpu *redist_vcpu;
> +	const struct vgic_register_region *regions;
> +	int nr_regions;
> +	struct kvm_io_device dev;
> +};
> +
>  struct vgic_dist {
>  	bool			in_kernel;
>  	bool			ready;
> @@ -132,6 +142,9 @@ struct vgic_dist {
>  	bool			enabled;
>  
>  	struct vgic_irq		*spis;
> +
> +	struct vgic_io_device	dist_iodev;
> +	struct vgic_io_device	*redist_iodevs;
>  };
>  
>  struct vgic_v2_cpu_if {
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> new file mode 100644
> index 0000000..f5628cb
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -0,0 +1,171 @@
> +/*
> + * VGIC MMIO 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/bitops.h>
> +#include <linux/bsearch.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <kvm/iodev.h>
> +#include <kvm/arm_vgic.h>
> +
> +#include "vgic.h"
> +#include "vgic-mmio.h"
> +
> +/* extract @num bytes at @offset bytes offset in data */
> +unsigned long extract_bytes(unsigned long data,
> +			    unsigned int offset, unsigned int num)
> +{
> +	return (data >> (offset * 8)) & GENMASK_ULL(num * 8 - 1, 0);
> +}
> +
> +unsigned long vgic_mmio_read_raz(struct kvm_vcpu *vcpu,
> +				 gpa_t addr, unsigned int len)
> +{
> +	return 0;
> +}
> +
> +unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
> +				 gpa_t addr, unsigned int len)
> +{
> +	return -1UL;
> +}
> +
> +void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
> +			unsigned int len, unsigned long val)
> +{
> +	/* Ignore */
> +}
> +
> +static int match_region(const void *key, const void *elt)
> +{
> +	const unsigned int offset = (unsigned long)key;
> +	const struct vgic_register_region *region = elt;
> +
> +	if (offset < region->reg_offset)
> +		return -1;
> +
> +	if (offset >= region->reg_offset + region->len)
> +		return 1;
> +
> +	return 0;
> +}
> +
> +/* Find the proper register handler entry given a certain address offset. */
> +static const struct vgic_register_region *
> +vgic_find_mmio_region(const struct vgic_register_region *region, int nr_regions,
> +		      unsigned int offset)
> +{
> +	return bsearch((void *)(uintptr_t)offset, region, nr_regions,
> +		       sizeof(region[0]), match_region);
> +}
> +
> +/*
> + * 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
> + * in memory if it had done the store itself, which is LE for the GIC, as the
> + * guest knows the GIC is always LE.
> + *
> + * We convert this value to the CPUs native format to deal with it as a data
> + * value.
> + */
> +unsigned long vgic_data_mmio_bus_to_host(const void *val, unsigned int len)
> +{
> +	unsigned long data = kvm_mmio_read_buf(val, len);
> +
> +	switch (len) {
> +	case 1:
> +		return data;
> +	case 2:
> +		return le16_to_cpu(data);
> +	case 4:
> +		return le32_to_cpu(data);
> +	default:
> +		return le64_to_cpu(data);
> +	}
> +}
> +
> +/*
> + * kvm_mmio_write_buf() expects a value in a format such that if converted to
> + * a byte array it is observed as the guest would see it if it could perform
> + * the load directly.  Since the GIC is LE, and the guest knows this, the
> + * guest expects a value in little endian format.
> + *
> + * We convert the data value from the CPUs native format to LE so that the
> + * value is returned in the proper format.
> + */
> +void vgic_data_host_to_mmio_bus(void *buf, unsigned int len,
> +				unsigned long data)
> +{
> +	switch (len) {
> +	case 1:
> +		break;
> +	case 2:
> +		data = cpu_to_le16(data);
> +		break;
> +	case 4:
> +		data = cpu_to_le32(data);
> +		break;
> +	default:
> +		data = cpu_to_le64(data);
> +	}
> +
> +	kvm_mmio_write_buf(buf, len, data);
> +}
> +
> +static
> +struct vgic_io_device *kvm_to_vgic_iodev(const struct kvm_io_device *dev)
> +{
> +	return container_of(dev, struct vgic_io_device, dev);
> +}
> +
> +static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
> +			      gpa_t addr, int len, void *val)
> +{
> +	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
> +	const struct vgic_register_region *region;
> +	struct kvm_vcpu *r_vcpu;
> +	unsigned long data;
> +
> +	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
> +				       addr - iodev->base_addr);
> +	if (!region)
> +		return -EOPNOTSUPP;
> +
> +	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
> +	data = region->read(r_vcpu, addr, len);
> +	vgic_data_host_to_mmio_bus(val, len, data);
> +	return 0;
> +}
> +
> +static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
> +			       gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
> +	const struct vgic_register_region *region;
> +	struct kvm_vcpu *r_vcpu;
> +	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)
> +		return -EOPNOTSUPP;
> +
> +	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
> +	region->write(r_vcpu, addr, len, data);
> +	return 0;
> +}
> +
> +struct kvm_io_device_ops kvm_io_gic_ops = {
> +	.read = dispatch_mmio_read,
> +	.write = dispatch_mmio_write,
> +};
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
> new file mode 100644
> index 0000000..18d3869
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -0,0 +1,77 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef __KVM_ARM_VGIC_MMIO_H__
> +#define __KVM_ARM_VGIC_MMIO_H__
> +
> +struct vgic_register_region {
> +	unsigned int reg_offset;
> +	unsigned int len;
> +	unsigned int bits_per_irq;
> +	unsigned long (*read)(struct kvm_vcpu *vcpu, gpa_t addr,
> +			      unsigned int len);
> +	void (*write)(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len,
> +		      unsigned long val);
> +};
> +
> +extern struct kvm_io_device_ops kvm_io_gic_ops;
> +
> +/*
> + * Some VGIC registers store per-IRQ information, with a different number
> + * of bits per IRQ. For those registers this macro is used.
> + * The _WITH_LENGTH version instantiates registers with a fixed length
> + * and is mutually exclusive with the _PER_IRQ version.
> + */
> +#define REGISTER_DESC_WITH_BITS_PER_IRQ(off, read_ops, write_ops, bpi)	\
> +	{								\
> +		.reg_offset = off,					\
> +		.bits_per_irq = bpi,					\
> +		.len = bpi * 1024 / 8,					\
> +		.read = read_ops,					\
> +		.write = write_ops,					\
> +	}
> +
> +#define REGISTER_DESC_WITH_LENGTH(off, read_ops, write_ops, length)	\
> +	{								\
> +		.reg_offset = off,					\
> +		.bits_per_irq = 0,					\
> +		.len = length,						\
> +		.read = read_ops,					\
> +		.write = write_ops,					\
> +	}
> +
> +int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
> +				  struct vgic_register_region *reg_desc,
> +				  struct vgic_io_device *region,
> +				  int nr_irqs, bool offset_private);
> +
> +unsigned long vgic_data_mmio_bus_to_host(const void *val, unsigned int len);
> +
> +void vgic_data_host_to_mmio_bus(void *buf, unsigned int len,
> +				unsigned long data);
> +
> +unsigned long extract_bytes(unsigned long data,
> +			    unsigned int offset, unsigned int num);
> +
> +unsigned long vgic_mmio_read_raz(struct kvm_vcpu *vcpu,
> +				 gpa_t addr, unsigned int len);
> +
> +unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
> +				 gpa_t addr, unsigned int len);
> +
> +void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
> +			unsigned int len, unsigned long val);
> +
> +#endif
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

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

* [PATCH v3 21/55] KVM: arm/arm64: vgic-new: Add MMIO handling framework
@ 2016-05-11  9:46     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11  9:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:34AM +0100, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Add an MMIO handling framework to the VGIC emulation:
> Each register is described by its offset, size (or number of bits per
> IRQ, if applicable) and the read/write handler functions. We provide
> initialization macros to describe each GIC register later easily.
> 
> Separate dispatch functions for read and write accesses are connected
> to the kvm_io_bus framework and binary-search for the responsible
> register handler based on the offset address within the region.
> We convert the incoming data (referenced by a pointer) to the host's
> endianess and use pass-by-value to hand the data over to the actual
> handler functions.
> 
> The register handler prototype and the endianess conversion are
> courtesy of Christoffer Dall.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - rework MMIO dispatching to use only one kvm_io_bus device
> - document purpose of register region macros
> - rename "this" parameter to "dev"
> - change IGROUPR to be RAO (returning 1 => Group1 IRQs)
> 
> Changelog v1 .. v2:
> * MASSIVE rework:
> - store register_region pointer in kvm_io_bus linked struct
> - replace write_mask_xxx functions with extract_bytes() implementation
> - change handler functions' prototypes to take and return unsigned long
> - use binary search to find matching register handler
> - convert endianess of input data in dispatch_mmio_xxx functions
> - improve readability of register initializer macros
> - remove any GICv2/GICv3 specific functions from vgic-mmio.c
> - rename file from vgic_mmio.c to vgic-mmio.c
> 
> Changelog v2 .. v3:
> - replace inclusion of vgic/vgic.h with arm_vgic.h
> 
>  include/kvm/vgic/vgic.h       |  13 ++++
>  virt/kvm/arm/vgic/vgic-mmio.c | 171 ++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h |  77 +++++++++++++++++++
>  3 files changed, 261 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio.c
>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio.h
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 2615205..4ec1270 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -106,6 +106,16 @@ struct vgic_irq {
>  	enum vgic_irq_config config;	/* Level or edge */
>  };
>  
> +struct vgic_register_region;
> +
> +struct vgic_io_device {
> +	gpa_t base_addr;
> +	struct kvm_vcpu *redist_vcpu;
> +	const struct vgic_register_region *regions;
> +	int nr_regions;
> +	struct kvm_io_device dev;
> +};
> +
>  struct vgic_dist {
>  	bool			in_kernel;
>  	bool			ready;
> @@ -132,6 +142,9 @@ struct vgic_dist {
>  	bool			enabled;
>  
>  	struct vgic_irq		*spis;
> +
> +	struct vgic_io_device	dist_iodev;
> +	struct vgic_io_device	*redist_iodevs;
>  };
>  
>  struct vgic_v2_cpu_if {
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> new file mode 100644
> index 0000000..f5628cb
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -0,0 +1,171 @@
> +/*
> + * VGIC MMIO 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/bitops.h>
> +#include <linux/bsearch.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <kvm/iodev.h>
> +#include <kvm/arm_vgic.h>
> +
> +#include "vgic.h"
> +#include "vgic-mmio.h"
> +
> +/* extract @num bytes at @offset bytes offset in data */
> +unsigned long extract_bytes(unsigned long data,
> +			    unsigned int offset, unsigned int num)
> +{
> +	return (data >> (offset * 8)) & GENMASK_ULL(num * 8 - 1, 0);
> +}
> +
> +unsigned long vgic_mmio_read_raz(struct kvm_vcpu *vcpu,
> +				 gpa_t addr, unsigned int len)
> +{
> +	return 0;
> +}
> +
> +unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
> +				 gpa_t addr, unsigned int len)
> +{
> +	return -1UL;
> +}
> +
> +void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
> +			unsigned int len, unsigned long val)
> +{
> +	/* Ignore */
> +}
> +
> +static int match_region(const void *key, const void *elt)
> +{
> +	const unsigned int offset = (unsigned long)key;
> +	const struct vgic_register_region *region = elt;
> +
> +	if (offset < region->reg_offset)
> +		return -1;
> +
> +	if (offset >= region->reg_offset + region->len)
> +		return 1;
> +
> +	return 0;
> +}
> +
> +/* Find the proper register handler entry given a certain address offset. */
> +static const struct vgic_register_region *
> +vgic_find_mmio_region(const struct vgic_register_region *region, int nr_regions,
> +		      unsigned int offset)
> +{
> +	return bsearch((void *)(uintptr_t)offset, region, nr_regions,
> +		       sizeof(region[0]), match_region);
> +}
> +
> +/*
> + * 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
> + * in memory if it had done the store itself, which is LE for the GIC, as the
> + * guest knows the GIC is always LE.
> + *
> + * We convert this value to the CPUs native format to deal with it as a data
> + * value.
> + */
> +unsigned long vgic_data_mmio_bus_to_host(const void *val, unsigned int len)
> +{
> +	unsigned long data = kvm_mmio_read_buf(val, len);
> +
> +	switch (len) {
> +	case 1:
> +		return data;
> +	case 2:
> +		return le16_to_cpu(data);
> +	case 4:
> +		return le32_to_cpu(data);
> +	default:
> +		return le64_to_cpu(data);
> +	}
> +}
> +
> +/*
> + * kvm_mmio_write_buf() expects a value in a format such that if converted to
> + * a byte array it is observed as the guest would see it if it could perform
> + * the load directly.  Since the GIC is LE, and the guest knows this, the
> + * guest expects a value in little endian format.
> + *
> + * We convert the data value from the CPUs native format to LE so that the
> + * value is returned in the proper format.
> + */
> +void vgic_data_host_to_mmio_bus(void *buf, unsigned int len,
> +				unsigned long data)
> +{
> +	switch (len) {
> +	case 1:
> +		break;
> +	case 2:
> +		data = cpu_to_le16(data);
> +		break;
> +	case 4:
> +		data = cpu_to_le32(data);
> +		break;
> +	default:
> +		data = cpu_to_le64(data);
> +	}
> +
> +	kvm_mmio_write_buf(buf, len, data);
> +}
> +
> +static
> +struct vgic_io_device *kvm_to_vgic_iodev(const struct kvm_io_device *dev)
> +{
> +	return container_of(dev, struct vgic_io_device, dev);
> +}
> +
> +static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
> +			      gpa_t addr, int len, void *val)
> +{
> +	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
> +	const struct vgic_register_region *region;
> +	struct kvm_vcpu *r_vcpu;
> +	unsigned long data;
> +
> +	region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
> +				       addr - iodev->base_addr);
> +	if (!region)
> +		return -EOPNOTSUPP;
> +
> +	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
> +	data = region->read(r_vcpu, addr, len);
> +	vgic_data_host_to_mmio_bus(val, len, data);
> +	return 0;
> +}
> +
> +static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
> +			       gpa_t addr, int len, const void *val)
> +{
> +	struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
> +	const struct vgic_register_region *region;
> +	struct kvm_vcpu *r_vcpu;
> +	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)
> +		return -EOPNOTSUPP;
> +
> +	r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu;
> +	region->write(r_vcpu, addr, len, data);
> +	return 0;
> +}
> +
> +struct kvm_io_device_ops kvm_io_gic_ops = {
> +	.read = dispatch_mmio_read,
> +	.write = dispatch_mmio_write,
> +};
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
> new file mode 100644
> index 0000000..18d3869
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -0,0 +1,77 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef __KVM_ARM_VGIC_MMIO_H__
> +#define __KVM_ARM_VGIC_MMIO_H__
> +
> +struct vgic_register_region {
> +	unsigned int reg_offset;
> +	unsigned int len;
> +	unsigned int bits_per_irq;
> +	unsigned long (*read)(struct kvm_vcpu *vcpu, gpa_t addr,
> +			      unsigned int len);
> +	void (*write)(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len,
> +		      unsigned long val);
> +};
> +
> +extern struct kvm_io_device_ops kvm_io_gic_ops;
> +
> +/*
> + * Some VGIC registers store per-IRQ information, with a different number
> + * of bits per IRQ. For those registers this macro is used.
> + * The _WITH_LENGTH version instantiates registers with a fixed length
> + * and is mutually exclusive with the _PER_IRQ version.
> + */
> +#define REGISTER_DESC_WITH_BITS_PER_IRQ(off, read_ops, write_ops, bpi)	\
> +	{								\
> +		.reg_offset = off,					\
> +		.bits_per_irq = bpi,					\
> +		.len = bpi * 1024 / 8,					\
> +		.read = read_ops,					\
> +		.write = write_ops,					\
> +	}
> +
> +#define REGISTER_DESC_WITH_LENGTH(off, read_ops, write_ops, length)	\
> +	{								\
> +		.reg_offset = off,					\
> +		.bits_per_irq = 0,					\
> +		.len = length,						\
> +		.read = read_ops,					\
> +		.write = write_ops,					\
> +	}
> +
> +int kvm_vgic_register_mmio_region(struct kvm *kvm, struct kvm_vcpu *vcpu,
> +				  struct vgic_register_region *reg_desc,
> +				  struct vgic_io_device *region,
> +				  int nr_irqs, bool offset_private);
> +
> +unsigned long vgic_data_mmio_bus_to_host(const void *val, unsigned int len);
> +
> +void vgic_data_host_to_mmio_bus(void *buf, unsigned int len,
> +				unsigned long data);
> +
> +unsigned long extract_bytes(unsigned long data,
> +			    unsigned int offset, unsigned int num);
> +
> +unsigned long vgic_mmio_read_raz(struct kvm_vcpu *vcpu,
> +				 gpa_t addr, unsigned int len);
> +
> +unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
> +				 gpa_t addr, unsigned int len);
> +
> +void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
> +			unsigned int len, unsigned long val);
> +
> +#endif
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

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

* Re: [PATCH v3 22/55] KVM: arm/arm64: vgic-new: Add GICv2 MMIO handling framework
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-11  9:50     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11  9:50 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 06, 2016 at 11:45:35AM +0100, Andre Przywara wrote:
> Create vgic-mmio-v2.c to describe GICv2 emulation specific handlers
> using the initializer macros provided by the VGIC MMIO framework.
> Provide a function to register the GICv2 distributor registers to
> the kvm_io_bus framework.
> The actual handler functions are still stubs in this patch.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
> Changelog v1 .. v2:
> - new patch, split out from the generic MMIO framework patch
> - use a separate file to hold GICv2 emulation specific handlers
> - replace _nyi stub functions with raz/wi versions
> 
> Changelog v2 .. v3:
> - replace kvm/vgic/vgic.h with kvm/arm_vgic.h
> - add vgic_register_dist_iodev() prototype
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 62 ++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.c    | 26 +++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h    |  2 ++
>  virt/kvm/arm/vgic/vgic.h         |  2 ++
>  4 files changed, 92 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v2.c
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> new file mode 100644
> index 0000000..2729a22
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -0,0 +1,62 @@
> +/*
> + * VGICv2 MMIO 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.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <kvm/iodev.h>
> +#include <kvm/arm_vgic.h>
> +
> +#include "vgic.h"
> +#include "vgic-mmio.h"
> +
> +static const struct vgic_register_region vgic_v2_dist_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 12),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 2),
> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> +};
> +
> +unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
> +{
> +	dev->regions = vgic_v2_dist_registers;
> +	dev->nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
> +
> +	kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
> +
> +	return SZ_4K;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index f5628cb..41cf4f4 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -169,3 +169,29 @@ struct kvm_io_device_ops kvm_io_gic_ops = {
>  	.read = dispatch_mmio_read,
>  	.write = dispatch_mmio_write,
>  };
> +
> +int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
> +			     enum vgic_type type)
> +{
> +	struct vgic_io_device *io_device = &kvm->arch.vgic.dist_iodev;
> +	int ret = 0;
> +	unsigned int len;
> +
> +	switch (type) {
> +	case VGIC_V2:
> +		len = vgic_v2_init_dist_iodev(io_device);
> +		break;
> +	default:
> +		BUG_ON(1);
> +	}
> +
> +	io_device->base_addr = dist_base_address;
> +	io_device->redist_vcpu = NULL;
> +
> +	mutex_lock(&kvm->slots_lock);
> +	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, dist_base_address,
> +				      len, &io_device->dev);
> +	mutex_unlock(&kvm->slots_lock);
> +
> +	return ret;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
> index 18d3869..4f4dd2b 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -74,4 +74,6 @@ unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
>  void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>  			unsigned int len, unsigned long val);
>  
> +unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
> +
>  #endif
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 81b1a20..fd9acaa 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -27,6 +27,8 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>  void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
>  void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
> +int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
> +			     enum vgic_type);
>  
>  #ifdef CONFIG_KVM_ARM_VGIC_V3
>  void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
> -- 
> 2.7.3
> 

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

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

* [PATCH v3 22/55] KVM: arm/arm64: vgic-new: Add GICv2 MMIO handling framework
@ 2016-05-11  9:50     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11  9:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:35AM +0100, Andre Przywara wrote:
> Create vgic-mmio-v2.c to describe GICv2 emulation specific handlers
> using the initializer macros provided by the VGIC MMIO framework.
> Provide a function to register the GICv2 distributor registers to
> the kvm_io_bus framework.
> The actual handler functions are still stubs in this patch.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
> Changelog v1 .. v2:
> - new patch, split out from the generic MMIO framework patch
> - use a separate file to hold GICv2 emulation specific handlers
> - replace _nyi stub functions with raz/wi versions
> 
> Changelog v2 .. v3:
> - replace kvm/vgic/vgic.h with kvm/arm_vgic.h
> - add vgic_register_dist_iodev() prototype
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 62 ++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.c    | 26 +++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h    |  2 ++
>  virt/kvm/arm/vgic/vgic.h         |  2 ++
>  4 files changed, 92 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v2.c
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> new file mode 100644
> index 0000000..2729a22
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -0,0 +1,62 @@
> +/*
> + * VGICv2 MMIO 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.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <kvm/iodev.h>
> +#include <kvm/arm_vgic.h>
> +
> +#include "vgic.h"
> +#include "vgic-mmio.h"
> +
> +static const struct vgic_register_region vgic_v2_dist_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 12),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 2),
> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> +	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> +};
> +
> +unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
> +{
> +	dev->regions = vgic_v2_dist_registers;
> +	dev->nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
> +
> +	kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
> +
> +	return SZ_4K;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index f5628cb..41cf4f4 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -169,3 +169,29 @@ struct kvm_io_device_ops kvm_io_gic_ops = {
>  	.read = dispatch_mmio_read,
>  	.write = dispatch_mmio_write,
>  };
> +
> +int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
> +			     enum vgic_type type)
> +{
> +	struct vgic_io_device *io_device = &kvm->arch.vgic.dist_iodev;
> +	int ret = 0;
> +	unsigned int len;
> +
> +	switch (type) {
> +	case VGIC_V2:
> +		len = vgic_v2_init_dist_iodev(io_device);
> +		break;
> +	default:
> +		BUG_ON(1);
> +	}
> +
> +	io_device->base_addr = dist_base_address;
> +	io_device->redist_vcpu = NULL;
> +
> +	mutex_lock(&kvm->slots_lock);
> +	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, dist_base_address,
> +				      len, &io_device->dev);
> +	mutex_unlock(&kvm->slots_lock);
> +
> +	return ret;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
> index 18d3869..4f4dd2b 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -74,4 +74,6 @@ unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
>  void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>  			unsigned int len, unsigned long val);
>  
> +unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
> +
>  #endif
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 81b1a20..fd9acaa 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -27,6 +27,8 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>  void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
>  void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
> +int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
> +			     enum vgic_type);
>  
>  #ifdef CONFIG_KVM_ARM_VGIC_V3
>  void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
> -- 
> 2.7.3
> 

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

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

* Re: [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
  2016-05-10 14:10     ` Eric Auger
@ 2016-05-11 11:30       ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 11:30 UTC (permalink / raw)
  To: Eric Auger, Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Hi,

On 10/05/16 15:10, Eric Auger wrote:
> On 05/06/2016 12:45 PM, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Processing maintenance interrupts and accessing the list registers
>> are dependent on the host's GIC version.
>> Introduce vgic-v2.c to contain GICv2 specific functions.
>> Implement the GICv2 specific code for syncing the emulation state
>> into the VGIC registers.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - remove explicit LR_STATE clearing on maintenance interrupt handling
>> - improve documentation for vgic_v2_populate_lr()
>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
>> - simplify multi-CPU source SGI handling
>>
>> Changelog v1 .. v2:
>> - inject the IRQ priority into the list register
>>
>> Changelog v2 .. v3:
>> - cleanup diff containing rebase artifacts
>>
>>  include/linux/irqchip/arm-gic.h |   1 +
>>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>>  4 files changed, 191 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>>
>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>> index 9c94026..be0d26f 100644
>> --- a/include/linux/irqchip/arm-gic.h
>> +++ b/include/linux/irqchip/arm-gic.h
>> @@ -76,6 +76,7 @@
>>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
>> +#define GICH_LR_PRIORITY_SHIFT		23
>>  #define GICH_LR_STATE			(3 << 28)
>>  #define GICH_LR_PENDING_BIT		(1 << 28)
>>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>> new file mode 100644
>> index 0000000..4cee616
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>> @@ -0,0 +1,178 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/irqchip/arm-gic.h>
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +
>> +#include "vgic.h"
>> +
>> +/*
>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>> + *
>> + * Warning: Calling this function may modify *val.
>> + */
>> +static unsigned long *u64_to_bitmask(u64 *val)
>> +{
>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>> +	*val = (*val >> 32) | (*val << 32);
>> +#endif
>> +	return (unsigned long *)val;
>> +}
>> +
>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +
>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>> +		u64 eisr = cpuif->vgic_eisr;
>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>> +		int lr;
>> +
>> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
> Didn't we say we could use vcpu->arch.vgic_cpu.used_lrs here?

Why would that be useful? Don't we just want to see those LRs that had a
maintenance interrupt received? I don't see the point if iterating over
the used LRs, where we need to check for this condition somehow manually?
Or what am I missing here?

>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
>> +
>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
>> +
>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>> +
>> +			cpuif->vgic_elrsr |= 1ULL << lr;

So are we good with removing this line (and the respective one in v3)?

Cheers,
Andre.

>> +		}
>> +	}
>> +
>> +	/* check and disable underflow maintenance IRQ */
> check?
> 
> Besides
> Reviewed-by: Eric Auger <eric.auger@linaro.org>
> 
> Eric
>> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
>> +
>> +	/*
>> +	 * In the next iterations of the vcpu loop, if we sync the
>> +	 * vgic state after flushing it, but before entering the guest
>> +	 * (this happens for pending signals and vmid rollovers), then
>> +	 * make sure we don't pick up any old maintenance interrupts
>> +	 * here.
>> +	 */
>> +	cpuif->vgic_eisr = 0;
>> +}
>> +
>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +
>> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
>> +}
>> +
>> +/*
>> + * transfer the content of the LRs back into the corresponding ap_list:
>> + * - active bit is transferred as is
>> + * - pending bit is
>> + *   - transferred as is in case of edge sensitive IRQs
>> + *   - set to the line-level (resample time) for level sensitive IRQs
>> + */
>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +	int lr;
>> +
>> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
>> +		u32 val = cpuif->vgic_lr[lr];
>> +		u32 intid = val & GICH_LR_VIRTUALID;
>> +		struct vgic_irq *irq;
>> +
>> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		/* Always preserve the active bit */
>> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
>> +
>> +		/* Edge is the only case where we preserve the pending bit */
>> +		if (irq->config == VGIC_CONFIG_EDGE &&
>> +		    (val & GICH_LR_PENDING_BIT)) {
>> +			irq->pending = true;
>> +
>> +			if (vgic_irq_is_sgi(intid)) {
>> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
>> +
>> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
>> +				irq->source |= (1 << cpuid);
>> +			}
>> +		}
>> +
>> +		/* Clear soft pending state when level IRQs have been acked */
>> +		if (irq->config == VGIC_CONFIG_LEVEL &&
>> +		    !(val & GICH_LR_PENDING_BIT)) {
>> +			irq->soft_pending = false;
>> +			irq->pending = irq->line_level;
>> +		}
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +	}
>> +}
>> +
>> +/*
>> + * Populates the particular LR with the state of a given IRQ:
>> + * - for an edge sensitive IRQ the pending state is cleared in struct vgic_irq
>> + * - for a level sensitive IRQ the pending state value is unchanged;
>> + *   it is dictated directly by the input level
>> + *
>> + * If @irq describes an SGI with multiple sources, we choose the
>> + * lowest-numbered source VCPU and clear that bit in the source bitmap.
>> + *
>> + * The irq_lock must be held by the caller.
>> + */
>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
>> +{
>> +	u32 val = irq->intid;
>> +
>> +	if (irq->pending) {
>> +		val |= GICH_LR_PENDING_BIT;
>> +
>> +		if (irq->config == VGIC_CONFIG_EDGE)
>> +			irq->pending = false;
>> +
>> +		if (vgic_irq_is_sgi(irq->intid)) {
>> +			u32 src = ffs(irq->source);
>> +
>> +			BUG_ON(!src);
>> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
>> +			irq->source &= ~(1 << (src - 1));
>> +			if (irq->source)
>> +				irq->pending = true;
>> +		}
>> +	}
>> +
>> +	if (irq->active)
>> +		val |= GICH_LR_ACTIVE_BIT;
>> +
>> +	if (irq->hw) {
>> +		val |= GICH_LR_HW;
>> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
>> +	} else {
>> +		if (irq->config == VGIC_CONFIG_LEVEL)
>> +			val |= GICH_LR_EOI;
>> +	}
>> +
>> +	/* The GICv2 LR only holds five bits of priority. */
>> +	val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
>> +
>> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
>> +}
>> +
>> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
>> +{
>> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index c6f8b9b..68d885c 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -397,10 +397,12 @@ retry:
>>  
>>  static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>>  {
>> +	vgic_v2_process_maintenance(vcpu);
>>  }
>>  
>>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>>  {
>> +	vgic_v2_fold_lr_state(vcpu);
>>  }
>>  
>>  /* Requires the ap_list_lock and the irq_lock to be held. */
>> @@ -409,14 +411,18 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>>  {
>>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
>>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
>> +
>> +	vgic_v2_populate_lr(vcpu, irq, lr);
>>  }
>>  
>>  static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
>>  {
>> +	vgic_v2_clear_lr(vcpu, lr);
>>  }
>>  
>>  static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>>  {
>> +	vgic_v2_set_underflow(vcpu);
>>  }
>>  
>>  static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 29b96b9..0db490e 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -22,4 +22,10 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  			      u32 intid);
>>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
>>  
>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>> +
>>  #endif
>>
> 

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

* [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
@ 2016-05-11 11:30       ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 10/05/16 15:10, Eric Auger wrote:
> On 05/06/2016 12:45 PM, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Processing maintenance interrupts and accessing the list registers
>> are dependent on the host's GIC version.
>> Introduce vgic-v2.c to contain GICv2 specific functions.
>> Implement the GICv2 specific code for syncing the emulation state
>> into the VGIC registers.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - remove explicit LR_STATE clearing on maintenance interrupt handling
>> - improve documentation for vgic_v2_populate_lr()
>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
>> - simplify multi-CPU source SGI handling
>>
>> Changelog v1 .. v2:
>> - inject the IRQ priority into the list register
>>
>> Changelog v2 .. v3:
>> - cleanup diff containing rebase artifacts
>>
>>  include/linux/irqchip/arm-gic.h |   1 +
>>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>>  4 files changed, 191 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>>
>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>> index 9c94026..be0d26f 100644
>> --- a/include/linux/irqchip/arm-gic.h
>> +++ b/include/linux/irqchip/arm-gic.h
>> @@ -76,6 +76,7 @@
>>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
>> +#define GICH_LR_PRIORITY_SHIFT		23
>>  #define GICH_LR_STATE			(3 << 28)
>>  #define GICH_LR_PENDING_BIT		(1 << 28)
>>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>> new file mode 100644
>> index 0000000..4cee616
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>> @@ -0,0 +1,178 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/irqchip/arm-gic.h>
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_host.h>
>> +
>> +#include "vgic.h"
>> +
>> +/*
>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>> + *
>> + * Warning: Calling this function may modify *val.
>> + */
>> +static unsigned long *u64_to_bitmask(u64 *val)
>> +{
>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>> +	*val = (*val >> 32) | (*val << 32);
>> +#endif
>> +	return (unsigned long *)val;
>> +}
>> +
>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +
>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>> +		u64 eisr = cpuif->vgic_eisr;
>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>> +		int lr;
>> +
>> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
> Didn't we say we could use vcpu->arch.vgic_cpu.used_lrs here?

Why would that be useful? Don't we just want to see those LRs that had a
maintenance interrupt received? I don't see the point if iterating over
the used LRs, where we need to check for this condition somehow manually?
Or what am I missing here?

>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
>> +
>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
>> +
>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>> +
>> +			cpuif->vgic_elrsr |= 1ULL << lr;

So are we good with removing this line (and the respective one in v3)?

Cheers,
Andre.

>> +		}
>> +	}
>> +
>> +	/* check and disable underflow maintenance IRQ */
> check?
> 
> Besides
> Reviewed-by: Eric Auger <eric.auger@linaro.org>
> 
> Eric
>> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
>> +
>> +	/*
>> +	 * In the next iterations of the vcpu loop, if we sync the
>> +	 * vgic state after flushing it, but before entering the guest
>> +	 * (this happens for pending signals and vmid rollovers), then
>> +	 * make sure we don't pick up any old maintenance interrupts
>> +	 * here.
>> +	 */
>> +	cpuif->vgic_eisr = 0;
>> +}
>> +
>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +
>> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
>> +}
>> +
>> +/*
>> + * transfer the content of the LRs back into the corresponding ap_list:
>> + * - active bit is transferred as is
>> + * - pending bit is
>> + *   - transferred as is in case of edge sensitive IRQs
>> + *   - set to the line-level (resample time) for level sensitive IRQs
>> + */
>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>> +	int lr;
>> +
>> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
>> +		u32 val = cpuif->vgic_lr[lr];
>> +		u32 intid = val & GICH_LR_VIRTUALID;
>> +		struct vgic_irq *irq;
>> +
>> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		/* Always preserve the active bit */
>> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
>> +
>> +		/* Edge is the only case where we preserve the pending bit */
>> +		if (irq->config == VGIC_CONFIG_EDGE &&
>> +		    (val & GICH_LR_PENDING_BIT)) {
>> +			irq->pending = true;
>> +
>> +			if (vgic_irq_is_sgi(intid)) {
>> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
>> +
>> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
>> +				irq->source |= (1 << cpuid);
>> +			}
>> +		}
>> +
>> +		/* Clear soft pending state when level IRQs have been acked */
>> +		if (irq->config == VGIC_CONFIG_LEVEL &&
>> +		    !(val & GICH_LR_PENDING_BIT)) {
>> +			irq->soft_pending = false;
>> +			irq->pending = irq->line_level;
>> +		}
>> +
>> +		spin_unlock(&irq->irq_lock);
>> +	}
>> +}
>> +
>> +/*
>> + * Populates the particular LR with the state of a given IRQ:
>> + * - for an edge sensitive IRQ the pending state is cleared in struct vgic_irq
>> + * - for a level sensitive IRQ the pending state value is unchanged;
>> + *   it is dictated directly by the input level
>> + *
>> + * If @irq describes an SGI with multiple sources, we choose the
>> + * lowest-numbered source VCPU and clear that bit in the source bitmap.
>> + *
>> + * The irq_lock must be held by the caller.
>> + */
>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
>> +{
>> +	u32 val = irq->intid;
>> +
>> +	if (irq->pending) {
>> +		val |= GICH_LR_PENDING_BIT;
>> +
>> +		if (irq->config == VGIC_CONFIG_EDGE)
>> +			irq->pending = false;
>> +
>> +		if (vgic_irq_is_sgi(irq->intid)) {
>> +			u32 src = ffs(irq->source);
>> +
>> +			BUG_ON(!src);
>> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
>> +			irq->source &= ~(1 << (src - 1));
>> +			if (irq->source)
>> +				irq->pending = true;
>> +		}
>> +	}
>> +
>> +	if (irq->active)
>> +		val |= GICH_LR_ACTIVE_BIT;
>> +
>> +	if (irq->hw) {
>> +		val |= GICH_LR_HW;
>> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
>> +	} else {
>> +		if (irq->config == VGIC_CONFIG_LEVEL)
>> +			val |= GICH_LR_EOI;
>> +	}
>> +
>> +	/* The GICv2 LR only holds five bits of priority. */
>> +	val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
>> +
>> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
>> +}
>> +
>> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
>> +{
>> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index c6f8b9b..68d885c 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -397,10 +397,12 @@ retry:
>>  
>>  static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>>  {
>> +	vgic_v2_process_maintenance(vcpu);
>>  }
>>  
>>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>>  {
>> +	vgic_v2_fold_lr_state(vcpu);
>>  }
>>  
>>  /* Requires the ap_list_lock and the irq_lock to be held. */
>> @@ -409,14 +411,18 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>>  {
>>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
>>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
>> +
>> +	vgic_v2_populate_lr(vcpu, irq, lr);
>>  }
>>  
>>  static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
>>  {
>> +	vgic_v2_clear_lr(vcpu, lr);
>>  }
>>  
>>  static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>>  {
>> +	vgic_v2_set_underflow(vcpu);
>>  }
>>  
>>  static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 29b96b9..0db490e 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -22,4 +22,10 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  			      u32 intid);
>>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
>>  
>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>> +
>>  #endif
>>
> 

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

* Re: [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
  2016-05-11 11:30       ` Andre Przywara
@ 2016-05-11 11:38         ` Eric Auger
  -1 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-11 11:38 UTC (permalink / raw)
  To: Andre Przywara, Marc Zyngier, Christoffer Dall
  Cc: kvmarm, kvm, linux-arm-kernel

On 05/11/2016 01:30 PM, Andre Przywara wrote:
> Hi,
> 
> On 10/05/16 15:10, Eric Auger wrote:
>> On 05/06/2016 12:45 PM, Andre Przywara wrote:
>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>
>>> Processing maintenance interrupts and accessing the list registers
>>> are dependent on the host's GIC version.
>>> Introduce vgic-v2.c to contain GICv2 specific functions.
>>> Implement the GICv2 specific code for syncing the emulation state
>>> into the VGIC registers.
>>>
>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>> Changelog RFC..v1:
>>> - remove explicit LR_STATE clearing on maintenance interrupt handling
>>> - improve documentation for vgic_v2_populate_lr()
>>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
>>> - simplify multi-CPU source SGI handling
>>>
>>> Changelog v1 .. v2:
>>> - inject the IRQ priority into the list register
>>>
>>> Changelog v2 .. v3:
>>> - cleanup diff containing rebase artifacts
>>>
>>>  include/linux/irqchip/arm-gic.h |   1 +
>>>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>>>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>>>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>>>  4 files changed, 191 insertions(+)
>>>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>>>
>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>>> index 9c94026..be0d26f 100644
>>> --- a/include/linux/irqchip/arm-gic.h
>>> +++ b/include/linux/irqchip/arm-gic.h
>>> @@ -76,6 +76,7 @@
>>>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>>>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>>>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
>>> +#define GICH_LR_PRIORITY_SHIFT		23
>>>  #define GICH_LR_STATE			(3 << 28)
>>>  #define GICH_LR_PENDING_BIT		(1 << 28)
>>>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
>>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>>> new file mode 100644
>>> index 0000000..4cee616
>>> --- /dev/null
>>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>>> @@ -0,0 +1,178 @@
>>> +/*
>>> + * Copyright (C) 2015, 2016 ARM Ltd.
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + * GNU General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU General Public License
>>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>> + */
>>> +
>>> +#include <linux/irqchip/arm-gic.h>
>>> +#include <linux/kvm.h>
>>> +#include <linux/kvm_host.h>
>>> +
>>> +#include "vgic.h"
>>> +
>>> +/*
>>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>>> + *
>>> + * Warning: Calling this function may modify *val.
>>> + */
>>> +static unsigned long *u64_to_bitmask(u64 *val)
>>> +{
>>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>>> +	*val = (*val >> 32) | (*val << 32);
>>> +#endif
>>> +	return (unsigned long *)val;
>>> +}
>>> +
>>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>>> +{
>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>> +
>>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>>> +		u64 eisr = cpuif->vgic_eisr;
>>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>>> +		int lr;
>>> +
>>> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
>> Didn't we say we could use vcpu->arch.vgic_cpu.used_lrs here?
> 
> Why would that be useful? Don't we just want to see those LRs that had a
> maintenance interrupt received? I don't see the point if iterating over
> the used LRs, where we need to check for this condition somehow manually?
> Or what am I missing here?

Well I thought that there is no use inspecting bits corresponding to
unused LRs, no?

Cheers

Eric
> 
>>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
>>> +
>>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
>>> +
>>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>>> +
>>> +			cpuif->vgic_elrsr |= 1ULL << lr;
> 
> So are we good with removing this line (and the respective one in v3)?
> 
> Cheers,
> Andre.
> 
>>> +		}
>>> +	}
>>> +
>>> +	/* check and disable underflow maintenance IRQ */
>> check?
>>
>> Besides
>> Reviewed-by: Eric Auger <eric.auger@linaro.org>
>>
>> Eric
>>> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
>>> +
>>> +	/*
>>> +	 * In the next iterations of the vcpu loop, if we sync the
>>> +	 * vgic state after flushing it, but before entering the guest
>>> +	 * (this happens for pending signals and vmid rollovers), then
>>> +	 * make sure we don't pick up any old maintenance interrupts
>>> +	 * here.
>>> +	 */
>>> +	cpuif->vgic_eisr = 0;
>>> +}
>>> +
>>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
>>> +{
>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>> +
>>> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
>>> +}
>>> +
>>> +/*
>>> + * transfer the content of the LRs back into the corresponding ap_list:
>>> + * - active bit is transferred as is
>>> + * - pending bit is
>>> + *   - transferred as is in case of edge sensitive IRQs
>>> + *   - set to the line-level (resample time) for level sensitive IRQs
>>> + */
>>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
>>> +{
>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>> +	int lr;
>>> +
>>> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
>>> +		u32 val = cpuif->vgic_lr[lr];
>>> +		u32 intid = val & GICH_LR_VIRTUALID;
>>> +		struct vgic_irq *irq;
>>> +
>>> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>>> +
>>> +		spin_lock(&irq->irq_lock);
>>> +
>>> +		/* Always preserve the active bit */
>>> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
>>> +
>>> +		/* Edge is the only case where we preserve the pending bit */
>>> +		if (irq->config == VGIC_CONFIG_EDGE &&
>>> +		    (val & GICH_LR_PENDING_BIT)) {
>>> +			irq->pending = true;
>>> +
>>> +			if (vgic_irq_is_sgi(intid)) {
>>> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
>>> +
>>> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
>>> +				irq->source |= (1 << cpuid);
>>> +			}
>>> +		}
>>> +
>>> +		/* Clear soft pending state when level IRQs have been acked */
>>> +		if (irq->config == VGIC_CONFIG_LEVEL &&
>>> +		    !(val & GICH_LR_PENDING_BIT)) {
>>> +			irq->soft_pending = false;
>>> +			irq->pending = irq->line_level;
>>> +		}
>>> +
>>> +		spin_unlock(&irq->irq_lock);
>>> +	}
>>> +}
>>> +
>>> +/*
>>> + * Populates the particular LR with the state of a given IRQ:
>>> + * - for an edge sensitive IRQ the pending state is cleared in struct vgic_irq
>>> + * - for a level sensitive IRQ the pending state value is unchanged;
>>> + *   it is dictated directly by the input level
>>> + *
>>> + * If @irq describes an SGI with multiple sources, we choose the
>>> + * lowest-numbered source VCPU and clear that bit in the source bitmap.
>>> + *
>>> + * The irq_lock must be held by the caller.
>>> + */
>>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
>>> +{
>>> +	u32 val = irq->intid;
>>> +
>>> +	if (irq->pending) {
>>> +		val |= GICH_LR_PENDING_BIT;
>>> +
>>> +		if (irq->config == VGIC_CONFIG_EDGE)
>>> +			irq->pending = false;
>>> +
>>> +		if (vgic_irq_is_sgi(irq->intid)) {
>>> +			u32 src = ffs(irq->source);
>>> +
>>> +			BUG_ON(!src);
>>> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
>>> +			irq->source &= ~(1 << (src - 1));
>>> +			if (irq->source)
>>> +				irq->pending = true;
>>> +		}
>>> +	}
>>> +
>>> +	if (irq->active)
>>> +		val |= GICH_LR_ACTIVE_BIT;
>>> +
>>> +	if (irq->hw) {
>>> +		val |= GICH_LR_HW;
>>> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
>>> +	} else {
>>> +		if (irq->config == VGIC_CONFIG_LEVEL)
>>> +			val |= GICH_LR_EOI;
>>> +	}
>>> +
>>> +	/* The GICv2 LR only holds five bits of priority. */
>>> +	val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
>>> +
>>> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
>>> +}
>>> +
>>> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
>>> +{
>>> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
>>> +}
>>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>>> index c6f8b9b..68d885c 100644
>>> --- a/virt/kvm/arm/vgic/vgic.c
>>> +++ b/virt/kvm/arm/vgic/vgic.c
>>> @@ -397,10 +397,12 @@ retry:
>>>  
>>>  static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>>>  {
>>> +	vgic_v2_process_maintenance(vcpu);
>>>  }
>>>  
>>>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>>>  {
>>> +	vgic_v2_fold_lr_state(vcpu);
>>>  }
>>>  
>>>  /* Requires the ap_list_lock and the irq_lock to be held. */
>>> @@ -409,14 +411,18 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>>>  {
>>>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
>>>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
>>> +
>>> +	vgic_v2_populate_lr(vcpu, irq, lr);
>>>  }
>>>  
>>>  static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
>>>  {
>>> +	vgic_v2_clear_lr(vcpu, lr);
>>>  }
>>>  
>>>  static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>>>  {
>>> +	vgic_v2_set_underflow(vcpu);
>>>  }
>>>  
>>>  static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
>>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>>> index 29b96b9..0db490e 100644
>>> --- a/virt/kvm/arm/vgic/vgic.h
>>> +++ b/virt/kvm/arm/vgic/vgic.h
>>> @@ -22,4 +22,10 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>>  			      u32 intid);
>>>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
>>>  
>>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>>> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
>>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>>> +
>>>  #endif
>>>
>>


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

* [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
@ 2016-05-11 11:38         ` Eric Auger
  0 siblings, 0 replies; 400+ messages in thread
From: Eric Auger @ 2016-05-11 11:38 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/11/2016 01:30 PM, Andre Przywara wrote:
> Hi,
> 
> On 10/05/16 15:10, Eric Auger wrote:
>> On 05/06/2016 12:45 PM, Andre Przywara wrote:
>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>
>>> Processing maintenance interrupts and accessing the list registers
>>> are dependent on the host's GIC version.
>>> Introduce vgic-v2.c to contain GICv2 specific functions.
>>> Implement the GICv2 specific code for syncing the emulation state
>>> into the VGIC registers.
>>>
>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>> Changelog RFC..v1:
>>> - remove explicit LR_STATE clearing on maintenance interrupt handling
>>> - improve documentation for vgic_v2_populate_lr()
>>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
>>> - simplify multi-CPU source SGI handling
>>>
>>> Changelog v1 .. v2:
>>> - inject the IRQ priority into the list register
>>>
>>> Changelog v2 .. v3:
>>> - cleanup diff containing rebase artifacts
>>>
>>>  include/linux/irqchip/arm-gic.h |   1 +
>>>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>>>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>>>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>>>  4 files changed, 191 insertions(+)
>>>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>>>
>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>>> index 9c94026..be0d26f 100644
>>> --- a/include/linux/irqchip/arm-gic.h
>>> +++ b/include/linux/irqchip/arm-gic.h
>>> @@ -76,6 +76,7 @@
>>>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>>>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>>>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
>>> +#define GICH_LR_PRIORITY_SHIFT		23
>>>  #define GICH_LR_STATE			(3 << 28)
>>>  #define GICH_LR_PENDING_BIT		(1 << 28)
>>>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
>>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>>> new file mode 100644
>>> index 0000000..4cee616
>>> --- /dev/null
>>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>>> @@ -0,0 +1,178 @@
>>> +/*
>>> + * Copyright (C) 2015, 2016 ARM Ltd.
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + * GNU General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU General Public License
>>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>> + */
>>> +
>>> +#include <linux/irqchip/arm-gic.h>
>>> +#include <linux/kvm.h>
>>> +#include <linux/kvm_host.h>
>>> +
>>> +#include "vgic.h"
>>> +
>>> +/*
>>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>>> + *
>>> + * Warning: Calling this function may modify *val.
>>> + */
>>> +static unsigned long *u64_to_bitmask(u64 *val)
>>> +{
>>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>>> +	*val = (*val >> 32) | (*val << 32);
>>> +#endif
>>> +	return (unsigned long *)val;
>>> +}
>>> +
>>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>>> +{
>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>> +
>>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>>> +		u64 eisr = cpuif->vgic_eisr;
>>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>>> +		int lr;
>>> +
>>> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
>> Didn't we say we could use vcpu->arch.vgic_cpu.used_lrs here?
> 
> Why would that be useful? Don't we just want to see those LRs that had a
> maintenance interrupt received? I don't see the point if iterating over
> the used LRs, where we need to check for this condition somehow manually?
> Or what am I missing here?

Well I thought that there is no use inspecting bits corresponding to
unused LRs, no?

Cheers

Eric
> 
>>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
>>> +
>>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
>>> +
>>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>>> +
>>> +			cpuif->vgic_elrsr |= 1ULL << lr;
> 
> So are we good with removing this line (and the respective one in v3)?
> 
> Cheers,
> Andre.
> 
>>> +		}
>>> +	}
>>> +
>>> +	/* check and disable underflow maintenance IRQ */
>> check?
>>
>> Besides
>> Reviewed-by: Eric Auger <eric.auger@linaro.org>
>>
>> Eric
>>> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
>>> +
>>> +	/*
>>> +	 * In the next iterations of the vcpu loop, if we sync the
>>> +	 * vgic state after flushing it, but before entering the guest
>>> +	 * (this happens for pending signals and vmid rollovers), then
>>> +	 * make sure we don't pick up any old maintenance interrupts
>>> +	 * here.
>>> +	 */
>>> +	cpuif->vgic_eisr = 0;
>>> +}
>>> +
>>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
>>> +{
>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>> +
>>> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
>>> +}
>>> +
>>> +/*
>>> + * transfer the content of the LRs back into the corresponding ap_list:
>>> + * - active bit is transferred as is
>>> + * - pending bit is
>>> + *   - transferred as is in case of edge sensitive IRQs
>>> + *   - set to the line-level (resample time) for level sensitive IRQs
>>> + */
>>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
>>> +{
>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>> +	int lr;
>>> +
>>> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
>>> +		u32 val = cpuif->vgic_lr[lr];
>>> +		u32 intid = val & GICH_LR_VIRTUALID;
>>> +		struct vgic_irq *irq;
>>> +
>>> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>>> +
>>> +		spin_lock(&irq->irq_lock);
>>> +
>>> +		/* Always preserve the active bit */
>>> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
>>> +
>>> +		/* Edge is the only case where we preserve the pending bit */
>>> +		if (irq->config == VGIC_CONFIG_EDGE &&
>>> +		    (val & GICH_LR_PENDING_BIT)) {
>>> +			irq->pending = true;
>>> +
>>> +			if (vgic_irq_is_sgi(intid)) {
>>> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
>>> +
>>> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
>>> +				irq->source |= (1 << cpuid);
>>> +			}
>>> +		}
>>> +
>>> +		/* Clear soft pending state when level IRQs have been acked */
>>> +		if (irq->config == VGIC_CONFIG_LEVEL &&
>>> +		    !(val & GICH_LR_PENDING_BIT)) {
>>> +			irq->soft_pending = false;
>>> +			irq->pending = irq->line_level;
>>> +		}
>>> +
>>> +		spin_unlock(&irq->irq_lock);
>>> +	}
>>> +}
>>> +
>>> +/*
>>> + * Populates the particular LR with the state of a given IRQ:
>>> + * - for an edge sensitive IRQ the pending state is cleared in struct vgic_irq
>>> + * - for a level sensitive IRQ the pending state value is unchanged;
>>> + *   it is dictated directly by the input level
>>> + *
>>> + * If @irq describes an SGI with multiple sources, we choose the
>>> + * lowest-numbered source VCPU and clear that bit in the source bitmap.
>>> + *
>>> + * The irq_lock must be held by the caller.
>>> + */
>>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
>>> +{
>>> +	u32 val = irq->intid;
>>> +
>>> +	if (irq->pending) {
>>> +		val |= GICH_LR_PENDING_BIT;
>>> +
>>> +		if (irq->config == VGIC_CONFIG_EDGE)
>>> +			irq->pending = false;
>>> +
>>> +		if (vgic_irq_is_sgi(irq->intid)) {
>>> +			u32 src = ffs(irq->source);
>>> +
>>> +			BUG_ON(!src);
>>> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
>>> +			irq->source &= ~(1 << (src - 1));
>>> +			if (irq->source)
>>> +				irq->pending = true;
>>> +		}
>>> +	}
>>> +
>>> +	if (irq->active)
>>> +		val |= GICH_LR_ACTIVE_BIT;
>>> +
>>> +	if (irq->hw) {
>>> +		val |= GICH_LR_HW;
>>> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
>>> +	} else {
>>> +		if (irq->config == VGIC_CONFIG_LEVEL)
>>> +			val |= GICH_LR_EOI;
>>> +	}
>>> +
>>> +	/* The GICv2 LR only holds five bits of priority. */
>>> +	val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
>>> +
>>> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
>>> +}
>>> +
>>> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
>>> +{
>>> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
>>> +}
>>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>>> index c6f8b9b..68d885c 100644
>>> --- a/virt/kvm/arm/vgic/vgic.c
>>> +++ b/virt/kvm/arm/vgic/vgic.c
>>> @@ -397,10 +397,12 @@ retry:
>>>  
>>>  static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>>>  {
>>> +	vgic_v2_process_maintenance(vcpu);
>>>  }
>>>  
>>>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>>>  {
>>> +	vgic_v2_fold_lr_state(vcpu);
>>>  }
>>>  
>>>  /* Requires the ap_list_lock and the irq_lock to be held. */
>>> @@ -409,14 +411,18 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>>>  {
>>>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
>>>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
>>> +
>>> +	vgic_v2_populate_lr(vcpu, irq, lr);
>>>  }
>>>  
>>>  static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
>>>  {
>>> +	vgic_v2_clear_lr(vcpu, lr);
>>>  }
>>>  
>>>  static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>>>  {
>>> +	vgic_v2_set_underflow(vcpu);
>>>  }
>>>  
>>>  static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
>>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>>> index 29b96b9..0db490e 100644
>>> --- a/virt/kvm/arm/vgic/vgic.h
>>> +++ b/virt/kvm/arm/vgic/vgic.h
>>> @@ -22,4 +22,10 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>>  			      u32 intid);
>>>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
>>>  
>>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>>> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
>>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>>> +
>>>  #endif
>>>
>>

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

* Re: [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-11 12:05     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 12:05 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 06, 2016 at 11:45:36AM +0100, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Those three registers are v2 emulation specific, so their implementation
> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
> as their implementation is pretty simple.
> When the guest enables the distributor, we kick all VCPUs to get
> potentially pending interrupts serviced.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - kick VCPUs is the distributor gets enabled
> - improve comment
> 
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> - use switch() statements to improve readability
> 
> Changelog v2 .. v3:
> - add vgic_kick_vcpus() implementation
> 
>  include/linux/irqchip/arm-gic.h  |  1 +
>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
>  virt/kvm/arm/vgic/vgic.c         | 15 +++++++++++++
>  virt/kvm/arm/vgic/vgic.h         |  4 ++++
>  4 files changed, 67 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> index be0d26f..fd05185 100644
> --- a/include/linux/irqchip/arm-gic.h
> +++ b/include/linux/irqchip/arm-gic.h
> @@ -33,6 +33,7 @@
>  
>  #define GIC_DIST_CTRL			0x000
>  #define GIC_DIST_CTR			0x004
> +#define GIC_DIST_IIDR			0x008
>  #define GIC_DIST_IGROUP			0x080
>  #define GIC_DIST_ENABLE_SET		0x100
>  #define GIC_DIST_ENABLE_CLEAR		0x180
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 2729a22..69e96f7 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -20,9 +20,55 @@
>  #include "vgic.h"
>  #include "vgic-mmio.h"
>  
> +static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
> +					    gpa_t addr, unsigned int len)
> +{
> +	u32 value;
> +
> +	switch (addr & 0x0c) {
> +	case GIC_DIST_CTRL:
> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
> +		break;
> +	case GIC_DIST_CTR:
> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> +		value = (value >> 5) - 1;
> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
> +		break;
> +	case GIC_DIST_IIDR:
> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> +		break;
> +	default:
> +		return 0;
> +	}
> +
> +	return extract_bytes(value, addr & 3, len);
> +}
> +
> +static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len,
> +				    unsigned long val)
> +{
> +	switch (addr & 0x0c) {
> +	case GIC_DIST_CTRL:
> +		if (!(addr & 1)) {

what is this !(addr & 1) check?

> +			struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> +			bool was_enabled = dist->enabled;
> +
> +			dist->enabled = val & GICD_ENABLE;
> +			if (!was_enabled && dist->enabled)
> +				vgic_kick_vcpus(vcpu->kvm);
> +		}
> +		break;
> +	case GIC_DIST_CTR:
> +	case GIC_DIST_IIDR:
> +		/* Nothing to do */
> +		return;
> +	}
> +}
> +
>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 12),
> +		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index c3dbcf3..5355de6 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -544,3 +544,18 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
>  
>  	return pending;
>  }
> +
> +void vgic_kick_vcpus(struct kvm *kvm)
> +{
> +	struct kvm_vcpu *vcpu;
> +	int c;
> +
> +	/*
> +	 * We've injected an interrupt, time to find out who deserves
> +	 * a good kick...
> +	 */
> +	kvm_for_each_vcpu(c, vcpu, kvm) {
> +		if (kvm_vgic_vcpu_pending_irq(vcpu))
> +			kvm_vcpu_kick(vcpu);
> +	}
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index fd9acaa..cf62015 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -16,11 +16,15 @@
>  #ifndef __KVM_ARM_VGIC_NEW_H__
>  #define __KVM_ARM_VGIC_NEW_H__
>  
> +#define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
> +#define IMPLEMENTER_ARM		0x43b
> +
>  #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
>  
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
> +void vgic_kick_vcpus(struct kvm *kvm);
>  
>  void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>  void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
@ 2016-05-11 12:05     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 12:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:36AM +0100, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Those three registers are v2 emulation specific, so their implementation
> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
> as their implementation is pretty simple.
> When the guest enables the distributor, we kick all VCPUs to get
> potentially pending interrupts serviced.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - kick VCPUs is the distributor gets enabled
> - improve comment
> 
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> - use switch() statements to improve readability
> 
> Changelog v2 .. v3:
> - add vgic_kick_vcpus() implementation
> 
>  include/linux/irqchip/arm-gic.h  |  1 +
>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
>  virt/kvm/arm/vgic/vgic.c         | 15 +++++++++++++
>  virt/kvm/arm/vgic/vgic.h         |  4 ++++
>  4 files changed, 67 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> index be0d26f..fd05185 100644
> --- a/include/linux/irqchip/arm-gic.h
> +++ b/include/linux/irqchip/arm-gic.h
> @@ -33,6 +33,7 @@
>  
>  #define GIC_DIST_CTRL			0x000
>  #define GIC_DIST_CTR			0x004
> +#define GIC_DIST_IIDR			0x008
>  #define GIC_DIST_IGROUP			0x080
>  #define GIC_DIST_ENABLE_SET		0x100
>  #define GIC_DIST_ENABLE_CLEAR		0x180
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 2729a22..69e96f7 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -20,9 +20,55 @@
>  #include "vgic.h"
>  #include "vgic-mmio.h"
>  
> +static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
> +					    gpa_t addr, unsigned int len)
> +{
> +	u32 value;
> +
> +	switch (addr & 0x0c) {
> +	case GIC_DIST_CTRL:
> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
> +		break;
> +	case GIC_DIST_CTR:
> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> +		value = (value >> 5) - 1;
> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
> +		break;
> +	case GIC_DIST_IIDR:
> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> +		break;
> +	default:
> +		return 0;
> +	}
> +
> +	return extract_bytes(value, addr & 3, len);
> +}
> +
> +static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len,
> +				    unsigned long val)
> +{
> +	switch (addr & 0x0c) {
> +	case GIC_DIST_CTRL:
> +		if (!(addr & 1)) {

what is this !(addr & 1) check?

> +			struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> +			bool was_enabled = dist->enabled;
> +
> +			dist->enabled = val & GICD_ENABLE;
> +			if (!was_enabled && dist->enabled)
> +				vgic_kick_vcpus(vcpu->kvm);
> +		}
> +		break;
> +	case GIC_DIST_CTR:
> +	case GIC_DIST_IIDR:
> +		/* Nothing to do */
> +		return;
> +	}
> +}
> +
>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 12),
> +		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index c3dbcf3..5355de6 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -544,3 +544,18 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
>  
>  	return pending;
>  }
> +
> +void vgic_kick_vcpus(struct kvm *kvm)
> +{
> +	struct kvm_vcpu *vcpu;
> +	int c;
> +
> +	/*
> +	 * We've injected an interrupt, time to find out who deserves
> +	 * a good kick...
> +	 */
> +	kvm_for_each_vcpu(c, vcpu, kvm) {
> +		if (kvm_vgic_vcpu_pending_irq(vcpu))
> +			kvm_vcpu_kick(vcpu);
> +	}
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index fd9acaa..cf62015 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -16,11 +16,15 @@
>  #ifndef __KVM_ARM_VGIC_NEW_H__
>  #define __KVM_ARM_VGIC_NEW_H__
>  
> +#define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
> +#define IMPLEMENTER_ARM		0x43b
> +
>  #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
>  
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
> +void vgic_kick_vcpus(struct kvm *kvm);
>  
>  void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>  void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
  2016-05-11 11:30       ` Andre Przywara
@ 2016-05-11 12:26         ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 12:26 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Eric Auger, Marc Zyngier, kvmarm, kvm, linux-arm-kernel

On Wed, May 11, 2016 at 12:30:36PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 10/05/16 15:10, Eric Auger wrote:
> > On 05/06/2016 12:45 PM, Andre Przywara wrote:
> >> From: Marc Zyngier <marc.zyngier@arm.com>
> >>
> >> Processing maintenance interrupts and accessing the list registers
> >> are dependent on the host's GIC version.
> >> Introduce vgic-v2.c to contain GICv2 specific functions.
> >> Implement the GICv2 specific code for syncing the emulation state
> >> into the VGIC registers.
> >>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changelog RFC..v1:
> >> - remove explicit LR_STATE clearing on maintenance interrupt handling
> >> - improve documentation for vgic_v2_populate_lr()
> >> - remove WARN_ON on non-edge IRQs in maintenance interrupts
> >> - simplify multi-CPU source SGI handling
> >>
> >> Changelog v1 .. v2:
> >> - inject the IRQ priority into the list register
> >>
> >> Changelog v2 .. v3:
> >> - cleanup diff containing rebase artifacts
> >>
> >>  include/linux/irqchip/arm-gic.h |   1 +
> >>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic.c        |   6 ++
> >>  virt/kvm/arm/vgic/vgic.h        |   6 ++
> >>  4 files changed, 191 insertions(+)
> >>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
> >>
> >> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> >> index 9c94026..be0d26f 100644
> >> --- a/include/linux/irqchip/arm-gic.h
> >> +++ b/include/linux/irqchip/arm-gic.h
> >> @@ -76,6 +76,7 @@
> >>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
> >>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
> >>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
> >> +#define GICH_LR_PRIORITY_SHIFT		23
> >>  #define GICH_LR_STATE			(3 << 28)
> >>  #define GICH_LR_PENDING_BIT		(1 << 28)
> >>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
> >> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> >> new file mode 100644
> >> index 0000000..4cee616
> >> --- /dev/null
> >> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> >> @@ -0,0 +1,178 @@
> >> +/*
> >> + * Copyright (C) 2015, 2016 ARM Ltd.
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License version 2 as
> >> + * published by the Free Software Foundation.
> >> + *
> >> + * This program is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >> + * GNU General Public License for more details.
> >> + *
> >> + * You should have received a copy of the GNU General Public License
> >> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> >> + */
> >> +
> >> +#include <linux/irqchip/arm-gic.h>
> >> +#include <linux/kvm.h>
> >> +#include <linux/kvm_host.h>
> >> +
> >> +#include "vgic.h"
> >> +
> >> +/*
> >> + * Call this function to convert a u64 value to an unsigned long * bitmask
> >> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
> >> + *
> >> + * Warning: Calling this function may modify *val.
> >> + */
> >> +static unsigned long *u64_to_bitmask(u64 *val)
> >> +{
> >> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
> >> +	*val = (*val >> 32) | (*val << 32);
> >> +#endif
> >> +	return (unsigned long *)val;
> >> +}
> >> +
> >> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> >> +
> >> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
> >> +		u64 eisr = cpuif->vgic_eisr;
> >> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
> >> +		int lr;
> >> +
> >> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
> > Didn't we say we could use vcpu->arch.vgic_cpu.used_lrs here?
> 
> Why would that be useful? Don't we just want to see those LRs that had a
> maintenance interrupt received? I don't see the point if iterating over
> the used LRs, where we need to check for this condition somehow manually?
> Or what am I missing here?

if we get rid of eisr eventually we can optimize the reading of that
away, but I honestly don't think we should be pursuing this straight
away.

> 
> >> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
> >> +
> >> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
> >> +
> >> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> >> +					     intid - VGIC_NR_PRIVATE_IRQS);
> >> +
> >> +			cpuif->vgic_elrsr |= 1ULL << lr;
> 
> So are we good with removing this line (and the respective one in v3)?
> 
Yes.

-Christoffer

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

* [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
@ 2016-05-11 12:26         ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 12:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, May 11, 2016 at 12:30:36PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 10/05/16 15:10, Eric Auger wrote:
> > On 05/06/2016 12:45 PM, Andre Przywara wrote:
> >> From: Marc Zyngier <marc.zyngier@arm.com>
> >>
> >> Processing maintenance interrupts and accessing the list registers
> >> are dependent on the host's GIC version.
> >> Introduce vgic-v2.c to contain GICv2 specific functions.
> >> Implement the GICv2 specific code for syncing the emulation state
> >> into the VGIC registers.
> >>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changelog RFC..v1:
> >> - remove explicit LR_STATE clearing on maintenance interrupt handling
> >> - improve documentation for vgic_v2_populate_lr()
> >> - remove WARN_ON on non-edge IRQs in maintenance interrupts
> >> - simplify multi-CPU source SGI handling
> >>
> >> Changelog v1 .. v2:
> >> - inject the IRQ priority into the list register
> >>
> >> Changelog v2 .. v3:
> >> - cleanup diff containing rebase artifacts
> >>
> >>  include/linux/irqchip/arm-gic.h |   1 +
> >>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic.c        |   6 ++
> >>  virt/kvm/arm/vgic/vgic.h        |   6 ++
> >>  4 files changed, 191 insertions(+)
> >>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
> >>
> >> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> >> index 9c94026..be0d26f 100644
> >> --- a/include/linux/irqchip/arm-gic.h
> >> +++ b/include/linux/irqchip/arm-gic.h
> >> @@ -76,6 +76,7 @@
> >>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
> >>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
> >>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
> >> +#define GICH_LR_PRIORITY_SHIFT		23
> >>  #define GICH_LR_STATE			(3 << 28)
> >>  #define GICH_LR_PENDING_BIT		(1 << 28)
> >>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
> >> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> >> new file mode 100644
> >> index 0000000..4cee616
> >> --- /dev/null
> >> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> >> @@ -0,0 +1,178 @@
> >> +/*
> >> + * Copyright (C) 2015, 2016 ARM Ltd.
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License version 2 as
> >> + * published by the Free Software Foundation.
> >> + *
> >> + * This program is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >> + * GNU General Public License for more details.
> >> + *
> >> + * You should have received a copy of the GNU General Public License
> >> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> >> + */
> >> +
> >> +#include <linux/irqchip/arm-gic.h>
> >> +#include <linux/kvm.h>
> >> +#include <linux/kvm_host.h>
> >> +
> >> +#include "vgic.h"
> >> +
> >> +/*
> >> + * Call this function to convert a u64 value to an unsigned long * bitmask
> >> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
> >> + *
> >> + * Warning: Calling this function may modify *val.
> >> + */
> >> +static unsigned long *u64_to_bitmask(u64 *val)
> >> +{
> >> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
> >> +	*val = (*val >> 32) | (*val << 32);
> >> +#endif
> >> +	return (unsigned long *)val;
> >> +}
> >> +
> >> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
> >> +{
> >> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
> >> +
> >> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
> >> +		u64 eisr = cpuif->vgic_eisr;
> >> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
> >> +		int lr;
> >> +
> >> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
> > Didn't we say we could use vcpu->arch.vgic_cpu.used_lrs here?
> 
> Why would that be useful? Don't we just want to see those LRs that had a
> maintenance interrupt received? I don't see the point if iterating over
> the used LRs, where we need to check for this condition somehow manually?
> Or what am I missing here?

if we get rid of eisr eventually we can optimize the reading of that
away, but I honestly don't think we should be pursuing this straight
away.

> 
> >> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
> >> +
> >> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
> >> +
> >> +			kvm_notify_acked_irq(vcpu->kvm, 0,
> >> +					     intid - VGIC_NR_PRIVATE_IRQS);
> >> +
> >> +			cpuif->vgic_elrsr |= 1ULL << lr;
> 
> So are we good with removing this line (and the respective one in v3)?
> 
Yes.

-Christoffer

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

* Re: [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-11 12:34     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 12:34 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
> As the enable register handlers are shared between the v2 and v3
> emulation, their implementation goes into vgic-mmio.c, to be easily
> referenced from the v3 emulation as well later.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - use lower bits of address to determine IRQ number
> - remove TODO, confirmed to be fine
> 
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
>  3 files changed, 69 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 69e96f7..448d1da 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index 41cf4f4..077ae86 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>  	/* Ignore */
>  }
>  
> +/*
> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
> + * of the enabled bit, so there is only one function for both here.
> + */
> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len)
> +{
> +	u32 intid = (addr & 0x7f) * 8;

is there anything we can do about this to make it more intuitive?  A
macro to generate the mask/offset based on bits per interrupt or
something?

> +	u32 value = 0;
> +	int i;
> +
> +	/* Loop over all IRQs affected by this read */
> +	for (i = 0; i < len * 8; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (irq->enabled)
> +			value |= (1U << i);

I couldn't find the code anywhere that enforces word-aligned accesses to
these registers.  Do we have that?

If that's not the case, doesn't this break of you do a non-word aligned
access?

> +	}
> +
> +	return extract_bytes(value, addr & 3, len);
> +}
> +
> +void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	int i;
> +
> +	for_each_set_bit(i, &val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->enabled = true;
> +		vgic_queue_irq_unlock(vcpu->kvm, irq);
> +	}
> +}
> +
> +void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	int i;
> +
> +	for_each_set_bit(i, &val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		irq->enabled = false;
> +
> +		spin_unlock(&irq->irq_lock);

nit: whitespace consistency with senable

> +	}
> +}
> +
>  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 4f4dd2b..188909a 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -74,6 +74,17 @@ unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
>  void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>  			unsigned int len, unsigned long val);
>  
> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len);
> +
> +void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val);
> +
> +void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val);
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
>  #endif
> -- 
> 2.7.3
> 

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

* [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
@ 2016-05-11 12:34     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 12:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
> As the enable register handlers are shared between the v2 and v3
> emulation, their implementation goes into vgic-mmio.c, to be easily
> referenced from the v3 emulation as well later.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - use lower bits of address to determine IRQ number
> - remove TODO, confirmed to be fine
> 
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
>  3 files changed, 69 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 69e96f7..448d1da 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index 41cf4f4..077ae86 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>  	/* Ignore */
>  }
>  
> +/*
> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
> + * of the enabled bit, so there is only one function for both here.
> + */
> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len)
> +{
> +	u32 intid = (addr & 0x7f) * 8;

is there anything we can do about this to make it more intuitive?  A
macro to generate the mask/offset based on bits per interrupt or
something?

> +	u32 value = 0;
> +	int i;
> +
> +	/* Loop over all IRQs affected by this read */
> +	for (i = 0; i < len * 8; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (irq->enabled)
> +			value |= (1U << i);

I couldn't find the code anywhere that enforces word-aligned accesses to
these registers.  Do we have that?

If that's not the case, doesn't this break of you do a non-word aligned
access?

> +	}
> +
> +	return extract_bytes(value, addr & 3, len);
> +}
> +
> +void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	int i;
> +
> +	for_each_set_bit(i, &val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->enabled = true;
> +		vgic_queue_irq_unlock(vcpu->kvm, irq);
> +	}
> +}
> +
> +void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	int i;
> +
> +	for_each_set_bit(i, &val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		irq->enabled = false;
> +
> +		spin_unlock(&irq->irq_lock);

nit: whitespace consistency with senable

> +	}
> +}
> +
>  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 4f4dd2b..188909a 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -74,6 +74,17 @@ unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
>  void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>  			unsigned int len, unsigned long val);
>  
> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len);
> +
> +void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val);
> +
> +void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
> +			     gpa_t addr, unsigned int len,
> +			     unsigned long val);
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
>  #endif
> -- 
> 2.7.3
> 

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

* Re: [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
  2016-05-11 12:05     ` Christoffer Dall
@ 2016-05-11 12:47       ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 12:47 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hej,

On 11/05/16 13:05, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:36AM +0100, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Those three registers are v2 emulation specific, so their implementation
>> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
>> as their implementation is pretty simple.
>> When the guest enables the distributor, we kick all VCPUs to get
>> potentially pending interrupts serviced.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - kick VCPUs is the distributor gets enabled
>> - improve comment
>>
>> Changelog v1 .. v2:
>> - adapt to new MMIO framework
>> - use switch() statements to improve readability
>>
>> Changelog v2 .. v3:
>> - add vgic_kick_vcpus() implementation
>>
>>  include/linux/irqchip/arm-gic.h  |  1 +
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
>>  virt/kvm/arm/vgic/vgic.c         | 15 +++++++++++++
>>  virt/kvm/arm/vgic/vgic.h         |  4 ++++
>>  4 files changed, 67 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>> index be0d26f..fd05185 100644
>> --- a/include/linux/irqchip/arm-gic.h
>> +++ b/include/linux/irqchip/arm-gic.h
>> @@ -33,6 +33,7 @@
>>  
>>  #define GIC_DIST_CTRL			0x000
>>  #define GIC_DIST_CTR			0x004
>> +#define GIC_DIST_IIDR			0x008
>>  #define GIC_DIST_IGROUP			0x080
>>  #define GIC_DIST_ENABLE_SET		0x100
>>  #define GIC_DIST_ENABLE_CLEAR		0x180
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index 2729a22..69e96f7 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -20,9 +20,55 @@
>>  #include "vgic.h"
>>  #include "vgic-mmio.h"
>>  
>> +static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
>> +					    gpa_t addr, unsigned int len)
>> +{
>> +	u32 value;
>> +
>> +	switch (addr & 0x0c) {
>> +	case GIC_DIST_CTRL:
>> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
>> +		break;
>> +	case GIC_DIST_CTR:
>> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +		value = (value >> 5) - 1;
>> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
>> +		break;
>> +	case GIC_DIST_IIDR:
>> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
>> +		break;
>> +	default:
>> +		return 0;
>> +	}
>> +
>> +	return extract_bytes(value, addr & 3, len);
>> +}
>> +
>> +static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>> +				    gpa_t addr, unsigned int len,
>> +				    unsigned long val)
>> +{
>> +	switch (addr & 0x0c) {
>> +	case GIC_DIST_CTRL:
>> +		if (!(addr & 1)) {
> 
> what is this !(addr & 1) check?

Mmmh, interesting. The original idea was that we care only about the
lowest significant byte. I guess this was somehow lost in translation
when Marc reworked the function. I think it should at least read:
"if (!(addr & 3))" to match the switch mask, otherwise for instance a
byte write to address 2 triggers the if branch as well.

I will fix the mask to 3 and add a comment.

Thanks,
Andre.


> 
>> +			struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>> +			bool was_enabled = dist->enabled;
>> +
>> +			dist->enabled = val & GICD_ENABLE;
>> +			if (!was_enabled && dist->enabled)
>> +				vgic_kick_vcpus(vcpu->kvm);
>> +		}
>> +		break;
>> +	case GIC_DIST_CTR:
>> +	case GIC_DIST_IIDR:
>> +		/* Nothing to do */
>> +		return;
>> +	}
>> +}
>> +
>>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 12),
>> +		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index c3dbcf3..5355de6 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -544,3 +544,18 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
>>  
>>  	return pending;
>>  }
>> +
>> +void vgic_kick_vcpus(struct kvm *kvm)
>> +{
>> +	struct kvm_vcpu *vcpu;
>> +	int c;
>> +
>> +	/*
>> +	 * We've injected an interrupt, time to find out who deserves
>> +	 * a good kick...
>> +	 */
>> +	kvm_for_each_vcpu(c, vcpu, kvm) {
>> +		if (kvm_vgic_vcpu_pending_irq(vcpu))
>> +			kvm_vcpu_kick(vcpu);
>> +	}
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index fd9acaa..cf62015 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -16,11 +16,15 @@
>>  #ifndef __KVM_ARM_VGIC_NEW_H__
>>  #define __KVM_ARM_VGIC_NEW_H__
>>  
>> +#define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
>> +#define IMPLEMENTER_ARM		0x43b
>> +
>>  #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
>>  
>>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  			      u32 intid);
>>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
>> +void vgic_kick_vcpus(struct kvm *kvm);
>>  
>>  void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>>  void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>> -- 
>> 2.7.3
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe kvm" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

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

* [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
@ 2016-05-11 12:47       ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 12:47 UTC (permalink / raw)
  To: linux-arm-kernel

Hej,

On 11/05/16 13:05, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:36AM +0100, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Those three registers are v2 emulation specific, so their implementation
>> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
>> as their implementation is pretty simple.
>> When the guest enables the distributor, we kick all VCPUs to get
>> potentially pending interrupts serviced.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - kick VCPUs is the distributor gets enabled
>> - improve comment
>>
>> Changelog v1 .. v2:
>> - adapt to new MMIO framework
>> - use switch() statements to improve readability
>>
>> Changelog v2 .. v3:
>> - add vgic_kick_vcpus() implementation
>>
>>  include/linux/irqchip/arm-gic.h  |  1 +
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
>>  virt/kvm/arm/vgic/vgic.c         | 15 +++++++++++++
>>  virt/kvm/arm/vgic/vgic.h         |  4 ++++
>>  4 files changed, 67 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>> index be0d26f..fd05185 100644
>> --- a/include/linux/irqchip/arm-gic.h
>> +++ b/include/linux/irqchip/arm-gic.h
>> @@ -33,6 +33,7 @@
>>  
>>  #define GIC_DIST_CTRL			0x000
>>  #define GIC_DIST_CTR			0x004
>> +#define GIC_DIST_IIDR			0x008
>>  #define GIC_DIST_IGROUP			0x080
>>  #define GIC_DIST_ENABLE_SET		0x100
>>  #define GIC_DIST_ENABLE_CLEAR		0x180
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index 2729a22..69e96f7 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -20,9 +20,55 @@
>>  #include "vgic.h"
>>  #include "vgic-mmio.h"
>>  
>> +static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
>> +					    gpa_t addr, unsigned int len)
>> +{
>> +	u32 value;
>> +
>> +	switch (addr & 0x0c) {
>> +	case GIC_DIST_CTRL:
>> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
>> +		break;
>> +	case GIC_DIST_CTR:
>> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +		value = (value >> 5) - 1;
>> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
>> +		break;
>> +	case GIC_DIST_IIDR:
>> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
>> +		break;
>> +	default:
>> +		return 0;
>> +	}
>> +
>> +	return extract_bytes(value, addr & 3, len);
>> +}
>> +
>> +static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>> +				    gpa_t addr, unsigned int len,
>> +				    unsigned long val)
>> +{
>> +	switch (addr & 0x0c) {
>> +	case GIC_DIST_CTRL:
>> +		if (!(addr & 1)) {
> 
> what is this !(addr & 1) check?

Mmmh, interesting. The original idea was that we care only about the
lowest significant byte. I guess this was somehow lost in translation
when Marc reworked the function. I think it should at least read:
"if (!(addr & 3))" to match the switch mask, otherwise for instance a
byte write to address 2 triggers the if branch as well.

I will fix the mask to 3 and add a comment.

Thanks,
Andre.


> 
>> +			struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>> +			bool was_enabled = dist->enabled;
>> +
>> +			dist->enabled = val & GICD_ENABLE;
>> +			if (!was_enabled && dist->enabled)
>> +				vgic_kick_vcpus(vcpu->kvm);
>> +		}
>> +		break;
>> +	case GIC_DIST_CTR:
>> +	case GIC_DIST_IIDR:
>> +		/* Nothing to do */
>> +		return;
>> +	}
>> +}
>> +
>>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 12),
>> +		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index c3dbcf3..5355de6 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
>> @@ -544,3 +544,18 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
>>  
>>  	return pending;
>>  }
>> +
>> +void vgic_kick_vcpus(struct kvm *kvm)
>> +{
>> +	struct kvm_vcpu *vcpu;
>> +	int c;
>> +
>> +	/*
>> +	 * We've injected an interrupt, time to find out who deserves
>> +	 * a good kick...
>> +	 */
>> +	kvm_for_each_vcpu(c, vcpu, kvm) {
>> +		if (kvm_vgic_vcpu_pending_irq(vcpu))
>> +			kvm_vcpu_kick(vcpu);
>> +	}
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index fd9acaa..cf62015 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -16,11 +16,15 @@
>>  #ifndef __KVM_ARM_VGIC_NEW_H__
>>  #define __KVM_ARM_VGIC_NEW_H__
>>  
>> +#define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
>> +#define IMPLEMENTER_ARM		0x43b
>> +
>>  #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
>>  
>>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>  			      u32 intid);
>>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
>> +void vgic_kick_vcpus(struct kvm *kvm);
>>  
>>  void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>>  void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>> -- 
>> 2.7.3
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe kvm" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

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

* Re: [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
  2016-05-11 12:05     ` Christoffer Dall
@ 2016-05-11 12:51       ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-11 12:51 UTC (permalink / raw)
  To: Christoffer Dall, Andre Przywara
  Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

On 11/05/16 13:05, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:36AM +0100, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Those three registers are v2 emulation specific, so their implementation
>> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
>> as their implementation is pretty simple.
>> When the guest enables the distributor, we kick all VCPUs to get
>> potentially pending interrupts serviced.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - kick VCPUs is the distributor gets enabled
>> - improve comment
>>
>> Changelog v1 .. v2:
>> - adapt to new MMIO framework
>> - use switch() statements to improve readability
>>
>> Changelog v2 .. v3:
>> - add vgic_kick_vcpus() implementation
>>
>>  include/linux/irqchip/arm-gic.h  |  1 +
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
>>  virt/kvm/arm/vgic/vgic.c         | 15 +++++++++++++
>>  virt/kvm/arm/vgic/vgic.h         |  4 ++++
>>  4 files changed, 67 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>> index be0d26f..fd05185 100644
>> --- a/include/linux/irqchip/arm-gic.h
>> +++ b/include/linux/irqchip/arm-gic.h
>> @@ -33,6 +33,7 @@
>>  
>>  #define GIC_DIST_CTRL			0x000
>>  #define GIC_DIST_CTR			0x004
>> +#define GIC_DIST_IIDR			0x008
>>  #define GIC_DIST_IGROUP			0x080
>>  #define GIC_DIST_ENABLE_SET		0x100
>>  #define GIC_DIST_ENABLE_CLEAR		0x180
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index 2729a22..69e96f7 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -20,9 +20,55 @@
>>  #include "vgic.h"
>>  #include "vgic-mmio.h"
>>  
>> +static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
>> +					    gpa_t addr, unsigned int len)
>> +{
>> +	u32 value;
>> +
>> +	switch (addr & 0x0c) {
>> +	case GIC_DIST_CTRL:
>> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
>> +		break;
>> +	case GIC_DIST_CTR:
>> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +		value = (value >> 5) - 1;
>> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
>> +		break;
>> +	case GIC_DIST_IIDR:
>> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
>> +		break;
>> +	default:
>> +		return 0;
>> +	}
>> +
>> +	return extract_bytes(value, addr & 3, len);
>> +}
>> +
>> +static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>> +				    gpa_t addr, unsigned int len,
>> +				    unsigned long val)
>> +{
>> +	switch (addr & 0x0c) {
>> +	case GIC_DIST_CTRL:
>> +		if (!(addr & 1)) {
> 
> what is this !(addr & 1) check?

We check that the write includes the lowest byte of the register. But as
we only have aligned accesses, it probably doesn't matter... I'll hack
that away.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
@ 2016-05-11 12:51       ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-11 12:51 UTC (permalink / raw)
  To: linux-arm-kernel

On 11/05/16 13:05, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:36AM +0100, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Those three registers are v2 emulation specific, so their implementation
>> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
>> as their implementation is pretty simple.
>> When the guest enables the distributor, we kick all VCPUs to get
>> potentially pending interrupts serviced.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - kick VCPUs is the distributor gets enabled
>> - improve comment
>>
>> Changelog v1 .. v2:
>> - adapt to new MMIO framework
>> - use switch() statements to improve readability
>>
>> Changelog v2 .. v3:
>> - add vgic_kick_vcpus() implementation
>>
>>  include/linux/irqchip/arm-gic.h  |  1 +
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
>>  virt/kvm/arm/vgic/vgic.c         | 15 +++++++++++++
>>  virt/kvm/arm/vgic/vgic.h         |  4 ++++
>>  4 files changed, 67 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>> index be0d26f..fd05185 100644
>> --- a/include/linux/irqchip/arm-gic.h
>> +++ b/include/linux/irqchip/arm-gic.h
>> @@ -33,6 +33,7 @@
>>  
>>  #define GIC_DIST_CTRL			0x000
>>  #define GIC_DIST_CTR			0x004
>> +#define GIC_DIST_IIDR			0x008
>>  #define GIC_DIST_IGROUP			0x080
>>  #define GIC_DIST_ENABLE_SET		0x100
>>  #define GIC_DIST_ENABLE_CLEAR		0x180
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index 2729a22..69e96f7 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -20,9 +20,55 @@
>>  #include "vgic.h"
>>  #include "vgic-mmio.h"
>>  
>> +static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
>> +					    gpa_t addr, unsigned int len)
>> +{
>> +	u32 value;
>> +
>> +	switch (addr & 0x0c) {
>> +	case GIC_DIST_CTRL:
>> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
>> +		break;
>> +	case GIC_DIST_CTR:
>> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +		value = (value >> 5) - 1;
>> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
>> +		break;
>> +	case GIC_DIST_IIDR:
>> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
>> +		break;
>> +	default:
>> +		return 0;
>> +	}
>> +
>> +	return extract_bytes(value, addr & 3, len);
>> +}
>> +
>> +static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>> +				    gpa_t addr, unsigned int len,
>> +				    unsigned long val)
>> +{
>> +	switch (addr & 0x0c) {
>> +	case GIC_DIST_CTRL:
>> +		if (!(addr & 1)) {
> 
> what is this !(addr & 1) check?

We check that the write includes the lowest byte of the register. But as
we only have aligned accesses, it probably doesn't matter... I'll hack
that away.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  2016-05-11 12:34     ` Christoffer Dall
@ 2016-05-11 13:04       ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 13:04 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 11/05/16 13:34, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
>> As the enable register handlers are shared between the v2 and v3
>> emulation, their implementation goes into vgic-mmio.c, to be easily
>> referenced from the v3 emulation as well later.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - use lower bits of address to determine IRQ number
>> - remove TODO, confirmed to be fine
>>
>> Changelog v1 .. v2:
>> - adapt to new MMIO framework
>>
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
>>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
>>  3 files changed, 69 insertions(+), 2 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index 69e96f7..448d1da 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>> index 41cf4f4..077ae86 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>>  	/* Ignore */
>>  }
>>  
>> +/*
>> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
>> + * of the enabled bit, so there is only one function for both here.
>> + */
>> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
>> +				    gpa_t addr, unsigned int len)
>> +{
>> +	u32 intid = (addr & 0x7f) * 8;
> 
> is there anything we can do about this to make it more intuitive?  A
> macro to generate the mask/offset based on bits per interrupt or
> something?

Yes, something where you give it the address and the bits-per-IRQ and it
tells you the IRQ number.
Not sure it is advisable to squash this into v4 still?

> 
>> +	u32 value = 0;
>> +	int i;
>> +
>> +	/* Loop over all IRQs affected by this read */
>> +	for (i = 0; i < len * 8; i++) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		if (irq->enabled)
>> +			value |= (1U << i);
> 
> I couldn't find the code anywhere that enforces word-aligned accesses to
> these registers.  Do we have that?

Not that I am aware of. I was suggesting this since we have one in the
IROUTER function. Architecturally we don't need to support halfword
accesses, it's: byte + word, word only or double-word + word, depending
on the actual register, IIRC.
As a fix we can at least deny (read: ignore) halfword accesses in
general in the dispatcher. Shall I do this (two two-liners)?
I think byte and word accesses are safe with the existing handlers last
time I checked.

> If that's not the case, doesn't this break of you do a non-word aligned
> access?

Why would it? vgic_data_host_to_mmio_bus and extract_bytes should cover
this, shouldn't they?

Cheers,
Andre.

> 
>> +	}
>> +
>> +	return extract_bytes(value, addr & 3, len);
>> +}
>> +
>> +void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
>> +			     gpa_t addr, unsigned int len,
>> +			     unsigned long val)
>> +{
>> +	u32 intid = (addr & 0x7f) * 8;
>> +	int i;
>> +
>> +	for_each_set_bit(i, &val, len * 8) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +		irq->enabled = true;
>> +		vgic_queue_irq_unlock(vcpu->kvm, irq);
>> +	}
>> +}
>> +
>> +void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
>> +			     gpa_t addr, unsigned int len,
>> +			     unsigned long val)
>> +{
>> +	u32 intid = (addr & 0x7f) * 8;
>> +	int i;
>> +
>> +	for_each_set_bit(i, &val, len * 8) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		irq->enabled = false;
>> +
>> +		spin_unlock(&irq->irq_lock);
> 
> nit: whitespace consistency with senable
> 
>> +	}
>> +}
>> +
>>  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 4f4dd2b..188909a 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.h
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
>> @@ -74,6 +74,17 @@ unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
>>  void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>>  			unsigned int len, unsigned long val);
>>  
>> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
>> +				    gpa_t addr, unsigned int len);
>> +
>> +void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
>> +			     gpa_t addr, unsigned int len,
>> +			     unsigned long val);
>> +
>> +void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
>> +			     gpa_t addr, unsigned int len,
>> +			     unsigned long val);
>> +
>>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>>  
>>  #endif
>> -- 
>> 2.7.3
>>
> 

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

* [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
@ 2016-05-11 13:04       ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 13:04 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 11/05/16 13:34, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
>> As the enable register handlers are shared between the v2 and v3
>> emulation, their implementation goes into vgic-mmio.c, to be easily
>> referenced from the v3 emulation as well later.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - use lower bits of address to determine IRQ number
>> - remove TODO, confirmed to be fine
>>
>> Changelog v1 .. v2:
>> - adapt to new MMIO framework
>>
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
>>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
>>  3 files changed, 69 insertions(+), 2 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index 69e96f7..448d1da 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>> index 41cf4f4..077ae86 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>>  	/* Ignore */
>>  }
>>  
>> +/*
>> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
>> + * of the enabled bit, so there is only one function for both here.
>> + */
>> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
>> +				    gpa_t addr, unsigned int len)
>> +{
>> +	u32 intid = (addr & 0x7f) * 8;
> 
> is there anything we can do about this to make it more intuitive?  A
> macro to generate the mask/offset based on bits per interrupt or
> something?

Yes, something where you give it the address and the bits-per-IRQ and it
tells you the IRQ number.
Not sure it is advisable to squash this into v4 still?

> 
>> +	u32 value = 0;
>> +	int i;
>> +
>> +	/* Loop over all IRQs affected by this read */
>> +	for (i = 0; i < len * 8; i++) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		if (irq->enabled)
>> +			value |= (1U << i);
> 
> I couldn't find the code anywhere that enforces word-aligned accesses to
> these registers.  Do we have that?

Not that I am aware of. I was suggesting this since we have one in the
IROUTER function. Architecturally we don't need to support halfword
accesses, it's: byte + word, word only or double-word + word, depending
on the actual register, IIRC.
As a fix we can at least deny (read: ignore) halfword accesses in
general in the dispatcher. Shall I do this (two two-liners)?
I think byte and word accesses are safe with the existing handlers last
time I checked.

> If that's not the case, doesn't this break of you do a non-word aligned
> access?

Why would it? vgic_data_host_to_mmio_bus and extract_bytes should cover
this, shouldn't they?

Cheers,
Andre.

> 
>> +	}
>> +
>> +	return extract_bytes(value, addr & 3, len);
>> +}
>> +
>> +void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
>> +			     gpa_t addr, unsigned int len,
>> +			     unsigned long val)
>> +{
>> +	u32 intid = (addr & 0x7f) * 8;
>> +	int i;
>> +
>> +	for_each_set_bit(i, &val, len * 8) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +		irq->enabled = true;
>> +		vgic_queue_irq_unlock(vcpu->kvm, irq);
>> +	}
>> +}
>> +
>> +void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
>> +			     gpa_t addr, unsigned int len,
>> +			     unsigned long val)
>> +{
>> +	u32 intid = (addr & 0x7f) * 8;
>> +	int i;
>> +
>> +	for_each_set_bit(i, &val, len * 8) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		irq->enabled = false;
>> +
>> +		spin_unlock(&irq->irq_lock);
> 
> nit: whitespace consistency with senable
> 
>> +	}
>> +}
>> +
>>  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 4f4dd2b..188909a 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.h
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
>> @@ -74,6 +74,17 @@ unsigned long vgic_mmio_read_rao(struct kvm_vcpu *vcpu,
>>  void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>>  			unsigned int len, unsigned long val);
>>  
>> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
>> +				    gpa_t addr, unsigned int len);
>> +
>> +void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
>> +			     gpa_t addr, unsigned int len,
>> +			     unsigned long val);
>> +
>> +void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
>> +			     gpa_t addr, unsigned int len,
>> +			     unsigned long val);
>> +
>>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>>  
>>  #endif
>> -- 
>> 2.7.3
>>
> 

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

* Re: [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
  2016-05-11 11:38         ` Eric Auger
@ 2016-05-11 13:09           ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 13:09 UTC (permalink / raw)
  To: Eric Auger, Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Hi,

On 11/05/16 12:38, Eric Auger wrote:
> On 05/11/2016 01:30 PM, Andre Przywara wrote:
>> Hi,
>>
>> On 10/05/16 15:10, Eric Auger wrote:
>>> On 05/06/2016 12:45 PM, Andre Przywara wrote:
>>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>>
>>>> Processing maintenance interrupts and accessing the list registers
>>>> are dependent on the host's GIC version.
>>>> Introduce vgic-v2.c to contain GICv2 specific functions.
>>>> Implement the GICv2 specific code for syncing the emulation state
>>>> into the VGIC registers.
>>>>
>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>> Changelog RFC..v1:
>>>> - remove explicit LR_STATE clearing on maintenance interrupt handling
>>>> - improve documentation for vgic_v2_populate_lr()
>>>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
>>>> - simplify multi-CPU source SGI handling
>>>>
>>>> Changelog v1 .. v2:
>>>> - inject the IRQ priority into the list register
>>>>
>>>> Changelog v2 .. v3:
>>>> - cleanup diff containing rebase artifacts
>>>>
>>>>  include/linux/irqchip/arm-gic.h |   1 +
>>>>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>>>>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>>>>  4 files changed, 191 insertions(+)
>>>>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>>>>
>>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>>>> index 9c94026..be0d26f 100644
>>>> --- a/include/linux/irqchip/arm-gic.h
>>>> +++ b/include/linux/irqchip/arm-gic.h
>>>> @@ -76,6 +76,7 @@
>>>>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>>>>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>>>>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
>>>> +#define GICH_LR_PRIORITY_SHIFT		23
>>>>  #define GICH_LR_STATE			(3 << 28)
>>>>  #define GICH_LR_PENDING_BIT		(1 << 28)
>>>>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
>>>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>>>> new file mode 100644
>>>> index 0000000..4cee616
>>>> --- /dev/null
>>>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>>>> @@ -0,0 +1,178 @@
>>>> +/*
>>>> + * Copyright (C) 2015, 2016 ARM Ltd.
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify
>>>> + * it under the terms of the GNU General Public License version 2 as
>>>> + * published by the Free Software Foundation.
>>>> + *
>>>> + * This program is distributed in the hope that it will be useful,
>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>> + * GNU General Public License for more details.
>>>> + *
>>>> + * You should have received a copy of the GNU General Public License
>>>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>>> + */
>>>> +
>>>> +#include <linux/irqchip/arm-gic.h>
>>>> +#include <linux/kvm.h>
>>>> +#include <linux/kvm_host.h>
>>>> +
>>>> +#include "vgic.h"
>>>> +
>>>> +/*
>>>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>>>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>>>> + *
>>>> + * Warning: Calling this function may modify *val.
>>>> + */
>>>> +static unsigned long *u64_to_bitmask(u64 *val)
>>>> +{
>>>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>>>> +	*val = (*val >> 32) | (*val << 32);
>>>> +#endif
>>>> +	return (unsigned long *)val;
>>>> +}
>>>> +
>>>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>>> +
>>>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>>>> +		u64 eisr = cpuif->vgic_eisr;
>>>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>>>> +		int lr;
>>>> +
>>>> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
>>> Didn't we say we could use vcpu->arch.vgic_cpu.used_lrs here?
>>
>> Why would that be useful? Don't we just want to see those LRs that had a
>> maintenance interrupt received? I don't see the point if iterating over
>> the used LRs, where we need to check for this condition somehow manually?
>> Or what am I missing here?
> 
> Well I thought that there is no use inspecting bits corresponding to
> unused LRs, no?

Mmh, maybe I got something wrong here, but this bitmap is supposedly
having only one bit set most of the time, also it points us to every LR
that we need to take care of. So it will never set bits for unused LRs.
By iterating over every used LR on the other hand we would touch LRs
that don't need servicing in this function, also the WARN_ON had to go
then (as we may touch EOIed IRQs).

Do you agree?

Cheers,
Andre.

> 
> Cheers
> 
> Eric
>>
>>>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
>>>> +
>>>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
>>>> +
>>>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>>>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>>>> +
>>>> +			cpuif->vgic_elrsr |= 1ULL << lr;
>>
>> So are we good with removing this line (and the respective one in v3)?
>>
>> Cheers,
>> Andre.
>>
>>>> +		}
>>>> +	}
>>>> +
>>>> +	/* check and disable underflow maintenance IRQ */
>>> check?
>>>
>>> Besides
>>> Reviewed-by: Eric Auger <eric.auger@linaro.org>
>>>
>>> Eric
>>>> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
>>>> +
>>>> +	/*
>>>> +	 * In the next iterations of the vcpu loop, if we sync the
>>>> +	 * vgic state after flushing it, but before entering the guest
>>>> +	 * (this happens for pending signals and vmid rollovers), then
>>>> +	 * make sure we don't pick up any old maintenance interrupts
>>>> +	 * here.
>>>> +	 */
>>>> +	cpuif->vgic_eisr = 0;
>>>> +}
>>>> +
>>>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>>> +
>>>> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
>>>> +}
>>>> +
>>>> +/*
>>>> + * transfer the content of the LRs back into the corresponding ap_list:
>>>> + * - active bit is transferred as is
>>>> + * - pending bit is
>>>> + *   - transferred as is in case of edge sensitive IRQs
>>>> + *   - set to the line-level (resample time) for level sensitive IRQs
>>>> + */
>>>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>>> +	int lr;
>>>> +
>>>> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
>>>> +		u32 val = cpuif->vgic_lr[lr];
>>>> +		u32 intid = val & GICH_LR_VIRTUALID;
>>>> +		struct vgic_irq *irq;
>>>> +
>>>> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>>>> +
>>>> +		spin_lock(&irq->irq_lock);
>>>> +
>>>> +		/* Always preserve the active bit */
>>>> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
>>>> +
>>>> +		/* Edge is the only case where we preserve the pending bit */
>>>> +		if (irq->config == VGIC_CONFIG_EDGE &&
>>>> +		    (val & GICH_LR_PENDING_BIT)) {
>>>> +			irq->pending = true;
>>>> +
>>>> +			if (vgic_irq_is_sgi(intid)) {
>>>> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
>>>> +
>>>> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
>>>> +				irq->source |= (1 << cpuid);
>>>> +			}
>>>> +		}
>>>> +
>>>> +		/* Clear soft pending state when level IRQs have been acked */
>>>> +		if (irq->config == VGIC_CONFIG_LEVEL &&
>>>> +		    !(val & GICH_LR_PENDING_BIT)) {
>>>> +			irq->soft_pending = false;
>>>> +			irq->pending = irq->line_level;
>>>> +		}
>>>> +
>>>> +		spin_unlock(&irq->irq_lock);
>>>> +	}
>>>> +}
>>>> +
>>>> +/*
>>>> + * Populates the particular LR with the state of a given IRQ:
>>>> + * - for an edge sensitive IRQ the pending state is cleared in struct vgic_irq
>>>> + * - for a level sensitive IRQ the pending state value is unchanged;
>>>> + *   it is dictated directly by the input level
>>>> + *
>>>> + * If @irq describes an SGI with multiple sources, we choose the
>>>> + * lowest-numbered source VCPU and clear that bit in the source bitmap.
>>>> + *
>>>> + * The irq_lock must be held by the caller.
>>>> + */
>>>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
>>>> +{
>>>> +	u32 val = irq->intid;
>>>> +
>>>> +	if (irq->pending) {
>>>> +		val |= GICH_LR_PENDING_BIT;
>>>> +
>>>> +		if (irq->config == VGIC_CONFIG_EDGE)
>>>> +			irq->pending = false;
>>>> +
>>>> +		if (vgic_irq_is_sgi(irq->intid)) {
>>>> +			u32 src = ffs(irq->source);
>>>> +
>>>> +			BUG_ON(!src);
>>>> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
>>>> +			irq->source &= ~(1 << (src - 1));
>>>> +			if (irq->source)
>>>> +				irq->pending = true;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	if (irq->active)
>>>> +		val |= GICH_LR_ACTIVE_BIT;
>>>> +
>>>> +	if (irq->hw) {
>>>> +		val |= GICH_LR_HW;
>>>> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
>>>> +	} else {
>>>> +		if (irq->config == VGIC_CONFIG_LEVEL)
>>>> +			val |= GICH_LR_EOI;
>>>> +	}
>>>> +
>>>> +	/* The GICv2 LR only holds five bits of priority. */
>>>> +	val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
>>>> +
>>>> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
>>>> +}
>>>> +
>>>> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
>>>> +{
>>>> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
>>>> +}
>>>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>>>> index c6f8b9b..68d885c 100644
>>>> --- a/virt/kvm/arm/vgic/vgic.c
>>>> +++ b/virt/kvm/arm/vgic/vgic.c
>>>> @@ -397,10 +397,12 @@ retry:
>>>>  
>>>>  static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>>>>  {
>>>> +	vgic_v2_process_maintenance(vcpu);
>>>>  }
>>>>  
>>>>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>>>>  {
>>>> +	vgic_v2_fold_lr_state(vcpu);
>>>>  }
>>>>  
>>>>  /* Requires the ap_list_lock and the irq_lock to be held. */
>>>> @@ -409,14 +411,18 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>>>>  {
>>>>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
>>>>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
>>>> +
>>>> +	vgic_v2_populate_lr(vcpu, irq, lr);
>>>>  }
>>>>  
>>>>  static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
>>>>  {
>>>> +	vgic_v2_clear_lr(vcpu, lr);
>>>>  }
>>>>  
>>>>  static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>>>>  {
>>>> +	vgic_v2_set_underflow(vcpu);
>>>>  }
>>>>  
>>>>  static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
>>>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>>>> index 29b96b9..0db490e 100644
>>>> --- a/virt/kvm/arm/vgic/vgic.h
>>>> +++ b/virt/kvm/arm/vgic/vgic.h
>>>> @@ -22,4 +22,10 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>>>  			      u32 intid);
>>>>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
>>>>  
>>>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>>>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>>>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>>>> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
>>>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>>>> +
>>>>  #endif
>>>>
>>>
> 

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

* [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
@ 2016-05-11 13:09           ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 13:09 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 11/05/16 12:38, Eric Auger wrote:
> On 05/11/2016 01:30 PM, Andre Przywara wrote:
>> Hi,
>>
>> On 10/05/16 15:10, Eric Auger wrote:
>>> On 05/06/2016 12:45 PM, Andre Przywara wrote:
>>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>>
>>>> Processing maintenance interrupts and accessing the list registers
>>>> are dependent on the host's GIC version.
>>>> Introduce vgic-v2.c to contain GICv2 specific functions.
>>>> Implement the GICv2 specific code for syncing the emulation state
>>>> into the VGIC registers.
>>>>
>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>> Changelog RFC..v1:
>>>> - remove explicit LR_STATE clearing on maintenance interrupt handling
>>>> - improve documentation for vgic_v2_populate_lr()
>>>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
>>>> - simplify multi-CPU source SGI handling
>>>>
>>>> Changelog v1 .. v2:
>>>> - inject the IRQ priority into the list register
>>>>
>>>> Changelog v2 .. v3:
>>>> - cleanup diff containing rebase artifacts
>>>>
>>>>  include/linux/irqchip/arm-gic.h |   1 +
>>>>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>>>>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>>>>  4 files changed, 191 insertions(+)
>>>>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>>>>
>>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>>>> index 9c94026..be0d26f 100644
>>>> --- a/include/linux/irqchip/arm-gic.h
>>>> +++ b/include/linux/irqchip/arm-gic.h
>>>> @@ -76,6 +76,7 @@
>>>>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>>>>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>>>>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
>>>> +#define GICH_LR_PRIORITY_SHIFT		23
>>>>  #define GICH_LR_STATE			(3 << 28)
>>>>  #define GICH_LR_PENDING_BIT		(1 << 28)
>>>>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
>>>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>>>> new file mode 100644
>>>> index 0000000..4cee616
>>>> --- /dev/null
>>>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>>>> @@ -0,0 +1,178 @@
>>>> +/*
>>>> + * Copyright (C) 2015, 2016 ARM Ltd.
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify
>>>> + * it under the terms of the GNU General Public License version 2 as
>>>> + * published by the Free Software Foundation.
>>>> + *
>>>> + * This program is distributed in the hope that it will be useful,
>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>> + * GNU General Public License for more details.
>>>> + *
>>>> + * You should have received a copy of the GNU General Public License
>>>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>>> + */
>>>> +
>>>> +#include <linux/irqchip/arm-gic.h>
>>>> +#include <linux/kvm.h>
>>>> +#include <linux/kvm_host.h>
>>>> +
>>>> +#include "vgic.h"
>>>> +
>>>> +/*
>>>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>>>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>>>> + *
>>>> + * Warning: Calling this function may modify *val.
>>>> + */
>>>> +static unsigned long *u64_to_bitmask(u64 *val)
>>>> +{
>>>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>>>> +	*val = (*val >> 32) | (*val << 32);
>>>> +#endif
>>>> +	return (unsigned long *)val;
>>>> +}
>>>> +
>>>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>>> +
>>>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>>>> +		u64 eisr = cpuif->vgic_eisr;
>>>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>>>> +		int lr;
>>>> +
>>>> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
>>> Didn't we say we could use vcpu->arch.vgic_cpu.used_lrs here?
>>
>> Why would that be useful? Don't we just want to see those LRs that had a
>> maintenance interrupt received? I don't see the point if iterating over
>> the used LRs, where we need to check for this condition somehow manually?
>> Or what am I missing here?
> 
> Well I thought that there is no use inspecting bits corresponding to
> unused LRs, no?

Mmh, maybe I got something wrong here, but this bitmap is supposedly
having only one bit set most of the time, also it points us to every LR
that we need to take care of. So it will never set bits for unused LRs.
By iterating over every used LR on the other hand we would touch LRs
that don't need servicing in this function, also the WARN_ON had to go
then (as we may touch EOIed IRQs).

Do you agree?

Cheers,
Andre.

> 
> Cheers
> 
> Eric
>>
>>>> +			u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
>>>> +
>>>> +			WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
>>>> +
>>>> +			kvm_notify_acked_irq(vcpu->kvm, 0,
>>>> +					     intid - VGIC_NR_PRIVATE_IRQS);
>>>> +
>>>> +			cpuif->vgic_elrsr |= 1ULL << lr;
>>
>> So are we good with removing this line (and the respective one in v3)?
>>
>> Cheers,
>> Andre.
>>
>>>> +		}
>>>> +	}
>>>> +
>>>> +	/* check and disable underflow maintenance IRQ */
>>> check?
>>>
>>> Besides
>>> Reviewed-by: Eric Auger <eric.auger@linaro.org>
>>>
>>> Eric
>>>> +	cpuif->vgic_hcr &= ~GICH_HCR_UIE;
>>>> +
>>>> +	/*
>>>> +	 * In the next iterations of the vcpu loop, if we sync the
>>>> +	 * vgic state after flushing it, but before entering the guest
>>>> +	 * (this happens for pending signals and vmid rollovers), then
>>>> +	 * make sure we don't pick up any old maintenance interrupts
>>>> +	 * here.
>>>> +	 */
>>>> +	cpuif->vgic_eisr = 0;
>>>> +}
>>>> +
>>>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>>> +
>>>> +	cpuif->vgic_hcr |= GICH_HCR_UIE;
>>>> +}
>>>> +
>>>> +/*
>>>> + * transfer the content of the LRs back into the corresponding ap_list:
>>>> + * - active bit is transferred as is
>>>> + * - pending bit is
>>>> + *   - transferred as is in case of edge sensitive IRQs
>>>> + *   - set to the line-level (resample time) for level sensitive IRQs
>>>> + */
>>>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>>> +	int lr;
>>>> +
>>>> +	for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
>>>> +		u32 val = cpuif->vgic_lr[lr];
>>>> +		u32 intid = val & GICH_LR_VIRTUALID;
>>>> +		struct vgic_irq *irq;
>>>> +
>>>> +		irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
>>>> +
>>>> +		spin_lock(&irq->irq_lock);
>>>> +
>>>> +		/* Always preserve the active bit */
>>>> +		irq->active = !!(val & GICH_LR_ACTIVE_BIT);
>>>> +
>>>> +		/* Edge is the only case where we preserve the pending bit */
>>>> +		if (irq->config == VGIC_CONFIG_EDGE &&
>>>> +		    (val & GICH_LR_PENDING_BIT)) {
>>>> +			irq->pending = true;
>>>> +
>>>> +			if (vgic_irq_is_sgi(intid)) {
>>>> +				u32 cpuid = val & GICH_LR_PHYSID_CPUID;
>>>> +
>>>> +				cpuid >>= GICH_LR_PHYSID_CPUID_SHIFT;
>>>> +				irq->source |= (1 << cpuid);
>>>> +			}
>>>> +		}
>>>> +
>>>> +		/* Clear soft pending state when level IRQs have been acked */
>>>> +		if (irq->config == VGIC_CONFIG_LEVEL &&
>>>> +		    !(val & GICH_LR_PENDING_BIT)) {
>>>> +			irq->soft_pending = false;
>>>> +			irq->pending = irq->line_level;
>>>> +		}
>>>> +
>>>> +		spin_unlock(&irq->irq_lock);
>>>> +	}
>>>> +}
>>>> +
>>>> +/*
>>>> + * Populates the particular LR with the state of a given IRQ:
>>>> + * - for an edge sensitive IRQ the pending state is cleared in struct vgic_irq
>>>> + * - for a level sensitive IRQ the pending state value is unchanged;
>>>> + *   it is dictated directly by the input level
>>>> + *
>>>> + * If @irq describes an SGI with multiple sources, we choose the
>>>> + * lowest-numbered source VCPU and clear that bit in the source bitmap.
>>>> + *
>>>> + * The irq_lock must be held by the caller.
>>>> + */
>>>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
>>>> +{
>>>> +	u32 val = irq->intid;
>>>> +
>>>> +	if (irq->pending) {
>>>> +		val |= GICH_LR_PENDING_BIT;
>>>> +
>>>> +		if (irq->config == VGIC_CONFIG_EDGE)
>>>> +			irq->pending = false;
>>>> +
>>>> +		if (vgic_irq_is_sgi(irq->intid)) {
>>>> +			u32 src = ffs(irq->source);
>>>> +
>>>> +			BUG_ON(!src);
>>>> +			val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
>>>> +			irq->source &= ~(1 << (src - 1));
>>>> +			if (irq->source)
>>>> +				irq->pending = true;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	if (irq->active)
>>>> +		val |= GICH_LR_ACTIVE_BIT;
>>>> +
>>>> +	if (irq->hw) {
>>>> +		val |= GICH_LR_HW;
>>>> +		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
>>>> +	} else {
>>>> +		if (irq->config == VGIC_CONFIG_LEVEL)
>>>> +			val |= GICH_LR_EOI;
>>>> +	}
>>>> +
>>>> +	/* The GICv2 LR only holds five bits of priority. */
>>>> +	val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
>>>> +
>>>> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
>>>> +}
>>>> +
>>>> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
>>>> +{
>>>> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
>>>> +}
>>>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>>>> index c6f8b9b..68d885c 100644
>>>> --- a/virt/kvm/arm/vgic/vgic.c
>>>> +++ b/virt/kvm/arm/vgic/vgic.c
>>>> @@ -397,10 +397,12 @@ retry:
>>>>  
>>>>  static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
>>>>  {
>>>> +	vgic_v2_process_maintenance(vcpu);
>>>>  }
>>>>  
>>>>  static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
>>>>  {
>>>> +	vgic_v2_fold_lr_state(vcpu);
>>>>  }
>>>>  
>>>>  /* Requires the ap_list_lock and the irq_lock to be held. */
>>>> @@ -409,14 +411,18 @@ static inline void vgic_populate_lr(struct kvm_vcpu *vcpu,
>>>>  {
>>>>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vcpu->arch.vgic_cpu.ap_list_lock));
>>>>  	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&irq->irq_lock));
>>>> +
>>>> +	vgic_v2_populate_lr(vcpu, irq, lr);
>>>>  }
>>>>  
>>>>  static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr)
>>>>  {
>>>> +	vgic_v2_clear_lr(vcpu, lr);
>>>>  }
>>>>  
>>>>  static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
>>>>  {
>>>> +	vgic_v2_set_underflow(vcpu);
>>>>  }
>>>>  
>>>>  static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
>>>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>>>> index 29b96b9..0db490e 100644
>>>> --- a/virt/kvm/arm/vgic/vgic.h
>>>> +++ b/virt/kvm/arm/vgic/vgic.h
>>>> @@ -22,4 +22,10 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>>>>  			      u32 intid);
>>>>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
>>>>  
>>>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
>>>> +void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>>>> +void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>>>> +void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
>>>> +void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>>>> +
>>>>  #endif
>>>>
>>>
> 

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

* Re: [PATCH v3 25/55] KVM: arm/arm64: vgic-new: Add PENDING registers handlers
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-11 13:11     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 13:11 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 06, 2016 at 11:45:38AM +0100, Andre Przywara wrote:
> The pending register handlers are shared between the v2 and v3
> emulation, so their implementation goes into vgic-mmio.c, to be easily
> referenced from the v3 emulation as well later.
> For level triggered interrupts the real line level is unaffected by
> this write, so we keep this state separate and combine it with the
> device's level to get the actual pending state.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - remove IRQ lock from read handler
> - remove TODO from clear pending handler
> 
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
>  virt/kvm/arm/vgic/vgic-mmio.c    | 60 ++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h    | 12 ++++++++
>  3 files changed, 74 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 448d1da..4b87e0a 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -76,9 +76,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>  		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index 077ae86..4df1af7 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -102,6 +102,66 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
>  	}
>  }
>  
> +unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
> +				     gpa_t addr, unsigned int len)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	u32 value = 0;
> +	int i;
> +
> +	/* Loop over all IRQs affected by this read */
> +	for (i = 0; i < len * 8; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (irq->pending)
> +			value |= (1U << i);

same question as on the previous patch

> +	}
> +
> +	return extract_bytes(value, addr & 3, len);
> +}
> +
> +void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
> +			      gpa_t addr, unsigned int len,
> +			      unsigned long val)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	int i;
> +
> +	for_each_set_bit(i, &val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->pending = true;
> +		if (irq->config == VGIC_CONFIG_LEVEL)
> +			irq->soft_pending = true;
> +
> +		vgic_queue_irq_unlock(vcpu->kvm, irq);
> +	}
> +}
> +
> +void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
> +			      gpa_t addr, unsigned int len,
> +			      unsigned long val)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	int i;
> +
> +	for_each_set_bit(i, &val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		if (irq->config == VGIC_CONFIG_LEVEL) {
> +			irq->soft_pending = false;
> +			irq->pending = irq->line_level;
> +		} else {
> +			irq->pending = false;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
>  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 188909a..d4fc029 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -85,6 +85,18 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
>  			     gpa_t addr, unsigned int len,
>  			     unsigned long val);
>  
> +unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
> +				     gpa_t addr, unsigned int len);
> +
> +void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
> +			      gpa_t addr, unsigned int len,
> +			      unsigned long val);
> +
> +void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
> +			      gpa_t addr, unsigned int len,
> +			      unsigned long val);
> +
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
>  #endif
> -- 
> 2.7.3
> 

Otherwise this looks good.

Thanks,
-Christoffer

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

* [PATCH v3 25/55] KVM: arm/arm64: vgic-new: Add PENDING registers handlers
@ 2016-05-11 13:11     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 13:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:38AM +0100, Andre Przywara wrote:
> The pending register handlers are shared between the v2 and v3
> emulation, so their implementation goes into vgic-mmio.c, to be easily
> referenced from the v3 emulation as well later.
> For level triggered interrupts the real line level is unaffected by
> this write, so we keep this state separate and combine it with the
> device's level to get the actual pending state.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - remove IRQ lock from read handler
> - remove TODO from clear pending handler
> 
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
>  virt/kvm/arm/vgic/vgic-mmio.c    | 60 ++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h    | 12 ++++++++
>  3 files changed, 74 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 448d1da..4b87e0a 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -76,9 +76,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>  		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index 077ae86..4df1af7 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -102,6 +102,66 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
>  	}
>  }
>  
> +unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
> +				     gpa_t addr, unsigned int len)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	u32 value = 0;
> +	int i;
> +
> +	/* Loop over all IRQs affected by this read */
> +	for (i = 0; i < len * 8; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (irq->pending)
> +			value |= (1U << i);

same question as on the previous patch

> +	}
> +
> +	return extract_bytes(value, addr & 3, len);
> +}
> +
> +void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
> +			      gpa_t addr, unsigned int len,
> +			      unsigned long val)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	int i;
> +
> +	for_each_set_bit(i, &val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->pending = true;
> +		if (irq->config == VGIC_CONFIG_LEVEL)
> +			irq->soft_pending = true;
> +
> +		vgic_queue_irq_unlock(vcpu->kvm, irq);
> +	}
> +}
> +
> +void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
> +			      gpa_t addr, unsigned int len,
> +			      unsigned long val)
> +{
> +	u32 intid = (addr & 0x7f) * 8;
> +	int i;
> +
> +	for_each_set_bit(i, &val, len * 8) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		if (irq->config == VGIC_CONFIG_LEVEL) {
> +			irq->soft_pending = false;
> +			irq->pending = irq->line_level;
> +		} else {
> +			irq->pending = false;
> +		}
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
>  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 188909a..d4fc029 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -85,6 +85,18 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
>  			     gpa_t addr, unsigned int len,
>  			     unsigned long val);
>  
> +unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
> +				     gpa_t addr, unsigned int len);
> +
> +void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
> +			      gpa_t addr, unsigned int len,
> +			      unsigned long val);
> +
> +void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
> +			      gpa_t addr, unsigned int len,
> +			      unsigned long val);
> +
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
>  #endif
> -- 
> 2.7.3
> 

Otherwise this looks good.

Thanks,
-Christoffer

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

* Re: [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  2016-05-11 12:34     ` Christoffer Dall
@ 2016-05-11 13:13       ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-11 13:13 UTC (permalink / raw)
  To: Christoffer Dall, Andre Przywara
  Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

On 11/05/16 13:34, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
>> As the enable register handlers are shared between the v2 and v3
>> emulation, their implementation goes into vgic-mmio.c, to be easily
>> referenced from the v3 emulation as well later.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - use lower bits of address to determine IRQ number
>> - remove TODO, confirmed to be fine
>>
>> Changelog v1 .. v2:
>> - adapt to new MMIO framework
>>
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
>>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
>>  3 files changed, 69 insertions(+), 2 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index 69e96f7..448d1da 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>> index 41cf4f4..077ae86 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>>  	/* Ignore */
>>  }
>>  
>> +/*
>> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
>> + * of the enabled bit, so there is only one function for both here.
>> + */
>> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
>> +				    gpa_t addr, unsigned int len)
>> +{
>> +	u32 intid = (addr & 0x7f) * 8;
> 
> is there anything we can do about this to make it more intuitive?  A
> macro to generate the mask/offset based on bits per interrupt or
> something?

Untested (and thus probably wrong):

#define VGIC_ADDR_IRQ_MASK(bits) ((1024 - 1) >> (4 - (bits))
#define VGIC_ADDR_IRQ_MULT(bits) (8 / (bits))
#define VGIC_ADDR_TO_INTID(addr, bits)  (((addr) & VGIC_ADDR_IRQ_MASK(bits)) * \
					 VGIC_ADDR_IRQ_MULT(bits))

	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
@ 2016-05-11 13:13       ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-11 13:13 UTC (permalink / raw)
  To: linux-arm-kernel

On 11/05/16 13:34, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
>> As the enable register handlers are shared between the v2 and v3
>> emulation, their implementation goes into vgic-mmio.c, to be easily
>> referenced from the v3 emulation as well later.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - use lower bits of address to determine IRQ number
>> - remove TODO, confirmed to be fine
>>
>> Changelog v1 .. v2:
>> - adapt to new MMIO framework
>>
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
>>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
>>  3 files changed, 69 insertions(+), 2 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index 69e96f7..448d1da 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>> index 41cf4f4..077ae86 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>>  	/* Ignore */
>>  }
>>  
>> +/*
>> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
>> + * of the enabled bit, so there is only one function for both here.
>> + */
>> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
>> +				    gpa_t addr, unsigned int len)
>> +{
>> +	u32 intid = (addr & 0x7f) * 8;
> 
> is there anything we can do about this to make it more intuitive?  A
> macro to generate the mask/offset based on bits per interrupt or
> something?

Untested (and thus probably wrong):

#define VGIC_ADDR_IRQ_MASK(bits) ((1024 - 1) >> (4 - (bits))
#define VGIC_ADDR_IRQ_MULT(bits) (8 / (bits))
#define VGIC_ADDR_TO_INTID(addr, bits)  (((addr) & VGIC_ADDR_IRQ_MASK(bits)) * \
					 VGIC_ADDR_IRQ_MULT(bits))

	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
  2016-05-11 12:26         ` Christoffer Dall
@ 2016-05-11 13:13           ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 13:13 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hej,

On 11/05/16 13:26, Christoffer Dall wrote:
> On Wed, May 11, 2016 at 12:30:36PM +0100, Andre Przywara wrote:
>> Hi,
>>
>> On 10/05/16 15:10, Eric Auger wrote:
>>> On 05/06/2016 12:45 PM, Andre Przywara wrote:
>>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>>
>>>> Processing maintenance interrupts and accessing the list registers
>>>> are dependent on the host's GIC version.
>>>> Introduce vgic-v2.c to contain GICv2 specific functions.
>>>> Implement the GICv2 specific code for syncing the emulation state
>>>> into the VGIC registers.
>>>>
>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>> Changelog RFC..v1:
>>>> - remove explicit LR_STATE clearing on maintenance interrupt handling
>>>> - improve documentation for vgic_v2_populate_lr()
>>>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
>>>> - simplify multi-CPU source SGI handling
>>>>
>>>> Changelog v1 .. v2:
>>>> - inject the IRQ priority into the list register
>>>>
>>>> Changelog v2 .. v3:
>>>> - cleanup diff containing rebase artifacts
>>>>
>>>>  include/linux/irqchip/arm-gic.h |   1 +
>>>>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>>>>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>>>>  4 files changed, 191 insertions(+)
>>>>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>>>>
>>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>>>> index 9c94026..be0d26f 100644
>>>> --- a/include/linux/irqchip/arm-gic.h
>>>> +++ b/include/linux/irqchip/arm-gic.h
>>>> @@ -76,6 +76,7 @@
>>>>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>>>>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>>>>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
>>>> +#define GICH_LR_PRIORITY_SHIFT		23
>>>>  #define GICH_LR_STATE			(3 << 28)
>>>>  #define GICH_LR_PENDING_BIT		(1 << 28)
>>>>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
>>>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>>>> new file mode 100644
>>>> index 0000000..4cee616
>>>> --- /dev/null
>>>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>>>> @@ -0,0 +1,178 @@
>>>> +/*
>>>> + * Copyright (C) 2015, 2016 ARM Ltd.
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify
>>>> + * it under the terms of the GNU General Public License version 2 as
>>>> + * published by the Free Software Foundation.
>>>> + *
>>>> + * This program is distributed in the hope that it will be useful,
>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>> + * GNU General Public License for more details.
>>>> + *
>>>> + * You should have received a copy of the GNU General Public License
>>>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>>> + */
>>>> +
>>>> +#include <linux/irqchip/arm-gic.h>
>>>> +#include <linux/kvm.h>
>>>> +#include <linux/kvm_host.h>
>>>> +
>>>> +#include "vgic.h"
>>>> +
>>>> +/*
>>>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>>>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>>>> + *
>>>> + * Warning: Calling this function may modify *val.
>>>> + */
>>>> +static unsigned long *u64_to_bitmask(u64 *val)
>>>> +{
>>>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>>>> +	*val = (*val >> 32) | (*val << 32);
>>>> +#endif
>>>> +	return (unsigned long *)val;
>>>> +}
>>>> +
>>>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>>> +
>>>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>>>> +		u64 eisr = cpuif->vgic_eisr;
>>>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>>>> +		int lr;
>>>> +
>>>> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
>>> Didn't we say we could use vcpu->arch.vgic_cpu.used_lrs here?
>>
>> Why would that be useful? Don't we just want to see those LRs that had a
>> maintenance interrupt received? I don't see the point if iterating over
>> the used LRs, where we need to check for this condition somehow manually?
>> Or what am I missing here?
> 
> if we get rid of eisr eventually we can optimize the reading of that
> away, but I honestly don't think we should be pursuing this straight
> away.

Yes, I realized that too when I tried to change the code. But then we
would need to somehow check for that condition anyway? Whereas right now
the hardware points us exactly to the LRs that need servicing?

Or am I confused about the meaning of the EISR bitmap?

And I agree that this possible optimization is something we should keep
for later. I guess we get plenty of opportunity once we remove the old VGIC.

Cheers,
Andre.

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

* [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend
@ 2016-05-11 13:13           ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 13:13 UTC (permalink / raw)
  To: linux-arm-kernel

Hej,

On 11/05/16 13:26, Christoffer Dall wrote:
> On Wed, May 11, 2016 at 12:30:36PM +0100, Andre Przywara wrote:
>> Hi,
>>
>> On 10/05/16 15:10, Eric Auger wrote:
>>> On 05/06/2016 12:45 PM, Andre Przywara wrote:
>>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>>
>>>> Processing maintenance interrupts and accessing the list registers
>>>> are dependent on the host's GIC version.
>>>> Introduce vgic-v2.c to contain GICv2 specific functions.
>>>> Implement the GICv2 specific code for syncing the emulation state
>>>> into the VGIC registers.
>>>>
>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>> Changelog RFC..v1:
>>>> - remove explicit LR_STATE clearing on maintenance interrupt handling
>>>> - improve documentation for vgic_v2_populate_lr()
>>>> - remove WARN_ON on non-edge IRQs in maintenance interrupts
>>>> - simplify multi-CPU source SGI handling
>>>>
>>>> Changelog v1 .. v2:
>>>> - inject the IRQ priority into the list register
>>>>
>>>> Changelog v2 .. v3:
>>>> - cleanup diff containing rebase artifacts
>>>>
>>>>  include/linux/irqchip/arm-gic.h |   1 +
>>>>  virt/kvm/arm/vgic/vgic-v2.c     | 178 ++++++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/vgic/vgic.c        |   6 ++
>>>>  virt/kvm/arm/vgic/vgic.h        |   6 ++
>>>>  4 files changed, 191 insertions(+)
>>>>  create mode 100644 virt/kvm/arm/vgic/vgic-v2.c
>>>>
>>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>>>> index 9c94026..be0d26f 100644
>>>> --- a/include/linux/irqchip/arm-gic.h
>>>> +++ b/include/linux/irqchip/arm-gic.h
>>>> @@ -76,6 +76,7 @@
>>>>  #define GICH_LR_VIRTUALID		(0x3ff << 0)
>>>>  #define GICH_LR_PHYSID_CPUID_SHIFT	(10)
>>>>  #define GICH_LR_PHYSID_CPUID		(0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
>>>> +#define GICH_LR_PRIORITY_SHIFT		23
>>>>  #define GICH_LR_STATE			(3 << 28)
>>>>  #define GICH_LR_PENDING_BIT		(1 << 28)
>>>>  #define GICH_LR_ACTIVE_BIT		(1 << 29)
>>>> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
>>>> new file mode 100644
>>>> index 0000000..4cee616
>>>> --- /dev/null
>>>> +++ b/virt/kvm/arm/vgic/vgic-v2.c
>>>> @@ -0,0 +1,178 @@
>>>> +/*
>>>> + * Copyright (C) 2015, 2016 ARM Ltd.
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify
>>>> + * it under the terms of the GNU General Public License version 2 as
>>>> + * published by the Free Software Foundation.
>>>> + *
>>>> + * This program is distributed in the hope that it will be useful,
>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>> + * GNU General Public License for more details.
>>>> + *
>>>> + * You should have received a copy of the GNU General Public License
>>>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>>> + */
>>>> +
>>>> +#include <linux/irqchip/arm-gic.h>
>>>> +#include <linux/kvm.h>
>>>> +#include <linux/kvm_host.h>
>>>> +
>>>> +#include "vgic.h"
>>>> +
>>>> +/*
>>>> + * Call this function to convert a u64 value to an unsigned long * bitmask
>>>> + * in a way that works on both 32-bit and 64-bit LE and BE platforms.
>>>> + *
>>>> + * Warning: Calling this function may modify *val.
>>>> + */
>>>> +static unsigned long *u64_to_bitmask(u64 *val)
>>>> +{
>>>> +#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
>>>> +	*val = (*val >> 32) | (*val << 32);
>>>> +#endif
>>>> +	return (unsigned long *)val;
>>>> +}
>>>> +
>>>> +void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
>>>> +
>>>> +	if (cpuif->vgic_misr & GICH_MISR_EOI) {
>>>> +		u64 eisr = cpuif->vgic_eisr;
>>>> +		unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
>>>> +		int lr;
>>>> +
>>>> +		for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
>>> Didn't we say we could use vcpu->arch.vgic_cpu.used_lrs here?
>>
>> Why would that be useful? Don't we just want to see those LRs that had a
>> maintenance interrupt received? I don't see the point if iterating over
>> the used LRs, where we need to check for this condition somehow manually?
>> Or what am I missing here?
> 
> if we get rid of eisr eventually we can optimize the reading of that
> away, but I honestly don't think we should be pursuing this straight
> away.

Yes, I realized that too when I tried to change the code. But then we
would need to somehow check for that condition anyway? Whereas right now
the hardware points us exactly to the LRs that need servicing?

Or am I confused about the meaning of the EISR bitmap?

And I agree that this possible optimization is something we should keep
for later. I guess we get plenty of opportunity once we remove the old VGIC.

Cheers,
Andre.

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

* Re: [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  2016-05-11 13:04       ` Andre Przywara
@ 2016-05-11 13:14         ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 13:14 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Wed, May 11, 2016 at 02:04:13PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 11/05/16 13:34, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
> >> As the enable register handlers are shared between the v2 and v3
> >> emulation, their implementation goes into vgic-mmio.c, to be easily
> >> referenced from the v3 emulation as well later.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changelog RFC..v1:
> >> - use lower bits of address to determine IRQ number
> >> - remove TODO, confirmed to be fine
> >>
> >> Changelog v1 .. v2:
> >> - adapt to new MMIO framework
> >>
> >>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
> >>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
> >>  3 files changed, 69 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> index 69e96f7..448d1da 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
> >>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> >> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
> >> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
> >>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> >> index 41cf4f4..077ae86 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> >> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
> >>  	/* Ignore */
> >>  }
> >>  
> >> +/*
> >> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
> >> + * of the enabled bit, so there is only one function for both here.
> >> + */
> >> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
> >> +				    gpa_t addr, unsigned int len)
> >> +{
> >> +	u32 intid = (addr & 0x7f) * 8;
> > 
> > is there anything we can do about this to make it more intuitive?  A
> > macro to generate the mask/offset based on bits per interrupt or
> > something?
> 
> Yes, something where you give it the address and the bits-per-IRQ and it
> tells you the IRQ number.
> Not sure it is advisable to squash this into v4 still?
> 
> > 
> >> +	u32 value = 0;
> >> +	int i;
> >> +
> >> +	/* Loop over all IRQs affected by this read */
> >> +	for (i = 0; i < len * 8; i++) {
> >> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +		if (irq->enabled)
> >> +			value |= (1U << i);
> > 
> > I couldn't find the code anywhere that enforces word-aligned accesses to
> > these registers.  Do we have that?
> 
> Not that I am aware of. I was suggesting this since we have one in the
> IROUTER function. Architecturally we don't need to support halfword
> accesses, it's: byte + word, word only or double-word + word, depending
> on the actual register, IIRC.
> As a fix we can at least deny (read: ignore) halfword accesses in
> general in the dispatcher. Shall I do this (two two-liners)?
> I think byte and word accesses are safe with the existing handlers last
> time I checked.
> 
> > If that's not the case, doesn't this break of you do a non-word aligned
> > access?
> 
> Why would it? vgic_data_host_to_mmio_bus and extract_bytes should cover
> this, shouldn't they?
> 

I think this breaks on a simple byte access.  Let's say you are
accessing byte 1 (addr & 0x7ff == 1), then because you start your loop
at 0, you're going to set bits [7:0] in the value variable, and then
extract bits [15:8] in extract_bytes(), right?

-Christoffer

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

* [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
@ 2016-05-11 13:14         ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 13:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, May 11, 2016 at 02:04:13PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 11/05/16 13:34, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
> >> As the enable register handlers are shared between the v2 and v3
> >> emulation, their implementation goes into vgic-mmio.c, to be easily
> >> referenced from the v3 emulation as well later.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changelog RFC..v1:
> >> - use lower bits of address to determine IRQ number
> >> - remove TODO, confirmed to be fine
> >>
> >> Changelog v1 .. v2:
> >> - adapt to new MMIO framework
> >>
> >>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
> >>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
> >>  3 files changed, 69 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> index 69e96f7..448d1da 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
> >>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> >> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
> >> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
> >>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> >> index 41cf4f4..077ae86 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> >> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
> >>  	/* Ignore */
> >>  }
> >>  
> >> +/*
> >> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
> >> + * of the enabled bit, so there is only one function for both here.
> >> + */
> >> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
> >> +				    gpa_t addr, unsigned int len)
> >> +{
> >> +	u32 intid = (addr & 0x7f) * 8;
> > 
> > is there anything we can do about this to make it more intuitive?  A
> > macro to generate the mask/offset based on bits per interrupt or
> > something?
> 
> Yes, something where you give it the address and the bits-per-IRQ and it
> tells you the IRQ number.
> Not sure it is advisable to squash this into v4 still?
> 
> > 
> >> +	u32 value = 0;
> >> +	int i;
> >> +
> >> +	/* Loop over all IRQs affected by this read */
> >> +	for (i = 0; i < len * 8; i++) {
> >> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >> +
> >> +		if (irq->enabled)
> >> +			value |= (1U << i);
> > 
> > I couldn't find the code anywhere that enforces word-aligned accesses to
> > these registers.  Do we have that?
> 
> Not that I am aware of. I was suggesting this since we have one in the
> IROUTER function. Architecturally we don't need to support halfword
> accesses, it's: byte + word, word only or double-word + word, depending
> on the actual register, IIRC.
> As a fix we can at least deny (read: ignore) halfword accesses in
> general in the dispatcher. Shall I do this (two two-liners)?
> I think byte and word accesses are safe with the existing handlers last
> time I checked.
> 
> > If that's not the case, doesn't this break of you do a non-word aligned
> > access?
> 
> Why would it? vgic_data_host_to_mmio_bus and extract_bytes should cover
> this, shouldn't they?
> 

I think this breaks on a simple byte access.  Let's say you are
accessing byte 1 (addr & 0x7ff == 1), then because you start your loop
at 0, you're going to set bits [7:0] in the value variable, and then
extract bits [15:8] in extract_bytes(), right?

-Christoffer

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

* Re: [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
  2016-05-11 12:51       ` Marc Zyngier
@ 2016-05-11 13:15         ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 13:15 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: linux-arm-kernel, Andre Przywara, kvmarm, kvm

On Wed, May 11, 2016 at 01:51:36PM +0100, Marc Zyngier wrote:
> On 11/05/16 13:05, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:36AM +0100, Andre Przywara wrote:
> >> From: Marc Zyngier <marc.zyngier@arm.com>
> >>
> >> Those three registers are v2 emulation specific, so their implementation
> >> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
> >> as their implementation is pretty simple.
> >> When the guest enables the distributor, we kick all VCPUs to get
> >> potentially pending interrupts serviced.
> >>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changelog RFC..v1:
> >> - kick VCPUs is the distributor gets enabled
> >> - improve comment
> >>
> >> Changelog v1 .. v2:
> >> - adapt to new MMIO framework
> >> - use switch() statements to improve readability
> >>
> >> Changelog v2 .. v3:
> >> - add vgic_kick_vcpus() implementation
> >>
> >>  include/linux/irqchip/arm-gic.h  |  1 +
> >>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
> >>  virt/kvm/arm/vgic/vgic.c         | 15 +++++++++++++
> >>  virt/kvm/arm/vgic/vgic.h         |  4 ++++
> >>  4 files changed, 67 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> >> index be0d26f..fd05185 100644
> >> --- a/include/linux/irqchip/arm-gic.h
> >> +++ b/include/linux/irqchip/arm-gic.h
> >> @@ -33,6 +33,7 @@
> >>  
> >>  #define GIC_DIST_CTRL			0x000
> >>  #define GIC_DIST_CTR			0x004
> >> +#define GIC_DIST_IIDR			0x008
> >>  #define GIC_DIST_IGROUP			0x080
> >>  #define GIC_DIST_ENABLE_SET		0x100
> >>  #define GIC_DIST_ENABLE_CLEAR		0x180
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> index 2729a22..69e96f7 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> @@ -20,9 +20,55 @@
> >>  #include "vgic.h"
> >>  #include "vgic-mmio.h"
> >>  
> >> +static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
> >> +					    gpa_t addr, unsigned int len)
> >> +{
> >> +	u32 value;
> >> +
> >> +	switch (addr & 0x0c) {
> >> +	case GIC_DIST_CTRL:
> >> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
> >> +		break;
> >> +	case GIC_DIST_CTR:
> >> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> >> +		value = (value >> 5) - 1;
> >> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
> >> +		break;
> >> +	case GIC_DIST_IIDR:
> >> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> >> +		break;
> >> +	default:
> >> +		return 0;
> >> +	}
> >> +
> >> +	return extract_bytes(value, addr & 3, len);
> >> +}
> >> +
> >> +static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
> >> +				    gpa_t addr, unsigned int len,
> >> +				    unsigned long val)
> >> +{
> >> +	switch (addr & 0x0c) {
> >> +	case GIC_DIST_CTRL:
> >> +		if (!(addr & 1)) {
> > 
> > what is this !(addr & 1) check?
> 
> We check that the write includes the lowest byte of the register. But as
> we only have aligned accesses, it probably doesn't matter... I'll hack
> that away.
> 
where do we check to only have aligned accesses?

-Christoffer

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

* [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
@ 2016-05-11 13:15         ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 13:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, May 11, 2016 at 01:51:36PM +0100, Marc Zyngier wrote:
> On 11/05/16 13:05, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:36AM +0100, Andre Przywara wrote:
> >> From: Marc Zyngier <marc.zyngier@arm.com>
> >>
> >> Those three registers are v2 emulation specific, so their implementation
> >> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
> >> as their implementation is pretty simple.
> >> When the guest enables the distributor, we kick all VCPUs to get
> >> potentially pending interrupts serviced.
> >>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changelog RFC..v1:
> >> - kick VCPUs is the distributor gets enabled
> >> - improve comment
> >>
> >> Changelog v1 .. v2:
> >> - adapt to new MMIO framework
> >> - use switch() statements to improve readability
> >>
> >> Changelog v2 .. v3:
> >> - add vgic_kick_vcpus() implementation
> >>
> >>  include/linux/irqchip/arm-gic.h  |  1 +
> >>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
> >>  virt/kvm/arm/vgic/vgic.c         | 15 +++++++++++++
> >>  virt/kvm/arm/vgic/vgic.h         |  4 ++++
> >>  4 files changed, 67 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> >> index be0d26f..fd05185 100644
> >> --- a/include/linux/irqchip/arm-gic.h
> >> +++ b/include/linux/irqchip/arm-gic.h
> >> @@ -33,6 +33,7 @@
> >>  
> >>  #define GIC_DIST_CTRL			0x000
> >>  #define GIC_DIST_CTR			0x004
> >> +#define GIC_DIST_IIDR			0x008
> >>  #define GIC_DIST_IGROUP			0x080
> >>  #define GIC_DIST_ENABLE_SET		0x100
> >>  #define GIC_DIST_ENABLE_CLEAR		0x180
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> index 2729a22..69e96f7 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> @@ -20,9 +20,55 @@
> >>  #include "vgic.h"
> >>  #include "vgic-mmio.h"
> >>  
> >> +static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
> >> +					    gpa_t addr, unsigned int len)
> >> +{
> >> +	u32 value;
> >> +
> >> +	switch (addr & 0x0c) {
> >> +	case GIC_DIST_CTRL:
> >> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
> >> +		break;
> >> +	case GIC_DIST_CTR:
> >> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> >> +		value = (value >> 5) - 1;
> >> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
> >> +		break;
> >> +	case GIC_DIST_IIDR:
> >> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> >> +		break;
> >> +	default:
> >> +		return 0;
> >> +	}
> >> +
> >> +	return extract_bytes(value, addr & 3, len);
> >> +}
> >> +
> >> +static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
> >> +				    gpa_t addr, unsigned int len,
> >> +				    unsigned long val)
> >> +{
> >> +	switch (addr & 0x0c) {
> >> +	case GIC_DIST_CTRL:
> >> +		if (!(addr & 1)) {
> > 
> > what is this !(addr & 1) check?
> 
> We check that the write includes the lowest byte of the register. But as
> we only have aligned accesses, it probably doesn't matter... I'll hack
> that away.
> 
where do we check to only have aligned accesses?

-Christoffer

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

* Re: [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  2016-05-11 13:04       ` Andre Przywara
@ 2016-05-11 13:16         ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 13:16 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Wed, May 11, 2016 at 02:04:13PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 11/05/16 13:34, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
> >> As the enable register handlers are shared between the v2 and v3
> >> emulation, their implementation goes into vgic-mmio.c, to be easily
> >> referenced from the v3 emulation as well later.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changelog RFC..v1:
> >> - use lower bits of address to determine IRQ number
> >> - remove TODO, confirmed to be fine
> >>
> >> Changelog v1 .. v2:
> >> - adapt to new MMIO framework
> >>
> >>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
> >>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
> >>  3 files changed, 69 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> index 69e96f7..448d1da 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
> >>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> >> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
> >> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
> >>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> >> index 41cf4f4..077ae86 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> >> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
> >>  	/* Ignore */
> >>  }
> >>  
> >> +/*
> >> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
> >> + * of the enabled bit, so there is only one function for both here.
> >> + */
> >> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
> >> +				    gpa_t addr, unsigned int len)
> >> +{
> >> +	u32 intid = (addr & 0x7f) * 8;
> > 
> > is there anything we can do about this to make it more intuitive?  A
> > macro to generate the mask/offset based on bits per interrupt or
> > something?
> 
> Yes, something where you give it the address and the bits-per-IRQ and it
> tells you the IRQ number.
> Not sure it is advisable to squash this into v4 still?
> 
I think it should be fairly mechanical and easy to squash, so would
prefer it, but if it gives you hours of headache, maybe not.

-Christoffer

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

* [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
@ 2016-05-11 13:16         ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 13:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, May 11, 2016 at 02:04:13PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 11/05/16 13:34, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
> >> As the enable register handlers are shared between the v2 and v3
> >> emulation, their implementation goes into vgic-mmio.c, to be easily
> >> referenced from the v3 emulation as well later.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changelog RFC..v1:
> >> - use lower bits of address to determine IRQ number
> >> - remove TODO, confirmed to be fine
> >>
> >> Changelog v1 .. v2:
> >> - adapt to new MMIO framework
> >>
> >>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
> >>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
> >>  3 files changed, 69 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> index 69e96f7..448d1da 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
> >>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> >> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
> >> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
> >>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> >> index 41cf4f4..077ae86 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> >> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
> >>  	/* Ignore */
> >>  }
> >>  
> >> +/*
> >> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
> >> + * of the enabled bit, so there is only one function for both here.
> >> + */
> >> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
> >> +				    gpa_t addr, unsigned int len)
> >> +{
> >> +	u32 intid = (addr & 0x7f) * 8;
> > 
> > is there anything we can do about this to make it more intuitive?  A
> > macro to generate the mask/offset based on bits per interrupt or
> > something?
> 
> Yes, something where you give it the address and the bits-per-IRQ and it
> tells you the IRQ number.
> Not sure it is advisable to squash this into v4 still?
> 
I think it should be fairly mechanical and easy to squash, so would
prefer it, but if it gives you hours of headache, maybe not.

-Christoffer

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

* Re: [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  2016-05-11 13:14         ` Christoffer Dall
@ 2016-05-11 13:24           ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 13:24 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm



On 11/05/16 14:14, Christoffer Dall wrote:
> On Wed, May 11, 2016 at 02:04:13PM +0100, Andre Przywara wrote:
>> Hi,
>>
>> On 11/05/16 13:34, Christoffer Dall wrote:
>>> On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
>>>> As the enable register handlers are shared between the v2 and v3
>>>> emulation, their implementation goes into vgic-mmio.c, to be easily
>>>> referenced from the v3 emulation as well later.
>>>>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>> Changelog RFC..v1:
>>>> - use lower bits of address to determine IRQ number
>>>> - remove TODO, confirmed to be fine
>>>>
>>>> Changelog v1 .. v2:
>>>> - adapt to new MMIO framework
>>>>
>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
>>>>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
>>>>  3 files changed, 69 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> index 69e96f7..448d1da 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>>>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>>>>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>>>> index 41cf4f4..077ae86 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>>>> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>>>>  	/* Ignore */
>>>>  }
>>>>  
>>>> +/*
>>>> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
>>>> + * of the enabled bit, so there is only one function for both here.
>>>> + */
>>>> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
>>>> +				    gpa_t addr, unsigned int len)
>>>> +{
>>>> +	u32 intid = (addr & 0x7f) * 8;
>>>
>>> is there anything we can do about this to make it more intuitive?  A
>>> macro to generate the mask/offset based on bits per interrupt or
>>> something?
>>
>> Yes, something where you give it the address and the bits-per-IRQ and it
>> tells you the IRQ number.
>> Not sure it is advisable to squash this into v4 still?
>>
>>>
>>>> +	u32 value = 0;
>>>> +	int i;
>>>> +
>>>> +	/* Loop over all IRQs affected by this read */
>>>> +	for (i = 0; i < len * 8; i++) {
>>>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>>>> +
>>>> +		if (irq->enabled)
>>>> +			value |= (1U << i);
>>>
>>> I couldn't find the code anywhere that enforces word-aligned accesses to
>>> these registers.  Do we have that?
>>
>> Not that I am aware of. I was suggesting this since we have one in the
>> IROUTER function. Architecturally we don't need to support halfword
>> accesses, it's: byte + word, word only or double-word + word, depending
>> on the actual register, IIRC.
>> As a fix we can at least deny (read: ignore) halfword accesses in
>> general in the dispatcher. Shall I do this (two two-liners)?
>> I think byte and word accesses are safe with the existing handlers last
>> time I checked.
>>
>>> If that's not the case, doesn't this break of you do a non-word aligned
>>> access?
>>
>> Why would it? vgic_data_host_to_mmio_bus and extract_bytes should cover
>> this, shouldn't they?
>>
> 
> I think this breaks on a simple byte access.  Let's say you are
> accessing byte 1 (addr & 0x7ff == 1), then because you start your loop
> at 0, you're going to set bits [7:0] in the value variable, and then
> extract bits [15:8] in extract_bytes(), right?

Looks like, yes. I thought that it would take care of that, because a
handler function shouldn't be bothered with this: it just acts on the
lower bytes (till the length) and extract_bytes() does the rest. I think
this is what the old magic vgic_reg_access does due to "regval >>
word_offset".

Do you care to fix this in extract_bytes?

Cheers,
Andre.

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

* [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
@ 2016-05-11 13:24           ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 13:24 UTC (permalink / raw)
  To: linux-arm-kernel



On 11/05/16 14:14, Christoffer Dall wrote:
> On Wed, May 11, 2016 at 02:04:13PM +0100, Andre Przywara wrote:
>> Hi,
>>
>> On 11/05/16 13:34, Christoffer Dall wrote:
>>> On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
>>>> As the enable register handlers are shared between the v2 and v3
>>>> emulation, their implementation goes into vgic-mmio.c, to be easily
>>>> referenced from the v3 emulation as well later.
>>>>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>> Changelog RFC..v1:
>>>> - use lower bits of address to determine IRQ number
>>>> - remove TODO, confirmed to be fine
>>>>
>>>> Changelog v1 .. v2:
>>>> - adapt to new MMIO framework
>>>>
>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
>>>>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
>>>>  3 files changed, 69 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> index 69e96f7..448d1da 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>>>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>>>>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>>>> index 41cf4f4..077ae86 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>>>> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>>>>  	/* Ignore */
>>>>  }
>>>>  
>>>> +/*
>>>> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
>>>> + * of the enabled bit, so there is only one function for both here.
>>>> + */
>>>> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
>>>> +				    gpa_t addr, unsigned int len)
>>>> +{
>>>> +	u32 intid = (addr & 0x7f) * 8;
>>>
>>> is there anything we can do about this to make it more intuitive?  A
>>> macro to generate the mask/offset based on bits per interrupt or
>>> something?
>>
>> Yes, something where you give it the address and the bits-per-IRQ and it
>> tells you the IRQ number.
>> Not sure it is advisable to squash this into v4 still?
>>
>>>
>>>> +	u32 value = 0;
>>>> +	int i;
>>>> +
>>>> +	/* Loop over all IRQs affected by this read */
>>>> +	for (i = 0; i < len * 8; i++) {
>>>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>>>> +
>>>> +		if (irq->enabled)
>>>> +			value |= (1U << i);
>>>
>>> I couldn't find the code anywhere that enforces word-aligned accesses to
>>> these registers.  Do we have that?
>>
>> Not that I am aware of. I was suggesting this since we have one in the
>> IROUTER function. Architecturally we don't need to support halfword
>> accesses, it's: byte + word, word only or double-word + word, depending
>> on the actual register, IIRC.
>> As a fix we can at least deny (read: ignore) halfword accesses in
>> general in the dispatcher. Shall I do this (two two-liners)?
>> I think byte and word accesses are safe with the existing handlers last
>> time I checked.
>>
>>> If that's not the case, doesn't this break of you do a non-word aligned
>>> access?
>>
>> Why would it? vgic_data_host_to_mmio_bus and extract_bytes should cover
>> this, shouldn't they?
>>
> 
> I think this breaks on a simple byte access.  Let's say you are
> accessing byte 1 (addr & 0x7ff == 1), then because you start your loop
> at 0, you're going to set bits [7:0] in the value variable, and then
> extract bits [15:8] in extract_bytes(), right?

Looks like, yes. I thought that it would take care of that, because a
handler function shouldn't be bothered with this: it just acts on the
lower bytes (till the length) and extract_bytes() does the rest. I think
this is what the old magic vgic_reg_access does due to "regval >>
word_offset".

Do you care to fix this in extract_bytes?

Cheers,
Andre.

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

* Re: [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
  2016-05-11 13:15         ` Christoffer Dall
@ 2016-05-11 13:27           ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-11 13:27 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: linux-arm-kernel, Andre Przywara, kvmarm, kvm

On 11/05/16 14:15, Christoffer Dall wrote:
> On Wed, May 11, 2016 at 01:51:36PM +0100, Marc Zyngier wrote:
>> On 11/05/16 13:05, Christoffer Dall wrote:
>>> On Fri, May 06, 2016 at 11:45:36AM +0100, Andre Przywara wrote:
>>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>>
>>>> Those three registers are v2 emulation specific, so their implementation
>>>> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
>>>> as their implementation is pretty simple.
>>>> When the guest enables the distributor, we kick all VCPUs to get
>>>> potentially pending interrupts serviced.
>>>>
>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>> Changelog RFC..v1:
>>>> - kick VCPUs is the distributor gets enabled
>>>> - improve comment
>>>>
>>>> Changelog v1 .. v2:
>>>> - adapt to new MMIO framework
>>>> - use switch() statements to improve readability
>>>>
>>>> Changelog v2 .. v3:
>>>> - add vgic_kick_vcpus() implementation
>>>>
>>>>  include/linux/irqchip/arm-gic.h  |  1 +
>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
>>>>  virt/kvm/arm/vgic/vgic.c         | 15 +++++++++++++
>>>>  virt/kvm/arm/vgic/vgic.h         |  4 ++++
>>>>  4 files changed, 67 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>>>> index be0d26f..fd05185 100644
>>>> --- a/include/linux/irqchip/arm-gic.h
>>>> +++ b/include/linux/irqchip/arm-gic.h
>>>> @@ -33,6 +33,7 @@
>>>>  
>>>>  #define GIC_DIST_CTRL			0x000
>>>>  #define GIC_DIST_CTR			0x004
>>>> +#define GIC_DIST_IIDR			0x008
>>>>  #define GIC_DIST_IGROUP			0x080
>>>>  #define GIC_DIST_ENABLE_SET		0x100
>>>>  #define GIC_DIST_ENABLE_CLEAR		0x180
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> index 2729a22..69e96f7 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> @@ -20,9 +20,55 @@
>>>>  #include "vgic.h"
>>>>  #include "vgic-mmio.h"
>>>>  
>>>> +static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
>>>> +					    gpa_t addr, unsigned int len)
>>>> +{
>>>> +	u32 value;
>>>> +
>>>> +	switch (addr & 0x0c) {
>>>> +	case GIC_DIST_CTRL:
>>>> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
>>>> +		break;
>>>> +	case GIC_DIST_CTR:
>>>> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>>>> +		value = (value >> 5) - 1;
>>>> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
>>>> +		break;
>>>> +	case GIC_DIST_IIDR:
>>>> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
>>>> +		break;
>>>> +	default:
>>>> +		return 0;
>>>> +	}
>>>> +
>>>> +	return extract_bytes(value, addr & 3, len);
>>>> +}
>>>> +
>>>> +static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>>>> +				    gpa_t addr, unsigned int len,
>>>> +				    unsigned long val)
>>>> +{
>>>> +	switch (addr & 0x0c) {
>>>> +	case GIC_DIST_CTRL:
>>>> +		if (!(addr & 1)) {
>>>
>>> what is this !(addr & 1) check?
>>
>> We check that the write includes the lowest byte of the register. But as
>> we only have aligned accesses, it probably doesn't matter... I'll hack
>> that away.
>>
> where do we check to only have aligned accesses?

Looks like a missing feature. The v2 spec says:

4.1.4 GIC register access
All registers support 32-bit word accesses with the access type defined
in Table 4-1 on page 4-73 and Table 4-2 on page 4-74.
In addition, the GICD_IPRIORITYRn, GICD_ITARGETSRn, GICD_CPENDSGIRn, and
GICD_SPENDSGIRn registers support byte accesses.

Similar thing for v3 (8.1.3).

By the look of it, we should add checks in all accessors. I'll get onto it.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
@ 2016-05-11 13:27           ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-11 13:27 UTC (permalink / raw)
  To: linux-arm-kernel

On 11/05/16 14:15, Christoffer Dall wrote:
> On Wed, May 11, 2016 at 01:51:36PM +0100, Marc Zyngier wrote:
>> On 11/05/16 13:05, Christoffer Dall wrote:
>>> On Fri, May 06, 2016 at 11:45:36AM +0100, Andre Przywara wrote:
>>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>>
>>>> Those three registers are v2 emulation specific, so their implementation
>>>> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
>>>> as their implementation is pretty simple.
>>>> When the guest enables the distributor, we kick all VCPUs to get
>>>> potentially pending interrupts serviced.
>>>>
>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>> Changelog RFC..v1:
>>>> - kick VCPUs is the distributor gets enabled
>>>> - improve comment
>>>>
>>>> Changelog v1 .. v2:
>>>> - adapt to new MMIO framework
>>>> - use switch() statements to improve readability
>>>>
>>>> Changelog v2 .. v3:
>>>> - add vgic_kick_vcpus() implementation
>>>>
>>>>  include/linux/irqchip/arm-gic.h  |  1 +
>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
>>>>  virt/kvm/arm/vgic/vgic.c         | 15 +++++++++++++
>>>>  virt/kvm/arm/vgic/vgic.h         |  4 ++++
>>>>  4 files changed, 67 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>>>> index be0d26f..fd05185 100644
>>>> --- a/include/linux/irqchip/arm-gic.h
>>>> +++ b/include/linux/irqchip/arm-gic.h
>>>> @@ -33,6 +33,7 @@
>>>>  
>>>>  #define GIC_DIST_CTRL			0x000
>>>>  #define GIC_DIST_CTR			0x004
>>>> +#define GIC_DIST_IIDR			0x008
>>>>  #define GIC_DIST_IGROUP			0x080
>>>>  #define GIC_DIST_ENABLE_SET		0x100
>>>>  #define GIC_DIST_ENABLE_CLEAR		0x180
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> index 2729a22..69e96f7 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> @@ -20,9 +20,55 @@
>>>>  #include "vgic.h"
>>>>  #include "vgic-mmio.h"
>>>>  
>>>> +static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
>>>> +					    gpa_t addr, unsigned int len)
>>>> +{
>>>> +	u32 value;
>>>> +
>>>> +	switch (addr & 0x0c) {
>>>> +	case GIC_DIST_CTRL:
>>>> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
>>>> +		break;
>>>> +	case GIC_DIST_CTR:
>>>> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>>>> +		value = (value >> 5) - 1;
>>>> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
>>>> +		break;
>>>> +	case GIC_DIST_IIDR:
>>>> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
>>>> +		break;
>>>> +	default:
>>>> +		return 0;
>>>> +	}
>>>> +
>>>> +	return extract_bytes(value, addr & 3, len);
>>>> +}
>>>> +
>>>> +static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>>>> +				    gpa_t addr, unsigned int len,
>>>> +				    unsigned long val)
>>>> +{
>>>> +	switch (addr & 0x0c) {
>>>> +	case GIC_DIST_CTRL:
>>>> +		if (!(addr & 1)) {
>>>
>>> what is this !(addr & 1) check?
>>
>> We check that the write includes the lowest byte of the register. But as
>> we only have aligned accesses, it probably doesn't matter... I'll hack
>> that away.
>>
> where do we check to only have aligned accesses?

Looks like a missing feature. The v2 spec says:

4.1.4 GIC register access
All registers support 32-bit word accesses with the access type defined
in Table 4-1 on page 4-73 and Table 4-2 on page 4-74.
In addition, the GICD_IPRIORITYRn, GICD_ITARGETSRn, GICD_CPENDSGIRn, and
GICD_SPENDSGIRn registers support byte accesses.

Similar thing for v3 (8.1.3).

By the look of it, we should add checks in all accessors. I'll get onto it.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
  2016-05-11 13:27           ` Marc Zyngier
@ 2016-05-11 13:36             ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 13:36 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Hi,

On 11/05/16 14:27, Marc Zyngier wrote:
> On 11/05/16 14:15, Christoffer Dall wrote:
>> On Wed, May 11, 2016 at 01:51:36PM +0100, Marc Zyngier wrote:
>>> On 11/05/16 13:05, Christoffer Dall wrote:
>>>> On Fri, May 06, 2016 at 11:45:36AM +0100, Andre Przywara wrote:
>>>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>>>
>>>>> Those three registers are v2 emulation specific, so their implementation
>>>>> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
>>>>> as their implementation is pretty simple.
>>>>> When the guest enables the distributor, we kick all VCPUs to get
>>>>> potentially pending interrupts serviced.
>>>>>
>>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>> ---
>>>>> Changelog RFC..v1:
>>>>> - kick VCPUs is the distributor gets enabled
>>>>> - improve comment
>>>>>
>>>>> Changelog v1 .. v2:
>>>>> - adapt to new MMIO framework
>>>>> - use switch() statements to improve readability
>>>>>
>>>>> Changelog v2 .. v3:
>>>>> - add vgic_kick_vcpus() implementation
>>>>>
>>>>>  include/linux/irqchip/arm-gic.h  |  1 +
>>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
>>>>>  virt/kvm/arm/vgic/vgic.c         | 15 +++++++++++++
>>>>>  virt/kvm/arm/vgic/vgic.h         |  4 ++++
>>>>>  4 files changed, 67 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>>>>> index be0d26f..fd05185 100644
>>>>> --- a/include/linux/irqchip/arm-gic.h
>>>>> +++ b/include/linux/irqchip/arm-gic.h
>>>>> @@ -33,6 +33,7 @@
>>>>>  
>>>>>  #define GIC_DIST_CTRL			0x000
>>>>>  #define GIC_DIST_CTR			0x004
>>>>> +#define GIC_DIST_IIDR			0x008
>>>>>  #define GIC_DIST_IGROUP			0x080
>>>>>  #define GIC_DIST_ENABLE_SET		0x100
>>>>>  #define GIC_DIST_ENABLE_CLEAR		0x180
>>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>>> index 2729a22..69e96f7 100644
>>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>>> @@ -20,9 +20,55 @@
>>>>>  #include "vgic.h"
>>>>>  #include "vgic-mmio.h"
>>>>>  
>>>>> +static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
>>>>> +					    gpa_t addr, unsigned int len)
>>>>> +{
>>>>> +	u32 value;
>>>>> +
>>>>> +	switch (addr & 0x0c) {
>>>>> +	case GIC_DIST_CTRL:
>>>>> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
>>>>> +		break;
>>>>> +	case GIC_DIST_CTR:
>>>>> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>>>>> +		value = (value >> 5) - 1;
>>>>> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
>>>>> +		break;
>>>>> +	case GIC_DIST_IIDR:
>>>>> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
>>>>> +		break;
>>>>> +	default:
>>>>> +		return 0;
>>>>> +	}
>>>>> +
>>>>> +	return extract_bytes(value, addr & 3, len);
>>>>> +}
>>>>> +
>>>>> +static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>>>>> +				    gpa_t addr, unsigned int len,
>>>>> +				    unsigned long val)
>>>>> +{
>>>>> +	switch (addr & 0x0c) {
>>>>> +	case GIC_DIST_CTRL:
>>>>> +		if (!(addr & 1)) {
>>>>
>>>> what is this !(addr & 1) check?
>>>
>>> We check that the write includes the lowest byte of the register. But as
>>> we only have aligned accesses, it probably doesn't matter... I'll hack
>>> that away.
>>>
>> where do we check to only have aligned accesses?
> 
> Looks like a missing feature. The v2 spec says:
> 
> 4.1.4 GIC register access
> All registers support 32-bit word accesses with the access type defined
> in Table 4-1 on page 4-73 and Table 4-2 on page 4-74.
> In addition, the GICD_IPRIORITYRn, GICD_ITARGETSRn, GICD_CPENDSGIRn, and
> GICD_SPENDSGIRn registers support byte accesses.
> 
> Similar thing for v3 (8.1.3).
> 
> By the look of it, we should add checks in all accessors. I'll get onto it.

What about to tag every register in our vgic_register_region with a
possible access width and do a generic check in
dispatch_mmio_{read,write}? Then we wouldn't need to touch every handler.

Cheers,
Andre.

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

* [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
@ 2016-05-11 13:36             ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 13:36 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 11/05/16 14:27, Marc Zyngier wrote:
> On 11/05/16 14:15, Christoffer Dall wrote:
>> On Wed, May 11, 2016 at 01:51:36PM +0100, Marc Zyngier wrote:
>>> On 11/05/16 13:05, Christoffer Dall wrote:
>>>> On Fri, May 06, 2016 at 11:45:36AM +0100, Andre Przywara wrote:
>>>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>>>
>>>>> Those three registers are v2 emulation specific, so their implementation
>>>>> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
>>>>> as their implementation is pretty simple.
>>>>> When the guest enables the distributor, we kick all VCPUs to get
>>>>> potentially pending interrupts serviced.
>>>>>
>>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>> ---
>>>>> Changelog RFC..v1:
>>>>> - kick VCPUs is the distributor gets enabled
>>>>> - improve comment
>>>>>
>>>>> Changelog v1 .. v2:
>>>>> - adapt to new MMIO framework
>>>>> - use switch() statements to improve readability
>>>>>
>>>>> Changelog v2 .. v3:
>>>>> - add vgic_kick_vcpus() implementation
>>>>>
>>>>>  include/linux/irqchip/arm-gic.h  |  1 +
>>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
>>>>>  virt/kvm/arm/vgic/vgic.c         | 15 +++++++++++++
>>>>>  virt/kvm/arm/vgic/vgic.h         |  4 ++++
>>>>>  4 files changed, 67 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>>>>> index be0d26f..fd05185 100644
>>>>> --- a/include/linux/irqchip/arm-gic.h
>>>>> +++ b/include/linux/irqchip/arm-gic.h
>>>>> @@ -33,6 +33,7 @@
>>>>>  
>>>>>  #define GIC_DIST_CTRL			0x000
>>>>>  #define GIC_DIST_CTR			0x004
>>>>> +#define GIC_DIST_IIDR			0x008
>>>>>  #define GIC_DIST_IGROUP			0x080
>>>>>  #define GIC_DIST_ENABLE_SET		0x100
>>>>>  #define GIC_DIST_ENABLE_CLEAR		0x180
>>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>>> index 2729a22..69e96f7 100644
>>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>>> @@ -20,9 +20,55 @@
>>>>>  #include "vgic.h"
>>>>>  #include "vgic-mmio.h"
>>>>>  
>>>>> +static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
>>>>> +					    gpa_t addr, unsigned int len)
>>>>> +{
>>>>> +	u32 value;
>>>>> +
>>>>> +	switch (addr & 0x0c) {
>>>>> +	case GIC_DIST_CTRL:
>>>>> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
>>>>> +		break;
>>>>> +	case GIC_DIST_CTR:
>>>>> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>>>>> +		value = (value >> 5) - 1;
>>>>> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
>>>>> +		break;
>>>>> +	case GIC_DIST_IIDR:
>>>>> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
>>>>> +		break;
>>>>> +	default:
>>>>> +		return 0;
>>>>> +	}
>>>>> +
>>>>> +	return extract_bytes(value, addr & 3, len);
>>>>> +}
>>>>> +
>>>>> +static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>>>>> +				    gpa_t addr, unsigned int len,
>>>>> +				    unsigned long val)
>>>>> +{
>>>>> +	switch (addr & 0x0c) {
>>>>> +	case GIC_DIST_CTRL:
>>>>> +		if (!(addr & 1)) {
>>>>
>>>> what is this !(addr & 1) check?
>>>
>>> We check that the write includes the lowest byte of the register. But as
>>> we only have aligned accesses, it probably doesn't matter... I'll hack
>>> that away.
>>>
>> where do we check to only have aligned accesses?
> 
> Looks like a missing feature. The v2 spec says:
> 
> 4.1.4 GIC register access
> All registers support 32-bit word accesses with the access type defined
> in Table 4-1 on page 4-73 and Table 4-2 on page 4-74.
> In addition, the GICD_IPRIORITYRn, GICD_ITARGETSRn, GICD_CPENDSGIRn, and
> GICD_SPENDSGIRn registers support byte accesses.
> 
> Similar thing for v3 (8.1.3).
> 
> By the look of it, we should add checks in all accessors. I'll get onto it.

What about to tag every register in our vgic_register_region with a
possible access width and do a generic check in
dispatch_mmio_{read,write}? Then we wouldn't need to touch every handler.

Cheers,
Andre.

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

* Re: [PATCH v3 27/55] KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-11 13:37     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 13:37 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, kvmarm, linux-arm-kernel, kvm

On Fri, May 06, 2016 at 11:45:40AM +0100, Andre Przywara wrote:
> The priority register handlers are shared between the v2 and v3
> emulation, so their implementation goes into vgic-mmio.c, to be
> easily referenced from the v3 emulation as well later.
> There is a corner case when we change the priority of a pending
> interrupt which we don't handle at the moment.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  2 +-
>  virt/kvm/arm/vgic/vgic-mmio.c    | 39 +++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h    |  7 +++++++
>  3 files changed, 47 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 054b52d..2e17250 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -84,7 +84,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
>  		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index dbf683e..d7fe9e6 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -282,6 +282,45 @@ retry:
>  	}
>  }
>  
> +unsigned long vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
> +				      gpa_t addr, unsigned int len)
> +{
> +	u32 intid = addr & 0x3ff;
> +	int i;
> +	u64 val = 0;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		val |= (u64)irq->priority << (i * 8);
> +	}
> +
> +	return val;

IPRIORITYRn is specifically one of the registers requiring byte access
to be implemented; why are we not doing the extract_bytes thing here?

> +}
> +
> +/*
> + * We currently don't handle changing the priority of an interrupt that
> + * is already pending on a VCPU. If there is a need for this, we would
> + * need to make this VCPU exit and re-evaluate the priorities, potentially
> + * leading to this interrupt getting presented now to the guest (if it has
> + * been masked by the priority mask before).

I thought we were just going to do a vcpu_kick here?

> + */
> +void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
> +			      gpa_t addr, unsigned int len,
> +			      unsigned long val)
> +{
> +	u32 intid = addr & 0x3ff;
> +	int i;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->priority = (val >> (i * 8)) & 0xff;

If I wasn't mistaken on my comment in the previous patch, then you have
a problem here too...

> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
>  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 fa875dc..cd04ac5 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -107,6 +107,13 @@ void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
>  			     gpa_t addr, unsigned int len,
>  			     unsigned long val);
>  
> +unsigned long vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
> +				      gpa_t addr, unsigned int len);
> +
> +void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
> +			      gpa_t addr, unsigned int len,
> +			      unsigned long val);
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
>  #endif
> -- 
> 2.7.3
> 
> 
> _______________________________________________
> 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] 400+ messages in thread

* [PATCH v3 27/55] KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
@ 2016-05-11 13:37     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 13:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:40AM +0100, Andre Przywara wrote:
> The priority register handlers are shared between the v2 and v3
> emulation, so their implementation goes into vgic-mmio.c, to be
> easily referenced from the v3 emulation as well later.
> There is a corner case when we change the priority of a pending
> interrupt which we don't handle at the moment.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  2 +-
>  virt/kvm/arm/vgic/vgic-mmio.c    | 39 +++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h    |  7 +++++++
>  3 files changed, 47 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 054b52d..2e17250 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -84,7 +84,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
>  		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index dbf683e..d7fe9e6 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -282,6 +282,45 @@ retry:
>  	}
>  }
>  
> +unsigned long vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
> +				      gpa_t addr, unsigned int len)
> +{
> +	u32 intid = addr & 0x3ff;
> +	int i;
> +	u64 val = 0;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		val |= (u64)irq->priority << (i * 8);
> +	}
> +
> +	return val;

IPRIORITYRn is specifically one of the registers requiring byte access
to be implemented; why are we not doing the extract_bytes thing here?

> +}
> +
> +/*
> + * We currently don't handle changing the priority of an interrupt that
> + * is already pending on a VCPU. If there is a need for this, we would
> + * need to make this VCPU exit and re-evaluate the priorities, potentially
> + * leading to this interrupt getting presented now to the guest (if it has
> + * been masked by the priority mask before).

I thought we were just going to do a vcpu_kick here?

> + */
> +void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
> +			      gpa_t addr, unsigned int len,
> +			      unsigned long val)
> +{
> +	u32 intid = addr & 0x3ff;
> +	int i;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->priority = (val >> (i * 8)) & 0xff;

If I wasn't mistaken on my comment in the previous patch, then you have
a problem here too...

> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
>  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 fa875dc..cd04ac5 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -107,6 +107,13 @@ void vgic_mmio_write_sactive(struct kvm_vcpu *vcpu,
>  			     gpa_t addr, unsigned int len,
>  			     unsigned long val);
>  
> +unsigned long vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
> +				      gpa_t addr, unsigned int len);
> +
> +void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
> +			      gpa_t addr, unsigned int len,
> +			      unsigned long val);
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
>  #endif
> -- 
> 2.7.3
> 
> 
> _______________________________________________
> 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] 400+ messages in thread

* Re: [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
  2016-05-11 13:27           ` Marc Zyngier
@ 2016-05-11 13:38             ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 13:38 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: Andre Przywara, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Wed, May 11, 2016 at 02:27:53PM +0100, Marc Zyngier wrote:
> On 11/05/16 14:15, Christoffer Dall wrote:
> > On Wed, May 11, 2016 at 01:51:36PM +0100, Marc Zyngier wrote:
> >> On 11/05/16 13:05, Christoffer Dall wrote:
> >>> On Fri, May 06, 2016 at 11:45:36AM +0100, Andre Przywara wrote:
> >>>> From: Marc Zyngier <marc.zyngier@arm.com>
> >>>>
> >>>> Those three registers are v2 emulation specific, so their implementation
> >>>> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
> >>>> as their implementation is pretty simple.
> >>>> When the guest enables the distributor, we kick all VCPUs to get
> >>>> potentially pending interrupts serviced.
> >>>>
> >>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>>> ---
> >>>> Changelog RFC..v1:
> >>>> - kick VCPUs is the distributor gets enabled
> >>>> - improve comment
> >>>>
> >>>> Changelog v1 .. v2:
> >>>> - adapt to new MMIO framework
> >>>> - use switch() statements to improve readability
> >>>>
> >>>> Changelog v2 .. v3:
> >>>> - add vgic_kick_vcpus() implementation
> >>>>
> >>>>  include/linux/irqchip/arm-gic.h  |  1 +
> >>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
> >>>>  virt/kvm/arm/vgic/vgic.c         | 15 +++++++++++++
> >>>>  virt/kvm/arm/vgic/vgic.h         |  4 ++++
> >>>>  4 files changed, 67 insertions(+), 1 deletion(-)
> >>>>
> >>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> >>>> index be0d26f..fd05185 100644
> >>>> --- a/include/linux/irqchip/arm-gic.h
> >>>> +++ b/include/linux/irqchip/arm-gic.h
> >>>> @@ -33,6 +33,7 @@
> >>>>  
> >>>>  #define GIC_DIST_CTRL			0x000
> >>>>  #define GIC_DIST_CTR			0x004
> >>>> +#define GIC_DIST_IIDR			0x008
> >>>>  #define GIC_DIST_IGROUP			0x080
> >>>>  #define GIC_DIST_ENABLE_SET		0x100
> >>>>  #define GIC_DIST_ENABLE_CLEAR		0x180
> >>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> index 2729a22..69e96f7 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> @@ -20,9 +20,55 @@
> >>>>  #include "vgic.h"
> >>>>  #include "vgic-mmio.h"
> >>>>  
> >>>> +static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
> >>>> +					    gpa_t addr, unsigned int len)
> >>>> +{
> >>>> +	u32 value;
> >>>> +
> >>>> +	switch (addr & 0x0c) {
> >>>> +	case GIC_DIST_CTRL:
> >>>> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
> >>>> +		break;
> >>>> +	case GIC_DIST_CTR:
> >>>> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> >>>> +		value = (value >> 5) - 1;
> >>>> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
> >>>> +		break;
> >>>> +	case GIC_DIST_IIDR:
> >>>> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> >>>> +		break;
> >>>> +	default:
> >>>> +		return 0;
> >>>> +	}
> >>>> +
> >>>> +	return extract_bytes(value, addr & 3, len);
> >>>> +}
> >>>> +
> >>>> +static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
> >>>> +				    gpa_t addr, unsigned int len,
> >>>> +				    unsigned long val)
> >>>> +{
> >>>> +	switch (addr & 0x0c) {
> >>>> +	case GIC_DIST_CTRL:
> >>>> +		if (!(addr & 1)) {
> >>>
> >>> what is this !(addr & 1) check?
> >>
> >> We check that the write includes the lowest byte of the register. But as
> >> we only have aligned accesses, it probably doesn't matter... I'll hack
> >> that away.
> >>
> > where do we check to only have aligned accesses?
> 
> Looks like a missing feature. The v2 spec says:
> 
> 4.1.4 GIC register access
> All registers support 32-bit word accesses with the access type defined
> in Table 4-1 on page 4-73 and Table 4-2 on page 4-74.
> In addition, the GICD_IPRIORITYRn, GICD_ITARGETSRn, GICD_CPENDSGIRn, and
> GICD_SPENDSGIRn registers support byte accesses.
> 
> Similar thing for v3 (8.1.3).
> 
> By the look of it, we should add checks in all accessors. I'll get onto it.
> 
Yeah, that's probably the easiest.

-Christoffer

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

* [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
@ 2016-05-11 13:38             ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 13:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, May 11, 2016 at 02:27:53PM +0100, Marc Zyngier wrote:
> On 11/05/16 14:15, Christoffer Dall wrote:
> > On Wed, May 11, 2016 at 01:51:36PM +0100, Marc Zyngier wrote:
> >> On 11/05/16 13:05, Christoffer Dall wrote:
> >>> On Fri, May 06, 2016 at 11:45:36AM +0100, Andre Przywara wrote:
> >>>> From: Marc Zyngier <marc.zyngier@arm.com>
> >>>>
> >>>> Those three registers are v2 emulation specific, so their implementation
> >>>> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
> >>>> as their implementation is pretty simple.
> >>>> When the guest enables the distributor, we kick all VCPUs to get
> >>>> potentially pending interrupts serviced.
> >>>>
> >>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>>> ---
> >>>> Changelog RFC..v1:
> >>>> - kick VCPUs is the distributor gets enabled
> >>>> - improve comment
> >>>>
> >>>> Changelog v1 .. v2:
> >>>> - adapt to new MMIO framework
> >>>> - use switch() statements to improve readability
> >>>>
> >>>> Changelog v2 .. v3:
> >>>> - add vgic_kick_vcpus() implementation
> >>>>
> >>>>  include/linux/irqchip/arm-gic.h  |  1 +
> >>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
> >>>>  virt/kvm/arm/vgic/vgic.c         | 15 +++++++++++++
> >>>>  virt/kvm/arm/vgic/vgic.h         |  4 ++++
> >>>>  4 files changed, 67 insertions(+), 1 deletion(-)
> >>>>
> >>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
> >>>> index be0d26f..fd05185 100644
> >>>> --- a/include/linux/irqchip/arm-gic.h
> >>>> +++ b/include/linux/irqchip/arm-gic.h
> >>>> @@ -33,6 +33,7 @@
> >>>>  
> >>>>  #define GIC_DIST_CTRL			0x000
> >>>>  #define GIC_DIST_CTR			0x004
> >>>> +#define GIC_DIST_IIDR			0x008
> >>>>  #define GIC_DIST_IGROUP			0x080
> >>>>  #define GIC_DIST_ENABLE_SET		0x100
> >>>>  #define GIC_DIST_ENABLE_CLEAR		0x180
> >>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> index 2729a22..69e96f7 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> @@ -20,9 +20,55 @@
> >>>>  #include "vgic.h"
> >>>>  #include "vgic-mmio.h"
> >>>>  
> >>>> +static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
> >>>> +					    gpa_t addr, unsigned int len)
> >>>> +{
> >>>> +	u32 value;
> >>>> +
> >>>> +	switch (addr & 0x0c) {
> >>>> +	case GIC_DIST_CTRL:
> >>>> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
> >>>> +		break;
> >>>> +	case GIC_DIST_CTR:
> >>>> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> >>>> +		value = (value >> 5) - 1;
> >>>> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
> >>>> +		break;
> >>>> +	case GIC_DIST_IIDR:
> >>>> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> >>>> +		break;
> >>>> +	default:
> >>>> +		return 0;
> >>>> +	}
> >>>> +
> >>>> +	return extract_bytes(value, addr & 3, len);
> >>>> +}
> >>>> +
> >>>> +static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
> >>>> +				    gpa_t addr, unsigned int len,
> >>>> +				    unsigned long val)
> >>>> +{
> >>>> +	switch (addr & 0x0c) {
> >>>> +	case GIC_DIST_CTRL:
> >>>> +		if (!(addr & 1)) {
> >>>
> >>> what is this !(addr & 1) check?
> >>
> >> We check that the write includes the lowest byte of the register. But as
> >> we only have aligned accesses, it probably doesn't matter... I'll hack
> >> that away.
> >>
> > where do we check to only have aligned accesses?
> 
> Looks like a missing feature. The v2 spec says:
> 
> 4.1.4 GIC register access
> All registers support 32-bit word accesses with the access type defined
> in Table 4-1 on page 4-73 and Table 4-2 on page 4-74.
> In addition, the GICD_IPRIORITYRn, GICD_ITARGETSRn, GICD_CPENDSGIRn, and
> GICD_SPENDSGIRn registers support byte accesses.
> 
> Similar thing for v3 (8.1.3).
> 
> By the look of it, we should add checks in all accessors. I'll get onto it.
> 
Yeah, that's probably the easiest.

-Christoffer

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

* Re: [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  2016-05-11 13:13       ` Marc Zyngier
@ 2016-05-11 13:39         ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 13:39 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Hi,

On 11/05/16 14:13, Marc Zyngier wrote:
> On 11/05/16 13:34, Christoffer Dall wrote:
>> On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
>>> As the enable register handlers are shared between the v2 and v3
>>> emulation, their implementation goes into vgic-mmio.c, to be easily
>>> referenced from the v3 emulation as well later.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>> Changelog RFC..v1:
>>> - use lower bits of address to determine IRQ number
>>> - remove TODO, confirmed to be fine
>>>
>>> Changelog v1 .. v2:
>>> - adapt to new MMIO framework
>>>
>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
>>>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
>>>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
>>>  3 files changed, 69 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> index 69e96f7..448d1da 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>>>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>>> index 41cf4f4..077ae86 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>>> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>>>  	/* Ignore */
>>>  }
>>>  
>>> +/*
>>> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
>>> + * of the enabled bit, so there is only one function for both here.
>>> + */
>>> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
>>> +				    gpa_t addr, unsigned int len)
>>> +{
>>> +	u32 intid = (addr & 0x7f) * 8;
>>
>> is there anything we can do about this to make it more intuitive?  A
>> macro to generate the mask/offset based on bits per interrupt or
>> something?
> 
> Untested (and thus probably wrong):
> 
> #define VGIC_ADDR_IRQ_MASK(bits) ((1024 - 1) >> (4 - (bits))

What about if bits is 8?
Wouldn't GENMASK(bits + 10 - 2, 0) do the trick?

> #define VGIC_ADDR_IRQ_MULT(bits) (8 / (bits))

IROUTER has a bits_per_irq value of 64. We just don't need to call it
from there, but it would be nice if it could cover this.
But I don't know a neat solution for this either.

Cheers,
Andre.

> #define VGIC_ADDR_TO_INTID(addr, bits)  (((addr) & VGIC_ADDR_IRQ_MASK(bits)) * \
> 					 VGIC_ADDR_IRQ_MULT(bits))
> 
> 	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
> 
> Thanks,
> 
> 	M.
> 

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

* [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
@ 2016-05-11 13:39         ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 13:39 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 11/05/16 14:13, Marc Zyngier wrote:
> On 11/05/16 13:34, Christoffer Dall wrote:
>> On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
>>> As the enable register handlers are shared between the v2 and v3
>>> emulation, their implementation goes into vgic-mmio.c, to be easily
>>> referenced from the v3 emulation as well later.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>> Changelog RFC..v1:
>>> - use lower bits of address to determine IRQ number
>>> - remove TODO, confirmed to be fine
>>>
>>> Changelog v1 .. v2:
>>> - adapt to new MMIO framework
>>>
>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
>>>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
>>>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
>>>  3 files changed, 69 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> index 69e96f7..448d1da 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>>>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>>> index 41cf4f4..077ae86 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>>> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>>>  	/* Ignore */
>>>  }
>>>  
>>> +/*
>>> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
>>> + * of the enabled bit, so there is only one function for both here.
>>> + */
>>> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
>>> +				    gpa_t addr, unsigned int len)
>>> +{
>>> +	u32 intid = (addr & 0x7f) * 8;
>>
>> is there anything we can do about this to make it more intuitive?  A
>> macro to generate the mask/offset based on bits per interrupt or
>> something?
> 
> Untested (and thus probably wrong):
> 
> #define VGIC_ADDR_IRQ_MASK(bits) ((1024 - 1) >> (4 - (bits))

What about if bits is 8?
Wouldn't GENMASK(bits + 10 - 2, 0) do the trick?

> #define VGIC_ADDR_IRQ_MULT(bits) (8 / (bits))

IROUTER has a bits_per_irq value of 64. We just don't need to call it
from there, but it would be nice if it could cover this.
But I don't know a neat solution for this either.

Cheers,
Andre.

> #define VGIC_ADDR_TO_INTID(addr, bits)  (((addr) & VGIC_ADDR_IRQ_MASK(bits)) * \
> 					 VGIC_ADDR_IRQ_MULT(bits))
> 
> 	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
> 
> Thanks,
> 
> 	M.
> 

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

* Re: [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  2016-05-11 13:24           ` Andre Przywara
@ 2016-05-11 13:41             ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 13:41 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Wed, May 11, 2016 at 02:24:22PM +0100, Andre Przywara wrote:
> 
> 
> On 11/05/16 14:14, Christoffer Dall wrote:
> > On Wed, May 11, 2016 at 02:04:13PM +0100, Andre Przywara wrote:
> >> Hi,
> >>
> >> On 11/05/16 13:34, Christoffer Dall wrote:
> >>> On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
> >>>> As the enable register handlers are shared between the v2 and v3
> >>>> emulation, their implementation goes into vgic-mmio.c, to be easily
> >>>> referenced from the v3 emulation as well later.
> >>>>
> >>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>>> ---
> >>>> Changelog RFC..v1:
> >>>> - use lower bits of address to determine IRQ number
> >>>> - remove TODO, confirmed to be fine
> >>>>
> >>>> Changelog v1 .. v2:
> >>>> - adapt to new MMIO framework
> >>>>
> >>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
> >>>>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
> >>>>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
> >>>>  3 files changed, 69 insertions(+), 2 deletions(-)
> >>>>
> >>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> index 69e96f7..448d1da 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
> >>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
> >>>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
> >>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> >>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >>>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
> >>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
> >>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >>>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
> >>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
> >>>>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> >>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> >>>> index 41cf4f4..077ae86 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> >>>> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
> >>>>  	/* Ignore */
> >>>>  }
> >>>>  
> >>>> +/*
> >>>> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
> >>>> + * of the enabled bit, so there is only one function for both here.
> >>>> + */
> >>>> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
> >>>> +				    gpa_t addr, unsigned int len)
> >>>> +{
> >>>> +	u32 intid = (addr & 0x7f) * 8;
> >>>
> >>> is there anything we can do about this to make it more intuitive?  A
> >>> macro to generate the mask/offset based on bits per interrupt or
> >>> something?
> >>
> >> Yes, something where you give it the address and the bits-per-IRQ and it
> >> tells you the IRQ number.
> >> Not sure it is advisable to squash this into v4 still?
> >>
> >>>
> >>>> +	u32 value = 0;
> >>>> +	int i;
> >>>> +
> >>>> +	/* Loop over all IRQs affected by this read */
> >>>> +	for (i = 0; i < len * 8; i++) {
> >>>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >>>> +
> >>>> +		if (irq->enabled)
> >>>> +			value |= (1U << i);
> >>>
> >>> I couldn't find the code anywhere that enforces word-aligned accesses to
> >>> these registers.  Do we have that?
> >>
> >> Not that I am aware of. I was suggesting this since we have one in the
> >> IROUTER function. Architecturally we don't need to support halfword
> >> accesses, it's: byte + word, word only or double-word + word, depending
> >> on the actual register, IIRC.
> >> As a fix we can at least deny (read: ignore) halfword accesses in
> >> general in the dispatcher. Shall I do this (two two-liners)?
> >> I think byte and word accesses are safe with the existing handlers last
> >> time I checked.
> >>
> >>> If that's not the case, doesn't this break of you do a non-word aligned
> >>> access?
> >>
> >> Why would it? vgic_data_host_to_mmio_bus and extract_bytes should cover
> >> this, shouldn't they?
> >>
> > 
> > I think this breaks on a simple byte access.  Let's say you are
> > accessing byte 1 (addr & 0x7ff == 1), then because you start your loop
> > at 0, you're going to set bits [7:0] in the value variable, and then
> > extract bits [15:8] in extract_bytes(), right?
> 
> Looks like, yes. I thought that it would take care of that, because a
> handler function shouldn't be bothered with this: it just acts on the
> lower bytes (till the length) and extract_bytes() does the rest. I think
> this is what the old magic vgic_reg_access does due to "regval >>
> word_offset".
> 
> Do you care to fix this in extract_bytes?
> 
I don't think this is a fix to extract_bytes.  I think the issue is with
how we build the values.  I though the semanticsehre were that the u32
value in this case would the entire 32-bit register, so can't we simply
mask off the lower bits in the addr on entry to these functions and add
additional checks if there are registers where specifically do not wish
to support byte accessed?

-Christoffer

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

* [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
@ 2016-05-11 13:41             ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 13:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, May 11, 2016 at 02:24:22PM +0100, Andre Przywara wrote:
> 
> 
> On 11/05/16 14:14, Christoffer Dall wrote:
> > On Wed, May 11, 2016 at 02:04:13PM +0100, Andre Przywara wrote:
> >> Hi,
> >>
> >> On 11/05/16 13:34, Christoffer Dall wrote:
> >>> On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
> >>>> As the enable register handlers are shared between the v2 and v3
> >>>> emulation, their implementation goes into vgic-mmio.c, to be easily
> >>>> referenced from the v3 emulation as well later.
> >>>>
> >>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>>> ---
> >>>> Changelog RFC..v1:
> >>>> - use lower bits of address to determine IRQ number
> >>>> - remove TODO, confirmed to be fine
> >>>>
> >>>> Changelog v1 .. v2:
> >>>> - adapt to new MMIO framework
> >>>>
> >>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
> >>>>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
> >>>>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
> >>>>  3 files changed, 69 insertions(+), 2 deletions(-)
> >>>>
> >>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> index 69e96f7..448d1da 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
> >>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
> >>>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
> >>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> >>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >>>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
> >>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
> >>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >>>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
> >>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
> >>>>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> >>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> >>>> index 41cf4f4..077ae86 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> >>>> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
> >>>>  	/* Ignore */
> >>>>  }
> >>>>  
> >>>> +/*
> >>>> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
> >>>> + * of the enabled bit, so there is only one function for both here.
> >>>> + */
> >>>> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
> >>>> +				    gpa_t addr, unsigned int len)
> >>>> +{
> >>>> +	u32 intid = (addr & 0x7f) * 8;
> >>>
> >>> is there anything we can do about this to make it more intuitive?  A
> >>> macro to generate the mask/offset based on bits per interrupt or
> >>> something?
> >>
> >> Yes, something where you give it the address and the bits-per-IRQ and it
> >> tells you the IRQ number.
> >> Not sure it is advisable to squash this into v4 still?
> >>
> >>>
> >>>> +	u32 value = 0;
> >>>> +	int i;
> >>>> +
> >>>> +	/* Loop over all IRQs affected by this read */
> >>>> +	for (i = 0; i < len * 8; i++) {
> >>>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> >>>> +
> >>>> +		if (irq->enabled)
> >>>> +			value |= (1U << i);
> >>>
> >>> I couldn't find the code anywhere that enforces word-aligned accesses to
> >>> these registers.  Do we have that?
> >>
> >> Not that I am aware of. I was suggesting this since we have one in the
> >> IROUTER function. Architecturally we don't need to support halfword
> >> accesses, it's: byte + word, word only or double-word + word, depending
> >> on the actual register, IIRC.
> >> As a fix we can at least deny (read: ignore) halfword accesses in
> >> general in the dispatcher. Shall I do this (two two-liners)?
> >> I think byte and word accesses are safe with the existing handlers last
> >> time I checked.
> >>
> >>> If that's not the case, doesn't this break of you do a non-word aligned
> >>> access?
> >>
> >> Why would it? vgic_data_host_to_mmio_bus and extract_bytes should cover
> >> this, shouldn't they?
> >>
> > 
> > I think this breaks on a simple byte access.  Let's say you are
> > accessing byte 1 (addr & 0x7ff == 1), then because you start your loop
> > at 0, you're going to set bits [7:0] in the value variable, and then
> > extract bits [15:8] in extract_bytes(), right?
> 
> Looks like, yes. I thought that it would take care of that, because a
> handler function shouldn't be bothered with this: it just acts on the
> lower bytes (till the length) and extract_bytes() does the rest. I think
> this is what the old magic vgic_reg_access does due to "regval >>
> word_offset".
> 
> Do you care to fix this in extract_bytes?
> 
I don't think this is a fix to extract_bytes.  I think the issue is with
how we build the values.  I though the semanticsehre were that the u32
value in this case would the entire 32-bit register, so can't we simply
mask off the lower bits in the addr on entry to these functions and add
additional checks if there are registers where specifically do not wish
to support byte accessed?

-Christoffer

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

* Re: [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  2016-05-11 13:13       ` Marc Zyngier
@ 2016-05-11 13:47         ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 13:47 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: linux-arm-kernel, Andre Przywara, kvmarm, kvm

On Wed, May 11, 2016 at 02:13:48PM +0100, Marc Zyngier wrote:
> On 11/05/16 13:34, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
> >> As the enable register handlers are shared between the v2 and v3
> >> emulation, their implementation goes into vgic-mmio.c, to be easily
> >> referenced from the v3 emulation as well later.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changelog RFC..v1:
> >> - use lower bits of address to determine IRQ number
> >> - remove TODO, confirmed to be fine
> >>
> >> Changelog v1 .. v2:
> >> - adapt to new MMIO framework
> >>
> >>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
> >>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
> >>  3 files changed, 69 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> index 69e96f7..448d1da 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
> >>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> >> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
> >> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
> >>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> >> index 41cf4f4..077ae86 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> >> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
> >>  	/* Ignore */
> >>  }
> >>  
> >> +/*
> >> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
> >> + * of the enabled bit, so there is only one function for both here.
> >> + */
> >> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
> >> +				    gpa_t addr, unsigned int len)
> >> +{
> >> +	u32 intid = (addr & 0x7f) * 8;
> > 
> > is there anything we can do about this to make it more intuitive?  A
> > macro to generate the mask/offset based on bits per interrupt or
> > something?
> 
> Untested (and thus probably wrong):
> 
> #define VGIC_ADDR_IRQ_MASK(bits) ((1024 - 1) >> (4 - (bits))

you're going to have to explain this to me, where is the (4 - bits)
coming from?

> #define VGIC_ADDR_IRQ_MULT(bits) (8 / (bits))
> #define VGIC_ADDR_TO_INTID(addr, bits)  (((addr) & VGIC_ADDR_IRQ_MASK(bits)) * \
> 					 VGIC_ADDR_IRQ_MULT(bits))


> 
> 	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
> 
> Thanks,
> 
> 	M.
> -- 
> Jazz is not dead. It just smells funny...

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

* [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
@ 2016-05-11 13:47         ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-11 13:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, May 11, 2016 at 02:13:48PM +0100, Marc Zyngier wrote:
> On 11/05/16 13:34, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
> >> As the enable register handlers are shared between the v2 and v3
> >> emulation, their implementation goes into vgic-mmio.c, to be easily
> >> referenced from the v3 emulation as well later.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changelog RFC..v1:
> >> - use lower bits of address to determine IRQ number
> >> - remove TODO, confirmed to be fine
> >>
> >> Changelog v1 .. v2:
> >> - adapt to new MMIO framework
> >>
> >>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
> >>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
> >>  3 files changed, 69 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> index 69e96f7..448d1da 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
> >>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
> >> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
> >> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
> >>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> >>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> >> index 41cf4f4..077ae86 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> >> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
> >>  	/* Ignore */
> >>  }
> >>  
> >> +/*
> >> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
> >> + * of the enabled bit, so there is only one function for both here.
> >> + */
> >> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
> >> +				    gpa_t addr, unsigned int len)
> >> +{
> >> +	u32 intid = (addr & 0x7f) * 8;
> > 
> > is there anything we can do about this to make it more intuitive?  A
> > macro to generate the mask/offset based on bits per interrupt or
> > something?
> 
> Untested (and thus probably wrong):
> 
> #define VGIC_ADDR_IRQ_MASK(bits) ((1024 - 1) >> (4 - (bits))

you're going to have to explain this to me, where is the (4 - bits)
coming from?

> #define VGIC_ADDR_IRQ_MULT(bits) (8 / (bits))
> #define VGIC_ADDR_TO_INTID(addr, bits)  (((addr) & VGIC_ADDR_IRQ_MASK(bits)) * \
> 					 VGIC_ADDR_IRQ_MULT(bits))


> 
> 	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
> 
> Thanks,
> 
> 	M.
> -- 
> Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3a] KVM: arm/arm64: pmu: abstract access to number of SPIs
  2016-05-10 14:58         ` Andrew Jones
@ 2016-05-11 13:52           ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 13:52 UTC (permalink / raw)
  To: Andrew Jones; +Cc: kvm, Marc Zyngier, kvmarm, linux-arm-kernel

Hi Drew,

On 10/05/16 15:58, Andrew Jones wrote:
> On Tue, May 10, 2016 at 03:35:06PM +0100, Andre Przywara wrote:
>> Currently the PMU uses a member of the struct vgic_dist directly,
>> which not only breaks abstraction, but will fail with the new VGIC.
>> Abstract this access in the VGIC header file.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Hi Eric, Marc,
>>
>> as this if-statement was quite confusing (it wasn't even the negation
>> that was wrong), I rewrote it a bit to be more readable.
>> This one works now with PPIs (after fixing kvmtool).
>>
>> Does that make sense?
>>
>> Cheers,
>> Andre.
>>
>>  include/kvm/arm_vgic.h |  2 ++
>>  virt/kvm/arm/pmu.c     | 19 +++++++++++--------
>>  2 files changed, 13 insertions(+), 8 deletions(-)
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index 6a98e05..d406f8e 100644
>> --- a/include/kvm/arm_vgic.h
>> +++ b/include/kvm/arm_vgic.h
>> @@ -351,6 +351,8 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
>>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>>  #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
>>  #define vgic_ready(k)		((k)->arch.vgic.ready)
>> +#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>> +				 ((i) < (k)->arch.vgic.nr_irqs))
>>  
>>  int vgic_v2_probe(struct device_node *vgic_node,
>>  		  const struct vgic_ops **ops,
>> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
>> index 575c7aa..6ab9d6b 100644
>> --- a/virt/kvm/arm/pmu.c
>> +++ b/virt/kvm/arm/pmu.c
>> @@ -436,6 +436,11 @@ static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
>>  	return 0;
>>  }
>>  
>> +/*
>> + * For one VM the interrupt type must be same for each vcpu.
>> + * As a PPI, the interrupt number is the same for all vcpus,
>> + * while as an SPI it must be a separate number per vcpu.
>> + */
>>  static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi)
> 
> While at it, I'd change this function name to have 'pmu' in it. It's
> just a static function, but without pmu in it it looks a bit confusing
> now to check the irq is [a valid] spi or ppi number, and then to call
> the generically named 'irq_is_valid' on it as well.

Yes, indeed. Did that in the new series.

Thanks!
Andre.

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

* [PATCH v3a] KVM: arm/arm64: pmu: abstract access to number of SPIs
@ 2016-05-11 13:52           ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 13:52 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Drew,

On 10/05/16 15:58, Andrew Jones wrote:
> On Tue, May 10, 2016 at 03:35:06PM +0100, Andre Przywara wrote:
>> Currently the PMU uses a member of the struct vgic_dist directly,
>> which not only breaks abstraction, but will fail with the new VGIC.
>> Abstract this access in the VGIC header file.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Hi Eric, Marc,
>>
>> as this if-statement was quite confusing (it wasn't even the negation
>> that was wrong), I rewrote it a bit to be more readable.
>> This one works now with PPIs (after fixing kvmtool).
>>
>> Does that make sense?
>>
>> Cheers,
>> Andre.
>>
>>  include/kvm/arm_vgic.h |  2 ++
>>  virt/kvm/arm/pmu.c     | 19 +++++++++++--------
>>  2 files changed, 13 insertions(+), 8 deletions(-)
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index 6a98e05..d406f8e 100644
>> --- a/include/kvm/arm_vgic.h
>> +++ b/include/kvm/arm_vgic.h
>> @@ -351,6 +351,8 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
>>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>>  #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
>>  #define vgic_ready(k)		((k)->arch.vgic.ready)
>> +#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>> +				 ((i) < (k)->arch.vgic.nr_irqs))
>>  
>>  int vgic_v2_probe(struct device_node *vgic_node,
>>  		  const struct vgic_ops **ops,
>> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
>> index 575c7aa..6ab9d6b 100644
>> --- a/virt/kvm/arm/pmu.c
>> +++ b/virt/kvm/arm/pmu.c
>> @@ -436,6 +436,11 @@ static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
>>  	return 0;
>>  }
>>  
>> +/*
>> + * For one VM the interrupt type must be same for each vcpu.
>> + * As a PPI, the interrupt number is the same for all vcpus,
>> + * while as an SPI it must be a separate number per vcpu.
>> + */
>>  static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi)
> 
> While at it, I'd change this function name to have 'pmu' in it. It's
> just a static function, but without pmu in it it looks a bit confusing
> now to check the irq is [a valid] spi or ppi number, and then to call
> the generically named 'irq_is_valid' on it as well.

Yes, indeed. Did that in the new series.

Thanks!
Andre.

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

* Re: [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  2016-05-11 13:13       ` Marc Zyngier
@ 2016-05-11 14:18         ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 14:18 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Hi,

On 11/05/16 14:13, Marc Zyngier wrote:
> On 11/05/16 13:34, Christoffer Dall wrote:
>> On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
>>> As the enable register handlers are shared between the v2 and v3
>>> emulation, their implementation goes into vgic-mmio.c, to be easily
>>> referenced from the v3 emulation as well later.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>> Changelog RFC..v1:
>>> - use lower bits of address to determine IRQ number
>>> - remove TODO, confirmed to be fine
>>>
>>> Changelog v1 .. v2:
>>> - adapt to new MMIO framework
>>>
>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
>>>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
>>>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
>>>  3 files changed, 69 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> index 69e96f7..448d1da 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>>>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>>> index 41cf4f4..077ae86 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>>> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>>>  	/* Ignore */
>>>  }
>>>  
>>> +/*
>>> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
>>> + * of the enabled bit, so there is only one function for both here.
>>> + */
>>> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
>>> +				    gpa_t addr, unsigned int len)
>>> +{
>>> +	u32 intid = (addr & 0x7f) * 8;
>>
>> is there anything we can do about this to make it more intuitive?  A
>> macro to generate the mask/offset based on bits per interrupt or
>> something?
> 
> Untested (and thus probably wrong):
> 
> #define VGIC_ADDR_IRQ_MASK(bits) ((1024 - 1) >> (4 - (bits))
> #define VGIC_ADDR_IRQ_MULT(bits) (8 / (bits))
> #define VGIC_ADDR_TO_INTID(addr, bits)  (((addr) & VGIC_ADDR_IRQ_MASK(bits)) * \
> 					 VGIC_ADDR_IRQ_MULT(bits))
> 

Would:

#define VGIC_ADDR_IRQ_MASK(bits) GENMASK_ULL((bits) + 10 - 1 - 1, 0)
#define VGIC_ADDR_TO_INTID(addr, bits) (((addr) &		\
			VGIC_ADDR_IRQ_MASK(bits)) * 64 / (bits) / 8)

work for all bitnesses?

Cheers,
Andre.

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

* [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
@ 2016-05-11 14:18         ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 14:18 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 11/05/16 14:13, Marc Zyngier wrote:
> On 11/05/16 13:34, Christoffer Dall wrote:
>> On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
>>> As the enable register handlers are shared between the v2 and v3
>>> emulation, their implementation goes into vgic-mmio.c, to be easily
>>> referenced from the v3 emulation as well later.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>> Changelog RFC..v1:
>>> - use lower bits of address to determine IRQ number
>>> - remove TODO, confirmed to be fine
>>>
>>> Changelog v1 .. v2:
>>> - adapt to new MMIO framework
>>>
>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
>>>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
>>>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
>>>  3 files changed, 69 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> index 69e96f7..448d1da 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>>>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>>> index 41cf4f4..077ae86 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>>> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>>>  	/* Ignore */
>>>  }
>>>  
>>> +/*
>>> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
>>> + * of the enabled bit, so there is only one function for both here.
>>> + */
>>> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
>>> +				    gpa_t addr, unsigned int len)
>>> +{
>>> +	u32 intid = (addr & 0x7f) * 8;
>>
>> is there anything we can do about this to make it more intuitive?  A
>> macro to generate the mask/offset based on bits per interrupt or
>> something?
> 
> Untested (and thus probably wrong):
> 
> #define VGIC_ADDR_IRQ_MASK(bits) ((1024 - 1) >> (4 - (bits))
> #define VGIC_ADDR_IRQ_MULT(bits) (8 / (bits))
> #define VGIC_ADDR_TO_INTID(addr, bits)  (((addr) & VGIC_ADDR_IRQ_MASK(bits)) * \
> 					 VGIC_ADDR_IRQ_MULT(bits))
> 

Would:

#define VGIC_ADDR_IRQ_MASK(bits) GENMASK_ULL((bits) + 10 - 1 - 1, 0)
#define VGIC_ADDR_TO_INTID(addr, bits) (((addr) &		\
			VGIC_ADDR_IRQ_MASK(bits)) * 64 / (bits) / 8)

work for all bitnesses?

Cheers,
Andre.

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

* Re: [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  2016-05-11 13:39         ` Andre Przywara
@ 2016-05-11 14:26           ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-11 14:26 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall
  Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

On 11/05/16 14:39, Andre Przywara wrote:
> Hi,
> 
> On 11/05/16 14:13, Marc Zyngier wrote:
>> On 11/05/16 13:34, Christoffer Dall wrote:
>>> On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
>>>> As the enable register handlers are shared between the v2 and v3
>>>> emulation, their implementation goes into vgic-mmio.c, to be easily
>>>> referenced from the v3 emulation as well later.
>>>>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>> Changelog RFC..v1:
>>>> - use lower bits of address to determine IRQ number
>>>> - remove TODO, confirmed to be fine
>>>>
>>>> Changelog v1 .. v2:
>>>> - adapt to new MMIO framework
>>>>
>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
>>>>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
>>>>  3 files changed, 69 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> index 69e96f7..448d1da 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>>>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>>>>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>>>> index 41cf4f4..077ae86 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>>>> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>>>>  	/* Ignore */
>>>>  }
>>>>  
>>>> +/*
>>>> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
>>>> + * of the enabled bit, so there is only one function for both here.
>>>> + */
>>>> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
>>>> +				    gpa_t addr, unsigned int len)
>>>> +{
>>>> +	u32 intid = (addr & 0x7f) * 8;
>>>
>>> is there anything we can do about this to make it more intuitive?  A
>>> macro to generate the mask/offset based on bits per interrupt or
>>> something?
>>
>> Untested (and thus probably wrong):
>>
>> #define VGIC_ADDR_IRQ_MASK(bits) ((1024 - 1) >> (4 - (bits))
> 
> What about if bits is 8?

Gnii. This should be ((1024 - 1) >> (4 - ffs(bits))

> Wouldn't GENMASK(bits + 10 - 2, 0) do the trick?

I really can't see how that works... It could be
GENMASK(10 - 1 - ffs(bits), 0) though.

>> #define VGIC_ADDR_IRQ_MULT(bits) (8 / (bits))
> 
> IROUTER has a bits_per_irq value of 64. We just don't need to call it
> from there, but it would be nice if it could cover this.
> But I don't know a neat solution for this either.

Me neither, but I don't see that as a major issue so far.

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
@ 2016-05-11 14:26           ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-11 14:26 UTC (permalink / raw)
  To: linux-arm-kernel

On 11/05/16 14:39, Andre Przywara wrote:
> Hi,
> 
> On 11/05/16 14:13, Marc Zyngier wrote:
>> On 11/05/16 13:34, Christoffer Dall wrote:
>>> On Fri, May 06, 2016 at 11:45:37AM +0100, Andre Przywara wrote:
>>>> As the enable register handlers are shared between the v2 and v3
>>>> emulation, their implementation goes into vgic-mmio.c, to be easily
>>>> referenced from the v3 emulation as well later.
>>>>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>> Changelog RFC..v1:
>>>> - use lower bits of address to determine IRQ number
>>>> - remove TODO, confirmed to be fine
>>>>
>>>> Changelog v1 .. v2:
>>>> - adapt to new MMIO framework
>>>>
>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  4 +--
>>>>  virt/kvm/arm/vgic/vgic-mmio.c    | 56 ++++++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/vgic/vgic-mmio.h    | 11 ++++++++
>>>>  3 files changed, 69 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> index 69e96f7..448d1da 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> @@ -72,9 +72,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
>>>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_SET,
>>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ENABLE_CLEAR,
>>>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
>>>>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>>>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>>>> index 41cf4f4..077ae86 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>>>> @@ -46,6 +46,62 @@ void vgic_mmio_write_wi(struct kvm_vcpu *vcpu, gpa_t addr,
>>>>  	/* Ignore */
>>>>  }
>>>>  
>>>> +/*
>>>> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
>>>> + * of the enabled bit, so there is only one function for both here.
>>>> + */
>>>> +unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu,
>>>> +				    gpa_t addr, unsigned int len)
>>>> +{
>>>> +	u32 intid = (addr & 0x7f) * 8;
>>>
>>> is there anything we can do about this to make it more intuitive?  A
>>> macro to generate the mask/offset based on bits per interrupt or
>>> something?
>>
>> Untested (and thus probably wrong):
>>
>> #define VGIC_ADDR_IRQ_MASK(bits) ((1024 - 1) >> (4 - (bits))
> 
> What about if bits is 8?

Gnii. This should be ((1024 - 1) >> (4 - ffs(bits))

> Wouldn't GENMASK(bits + 10 - 2, 0) do the trick?

I really can't see how that works... It could be
GENMASK(10 - 1 - ffs(bits), 0) though.

>> #define VGIC_ADDR_IRQ_MULT(bits) (8 / (bits))
> 
> IROUTER has a bits_per_irq value of 64. We just don't need to call it
> from there, but it would be nice if it could cover this.
> But I don't know a neat solution for this either.

Me neither, but I don't see that as a major issue so far.

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
  2016-05-11 14:18         ` Andre Przywara
@ 2016-05-11 14:28           ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 14:28 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

On 11/05/16 15:18, Andre Przywara wrote:
> Would:
> 
> #define VGIC_ADDR_IRQ_MASK(bits) GENMASK_ULL((bits) + 10 - 1 - 1, 0)

Nonsense. Must be ... ilog2(bits) ..., of course.

Andre.

> #define VGIC_ADDR_TO_INTID(addr, bits) (((addr) &		\
> 			VGIC_ADDR_IRQ_MASK(bits)) * 64 / (bits) / 8)
> 
> work for all bitnesses?

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

* [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers
@ 2016-05-11 14:28           ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-11 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

On 11/05/16 15:18, Andre Przywara wrote:
> Would:
> 
> #define VGIC_ADDR_IRQ_MASK(bits) GENMASK_ULL((bits) + 10 - 1 - 1, 0)

Nonsense. Must be ... ilog2(bits) ..., of course.

Andre.

> #define VGIC_ADDR_TO_INTID(addr, bits) (((addr) &		\
> 			VGIC_ADDR_IRQ_MASK(bits)) * 64 / (bits) / 8)
> 
> work for all bitnesses?

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

* Re: [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
  2016-05-11 13:36             ` Andre Przywara
@ 2016-05-11 14:40               ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-11 14:40 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

On 11/05/16 14:36, Andre Przywara wrote:
> Hi,
> 
> On 11/05/16 14:27, Marc Zyngier wrote:
>> On 11/05/16 14:15, Christoffer Dall wrote:
>>> On Wed, May 11, 2016 at 01:51:36PM +0100, Marc Zyngier wrote:
>>>> On 11/05/16 13:05, Christoffer Dall wrote:
>>>>> On Fri, May 06, 2016 at 11:45:36AM +0100, Andre Przywara wrote:
>>>>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>>>>
>>>>>> Those three registers are v2 emulation specific, so their implementation
>>>>>> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
>>>>>> as their implementation is pretty simple.
>>>>>> When the guest enables the distributor, we kick all VCPUs to get
>>>>>> potentially pending interrupts serviced.
>>>>>>
>>>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>>> ---
>>>>>> Changelog RFC..v1:
>>>>>> - kick VCPUs is the distributor gets enabled
>>>>>> - improve comment
>>>>>>
>>>>>> Changelog v1 .. v2:
>>>>>> - adapt to new MMIO framework
>>>>>> - use switch() statements to improve readability
>>>>>>
>>>>>> Changelog v2 .. v3:
>>>>>> - add vgic_kick_vcpus() implementation
>>>>>>
>>>>>>  include/linux/irqchip/arm-gic.h  |  1 +
>>>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
>>>>>>  virt/kvm/arm/vgic/vgic.c         | 15 +++++++++++++
>>>>>>  virt/kvm/arm/vgic/vgic.h         |  4 ++++
>>>>>>  4 files changed, 67 insertions(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>>>>>> index be0d26f..fd05185 100644
>>>>>> --- a/include/linux/irqchip/arm-gic.h
>>>>>> +++ b/include/linux/irqchip/arm-gic.h
>>>>>> @@ -33,6 +33,7 @@
>>>>>>  
>>>>>>  #define GIC_DIST_CTRL			0x000
>>>>>>  #define GIC_DIST_CTR			0x004
>>>>>> +#define GIC_DIST_IIDR			0x008
>>>>>>  #define GIC_DIST_IGROUP			0x080
>>>>>>  #define GIC_DIST_ENABLE_SET		0x100
>>>>>>  #define GIC_DIST_ENABLE_CLEAR		0x180
>>>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>>>> index 2729a22..69e96f7 100644
>>>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>>>> @@ -20,9 +20,55 @@
>>>>>>  #include "vgic.h"
>>>>>>  #include "vgic-mmio.h"
>>>>>>  
>>>>>> +static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
>>>>>> +					    gpa_t addr, unsigned int len)
>>>>>> +{
>>>>>> +	u32 value;
>>>>>> +
>>>>>> +	switch (addr & 0x0c) {
>>>>>> +	case GIC_DIST_CTRL:
>>>>>> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
>>>>>> +		break;
>>>>>> +	case GIC_DIST_CTR:
>>>>>> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>>>>>> +		value = (value >> 5) - 1;
>>>>>> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
>>>>>> +		break;
>>>>>> +	case GIC_DIST_IIDR:
>>>>>> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
>>>>>> +		break;
>>>>>> +	default:
>>>>>> +		return 0;
>>>>>> +	}
>>>>>> +
>>>>>> +	return extract_bytes(value, addr & 3, len);
>>>>>> +}
>>>>>> +
>>>>>> +static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>>>>>> +				    gpa_t addr, unsigned int len,
>>>>>> +				    unsigned long val)
>>>>>> +{
>>>>>> +	switch (addr & 0x0c) {
>>>>>> +	case GIC_DIST_CTRL:
>>>>>> +		if (!(addr & 1)) {
>>>>>
>>>>> what is this !(addr & 1) check?
>>>>
>>>> We check that the write includes the lowest byte of the register. But as
>>>> we only have aligned accesses, it probably doesn't matter... I'll hack
>>>> that away.
>>>>
>>> where do we check to only have aligned accesses?
>>
>> Looks like a missing feature. The v2 spec says:
>>
>> 4.1.4 GIC register access
>> All registers support 32-bit word accesses with the access type defined
>> in Table 4-1 on page 4-73 and Table 4-2 on page 4-74.
>> In addition, the GICD_IPRIORITYRn, GICD_ITARGETSRn, GICD_CPENDSGIRn, and
>> GICD_SPENDSGIRn registers support byte accesses.
>>
>> Similar thing for v3 (8.1.3).
>>
>> By the look of it, we should add checks in all accessors. I'll get onto it.
> 
> What about to tag every register in our vgic_register_region with a
> possible access width and do a generic check in
> dispatch_mmio_{read,write}? Then we wouldn't need to touch every handler.

That's my plan.

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
@ 2016-05-11 14:40               ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-11 14:40 UTC (permalink / raw)
  To: linux-arm-kernel

On 11/05/16 14:36, Andre Przywara wrote:
> Hi,
> 
> On 11/05/16 14:27, Marc Zyngier wrote:
>> On 11/05/16 14:15, Christoffer Dall wrote:
>>> On Wed, May 11, 2016 at 01:51:36PM +0100, Marc Zyngier wrote:
>>>> On 11/05/16 13:05, Christoffer Dall wrote:
>>>>> On Fri, May 06, 2016 at 11:45:36AM +0100, Andre Przywara wrote:
>>>>>> From: Marc Zyngier <marc.zyngier@arm.com>
>>>>>>
>>>>>> Those three registers are v2 emulation specific, so their implementation
>>>>>> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
>>>>>> as their implementation is pretty simple.
>>>>>> When the guest enables the distributor, we kick all VCPUs to get
>>>>>> potentially pending interrupts serviced.
>>>>>>
>>>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>>> ---
>>>>>> Changelog RFC..v1:
>>>>>> - kick VCPUs is the distributor gets enabled
>>>>>> - improve comment
>>>>>>
>>>>>> Changelog v1 .. v2:
>>>>>> - adapt to new MMIO framework
>>>>>> - use switch() statements to improve readability
>>>>>>
>>>>>> Changelog v2 .. v3:
>>>>>> - add vgic_kick_vcpus() implementation
>>>>>>
>>>>>>  include/linux/irqchip/arm-gic.h  |  1 +
>>>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 48 +++++++++++++++++++++++++++++++++++++++-
>>>>>>  virt/kvm/arm/vgic/vgic.c         | 15 +++++++++++++
>>>>>>  virt/kvm/arm/vgic/vgic.h         |  4 ++++
>>>>>>  4 files changed, 67 insertions(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
>>>>>> index be0d26f..fd05185 100644
>>>>>> --- a/include/linux/irqchip/arm-gic.h
>>>>>> +++ b/include/linux/irqchip/arm-gic.h
>>>>>> @@ -33,6 +33,7 @@
>>>>>>  
>>>>>>  #define GIC_DIST_CTRL			0x000
>>>>>>  #define GIC_DIST_CTR			0x004
>>>>>> +#define GIC_DIST_IIDR			0x008
>>>>>>  #define GIC_DIST_IGROUP			0x080
>>>>>>  #define GIC_DIST_ENABLE_SET		0x100
>>>>>>  #define GIC_DIST_ENABLE_CLEAR		0x180
>>>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>>>> index 2729a22..69e96f7 100644
>>>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>>>> @@ -20,9 +20,55 @@
>>>>>>  #include "vgic.h"
>>>>>>  #include "vgic-mmio.h"
>>>>>>  
>>>>>> +static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
>>>>>> +					    gpa_t addr, unsigned int len)
>>>>>> +{
>>>>>> +	u32 value;
>>>>>> +
>>>>>> +	switch (addr & 0x0c) {
>>>>>> +	case GIC_DIST_CTRL:
>>>>>> +		value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
>>>>>> +		break;
>>>>>> +	case GIC_DIST_CTR:
>>>>>> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>>>>>> +		value = (value >> 5) - 1;
>>>>>> +		value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
>>>>>> +		break;
>>>>>> +	case GIC_DIST_IIDR:
>>>>>> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
>>>>>> +		break;
>>>>>> +	default:
>>>>>> +		return 0;
>>>>>> +	}
>>>>>> +
>>>>>> +	return extract_bytes(value, addr & 3, len);
>>>>>> +}
>>>>>> +
>>>>>> +static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>>>>>> +				    gpa_t addr, unsigned int len,
>>>>>> +				    unsigned long val)
>>>>>> +{
>>>>>> +	switch (addr & 0x0c) {
>>>>>> +	case GIC_DIST_CTRL:
>>>>>> +		if (!(addr & 1)) {
>>>>>
>>>>> what is this !(addr & 1) check?
>>>>
>>>> We check that the write includes the lowest byte of the register. But as
>>>> we only have aligned accesses, it probably doesn't matter... I'll hack
>>>> that away.
>>>>
>>> where do we check to only have aligned accesses?
>>
>> Looks like a missing feature. The v2 spec says:
>>
>> 4.1.4 GIC register access
>> All registers support 32-bit word accesses with the access type defined
>> in Table 4-1 on page 4-73 and Table 4-2 on page 4-74.
>> In addition, the GICD_IPRIORITYRn, GICD_ITARGETSRn, GICD_CPENDSGIRn, and
>> GICD_SPENDSGIRn registers support byte accesses.
>>
>> Similar thing for v3 (8.1.3).
>>
>> By the look of it, we should add checks in all accessors. I'll get onto it.
> 
> What about to tag every register in our vgic_register_region with a
> possible access width and do a generic check in
> dispatch_mmio_{read,write}? Then we wouldn't need to touch every handler.

That's my plan.

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 28/55] KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-12  8:32     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12  8:32 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 06, 2016 at 11:45:41AM +0100, Andre Przywara wrote:
> The config register handlers are shared between the v2 and v3
> emulation, so their implementation goes into vgic-mmio.c, to be
> easily referenced from the v3 emulation as well later.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  2 +-
>  virt/kvm/arm/vgic/vgic-mmio.c    | 46 ++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h    |  7 ++++++
>  3 files changed, 54 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 2e17250..2a953ec 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -88,7 +88,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 2),
> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index d7fe9e6..19fed56 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -321,6 +321,52 @@ void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
>  	}
>  }
>  
> +unsigned long vgic_mmio_read_config(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len)
> +{
> +	u32 intid = (addr & 0xff) * 4;
> +	u32 value = 0;
> +	int i;
> +
> +	for (i = 0; i < len * 4; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (irq->config == VGIC_CONFIG_EDGE)
> +			value |= (2U << (i * 2));
> +	}
> +
> +	return extract_bytes(value, addr & 3, len);
> +}
> +
> +void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
> +			    gpa_t addr, unsigned int len,
> +			    unsigned long val)
> +{
> +	u32 intid = (addr & 0xff) * 4;
> +	int i;
> +
> +	for (i = 0; i < len * 4; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (intid + i < 16)

s/16/VGIC_NR_SGIS/

> +			continue;

It's implementation defined if software can program the configuration of
PPIs, and since our timer code relies on its virtual PPI always being
level triggered, I think we should change the above to
VGIC_NR_PRIVATE_IRQS and then if someone ever needs a configurable
virtual PPI, we can add that later.

> +
> +		/*
> +		 * The spec says that interrupts must be disabled before
> +		 * changing the configuration to avoid UNDEFINED behaviour.
> +		 */

not sure what this comment tells us about the implementation?  Should we
check that the IRQ is disabled before proceeding?

> +
> +		spin_lock(&irq->irq_lock);
> +		if (test_bit(i * 2 + 1, &val)) {
> +			irq->config = VGIC_CONFIG_EDGE;
> +		} else {
> +			irq->config = VGIC_CONFIG_LEVEL;
> +			irq->pending = irq->line_level | irq->soft_pending;
> +		}
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
>  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 cd04ac5..884eb71 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -114,6 +114,13 @@ void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
>  			      gpa_t addr, unsigned int len,
>  			      unsigned long val);
>  
> +unsigned long vgic_mmio_read_config(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len);
> +
> +void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
> +			    gpa_t addr, unsigned int len,
> +			    unsigned long val);
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
>  #endif
> -- 
> 2.7.3
> 

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

* [PATCH v3 28/55] KVM: arm/arm64: vgic-new: Add CONFIG registers handlers
@ 2016-05-12  8:32     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12  8:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:41AM +0100, Andre Przywara wrote:
> The config register handlers are shared between the v2 and v3
> emulation, so their implementation goes into vgic-mmio.c, to be
> easily referenced from the v3 emulation as well later.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  2 +-
>  virt/kvm/arm/vgic/vgic-mmio.c    | 46 ++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h    |  7 ++++++
>  3 files changed, 54 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 2e17250..2a953ec 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -88,7 +88,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 2),
> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index d7fe9e6..19fed56 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -321,6 +321,52 @@ void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
>  	}
>  }
>  
> +unsigned long vgic_mmio_read_config(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len)
> +{
> +	u32 intid = (addr & 0xff) * 4;
> +	u32 value = 0;
> +	int i;
> +
> +	for (i = 0; i < len * 4; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (irq->config == VGIC_CONFIG_EDGE)
> +			value |= (2U << (i * 2));
> +	}
> +
> +	return extract_bytes(value, addr & 3, len);
> +}
> +
> +void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
> +			    gpa_t addr, unsigned int len,
> +			    unsigned long val)
> +{
> +	u32 intid = (addr & 0xff) * 4;
> +	int i;
> +
> +	for (i = 0; i < len * 4; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		if (intid + i < 16)

s/16/VGIC_NR_SGIS/

> +			continue;

It's implementation defined if software can program the configuration of
PPIs, and since our timer code relies on its virtual PPI always being
level triggered, I think we should change the above to
VGIC_NR_PRIVATE_IRQS and then if someone ever needs a configurable
virtual PPI, we can add that later.

> +
> +		/*
> +		 * The spec says that interrupts must be disabled before
> +		 * changing the configuration to avoid UNDEFINED behaviour.
> +		 */

not sure what this comment tells us about the implementation?  Should we
check that the IRQ is disabled before proceeding?

> +
> +		spin_lock(&irq->irq_lock);
> +		if (test_bit(i * 2 + 1, &val)) {
> +			irq->config = VGIC_CONFIG_EDGE;
> +		} else {
> +			irq->config = VGIC_CONFIG_LEVEL;
> +			irq->pending = irq->line_level | irq->soft_pending;
> +		}
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
>  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 cd04ac5..884eb71 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -114,6 +114,13 @@ void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
>  			      gpa_t addr, unsigned int len,
>  			      unsigned long val);
>  
> +unsigned long vgic_mmio_read_config(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len);
> +
> +void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
> +			    gpa_t addr, unsigned int len,
> +			    unsigned long val);
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
>  #endif
> -- 
> 2.7.3
> 

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

* Re: [PATCH v3 29/55] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-12  8:35     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12  8:35 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:45:42AM +0100, Andre Przywara wrote:
> The target register handlers are v2 emulation specific, so their
> implementation lives entirely in vgic-mmio-v2.c.
> We copy the old VGIC behaviour of assigning an IRQ to the first VCPU
> set in the target mask instead of making it possibly pending on
> multiple VCPUs.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - remove runtime VCPU determination from this v2-only register
> - fold in implementation of vgic_v2_irq_change_affinity()
> - replace ffs() with __ffs()
> 
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 43 +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 42 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 2a953ec..888529e 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -66,6 +66,47 @@ static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>  	}
>  }
>  
> +static unsigned long vgic_mmio_read_target(struct kvm_vcpu *vcpu,
> +					   gpa_t addr, unsigned int len)
> +{
> +	u32 intid = addr & 0x3ff;
> +	int i;
> +	u64 val = 0;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		val |= (u64)irq->targets << (i * 8);
> +	}
> +
> +	return val;

this register should allow byte access, so you're missing a call to
extract_bytes() ?


> +}
> +
> +static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
> +				   gpa_t addr, unsigned int len,
> +				   unsigned long val)
> +{
> +	u32 intid = addr & 0x3ff;
> +	int i;
> +
> +	/* GICD_ITARGETSR[0-7] are read-only */
> +	if (intid < VGIC_NR_PRIVATE_IRQS)
> +		return;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid + i);
> +		int target;
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		irq->targets = (val >> (i * 8)) & 0xff;

this doesn't seem right given byte accesses either, and I don't see the
fixups we have in the works fixing it...

> +		target = irq->targets ? __ffs(irq->targets) : 0;
> +		irq->target_vcpu = kvm_get_vcpu(vcpu->kvm, target);
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -86,7 +127,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>  		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +		vgic_mmio_read_target, vgic_mmio_write_target, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
>  		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
> -- 
> 2.7.3
> 

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

* [PATCH v3 29/55] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
@ 2016-05-12  8:35     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12  8:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:42AM +0100, Andre Przywara wrote:
> The target register handlers are v2 emulation specific, so their
> implementation lives entirely in vgic-mmio-v2.c.
> We copy the old VGIC behaviour of assigning an IRQ to the first VCPU
> set in the target mask instead of making it possibly pending on
> multiple VCPUs.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - remove runtime VCPU determination from this v2-only register
> - fold in implementation of vgic_v2_irq_change_affinity()
> - replace ffs() with __ffs()
> 
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 43 +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 42 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 2a953ec..888529e 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -66,6 +66,47 @@ static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>  	}
>  }
>  
> +static unsigned long vgic_mmio_read_target(struct kvm_vcpu *vcpu,
> +					   gpa_t addr, unsigned int len)
> +{
> +	u32 intid = addr & 0x3ff;
> +	int i;
> +	u64 val = 0;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		val |= (u64)irq->targets << (i * 8);
> +	}
> +
> +	return val;

this register should allow byte access, so you're missing a call to
extract_bytes() ?


> +}
> +
> +static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
> +				   gpa_t addr, unsigned int len,
> +				   unsigned long val)
> +{
> +	u32 intid = addr & 0x3ff;
> +	int i;
> +
> +	/* GICD_ITARGETSR[0-7] are read-only */
> +	if (intid < VGIC_NR_PRIVATE_IRQS)
> +		return;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid + i);
> +		int target;
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		irq->targets = (val >> (i * 8)) & 0xff;

this doesn't seem right given byte accesses either, and I don't see the
fixups we have in the works fixing it...

> +		target = irq->targets ? __ffs(irq->targets) : 0;
> +		irq->target_vcpu = kvm_get_vcpu(vcpu->kvm, target);
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -86,7 +127,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
>  		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +		vgic_mmio_read_target, vgic_mmio_write_target, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
>  		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
> -- 
> 2.7.3
> 

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

* Re: [PATCH v3 29/55] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
  2016-05-12  8:35     ` Christoffer Dall
@ 2016-05-12  8:39       ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-12  8:39 UTC (permalink / raw)
  To: Christoffer Dall, Andre Przywara; +Cc: linux-arm-kernel, kvmarm, kvm

On 12/05/16 09:35, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:42AM +0100, Andre Przywara wrote:
>> The target register handlers are v2 emulation specific, so their
>> implementation lives entirely in vgic-mmio-v2.c.
>> We copy the old VGIC behaviour of assigning an IRQ to the first VCPU
>> set in the target mask instead of making it possibly pending on
>> multiple VCPUs.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - remove runtime VCPU determination from this v2-only register
>> - fold in implementation of vgic_v2_irq_change_affinity()
>> - replace ffs() with __ffs()
>>
>> Changelog v1 .. v2:
>> - adapt to new MMIO framework
>>
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 43 +++++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 42 insertions(+), 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index 2a953ec..888529e 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -66,6 +66,47 @@ static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>>  	}
>>  }
>>  
>> +static unsigned long vgic_mmio_read_target(struct kvm_vcpu *vcpu,
>> +					   gpa_t addr, unsigned int len)
>> +{
>> +	u32 intid = addr & 0x3ff;
>> +	int i;
>> +	u64 val = 0;
>> +
>> +	for (i = 0; i < len; i++) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		val |= (u64)irq->targets << (i * 8);
>> +	}
>> +
>> +	return val;
> 
> this register should allow byte access, so you're missing a call to
> extract_bytes() ?
> 
> 
>> +}
>> +
>> +static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
>> +				   gpa_t addr, unsigned int len,
>> +				   unsigned long val)
>> +{
>> +	u32 intid = addr & 0x3ff;
>> +	int i;
>> +
>> +	/* GICD_ITARGETSR[0-7] are read-only */
>> +	if (intid < VGIC_NR_PRIVATE_IRQS)
>> +		return;
>> +
>> +	for (i = 0; i < len; i++) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid + i);
>> +		int target;
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		irq->targets = (val >> (i * 8)) & 0xff;
> 
> this doesn't seem right given byte accesses either, and I don't see the
> fixups we have in the works fixing it...

I'll give it a whirl. the priority stuff needs addressing as well.

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 29/55] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
@ 2016-05-12  8:39       ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-12  8:39 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/05/16 09:35, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:42AM +0100, Andre Przywara wrote:
>> The target register handlers are v2 emulation specific, so their
>> implementation lives entirely in vgic-mmio-v2.c.
>> We copy the old VGIC behaviour of assigning an IRQ to the first VCPU
>> set in the target mask instead of making it possibly pending on
>> multiple VCPUs.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - remove runtime VCPU determination from this v2-only register
>> - fold in implementation of vgic_v2_irq_change_affinity()
>> - replace ffs() with __ffs()
>>
>> Changelog v1 .. v2:
>> - adapt to new MMIO framework
>>
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 43 +++++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 42 insertions(+), 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index 2a953ec..888529e 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -66,6 +66,47 @@ static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>>  	}
>>  }
>>  
>> +static unsigned long vgic_mmio_read_target(struct kvm_vcpu *vcpu,
>> +					   gpa_t addr, unsigned int len)
>> +{
>> +	u32 intid = addr & 0x3ff;
>> +	int i;
>> +	u64 val = 0;
>> +
>> +	for (i = 0; i < len; i++) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
>> +
>> +		val |= (u64)irq->targets << (i * 8);
>> +	}
>> +
>> +	return val;
> 
> this register should allow byte access, so you're missing a call to
> extract_bytes() ?
> 
> 
>> +}
>> +
>> +static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
>> +				   gpa_t addr, unsigned int len,
>> +				   unsigned long val)
>> +{
>> +	u32 intid = addr & 0x3ff;
>> +	int i;
>> +
>> +	/* GICD_ITARGETSR[0-7] are read-only */
>> +	if (intid < VGIC_NR_PRIVATE_IRQS)
>> +		return;
>> +
>> +	for (i = 0; i < len; i++) {
>> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid + i);
>> +		int target;
>> +
>> +		spin_lock(&irq->irq_lock);
>> +
>> +		irq->targets = (val >> (i * 8)) & 0xff;
> 
> this doesn't seem right given byte accesses either, and I don't see the
> fixups we have in the works fixing it...

I'll give it a whirl. the priority stuff needs addressing as well.

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 30/55] KVM: arm/arm64: vgic-new: Add SGIR register handler
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-12  8:40     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12  8:40 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 06, 2016 at 11:45:43AM +0100, Andre Przywara wrote:
> Triggering an IPI via this register is v2 specific, so the
> implementation lives entirely in vgic-mmio-v2.c.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - silently return on illegal TargetListFilter value (=3)
> 
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 43 +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 42 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 888529e..8f8ea57 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -66,6 +66,47 @@ static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>  	}
>  }
>  
> +static void vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
> +				 gpa_t addr, unsigned int len,
> +				 unsigned long val)
> +{
> +	int nr_vcpus = atomic_read(&source_vcpu->kvm->online_vcpus);
> +	int intid = val & 0xf;
> +	int targets = (val >> 16) & 0xff;
> +	int mode = (val >> 24) & 0x03;
> +	int c;
> +	struct kvm_vcpu *vcpu;
> +
> +	switch (mode) {
> +	case 0x0:		/* as specified by targets */
> +		break;
> +	case 0x1:
> +		targets = (1U << nr_vcpus) - 1;			/* all, ... */
> +		targets &= ~(1U << source_vcpu->vcpu_id);	/* but self */
> +		break;
> +	case 0x2:		/* this very vCPU only */
> +		targets = (1U << source_vcpu->vcpu_id);
> +		break;
> +	case 0x3:		/* reserved */
> +		return;
> +	}
> +
> +	kvm_for_each_vcpu(c, vcpu, source_vcpu->kvm) {
> +		struct vgic_irq *irq;
> +
> +		if (!(targets & (1U << c)))
> +			continue;
> +
> +		irq = vgic_get_irq(source_vcpu->kvm, vcpu, intid);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->pending = true;
> +		irq->source |= 1U << source_vcpu->vcpu_id;
> +
> +		vgic_queue_irq_unlock(source_vcpu->kvm, irq);
> +	}
> +}
> +
>  static unsigned long vgic_mmio_read_target(struct kvm_vcpu *vcpu,
>  					   gpa_t addr, unsigned int len)
>  {
> @@ -131,7 +172,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
>  		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +		vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

(assuming the alignment check is fixed by other patches)

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

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

* [PATCH v3 30/55] KVM: arm/arm64: vgic-new: Add SGIR register handler
@ 2016-05-12  8:40     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12  8:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:43AM +0100, Andre Przywara wrote:
> Triggering an IPI via this register is v2 specific, so the
> implementation lives entirely in vgic-mmio-v2.c.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - silently return on illegal TargetListFilter value (=3)
> 
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 43 +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 42 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 888529e..8f8ea57 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -66,6 +66,47 @@ static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
>  	}
>  }
>  
> +static void vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
> +				 gpa_t addr, unsigned int len,
> +				 unsigned long val)
> +{
> +	int nr_vcpus = atomic_read(&source_vcpu->kvm->online_vcpus);
> +	int intid = val & 0xf;
> +	int targets = (val >> 16) & 0xff;
> +	int mode = (val >> 24) & 0x03;
> +	int c;
> +	struct kvm_vcpu *vcpu;
> +
> +	switch (mode) {
> +	case 0x0:		/* as specified by targets */
> +		break;
> +	case 0x1:
> +		targets = (1U << nr_vcpus) - 1;			/* all, ... */
> +		targets &= ~(1U << source_vcpu->vcpu_id);	/* but self */
> +		break;
> +	case 0x2:		/* this very vCPU only */
> +		targets = (1U << source_vcpu->vcpu_id);
> +		break;
> +	case 0x3:		/* reserved */
> +		return;
> +	}
> +
> +	kvm_for_each_vcpu(c, vcpu, source_vcpu->kvm) {
> +		struct vgic_irq *irq;
> +
> +		if (!(targets & (1U << c)))
> +			continue;
> +
> +		irq = vgic_get_irq(source_vcpu->kvm, vcpu, intid);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->pending = true;
> +		irq->source |= 1U << source_vcpu->vcpu_id;
> +
> +		vgic_queue_irq_unlock(source_vcpu->kvm, irq);
> +	}
> +}
> +
>  static unsigned long vgic_mmio_read_target(struct kvm_vcpu *vcpu,
>  					   gpa_t addr, unsigned int len)
>  {
> @@ -131,7 +172,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
>  		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +		vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

(assuming the alignment check is fixed by other patches)

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

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

* Re: [PATCH v3 29/55] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
  2016-05-12  8:35     ` Christoffer Dall
@ 2016-05-12  8:54       ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12  8:54 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Thu, May 12, 2016 at 10:35:49AM +0200, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:42AM +0100, Andre Przywara wrote:
> > The target register handlers are v2 emulation specific, so their
> > implementation lives entirely in vgic-mmio-v2.c.
> > We copy the old VGIC behaviour of assigning an IRQ to the first VCPU
> > set in the target mask instead of making it possibly pending on
> > multiple VCPUs.
> > 
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> > Changelog RFC..v1:
> > - remove runtime VCPU determination from this v2-only register
> > - fold in implementation of vgic_v2_irq_change_affinity()
> > - replace ffs() with __ffs()
> > 
> > Changelog v1 .. v2:
> > - adapt to new MMIO framework
> > 
> >  virt/kvm/arm/vgic/vgic-mmio-v2.c | 43 +++++++++++++++++++++++++++++++++++++++-
> >  1 file changed, 42 insertions(+), 1 deletion(-)
> > 
> > diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> > index 2a953ec..888529e 100644
> > --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> > +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> > @@ -66,6 +66,47 @@ static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
> >  	}
> >  }
> >  
> > +static unsigned long vgic_mmio_read_target(struct kvm_vcpu *vcpu,
> > +					   gpa_t addr, unsigned int len)
> > +{
> > +	u32 intid = addr & 0x3ff;
> > +	int i;
> > +	u64 val = 0;
> > +
> > +	for (i = 0; i < len; i++) {
> > +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> > +
> > +		val |= (u64)irq->targets << (i * 8);
> > +	}
> > +
> > +	return val;
> 
> this register should allow byte access, so you're missing a call to
> extract_bytes() ?
> 
Strike that, not enough coffee this morning.

I was in the mindset that val was always being constructed as the full
32-bit register value.

> 
> > +}
> > +
> > +static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
> > +				   gpa_t addr, unsigned int len,
> > +				   unsigned long val)
> > +{
> > +	u32 intid = addr & 0x3ff;
> > +	int i;
> > +
> > +	/* GICD_ITARGETSR[0-7] are read-only */
> > +	if (intid < VGIC_NR_PRIVATE_IRQS)
> > +		return;
> > +
> > +	for (i = 0; i < len; i++) {
> > +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid + i);
> > +		int target;
> > +
> > +		spin_lock(&irq->irq_lock);
> > +
> > +		irq->targets = (val >> (i * 8)) & 0xff;
> 
> this doesn't seem right given byte accesses either, and I don't see the
> fixups we have in the works fixing it...
> 

Strike that too, sorry.

-Christoffer

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

* [PATCH v3 29/55] KVM: arm/arm64: vgic-new: Add TARGET registers handlers
@ 2016-05-12  8:54       ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12  8:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 12, 2016 at 10:35:49AM +0200, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:42AM +0100, Andre Przywara wrote:
> > The target register handlers are v2 emulation specific, so their
> > implementation lives entirely in vgic-mmio-v2.c.
> > We copy the old VGIC behaviour of assigning an IRQ to the first VCPU
> > set in the target mask instead of making it possibly pending on
> > multiple VCPUs.
> > 
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> > Changelog RFC..v1:
> > - remove runtime VCPU determination from this v2-only register
> > - fold in implementation of vgic_v2_irq_change_affinity()
> > - replace ffs() with __ffs()
> > 
> > Changelog v1 .. v2:
> > - adapt to new MMIO framework
> > 
> >  virt/kvm/arm/vgic/vgic-mmio-v2.c | 43 +++++++++++++++++++++++++++++++++++++++-
> >  1 file changed, 42 insertions(+), 1 deletion(-)
> > 
> > diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> > index 2a953ec..888529e 100644
> > --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> > +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> > @@ -66,6 +66,47 @@ static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
> >  	}
> >  }
> >  
> > +static unsigned long vgic_mmio_read_target(struct kvm_vcpu *vcpu,
> > +					   gpa_t addr, unsigned int len)
> > +{
> > +	u32 intid = addr & 0x3ff;
> > +	int i;
> > +	u64 val = 0;
> > +
> > +	for (i = 0; i < len; i++) {
> > +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> > +
> > +		val |= (u64)irq->targets << (i * 8);
> > +	}
> > +
> > +	return val;
> 
> this register should allow byte access, so you're missing a call to
> extract_bytes() ?
> 
Strike that, not enough coffee this morning.

I was in the mindset that val was always being constructed as the full
32-bit register value.

> 
> > +}
> > +
> > +static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
> > +				   gpa_t addr, unsigned int len,
> > +				   unsigned long val)
> > +{
> > +	u32 intid = addr & 0x3ff;
> > +	int i;
> > +
> > +	/* GICD_ITARGETSR[0-7] are read-only */
> > +	if (intid < VGIC_NR_PRIVATE_IRQS)
> > +		return;
> > +
> > +	for (i = 0; i < len; i++) {
> > +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid + i);
> > +		int target;
> > +
> > +		spin_lock(&irq->irq_lock);
> > +
> > +		irq->targets = (val >> (i * 8)) & 0xff;
> 
> this doesn't seem right given byte accesses either, and I don't see the
> fixups we have in the works fixing it...
> 

Strike that too, sorry.

-Christoffer

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

* Re: [PATCH v3 31/55] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-12  9:09     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12  9:09 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:45:44AM +0100, Andre Przywara wrote:
> As this register is v2 specific, its implementation lives entirely
> in vgic-mmio-v2.c.
> This register allows setting the source mask of an IPI.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - remove IRQ lock from read handler
> - update pending bit on setting the first / clearing the last bit
> - queue virtual IRQ if necessary
> 
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 62 ++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 60 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 8f8ea57..8006ac0 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -148,6 +148,64 @@ static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
>  	}
>  }
>  
> +static unsigned long vgic_mmio_read_sgipend(struct kvm_vcpu *vcpu,
> +					    gpa_t addr, unsigned int len)
> +{
> +	u32 intid = addr & 0x0f;
> +	int i;
> +	u64 val = 0;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		val |= (u64)irq->source << (i * 8);
> +	}
> +	return val;
> +}
> +
> +static void vgic_mmio_write_sgipendc(struct kvm_vcpu *vcpu,
> +				     gpa_t addr, unsigned int len,
> +				     unsigned long val)
> +{
> +	u32 intid = addr & 0x0f;
> +	int i;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		irq->source &= ~((val >> (i * 8)) & 0xff);
> +		if (!irq->source)
> +			irq->pending = false;
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
> +				     gpa_t addr, unsigned int len,
> +				     unsigned long val)
> +{
> +	u32 intid = addr & 0x0f;
> +	int i;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		irq->source |= (val >> (i * 8)) & 0xff;
> +
> +		if (irq->source) {
> +			irq->pending = true;
> +			vgic_queue_irq_unlock(vcpu->kvm, irq);
> +		} else {
> +			spin_unlock(&irq->irq_lock);
> +		}
> +	}
> +}
> +
>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -174,9 +232,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
>  		vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> +		vgic_mmio_read_sgipend, vgic_mmio_write_sgipendc, 16),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> +		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
>  };
>  
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
> -- 
> 2.7.3
> 

Again, assuming alignment checking is fixed:

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

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

* [PATCH v3 31/55] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers
@ 2016-05-12  9:09     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12  9:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:44AM +0100, Andre Przywara wrote:
> As this register is v2 specific, its implementation lives entirely
> in vgic-mmio-v2.c.
> This register allows setting the source mask of an IPI.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - remove IRQ lock from read handler
> - update pending bit on setting the first / clearing the last bit
> - queue virtual IRQ if necessary
> 
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c | 62 ++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 60 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 8f8ea57..8006ac0 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -148,6 +148,64 @@ static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
>  	}
>  }
>  
> +static unsigned long vgic_mmio_read_sgipend(struct kvm_vcpu *vcpu,
> +					    gpa_t addr, unsigned int len)
> +{
> +	u32 intid = addr & 0x0f;
> +	int i;
> +	u64 val = 0;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		val |= (u64)irq->source << (i * 8);
> +	}
> +	return val;
> +}
> +
> +static void vgic_mmio_write_sgipendc(struct kvm_vcpu *vcpu,
> +				     gpa_t addr, unsigned int len,
> +				     unsigned long val)
> +{
> +	u32 intid = addr & 0x0f;
> +	int i;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		irq->source &= ~((val >> (i * 8)) & 0xff);
> +		if (!irq->source)
> +			irq->pending = false;
> +
> +		spin_unlock(&irq->irq_lock);
> +	}
> +}
> +
> +static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
> +				     gpa_t addr, unsigned int len,
> +				     unsigned long val)
> +{
> +	u32 intid = addr & 0x0f;
> +	int i;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +
> +		irq->source |= (val >> (i * 8)) & 0xff;
> +
> +		if (irq->source) {
> +			irq->pending = true;
> +			vgic_queue_irq_unlock(vcpu->kvm, irq);
> +		} else {
> +			spin_unlock(&irq->irq_lock);
> +		}
> +	}
> +}
> +
>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -174,9 +232,9 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SOFTINT,
>  		vgic_mmio_read_raz, vgic_mmio_write_sgir, 4),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_CLEAR,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> +		vgic_mmio_read_sgipend, vgic_mmio_write_sgipendc, 16),
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_SGI_PENDING_SET,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> +		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
>  };
>  
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
> -- 
> 2.7.3
> 

Again, assuming alignment checking is fixed:

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

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

* Re: [PATCH v3 27/55] KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-12  9:10     ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-12  9:10 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall
  Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> The priority register handlers are shared between the v2 and v3
> emulation, so their implementation goes into vgic-mmio.c, to be
> easily referenced from the v3 emulation as well later.
> There is a corner case when we change the priority of a pending
> interrupt which we don't handle at the moment.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  2 +-
>  virt/kvm/arm/vgic/vgic-mmio.c    | 39 +++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h    |  7 +++++++
>  3 files changed, 47 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 054b52d..2e17250 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -84,7 +84,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
>  		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index dbf683e..d7fe9e6 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -282,6 +282,45 @@ retry:
>  	}
>  }
>  
> +unsigned long vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
> +				      gpa_t addr, unsigned int len)
> +{
> +	u32 intid = addr & 0x3ff;
> +	int i;
> +	u64 val = 0;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		val |= (u64)irq->priority << (i * 8);
> +	}
> +
> +	return val;
> +}
> +
> +/*
> + * We currently don't handle changing the priority of an interrupt that
> + * is already pending on a VCPU. If there is a need for this, we would
> + * need to make this VCPU exit and re-evaluate the priorities, potentially
> + * leading to this interrupt getting presented now to the guest (if it has
> + * been masked by the priority mask before).
> + */
> +void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
> +			      gpa_t addr, unsigned int len,
> +			      unsigned long val)
> +{
> +	u32 intid = addr & 0x3ff;
> +	int i;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->priority = (val >> (i * 8)) & 0xff;

This is wrong. We should only write the number of bits of priority we
actually emulate. And given that we use a common framework for v2 and
v3, this should probably be 5 bits (32 priorities should be enough for
everybody).

I'll try and cook something.

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 27/55] KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
@ 2016-05-12  9:10     ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-12  9:10 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> The priority register handlers are shared between the v2 and v3
> emulation, so their implementation goes into vgic-mmio.c, to be
> easily referenced from the v3 emulation as well later.
> There is a corner case when we change the priority of a pending
> interrupt which we don't handle at the moment.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v2.c |  2 +-
>  virt/kvm/arm/vgic/vgic-mmio.c    | 39 +++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.h    |  7 +++++++
>  3 files changed, 47 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index 054b52d..2e17250 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -84,7 +84,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_CLEAR,
>  		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PRI,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_TARGET,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_CONFIG,
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index dbf683e..d7fe9e6 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -282,6 +282,45 @@ retry:
>  	}
>  }
>  
> +unsigned long vgic_mmio_read_priority(struct kvm_vcpu *vcpu,
> +				      gpa_t addr, unsigned int len)
> +{
> +	u32 intid = addr & 0x3ff;
> +	int i;
> +	u64 val = 0;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		val |= (u64)irq->priority << (i * 8);
> +	}
> +
> +	return val;
> +}
> +
> +/*
> + * We currently don't handle changing the priority of an interrupt that
> + * is already pending on a VCPU. If there is a need for this, we would
> + * need to make this VCPU exit and re-evaluate the priorities, potentially
> + * leading to this interrupt getting presented now to the guest (if it has
> + * been masked by the priority mask before).
> + */
> +void vgic_mmio_write_priority(struct kvm_vcpu *vcpu,
> +			      gpa_t addr, unsigned int len,
> +			      unsigned long val)
> +{
> +	u32 intid = addr & 0x3ff;
> +	int i;
> +
> +	for (i = 0; i < len; i++) {
> +		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->priority = (val >> (i * 8)) & 0xff;

This is wrong. We should only write the number of bits of priority we
actually emulate. And given that we use a common framework for v2 and
v3, this should probably be 5 bits (32 priorities should be enough for
everybody).

I'll try and cook something.

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 27/55] KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
  2016-05-12  9:10     ` Marc Zyngier
@ 2016-05-12  9:56       ` Peter Maydell
  -1 siblings, 0 replies; 400+ messages in thread
From: Peter Maydell @ 2016-05-12  9:56 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: Andre Przywara, kvm-devel, arm-mail-list, kvmarm

On 12 May 2016 at 10:10, Marc Zyngier <marc.zyngier@arm.com> wrote:
> This is wrong. We should only write the number of bits of priority we
> actually emulate. And given that we use a common framework for v2 and
> v3, this should probably be 5 bits (32 priorities should be enough for
> everybody).

FWIW QEMU's GICv2 and GICv3 emulations both implement the full
8 bits of priority.

thanks
-- PMM

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

* [PATCH v3 27/55] KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
@ 2016-05-12  9:56       ` Peter Maydell
  0 siblings, 0 replies; 400+ messages in thread
From: Peter Maydell @ 2016-05-12  9:56 UTC (permalink / raw)
  To: linux-arm-kernel

On 12 May 2016 at 10:10, Marc Zyngier <marc.zyngier@arm.com> wrote:
> This is wrong. We should only write the number of bits of priority we
> actually emulate. And given that we use a common framework for v2 and
> v3, this should probably be 5 bits (32 priorities should be enough for
> everybody).

FWIW QEMU's GICv2 and GICv3 emulations both implement the full
8 bits of priority.

thanks
-- PMM

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

* Re: [PATCH v3 27/55] KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
  2016-05-12  9:56       ` Peter Maydell
@ 2016-05-12 10:09         ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-12 10:09 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Andre Przywara, Christoffer Dall, arm-mail-list, kvmarm, kvm-devel

On 12/05/16 10:56, Peter Maydell wrote:
> On 12 May 2016 at 10:10, Marc Zyngier <marc.zyngier@arm.com> wrote:
>> This is wrong. We should only write the number of bits of priority we
>> actually emulate. And given that we use a common framework for v2 and
>> v3, this should probably be 5 bits (32 priorities should be enough for
>> everybody).
> 
> FWIW QEMU's GICv2 and GICv3 emulations both implement the full
> 8 bits of priority.

On GICv2, GICH_APR is only 32bit, implying that a guest can only ever
use 5 bits of priority. GICH_VTR also says that the only allowed value
for PRIbits is 32 priority levels (iow 5 bits).

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 27/55] KVM: arm/arm64: vgic-new: Add PRIORITY registers handlers
@ 2016-05-12 10:09         ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-12 10:09 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/05/16 10:56, Peter Maydell wrote:
> On 12 May 2016 at 10:10, Marc Zyngier <marc.zyngier@arm.com> wrote:
>> This is wrong. We should only write the number of bits of priority we
>> actually emulate. And given that we use a common framework for v2 and
>> v3, this should probably be 5 bits (32 priorities should be enough for
>> everybody).
> 
> FWIW QEMU's GICv2 and GICv3 emulations both implement the full
> 8 bits of priority.

On GICv2, GICH_APR is only 32bit, implying that a guest can only ever
use 5 bits of priority. GICH_VTR also says that the only allowed value
for PRIbits is 32 priority levels (iow 5 bits).

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 32/55] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-12 10:26     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 10:26 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 06, 2016 at 11:45:45AM +0100, Andre Przywara wrote:
> Create a new file called vgic-mmio-v3.c and describe the GICv3
> distributor and redistributor registers there.
> This adds a special macro to deal with the split of SGI/PPI in the
> redistributor and SPIs in the distributor, which allows us to reuse
> the existing GICv2 handlers for those registers which are compatible.
> Also we provide a function to deal with the registration of the two
> separate redistributor frames per VCPU.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Reviewed-by: Eric Auger <eric.auger@linaro.org>
> ---
> Changelog RFC..v1:
> - adapt to new MMIO registration approach:
>   register one device for the distributor and two for each VCPU
> - implement special handling for private interrupts
> - remove empty stub functions
> - make IGROUPR return RAO
> 
> Changelog v1 .. v2:
> - adapt to new framework, introduce vgic-mmio-v3.c
> - remove userland register access functions (for now)
> - precompute .len when describing a VGIC register
> - add missed pointer incrementation on registering redist regions
> - replace _nyi stub functions with raz/wi versions
> 
> Changelog v2 .. v3:
> - replace inclusion of kvm/vgic/vgic.h with kvm/arm_vgic.h
> - add prototype and stub code for vgic_register_redist_iodevs
> - rename register struct variables _rdbase_ and _sgibase_
> 
>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.c    |   5 +
>  virt/kvm/arm/vgic/vgic-mmio.h    |   2 +
>  virt/kvm/arm/vgic/vgic.h         |   7 ++
>  4 files changed, 205 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> new file mode 100644
> index 0000000..06c7ec5
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -0,0 +1,191 @@
> +/*
> + * VGICv3 MMIO 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 <kvm/iodev.h>
> +#include <kvm/arm_vgic.h>
> +
> +#include <asm/kvm_emulate.h>
> +
> +#include "vgic.h"
> +#include "vgic-mmio.h"
> +
> +/*
> + * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
> + * redistributors, while SPIs are covered by registers in the distributor
> + * block. Trying to set private IRQs in this block gets ignored.
> + * We take some special care here to fix the calculation of the register
> + * offset.
> + */
> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, read_ops, write_ops, bpi) \
> +	{								\
> +		.reg_offset = off,					\
> +		.bits_per_irq = bpi,					\
> +		.len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8,		\
> +		.read = vgic_mmio_read_raz,				\
> +		.write = vgic_mmio_write_wi,				\
> +	}, {								\
> +		.reg_offset = off + (bpi * VGIC_NR_PRIVATE_IRQS) / 8,	\
> +		.bits_per_irq = bpi,					\
> +		.len = (bpi * (1024 - VGIC_NR_PRIVATE_IRQS)) / 8,	\
> +		.read = read_ops,					\
> +		.write = write_ops,					\
> +	}
> +
> +static const struct vgic_register_region vgic_v3_dist_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
> +	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
> +};
> +
> +static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
> +};
> +
> +static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
> +		vgic_mmio_read_config, vgic_mmio_write_config, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +};
> +
> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
> +{
> +	dev->regions = vgic_v3_dist_registers;
> +	dev->nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
> +
> +	kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
> +
> +	return SZ_64K;
> +}
> +
> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
> +{
> +	int nr_vcpus = atomic_read(&kvm->online_vcpus);
> +	struct kvm_vcpu *vcpu;
> +	struct vgic_io_device *devices, *device;
> +	int c, ret = 0;
> +
> +	devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
> +			  GFP_KERNEL);
> +	if (!devices)
> +		return -ENOMEM;
> +
> +	device = devices;
> +	kvm_for_each_vcpu(c, vcpu, kvm) {
> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
> +		device->base_addr = redist_base_address;
> +		device->regions = vgic_v3_rdbase_registers;
> +		device->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
> +		device->redist_vcpu = vcpu;
> +
> +		mutex_lock(&kvm->slots_lock);
> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> +					      redist_base_address,
> +					      SZ_64K, &device->dev);
> +		mutex_unlock(&kvm->slots_lock);
> +
> +		if (ret)
> +			break;
> +
> +		device++;
> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
> +		device->base_addr = redist_base_address + SZ_64K;
> +		device->regions = vgic_v3_sgibase_registers;
> +		device->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
> +		device->redist_vcpu = vcpu;
> +
> +		mutex_lock(&kvm->slots_lock);
> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> +					      redist_base_address + SZ_64K,
> +					      SZ_64K, &device->dev);
> +		mutex_unlock(&kvm->slots_lock);
> +		if (ret) {
> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
> +						  &devices[c * 2].dev);
> +			break;
> +		}
> +		device++;
> +		redist_base_address += 2 * SZ_64K;

while I think this whole thing is actually correct, I think it could
have been much more clear by, in the beginning of the loop doing:

	gpa_t rd_base = redist_base_address + c * SZ_64K * 2;
	gpa_t sgi_base = rd_base + SZ_64K;
	struct vgic_io_device *rd_dev = &devices[c];
	struct vgic_io_device *sgi_dev = &devices[c + 1];

and then referring directly to these variables.

> +	}
> +
> +	if (ret) {
> +		for (c--; c >= 0; c--) {

holy dark mother of all that's evil; I think this is correct.

> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
> +						  &devices[c * 2].dev);
> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
> +						  &devices[c * 2 + 1].dev);

do we really need this though?  Can't we just rely on KVM to tear down
thew whole bus infrastructure as we're returning an error anyway?

(have you looked at what the unregister_dev function does, it's full of
kmallocs and other fun stuff).


Thanks,
-Christoffer

> +		}
> +		kfree(devices);
> +	} else {
> +		kvm->arch.vgic.redist_iodevs = devices;
> +	}
> +
> +	return ret;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index 19fed56..d1b88d2 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -502,6 +502,11 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
>  	case VGIC_V2:
>  		len = vgic_v2_init_dist_iodev(io_device);
>  		break;
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +	case VGIC_V3:
> +		len = vgic_v3_init_dist_iodev(io_device);
> +		break;
> +#endif
>  	default:
>  		BUG_ON(1);
>  	}
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
> index 884eb71..3585ac6 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -123,4 +123,6 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>  
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
> +
>  #endif
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index cf62015..39a8a65 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -40,6 +40,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
>  void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
>  #else
>  static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
>  {
> @@ -61,6 +62,12 @@ static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
>  static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>  {
>  }
> +
> +static inline int vgic_register_redist_iodevs(struct kvm *kvm,
> +					      gpa_t dist_base_address)
> +{
> +	return -ENODEV;
> +}
>  #endif
>  
>  #endif
> -- 
> 2.7.3
> 

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

* [PATCH v3 32/55] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
@ 2016-05-12 10:26     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 10:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:45AM +0100, Andre Przywara wrote:
> Create a new file called vgic-mmio-v3.c and describe the GICv3
> distributor and redistributor registers there.
> This adds a special macro to deal with the split of SGI/PPI in the
> redistributor and SPIs in the distributor, which allows us to reuse
> the existing GICv2 handlers for those registers which are compatible.
> Also we provide a function to deal with the registration of the two
> separate redistributor frames per VCPU.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Reviewed-by: Eric Auger <eric.auger@linaro.org>
> ---
> Changelog RFC..v1:
> - adapt to new MMIO registration approach:
>   register one device for the distributor and two for each VCPU
> - implement special handling for private interrupts
> - remove empty stub functions
> - make IGROUPR return RAO
> 
> Changelog v1 .. v2:
> - adapt to new framework, introduce vgic-mmio-v3.c
> - remove userland register access functions (for now)
> - precompute .len when describing a VGIC register
> - add missed pointer incrementation on registering redist regions
> - replace _nyi stub functions with raz/wi versions
> 
> Changelog v2 .. v3:
> - replace inclusion of kvm/vgic/vgic.h with kvm/arm_vgic.h
> - add prototype and stub code for vgic_register_redist_iodevs
> - rename register struct variables _rdbase_ and _sgibase_
> 
>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-mmio.c    |   5 +
>  virt/kvm/arm/vgic/vgic-mmio.h    |   2 +
>  virt/kvm/arm/vgic/vgic.h         |   7 ++
>  4 files changed, 205 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> new file mode 100644
> index 0000000..06c7ec5
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -0,0 +1,191 @@
> +/*
> + * VGICv3 MMIO 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 <kvm/iodev.h>
> +#include <kvm/arm_vgic.h>
> +
> +#include <asm/kvm_emulate.h>
> +
> +#include "vgic.h"
> +#include "vgic-mmio.h"
> +
> +/*
> + * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
> + * redistributors, while SPIs are covered by registers in the distributor
> + * block. Trying to set private IRQs in this block gets ignored.
> + * We take some special care here to fix the calculation of the register
> + * offset.
> + */
> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, read_ops, write_ops, bpi) \
> +	{								\
> +		.reg_offset = off,					\
> +		.bits_per_irq = bpi,					\
> +		.len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8,		\
> +		.read = vgic_mmio_read_raz,				\
> +		.write = vgic_mmio_write_wi,				\
> +	}, {								\
> +		.reg_offset = off + (bpi * VGIC_NR_PRIVATE_IRQS) / 8,	\
> +		.bits_per_irq = bpi,					\
> +		.len = (bpi * (1024 - VGIC_NR_PRIVATE_IRQS)) / 8,	\
> +		.read = read_ops,					\
> +		.write = write_ops,					\
> +	}
> +
> +static const struct vgic_register_region vgic_v3_dist_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
> +	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
> +};
> +
> +static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
> +};
> +
> +static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
> +	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
> +		vgic_mmio_read_config, vgic_mmio_write_config, 8),
> +	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +};
> +
> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
> +{
> +	dev->regions = vgic_v3_dist_registers;
> +	dev->nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
> +
> +	kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
> +
> +	return SZ_64K;
> +}
> +
> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
> +{
> +	int nr_vcpus = atomic_read(&kvm->online_vcpus);
> +	struct kvm_vcpu *vcpu;
> +	struct vgic_io_device *devices, *device;
> +	int c, ret = 0;
> +
> +	devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
> +			  GFP_KERNEL);
> +	if (!devices)
> +		return -ENOMEM;
> +
> +	device = devices;
> +	kvm_for_each_vcpu(c, vcpu, kvm) {
> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
> +		device->base_addr = redist_base_address;
> +		device->regions = vgic_v3_rdbase_registers;
> +		device->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
> +		device->redist_vcpu = vcpu;
> +
> +		mutex_lock(&kvm->slots_lock);
> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> +					      redist_base_address,
> +					      SZ_64K, &device->dev);
> +		mutex_unlock(&kvm->slots_lock);
> +
> +		if (ret)
> +			break;
> +
> +		device++;
> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
> +		device->base_addr = redist_base_address + SZ_64K;
> +		device->regions = vgic_v3_sgibase_registers;
> +		device->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
> +		device->redist_vcpu = vcpu;
> +
> +		mutex_lock(&kvm->slots_lock);
> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
> +					      redist_base_address + SZ_64K,
> +					      SZ_64K, &device->dev);
> +		mutex_unlock(&kvm->slots_lock);
> +		if (ret) {
> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
> +						  &devices[c * 2].dev);
> +			break;
> +		}
> +		device++;
> +		redist_base_address += 2 * SZ_64K;

while I think this whole thing is actually correct, I think it could
have been much more clear by, in the beginning of the loop doing:

	gpa_t rd_base = redist_base_address + c * SZ_64K * 2;
	gpa_t sgi_base = rd_base + SZ_64K;
	struct vgic_io_device *rd_dev = &devices[c];
	struct vgic_io_device *sgi_dev = &devices[c + 1];

and then referring directly to these variables.

> +	}
> +
> +	if (ret) {
> +		for (c--; c >= 0; c--) {

holy dark mother of all that's evil; I think this is correct.

> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
> +						  &devices[c * 2].dev);
> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
> +						  &devices[c * 2 + 1].dev);

do we really need this though?  Can't we just rely on KVM to tear down
thew whole bus infrastructure as we're returning an error anyway?

(have you looked at what the unregister_dev function does, it's full of
kmallocs and other fun stuff).


Thanks,
-Christoffer

> +		}
> +		kfree(devices);
> +	} else {
> +		kvm->arch.vgic.redist_iodevs = devices;
> +	}
> +
> +	return ret;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index 19fed56..d1b88d2 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -502,6 +502,11 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
>  	case VGIC_V2:
>  		len = vgic_v2_init_dist_iodev(io_device);
>  		break;
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +	case VGIC_V3:
> +		len = vgic_v3_init_dist_iodev(io_device);
> +		break;
> +#endif
>  	default:
>  		BUG_ON(1);
>  	}
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
> index 884eb71..3585ac6 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.h
> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
> @@ -123,4 +123,6 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>  
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
> +
>  #endif
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index cf62015..39a8a65 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -40,6 +40,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
>  void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
>  #else
>  static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
>  {
> @@ -61,6 +62,12 @@ static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
>  static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>  {
>  }
> +
> +static inline int vgic_register_redist_iodevs(struct kvm *kvm,
> +					      gpa_t dist_base_address)
> +{
> +	return -ENODEV;
> +}
>  #endif
>  
>  #endif
> -- 
> 2.7.3
> 

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

* Re: [PATCH v3 32/55] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
  2016-05-12 10:26     ` Christoffer Dall
@ 2016-05-12 10:52       ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-12 10:52 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 12/05/16 11:26, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:45AM +0100, Andre Przywara wrote:
>> Create a new file called vgic-mmio-v3.c and describe the GICv3
>> distributor and redistributor registers there.
>> This adds a special macro to deal with the split of SGI/PPI in the
>> redistributor and SPIs in the distributor, which allows us to reuse
>> the existing GICv2 handlers for those registers which are compatible.
>> Also we provide a function to deal with the registration of the two
>> separate redistributor frames per VCPU.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> Reviewed-by: Eric Auger <eric.auger@linaro.org>
>> ---
>> Changelog RFC..v1:
>> - adapt to new MMIO registration approach:
>>   register one device for the distributor and two for each VCPU
>> - implement special handling for private interrupts
>> - remove empty stub functions
>> - make IGROUPR return RAO
>>
>> Changelog v1 .. v2:
>> - adapt to new framework, introduce vgic-mmio-v3.c
>> - remove userland register access functions (for now)
>> - precompute .len when describing a VGIC register
>> - add missed pointer incrementation on registering redist regions
>> - replace _nyi stub functions with raz/wi versions
>>
>> Changelog v2 .. v3:
>> - replace inclusion of kvm/vgic/vgic.h with kvm/arm_vgic.h
>> - add prototype and stub code for vgic_register_redist_iodevs
>> - rename register struct variables _rdbase_ and _sgibase_
>>
>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-mmio.c    |   5 +
>>  virt/kvm/arm/vgic/vgic-mmio.h    |   2 +
>>  virt/kvm/arm/vgic/vgic.h         |   7 ++
>>  4 files changed, 205 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> new file mode 100644
>> index 0000000..06c7ec5
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> @@ -0,0 +1,191 @@
>> +/*
>> + * VGICv3 MMIO 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 <kvm/iodev.h>
>> +#include <kvm/arm_vgic.h>
>> +
>> +#include <asm/kvm_emulate.h>
>> +
>> +#include "vgic.h"
>> +#include "vgic-mmio.h"
>> +
>> +/*
>> + * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
>> + * redistributors, while SPIs are covered by registers in the distributor
>> + * block. Trying to set private IRQs in this block gets ignored.
>> + * We take some special care here to fix the calculation of the register
>> + * offset.
>> + */
>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, read_ops, write_ops, bpi) \
>> +	{								\
>> +		.reg_offset = off,					\
>> +		.bits_per_irq = bpi,					\
>> +		.len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8,		\
>> +		.read = vgic_mmio_read_raz,				\
>> +		.write = vgic_mmio_write_wi,				\
>> +	}, {								\
>> +		.reg_offset = off + (bpi * VGIC_NR_PRIVATE_IRQS) / 8,	\
>> +		.bits_per_irq = bpi,					\
>> +		.len = (bpi * (1024 - VGIC_NR_PRIVATE_IRQS)) / 8,	\
>> +		.read = read_ops,					\
>> +		.write = write_ops,					\
>> +	}
>> +
>> +static const struct vgic_register_region vgic_v3_dist_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
>> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
>> +	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
>> +};
>> +
>> +static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
>> +};
>> +
>> +static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
>> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
>> +		vgic_mmio_read_config, vgic_mmio_write_config, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +};
>> +
>> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
>> +{
>> +	dev->regions = vgic_v3_dist_registers;
>> +	dev->nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
>> +
>> +	kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
>> +
>> +	return SZ_64K;
>> +}
>> +
>> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
>> +{
>> +	int nr_vcpus = atomic_read(&kvm->online_vcpus);
>> +	struct kvm_vcpu *vcpu;
>> +	struct vgic_io_device *devices, *device;
>> +	int c, ret = 0;
>> +
>> +	devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
>> +			  GFP_KERNEL);
>> +	if (!devices)
>> +		return -ENOMEM;
>> +
>> +	device = devices;
>> +	kvm_for_each_vcpu(c, vcpu, kvm) {
>> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>> +		device->base_addr = redist_base_address;
>> +		device->regions = vgic_v3_rdbase_registers;
>> +		device->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
>> +		device->redist_vcpu = vcpu;
>> +
>> +		mutex_lock(&kvm->slots_lock);
>> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> +					      redist_base_address,
>> +					      SZ_64K, &device->dev);
>> +		mutex_unlock(&kvm->slots_lock);
>> +
>> +		if (ret)
>> +			break;
>> +
>> +		device++;
>> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>> +		device->base_addr = redist_base_address + SZ_64K;
>> +		device->regions = vgic_v3_sgibase_registers;
>> +		device->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
>> +		device->redist_vcpu = vcpu;
>> +
>> +		mutex_lock(&kvm->slots_lock);
>> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> +					      redist_base_address + SZ_64K,
>> +					      SZ_64K, &device->dev);
>> +		mutex_unlock(&kvm->slots_lock);
>> +		if (ret) {
>> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> +						  &devices[c * 2].dev);
>> +			break;
>> +		}
>> +		device++;
>> +		redist_base_address += 2 * SZ_64K;
> 
> while I think this whole thing is actually correct, I think it could
> have been much more clear by, in the beginning of the loop doing:
> 
> 	gpa_t rd_base = redist_base_address + c * SZ_64K * 2;
> 	gpa_t sgi_base = rd_base + SZ_64K;
> 	struct vgic_io_device *rd_dev = &devices[c];
> 	struct vgic_io_device *sgi_dev = &devices[c + 1];
> 
> and then referring directly to these variables.

Yeah, looks useful, not sure we want to change it last minute though.

>> +	}
>> +
>> +	if (ret) {
>> +		for (c--; c >= 0; c--) {
> 
> holy dark mother of all that's evil; I think this is correct.
> 
>> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> +						  &devices[c * 2].dev);
>> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> +						  &devices[c * 2 + 1].dev);
> 
> do we really need this though?  Can't we just rely on KVM to tear down
> thew whole bus infrastructure as we're returning an error anyway?

I haven't checked if this is really necessary, but this missing teardown
was mentioned multiple times in previous reviews, so I just did it.
We can remove it once we have proven that it's pointless later.

> (have you looked at what the unregister_dev function does, it's full of
> kmallocs and other fun stuff).

TBH, this whole kvm_io_bus framework is really weird (I think
registering a new region copies every thing it had before) and designed
for the x86 use case. But it shouldn't be this series which fixes this.

Cheers,
Andre.

> 
> Thanks,
> -Christoffer
> 
>> +		}
>> +		kfree(devices);
>> +	} else {
>> +		kvm->arch.vgic.redist_iodevs = devices;
>> +	}
>> +
>> +	return ret;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>> index 19fed56..d1b88d2 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>> @@ -502,6 +502,11 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
>>  	case VGIC_V2:
>>  		len = vgic_v2_init_dist_iodev(io_device);
>>  		break;
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +	case VGIC_V3:
>> +		len = vgic_v3_init_dist_iodev(io_device);
>> +		break;
>> +#endif
>>  	default:
>>  		BUG_ON(1);
>>  	}
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
>> index 884eb71..3585ac6 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.h
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
>> @@ -123,4 +123,6 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>>  
>>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>>  
>> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
>> +
>>  #endif
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index cf62015..39a8a65 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -40,6 +40,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
>>  void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>>  void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
>>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
>> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
>>  #else
>>  static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
>>  {
>> @@ -61,6 +62,12 @@ static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
>>  static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>>  {
>>  }
>> +
>> +static inline int vgic_register_redist_iodevs(struct kvm *kvm,
>> +					      gpa_t dist_base_address)
>> +{
>> +	return -ENODEV;
>> +}
>>  #endif
>>  
>>  #endif
>> -- 
>> 2.7.3
>>
> 
> 

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

* [PATCH v3 32/55] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
@ 2016-05-12 10:52       ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-12 10:52 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 12/05/16 11:26, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:45AM +0100, Andre Przywara wrote:
>> Create a new file called vgic-mmio-v3.c and describe the GICv3
>> distributor and redistributor registers there.
>> This adds a special macro to deal with the split of SGI/PPI in the
>> redistributor and SPIs in the distributor, which allows us to reuse
>> the existing GICv2 handlers for those registers which are compatible.
>> Also we provide a function to deal with the registration of the two
>> separate redistributor frames per VCPU.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> Reviewed-by: Eric Auger <eric.auger@linaro.org>
>> ---
>> Changelog RFC..v1:
>> - adapt to new MMIO registration approach:
>>   register one device for the distributor and two for each VCPU
>> - implement special handling for private interrupts
>> - remove empty stub functions
>> - make IGROUPR return RAO
>>
>> Changelog v1 .. v2:
>> - adapt to new framework, introduce vgic-mmio-v3.c
>> - remove userland register access functions (for now)
>> - precompute .len when describing a VGIC register
>> - add missed pointer incrementation on registering redist regions
>> - replace _nyi stub functions with raz/wi versions
>>
>> Changelog v2 .. v3:
>> - replace inclusion of kvm/vgic/vgic.h with kvm/arm_vgic.h
>> - add prototype and stub code for vgic_register_redist_iodevs
>> - rename register struct variables _rdbase_ and _sgibase_
>>
>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-mmio.c    |   5 +
>>  virt/kvm/arm/vgic/vgic-mmio.h    |   2 +
>>  virt/kvm/arm/vgic/vgic.h         |   7 ++
>>  4 files changed, 205 insertions(+)
>>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> new file mode 100644
>> index 0000000..06c7ec5
>> --- /dev/null
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> @@ -0,0 +1,191 @@
>> +/*
>> + * VGICv3 MMIO 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 <kvm/iodev.h>
>> +#include <kvm/arm_vgic.h>
>> +
>> +#include <asm/kvm_emulate.h>
>> +
>> +#include "vgic.h"
>> +#include "vgic-mmio.h"
>> +
>> +/*
>> + * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
>> + * redistributors, while SPIs are covered by registers in the distributor
>> + * block. Trying to set private IRQs in this block gets ignored.
>> + * We take some special care here to fix the calculation of the register
>> + * offset.
>> + */
>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, read_ops, write_ops, bpi) \
>> +	{								\
>> +		.reg_offset = off,					\
>> +		.bits_per_irq = bpi,					\
>> +		.len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8,		\
>> +		.read = vgic_mmio_read_raz,				\
>> +		.write = vgic_mmio_write_wi,				\
>> +	}, {								\
>> +		.reg_offset = off + (bpi * VGIC_NR_PRIVATE_IRQS) / 8,	\
>> +		.bits_per_irq = bpi,					\
>> +		.len = (bpi * (1024 - VGIC_NR_PRIVATE_IRQS)) / 8,	\
>> +		.read = read_ops,					\
>> +		.write = write_ops,					\
>> +	}
>> +
>> +static const struct vgic_register_region vgic_v3_dist_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
>> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
>> +	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
>> +};
>> +
>> +static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
>> +};
>> +
>> +static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
>> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
>> +		vgic_mmio_read_config, vgic_mmio_write_config, 8),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>> +};
>> +
>> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
>> +{
>> +	dev->regions = vgic_v3_dist_registers;
>> +	dev->nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
>> +
>> +	kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
>> +
>> +	return SZ_64K;
>> +}
>> +
>> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
>> +{
>> +	int nr_vcpus = atomic_read(&kvm->online_vcpus);
>> +	struct kvm_vcpu *vcpu;
>> +	struct vgic_io_device *devices, *device;
>> +	int c, ret = 0;
>> +
>> +	devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
>> +			  GFP_KERNEL);
>> +	if (!devices)
>> +		return -ENOMEM;
>> +
>> +	device = devices;
>> +	kvm_for_each_vcpu(c, vcpu, kvm) {
>> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>> +		device->base_addr = redist_base_address;
>> +		device->regions = vgic_v3_rdbase_registers;
>> +		device->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
>> +		device->redist_vcpu = vcpu;
>> +
>> +		mutex_lock(&kvm->slots_lock);
>> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> +					      redist_base_address,
>> +					      SZ_64K, &device->dev);
>> +		mutex_unlock(&kvm->slots_lock);
>> +
>> +		if (ret)
>> +			break;
>> +
>> +		device++;
>> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>> +		device->base_addr = redist_base_address + SZ_64K;
>> +		device->regions = vgic_v3_sgibase_registers;
>> +		device->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
>> +		device->redist_vcpu = vcpu;
>> +
>> +		mutex_lock(&kvm->slots_lock);
>> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>> +					      redist_base_address + SZ_64K,
>> +					      SZ_64K, &device->dev);
>> +		mutex_unlock(&kvm->slots_lock);
>> +		if (ret) {
>> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> +						  &devices[c * 2].dev);
>> +			break;
>> +		}
>> +		device++;
>> +		redist_base_address += 2 * SZ_64K;
> 
> while I think this whole thing is actually correct, I think it could
> have been much more clear by, in the beginning of the loop doing:
> 
> 	gpa_t rd_base = redist_base_address + c * SZ_64K * 2;
> 	gpa_t sgi_base = rd_base + SZ_64K;
> 	struct vgic_io_device *rd_dev = &devices[c];
> 	struct vgic_io_device *sgi_dev = &devices[c + 1];
> 
> and then referring directly to these variables.

Yeah, looks useful, not sure we want to change it last minute though.

>> +	}
>> +
>> +	if (ret) {
>> +		for (c--; c >= 0; c--) {
> 
> holy dark mother of all that's evil; I think this is correct.
> 
>> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> +						  &devices[c * 2].dev);
>> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>> +						  &devices[c * 2 + 1].dev);
> 
> do we really need this though?  Can't we just rely on KVM to tear down
> thew whole bus infrastructure as we're returning an error anyway?

I haven't checked if this is really necessary, but this missing teardown
was mentioned multiple times in previous reviews, so I just did it.
We can remove it once we have proven that it's pointless later.

> (have you looked at what the unregister_dev function does, it's full of
> kmallocs and other fun stuff).

TBH, this whole kvm_io_bus framework is really weird (I think
registering a new region copies every thing it had before) and designed
for the x86 use case. But it shouldn't be this series which fixes this.

Cheers,
Andre.

> 
> Thanks,
> -Christoffer
> 
>> +		}
>> +		kfree(devices);
>> +	} else {
>> +		kvm->arch.vgic.redist_iodevs = devices;
>> +	}
>> +
>> +	return ret;
>> +}
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
>> index 19fed56..d1b88d2 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
>> @@ -502,6 +502,11 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
>>  	case VGIC_V2:
>>  		len = vgic_v2_init_dist_iodev(io_device);
>>  		break;
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +	case VGIC_V3:
>> +		len = vgic_v3_init_dist_iodev(io_device);
>> +		break;
>> +#endif
>>  	default:
>>  		BUG_ON(1);
>>  	}
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
>> index 884eb71..3585ac6 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio.h
>> +++ b/virt/kvm/arm/vgic/vgic-mmio.h
>> @@ -123,4 +123,6 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu,
>>  
>>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>>  
>> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev);
>> +
>>  #endif
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index cf62015..39a8a65 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -40,6 +40,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
>>  void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>>  void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
>>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
>> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
>>  #else
>>  static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
>>  {
>> @@ -61,6 +62,12 @@ static inline void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
>>  static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>>  {
>>  }
>> +
>> +static inline int vgic_register_redist_iodevs(struct kvm *kvm,
>> +					      gpa_t dist_base_address)
>> +{
>> +	return -ENODEV;
>> +}
>>  #endif
>>  
>>  #endif
>> -- 
>> 2.7.3
>>
> 
> 

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

* Re: [PATCH v3 32/55] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
  2016-05-12 10:52       ` Andre Przywara
@ 2016-05-12 10:58         ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-12 10:58 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall
  Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

On 12/05/16 11:52, Andre Przywara wrote:
> Hi,
> 
> On 12/05/16 11:26, Christoffer Dall wrote:
>> On Fri, May 06, 2016 at 11:45:45AM +0100, Andre Przywara wrote:
>>> Create a new file called vgic-mmio-v3.c and describe the GICv3
>>> distributor and redistributor registers there.
>>> This adds a special macro to deal with the split of SGI/PPI in the
>>> redistributor and SPIs in the distributor, which allows us to reuse
>>> the existing GICv2 handlers for those registers which are compatible.
>>> Also we provide a function to deal with the registration of the two
>>> separate redistributor frames per VCPU.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> Reviewed-by: Eric Auger <eric.auger@linaro.org>
>>> ---
>>> Changelog RFC..v1:
>>> - adapt to new MMIO registration approach:
>>>   register one device for the distributor and two for each VCPU
>>> - implement special handling for private interrupts
>>> - remove empty stub functions
>>> - make IGROUPR return RAO
>>>
>>> Changelog v1 .. v2:
>>> - adapt to new framework, introduce vgic-mmio-v3.c
>>> - remove userland register access functions (for now)
>>> - precompute .len when describing a VGIC register
>>> - add missed pointer incrementation on registering redist regions
>>> - replace _nyi stub functions with raz/wi versions
>>>
>>> Changelog v2 .. v3:
>>> - replace inclusion of kvm/vgic/vgic.h with kvm/arm_vgic.h
>>> - add prototype and stub code for vgic_register_redist_iodevs
>>> - rename register struct variables _rdbase_ and _sgibase_
>>>
>>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
>>>  virt/kvm/arm/vgic/vgic-mmio.c    |   5 +
>>>  virt/kvm/arm/vgic/vgic-mmio.h    |   2 +
>>>  virt/kvm/arm/vgic/vgic.h         |   7 ++
>>>  4 files changed, 205 insertions(+)
>>>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>> new file mode 100644
>>> index 0000000..06c7ec5
>>> --- /dev/null
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>> @@ -0,0 +1,191 @@
>>> +/*
>>> + * VGICv3 MMIO 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 <kvm/iodev.h>
>>> +#include <kvm/arm_vgic.h>
>>> +
>>> +#include <asm/kvm_emulate.h>
>>> +
>>> +#include "vgic.h"
>>> +#include "vgic-mmio.h"
>>> +
>>> +/*
>>> + * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
>>> + * redistributors, while SPIs are covered by registers in the distributor
>>> + * block. Trying to set private IRQs in this block gets ignored.
>>> + * We take some special care here to fix the calculation of the register
>>> + * offset.
>>> + */
>>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, read_ops, write_ops, bpi) \
>>> +	{								\
>>> +		.reg_offset = off,					\
>>> +		.bits_per_irq = bpi,					\
>>> +		.len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8,		\
>>> +		.read = vgic_mmio_read_raz,				\
>>> +		.write = vgic_mmio_write_wi,				\
>>> +	}, {								\
>>> +		.reg_offset = off + (bpi * VGIC_NR_PRIVATE_IRQS) / 8,	\
>>> +		.bits_per_irq = bpi,					\
>>> +		.len = (bpi * (1024 - VGIC_NR_PRIVATE_IRQS)) / 8,	\
>>> +		.read = read_ops,					\
>>> +		.write = write_ops,					\
>>> +	}
>>> +
>>> +static const struct vgic_register_region vgic_v3_dist_registers[] = {
>>> +	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>>> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
>>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
>>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
>>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
>>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
>>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
>>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
>>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
>>> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
>>> +	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
>>> +};
>>> +
>>> +static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
>>> +};
>>> +
>>> +static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
>>> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
>>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
>>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
>>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
>>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
>>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
>>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
>>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
>>> +		vgic_mmio_read_config, vgic_mmio_write_config, 8),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>>> +};
>>> +
>>> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
>>> +{
>>> +	dev->regions = vgic_v3_dist_registers;
>>> +	dev->nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
>>> +
>>> +	kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
>>> +
>>> +	return SZ_64K;
>>> +}
>>> +
>>> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
>>> +{
>>> +	int nr_vcpus = atomic_read(&kvm->online_vcpus);
>>> +	struct kvm_vcpu *vcpu;
>>> +	struct vgic_io_device *devices, *device;
>>> +	int c, ret = 0;
>>> +
>>> +	devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
>>> +			  GFP_KERNEL);
>>> +	if (!devices)
>>> +		return -ENOMEM;
>>> +
>>> +	device = devices;
>>> +	kvm_for_each_vcpu(c, vcpu, kvm) {
>>> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>>> +		device->base_addr = redist_base_address;
>>> +		device->regions = vgic_v3_rdbase_registers;
>>> +		device->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
>>> +		device->redist_vcpu = vcpu;
>>> +
>>> +		mutex_lock(&kvm->slots_lock);
>>> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>>> +					      redist_base_address,
>>> +					      SZ_64K, &device->dev);
>>> +		mutex_unlock(&kvm->slots_lock);
>>> +
>>> +		if (ret)
>>> +			break;
>>> +
>>> +		device++;
>>> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>>> +		device->base_addr = redist_base_address + SZ_64K;
>>> +		device->regions = vgic_v3_sgibase_registers;
>>> +		device->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
>>> +		device->redist_vcpu = vcpu;
>>> +
>>> +		mutex_lock(&kvm->slots_lock);
>>> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>>> +					      redist_base_address + SZ_64K,
>>> +					      SZ_64K, &device->dev);
>>> +		mutex_unlock(&kvm->slots_lock);
>>> +		if (ret) {
>>> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>>> +						  &devices[c * 2].dev);
>>> +			break;
>>> +		}
>>> +		device++;
>>> +		redist_base_address += 2 * SZ_64K;
>>
>> while I think this whole thing is actually correct, I think it could
>> have been much more clear by, in the beginning of the loop doing:
>>
>> 	gpa_t rd_base = redist_base_address + c * SZ_64K * 2;
>> 	gpa_t sgi_base = rd_base + SZ_64K;
>> 	struct vgic_io_device *rd_dev = &devices[c];
>> 	struct vgic_io_device *sgi_dev = &devices[c + 1];
>>
>> and then referring directly to these variables.
> 
> Yeah, looks useful, not sure we want to change it last minute though.

Why not? We're changing much more fundamental things already. I'd rather
have something that I can easily read and convince myself that it does
the right thing rather than merge something that I'm suspicious of.

In other words, we fix it.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 32/55] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework
@ 2016-05-12 10:58         ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-12 10:58 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/05/16 11:52, Andre Przywara wrote:
> Hi,
> 
> On 12/05/16 11:26, Christoffer Dall wrote:
>> On Fri, May 06, 2016 at 11:45:45AM +0100, Andre Przywara wrote:
>>> Create a new file called vgic-mmio-v3.c and describe the GICv3
>>> distributor and redistributor registers there.
>>> This adds a special macro to deal with the split of SGI/PPI in the
>>> redistributor and SPIs in the distributor, which allows us to reuse
>>> the existing GICv2 handlers for those registers which are compatible.
>>> Also we provide a function to deal with the registration of the two
>>> separate redistributor frames per VCPU.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> Reviewed-by: Eric Auger <eric.auger@linaro.org>
>>> ---
>>> Changelog RFC..v1:
>>> - adapt to new MMIO registration approach:
>>>   register one device for the distributor and two for each VCPU
>>> - implement special handling for private interrupts
>>> - remove empty stub functions
>>> - make IGROUPR return RAO
>>>
>>> Changelog v1 .. v2:
>>> - adapt to new framework, introduce vgic-mmio-v3.c
>>> - remove userland register access functions (for now)
>>> - precompute .len when describing a VGIC register
>>> - add missed pointer incrementation on registering redist regions
>>> - replace _nyi stub functions with raz/wi versions
>>>
>>> Changelog v2 .. v3:
>>> - replace inclusion of kvm/vgic/vgic.h with kvm/arm_vgic.h
>>> - add prototype and stub code for vgic_register_redist_iodevs
>>> - rename register struct variables _rdbase_ and _sgibase_
>>>
>>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 191 +++++++++++++++++++++++++++++++++++++++
>>>  virt/kvm/arm/vgic/vgic-mmio.c    |   5 +
>>>  virt/kvm/arm/vgic/vgic-mmio.h    |   2 +
>>>  virt/kvm/arm/vgic/vgic.h         |   7 ++
>>>  4 files changed, 205 insertions(+)
>>>  create mode 100644 virt/kvm/arm/vgic/vgic-mmio-v3.c
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>> new file mode 100644
>>> index 0000000..06c7ec5
>>> --- /dev/null
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>> @@ -0,0 +1,191 @@
>>> +/*
>>> + * VGICv3 MMIO 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 <kvm/iodev.h>
>>> +#include <kvm/arm_vgic.h>
>>> +
>>> +#include <asm/kvm_emulate.h>
>>> +
>>> +#include "vgic.h"
>>> +#include "vgic-mmio.h"
>>> +
>>> +/*
>>> + * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
>>> + * redistributors, while SPIs are covered by registers in the distributor
>>> + * block. Trying to set private IRQs in this block gets ignored.
>>> + * We take some special care here to fix the calculation of the register
>>> + * offset.
>>> + */
>>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(off, read_ops, write_ops, bpi) \
>>> +	{								\
>>> +		.reg_offset = off,					\
>>> +		.bits_per_irq = bpi,					\
>>> +		.len = (bpi * VGIC_NR_PRIVATE_IRQS) / 8,		\
>>> +		.read = vgic_mmio_read_raz,				\
>>> +		.write = vgic_mmio_write_wi,				\
>>> +	}, {								\
>>> +		.reg_offset = off + (bpi * VGIC_NR_PRIVATE_IRQS) / 8,	\
>>> +		.bits_per_irq = bpi,					\
>>> +		.len = (bpi * (1024 - VGIC_NR_PRIVATE_IRQS)) / 8,	\
>>> +		.read = read_ops,					\
>>> +		.write = write_ops,					\
>>> +	}
>>> +
>>> +static const struct vgic_register_region vgic_v3_dist_registers[] = {
>>> +	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>>> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
>>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICENABLER,
>>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISPENDR,
>>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICPENDR,
>>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISACTIVER,
>>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICACTIVER,
>>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IPRIORITYR,
>>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 8),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ITARGETSR,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ICFGR,
>>> +		vgic_mmio_read_config, vgic_mmio_write_config, 2),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>>> +	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
>>> +	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
>>> +};
>>> +
>>> +static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
>>> +};
>>> +
>>> +static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_IGROUPR0,
>>> +		vgic_mmio_read_rao, vgic_mmio_write_wi, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISENABLER0,
>>> +		vgic_mmio_read_enable, vgic_mmio_write_senable, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICENABLER0,
>>> +		vgic_mmio_read_enable, vgic_mmio_write_cenable, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISPENDR0,
>>> +		vgic_mmio_read_pending, vgic_mmio_write_spending, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICPENDR0,
>>> +		vgic_mmio_read_pending, vgic_mmio_write_cpending, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ISACTIVER0,
>>> +		vgic_mmio_read_active, vgic_mmio_write_sactive, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICACTIVER0,
>>> +		vgic_mmio_read_active, vgic_mmio_write_cactive, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_IPRIORITYR0,
>>> +		vgic_mmio_read_priority, vgic_mmio_write_priority, 32),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_ICFGR0,
>>> +		vgic_mmio_read_config, vgic_mmio_write_config, 8),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_IGRPMODR0,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>>> +	REGISTER_DESC_WITH_LENGTH(GICR_NSACR,
>>> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>>> +};
>>> +
>>> +unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
>>> +{
>>> +	dev->regions = vgic_v3_dist_registers;
>>> +	dev->nr_regions = ARRAY_SIZE(vgic_v3_dist_registers);
>>> +
>>> +	kvm_iodevice_init(&dev->dev, &kvm_io_gic_ops);
>>> +
>>> +	return SZ_64K;
>>> +}
>>> +
>>> +int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
>>> +{
>>> +	int nr_vcpus = atomic_read(&kvm->online_vcpus);
>>> +	struct kvm_vcpu *vcpu;
>>> +	struct vgic_io_device *devices, *device;
>>> +	int c, ret = 0;
>>> +
>>> +	devices = kmalloc(sizeof(struct vgic_io_device) * nr_vcpus * 2,
>>> +			  GFP_KERNEL);
>>> +	if (!devices)
>>> +		return -ENOMEM;
>>> +
>>> +	device = devices;
>>> +	kvm_for_each_vcpu(c, vcpu, kvm) {
>>> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>>> +		device->base_addr = redist_base_address;
>>> +		device->regions = vgic_v3_rdbase_registers;
>>> +		device->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
>>> +		device->redist_vcpu = vcpu;
>>> +
>>> +		mutex_lock(&kvm->slots_lock);
>>> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>>> +					      redist_base_address,
>>> +					      SZ_64K, &device->dev);
>>> +		mutex_unlock(&kvm->slots_lock);
>>> +
>>> +		if (ret)
>>> +			break;
>>> +
>>> +		device++;
>>> +		kvm_iodevice_init(&device->dev, &kvm_io_gic_ops);
>>> +		device->base_addr = redist_base_address + SZ_64K;
>>> +		device->regions = vgic_v3_sgibase_registers;
>>> +		device->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
>>> +		device->redist_vcpu = vcpu;
>>> +
>>> +		mutex_lock(&kvm->slots_lock);
>>> +		ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS,
>>> +					      redist_base_address + SZ_64K,
>>> +					      SZ_64K, &device->dev);
>>> +		mutex_unlock(&kvm->slots_lock);
>>> +		if (ret) {
>>> +			kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS,
>>> +						  &devices[c * 2].dev);
>>> +			break;
>>> +		}
>>> +		device++;
>>> +		redist_base_address += 2 * SZ_64K;
>>
>> while I think this whole thing is actually correct, I think it could
>> have been much more clear by, in the beginning of the loop doing:
>>
>> 	gpa_t rd_base = redist_base_address + c * SZ_64K * 2;
>> 	gpa_t sgi_base = rd_base + SZ_64K;
>> 	struct vgic_io_device *rd_dev = &devices[c];
>> 	struct vgic_io_device *sgi_dev = &devices[c + 1];
>>
>> and then referring directly to these variables.
> 
> Yeah, looks useful, not sure we want to change it last minute though.

Why not? We're changing much more fundamental things already. I'd rather
have something that I can easily read and convince myself that it does
the right thing rather than merge something that I'm suspicious of.

In other words, we fix it.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 17/55] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-12 11:46     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 11:46 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:45:30AM +0100, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Implement the framework for syncing IRQs between our emulation and
> the list registers, which represent the guest's view of IRQs.
> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
> which gets called on guest entry and exit.
> The code talking to the actual GICv2/v3 hardware is added in the
> following patches.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---

[...]

> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 4fb20fd..c6f8b9b 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c

[...]

> +
> +/* Requires the VCPU's ap_list_lock to be held. */
> +static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
> +
> +	if (unlikely(!vcpu->kvm->arch.vgic.enabled))
> +		goto out_clean;


I know I said I reviewed this, but thinking about this more carefully,
doesn't the enable bit actually tell us if forwarding of pending
interrupts is enabled, but not whether or not the vgic exists?

So you could imagine a guest that turns off the GIC, but still has
active interrupts that it wants to disable/EOI, in the case of
shutdown/reboot for example, or is this architecturally not allowed?

If it is, then we should, at least theoretically, still forward active
interrupts in LRs despite the enabled bit being clear, but modify the
oracle to take the global enable bit into account.

Thanks,
-Christoffer

> +
> +	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
> +		vgic_set_underflow(vcpu);
> +		vgic_sort_ap_list(vcpu);
> +	}
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +
> +		if (unlikely(vgic_target_oracle(irq) != vcpu))
> +			goto next;
> +
> +		/*
> +		 * If we get an SGI with multiple sources, try to get
> +		 * them in all at once.
> +		 */
> +		do {
> +			vgic_populate_lr(vcpu, irq, count++);
> +		} while (irq->source && count < kvm_vgic_global_state.nr_lr);
> +
> +next:
> +		spin_unlock(&irq->irq_lock);
> +
> +		if (count == kvm_vgic_global_state.nr_lr)
> +			break;
> +	}
> +
> +out_clean:
> +	vcpu->arch.vgic_cpu.used_lrs = count;
> +
> +	/* Nuke remaining LRs */
> +	for ( ; count < kvm_vgic_global_state.nr_lr; count++)
> +		vgic_clear_lr(vcpu, count);
> +}
> +

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

* [PATCH v3 17/55] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
@ 2016-05-12 11:46     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 11:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:30AM +0100, Andre Przywara wrote:
> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Implement the framework for syncing IRQs between our emulation and
> the list registers, which represent the guest's view of IRQs.
> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
> which gets called on guest entry and exit.
> The code talking to the actual GICv2/v3 hardware is added in the
> following patches.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---

[...]

> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 4fb20fd..c6f8b9b 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c

[...]

> +
> +/* Requires the VCPU's ap_list_lock to be held. */
> +static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	struct vgic_irq *irq;
> +	int count = 0;
> +
> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
> +
> +	if (unlikely(!vcpu->kvm->arch.vgic.enabled))
> +		goto out_clean;


I know I said I reviewed this, but thinking about this more carefully,
doesn't the enable bit actually tell us if forwarding of pending
interrupts is enabled, but not whether or not the vgic exists?

So you could imagine a guest that turns off the GIC, but still has
active interrupts that it wants to disable/EOI, in the case of
shutdown/reboot for example, or is this architecturally not allowed?

If it is, then we should, at least theoretically, still forward active
interrupts in LRs despite the enabled bit being clear, but modify the
oracle to take the global enable bit into account.

Thanks,
-Christoffer

> +
> +	if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
> +		vgic_set_underflow(vcpu);
> +		vgic_sort_ap_list(vcpu);
> +	}
> +
> +	list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
> +		spin_lock(&irq->irq_lock);
> +
> +		if (unlikely(vgic_target_oracle(irq) != vcpu))
> +			goto next;
> +
> +		/*
> +		 * If we get an SGI with multiple sources, try to get
> +		 * them in all at once.
> +		 */
> +		do {
> +			vgic_populate_lr(vcpu, irq, count++);
> +		} while (irq->source && count < kvm_vgic_global_state.nr_lr);
> +
> +next:
> +		spin_unlock(&irq->irq_lock);
> +
> +		if (count == kvm_vgic_global_state.nr_lr)
> +			break;
> +	}
> +
> +out_clean:
> +	vcpu->arch.vgic_cpu.used_lrs = count;
> +
> +	/* Nuke remaining LRs */
> +	for ( ; count < kvm_vgic_global_state.nr_lr; count++)
> +		vgic_clear_lr(vcpu, count);
> +}
> +

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

* Re: [PATCH v3 33/55] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-12 11:47     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 11:47 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:45:46AM +0100, Andre Przywara wrote:
> As in the GICv2 emulation we handle those three registers in one
> function.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - kick VCPUs if distributor gets enabled
> 
> Changelog v1 .. v2:
> - rewrite write handler to use switch statement
> 
>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 50 +++++++++++++++++++++++++++++++++++++++-
>  virt/kvm/arm/vgic/vgic.h         |  2 ++
>  2 files changed, 51 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index 06c7ec5..5f4558c 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -22,6 +22,54 @@
>  #include "vgic.h"
>  #include "vgic-mmio.h"
>  
> +static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
> +					    gpa_t addr, unsigned int len)
> +{
> +	u32 value = 0;
> +
> +	switch (addr & 0x0c) {
> +	case GICD_CTLR:
> +		if (vcpu->kvm->arch.vgic.enabled)
> +			value |= GICD_CTLR_ENABLE_SS_G1;
> +		value |= GICD_CTLR_ARE_NS | GICD_CTLR_DS;
> +		break;
> +	case GICD_TYPER:
> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> +		value = (value >> 5) - 1;
> +		value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
> +		break;
> +	case GICD_IIDR:
> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> +		break;
> +	default:
> +		return 0;
> +	}
> +
> +	return extract_bytes(value, addr & 3, len);

why do we return extract_bytes here?  This register can only be accessed
in full with a 32-bit aligned access, right?

> +}
> +
> +static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len,
> +				    unsigned long val)
> +{
> +	switch (addr & 0x0c) {
> +	case GICD_CTLR:
> +		if (!(addr & 1)) {

obviously same question as on the v2 counterpart

> +			struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> +			bool was_enabled = dist->enabled;
> +
> +			dist->enabled = val & GICD_CTLR_ENABLE_SS_G1;
> +
> +			if (!was_enabled && dist->enabled)
> +				vgic_kick_vcpus(vcpu->kvm);
> +		}
> +		break;
> +	case GICD_TYPER:
> +	case GICD_IIDR:
> +		return;
> +	}
> +}
> +
>  /*
>   * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
>   * redistributors, while SPIs are covered by registers in the distributor
> @@ -46,7 +94,7 @@
>  
>  static const struct vgic_register_region vgic_v3_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> +		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 39a8a65..635e2e2 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -19,6 +19,8 @@
>  #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
>  #define IMPLEMENTER_ARM		0x43b
>  
> +#define INTERRUPT_ID_BITS_SPIS	10
> +
>  #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
>  
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> -- 
> 2.7.3
> 

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

* [PATCH v3 33/55] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
@ 2016-05-12 11:47     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 11:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:46AM +0100, Andre Przywara wrote:
> As in the GICv2 emulation we handle those three registers in one
> function.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - kick VCPUs if distributor gets enabled
> 
> Changelog v1 .. v2:
> - rewrite write handler to use switch statement
> 
>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 50 +++++++++++++++++++++++++++++++++++++++-
>  virt/kvm/arm/vgic/vgic.h         |  2 ++
>  2 files changed, 51 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index 06c7ec5..5f4558c 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -22,6 +22,54 @@
>  #include "vgic.h"
>  #include "vgic-mmio.h"
>  
> +static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
> +					    gpa_t addr, unsigned int len)
> +{
> +	u32 value = 0;
> +
> +	switch (addr & 0x0c) {
> +	case GICD_CTLR:
> +		if (vcpu->kvm->arch.vgic.enabled)
> +			value |= GICD_CTLR_ENABLE_SS_G1;
> +		value |= GICD_CTLR_ARE_NS | GICD_CTLR_DS;
> +		break;
> +	case GICD_TYPER:
> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> +		value = (value >> 5) - 1;
> +		value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
> +		break;
> +	case GICD_IIDR:
> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> +		break;
> +	default:
> +		return 0;
> +	}
> +
> +	return extract_bytes(value, addr & 3, len);

why do we return extract_bytes here?  This register can only be accessed
in full with a 32-bit aligned access, right?

> +}
> +
> +static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len,
> +				    unsigned long val)
> +{
> +	switch (addr & 0x0c) {
> +	case GICD_CTLR:
> +		if (!(addr & 1)) {

obviously same question as on the v2 counterpart

> +			struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> +			bool was_enabled = dist->enabled;
> +
> +			dist->enabled = val & GICD_CTLR_ENABLE_SS_G1;
> +
> +			if (!was_enabled && dist->enabled)
> +				vgic_kick_vcpus(vcpu->kvm);
> +		}
> +		break;
> +	case GICD_TYPER:
> +	case GICD_IIDR:
> +		return;
> +	}
> +}
> +
>  /*
>   * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
>   * redistributors, while SPIs are covered by registers in the distributor
> @@ -46,7 +94,7 @@
>  
>  static const struct vgic_register_region vgic_v3_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> +		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 39a8a65..635e2e2 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -19,6 +19,8 @@
>  #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
>  #define IMPLEMENTER_ARM		0x43b
>  
> +#define INTERRUPT_ID_BITS_SPIS	10
> +
>  #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
>  
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> -- 
> 2.7.3
> 

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

* Re: [PATCH v3 34/55] KVM: arm/arm64: vgic-new: Add GICv3 redistributor IIDR and TYPER handler
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-12 11:59     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 11:59 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:45:47AM +0100, Andre Przywara wrote:
> The redistributor TYPER tells the OS about the associated MPIDR,
> also the LAST bit is crucial to determine the number of redistributors.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 44 ++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 42 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index 5f4558c..d137242 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -71,6 +71,46 @@ static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
>  }
>  
>  /*
> + * We use a compressed version of the MPIDR (all 32 bits in one 32-bit word)
> + * when we store the target MPIDR written by the guest.
> + */
> +static u32 compress_mpidr(unsigned long mpidr)
> +{
> +	u32 ret;
> +
> +	ret = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> +	ret |= MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8;
> +	ret |= MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16;
> +	ret |= MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24;
> +
> +	return ret;
> +}
> +
> +static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
> +					      gpa_t addr, unsigned int len)
> +{
> +	unsigned long mpidr = kvm_vcpu_get_mpidr_aff(vcpu);
> +	int target_vcpu_id = vcpu->vcpu_id;
> +	u64 value;
> +
> +	value = (u64)compress_mpidr(mpidr) << 32;
> +	value |= ((target_vcpu_id & 0xffff) << 8);
> +	if (target_vcpu_id == atomic_read(&vcpu->kvm->online_vcpus) - 1)
> +		value |= GICR_TYPER_LAST;
> +
> +	return extract_bytes(value, addr & 7, len);
> +}
> +
> +static unsigned long vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
> +					     gpa_t addr, unsigned int len)
> +{
> +	u32 value;
> +
> +	value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> +	return extract_bytes(value, addr & 3, len);
> +}
> +
> +/*
>   * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
>   * redistributors, while SPIs are covered by registers in the distributor
>   * block. Trying to set private IRQs in this block gets ignored.
> @@ -127,9 +167,9 @@ static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>  	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +		vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4),
>  	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +		vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8),
>  	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>  	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
> -- 
> 2.7.3
> 
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

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

* [PATCH v3 34/55] KVM: arm/arm64: vgic-new: Add GICv3 redistributor IIDR and TYPER handler
@ 2016-05-12 11:59     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 11:59 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:47AM +0100, Andre Przywara wrote:
> The redistributor TYPER tells the OS about the associated MPIDR,
> also the LAST bit is crucial to determine the number of redistributors.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 44 ++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 42 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index 5f4558c..d137242 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -71,6 +71,46 @@ static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
>  }
>  
>  /*
> + * We use a compressed version of the MPIDR (all 32 bits in one 32-bit word)
> + * when we store the target MPIDR written by the guest.
> + */
> +static u32 compress_mpidr(unsigned long mpidr)
> +{
> +	u32 ret;
> +
> +	ret = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> +	ret |= MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8;
> +	ret |= MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16;
> +	ret |= MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24;
> +
> +	return ret;
> +}
> +
> +static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
> +					      gpa_t addr, unsigned int len)
> +{
> +	unsigned long mpidr = kvm_vcpu_get_mpidr_aff(vcpu);
> +	int target_vcpu_id = vcpu->vcpu_id;
> +	u64 value;
> +
> +	value = (u64)compress_mpidr(mpidr) << 32;
> +	value |= ((target_vcpu_id & 0xffff) << 8);
> +	if (target_vcpu_id == atomic_read(&vcpu->kvm->online_vcpus) - 1)
> +		value |= GICR_TYPER_LAST;
> +
> +	return extract_bytes(value, addr & 7, len);
> +}
> +
> +static unsigned long vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
> +					     gpa_t addr, unsigned int len)
> +{
> +	u32 value;
> +
> +	value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> +	return extract_bytes(value, addr & 3, len);
> +}
> +
> +/*
>   * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
>   * redistributors, while SPIs are covered by registers in the distributor
>   * block. Trying to set private IRQs in this block gets ignored.
> @@ -127,9 +167,9 @@ static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
>  	REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 4),
> +		vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4),
>  	REGISTER_DESC_WITH_LENGTH(GICR_TYPER,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
> +		vgic_mmio_read_v3r_typer, vgic_mmio_write_wi, 8),
>  	REGISTER_DESC_WITH_LENGTH(GICR_PROPBASER,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>  	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
> -- 
> 2.7.3
> 
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

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

* Re: [PATCH v3 35/55] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-12 12:12     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 12:12 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:45:48AM +0100, Andre Przywara wrote:
> We implement the only one ID register that is required by the
> architecture, also this is the one that Linux actually checks.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 20 ++++++++++++++++++--
>  1 file changed, 18 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index d137242..48fba9c 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -110,6 +110,22 @@ static unsigned long vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
>  	return extract_bytes(value, addr & 3, len);
>  }
>  
> +static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
> +					      gpa_t addr, unsigned int len)
> +{
> +	u32 regnr = (addr & 0x3f) - (GICD_IDREGS & 0x3f);

this regnr thing is confusing, because it's not an index, it's an
address offset.

why can't you do:

	switch (addr & 0xffff) {
	case GICD_PIDR2:
	}


> +	u32 reg = 0;
> +
> +	switch (regnr + GICD_IDREGS) {
> +	case GICD_PIDR2:
> +		/* report a GICv3 compliant implementation */
> +		reg = 0x3b;
> +		break;
> +	}
> +
> +	return extract_bytes(reg, addr & 3, len);
> +}
> +
>  /*
>   * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
>   * redistributors, while SPIs are covered by registers in the distributor
> @@ -160,7 +176,7 @@ static const struct vgic_register_region vgic_v3_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
>  	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
> +		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
>  };
>  
>  static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
> @@ -175,7 +191,7 @@ static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>  	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
> +		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
>  };
>  
>  static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v3 35/55] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
@ 2016-05-12 12:12     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 12:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:48AM +0100, Andre Przywara wrote:
> We implement the only one ID register that is required by the
> architecture, also this is the one that Linux actually checks.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 20 ++++++++++++++++++--
>  1 file changed, 18 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index d137242..48fba9c 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -110,6 +110,22 @@ static unsigned long vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
>  	return extract_bytes(value, addr & 3, len);
>  }
>  
> +static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
> +					      gpa_t addr, unsigned int len)
> +{
> +	u32 regnr = (addr & 0x3f) - (GICD_IDREGS & 0x3f);

this regnr thing is confusing, because it's not an index, it's an
address offset.

why can't you do:

	switch (addr & 0xffff) {
	case GICD_PIDR2:
	}


> +	u32 reg = 0;
> +
> +	switch (regnr + GICD_IDREGS) {
> +	case GICD_PIDR2:
> +		/* report a GICv3 compliant implementation */
> +		reg = 0x3b;
> +		break;
> +	}
> +
> +	return extract_bytes(reg, addr & 3, len);
> +}
> +
>  /*
>   * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
>   * redistributors, while SPIs are covered by registers in the distributor
> @@ -160,7 +176,7 @@ static const struct vgic_register_region vgic_v3_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
>  	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
> +		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
>  };
>  
>  static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
> @@ -175,7 +191,7 @@ static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GICR_PENDBASER,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 8),
>  	REGISTER_DESC_WITH_LENGTH(GICR_IDREGS,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 48),
> +		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
>  };
>  
>  static const struct vgic_register_region vgic_v3_sgibase_registers[] = {
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v3 13/55] KVM: arm/arm64: vgic-new: Add data structure definitions
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-12 12:12     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 12:12 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 06, 2016 at 11:45:26AM +0100, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Add a new header file for the new and improved GIC implementation.
> The big change is that we now have a struct vgic_irq per IRQ instead
> of spreading all the information over various bitmaps.
> 
> We include this new header conditionally from within the old header
> file for the time being to avoid touching all the users.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changes RFC .. v1:
> - adapt to 4.6-rc (adding live_lrs member)
> - elaborate on ap_list usage
> 
> Changes v1 .. v2:
> - change data type of dist->enabled to bool
> 
>  include/kvm/arm_vgic.h  |   5 ++
>  include/kvm/vgic/vgic.h | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 206 insertions(+)
>  create mode 100644 include/kvm/vgic/vgic.h
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index c14ff77..d406f8e 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -19,6 +19,10 @@
>  #ifndef __ASM_ARM_KVM_VGIC_H
>  #define __ASM_ARM_KVM_VGIC_H
>  
> +#ifdef CONFIG_KVM_NEW_VGIC
> +#include <kvm/vgic/vgic.h>
> +#else
> +
>  #include <linux/kernel.h>
>  #include <linux/kvm.h>
>  #include <linux/irqreturn.h>
> @@ -366,4 +370,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>  }
>  #endif
>  
> +#endif	/* old VGIC include */
>  #endif
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> new file mode 100644
> index 0000000..39933ee
> --- /dev/null
> +++ b/include/kvm/vgic/vgic.h
> @@ -0,0 +1,201 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef __ASM_ARM_KVM_VGIC_VGIC_H
> +#define __ASM_ARM_KVM_VGIC_VGIC_H
> +
> +#include <linux/kernel.h>
> +#include <linux/kvm.h>
> +#include <linux/irqreturn.h>
> +#include <linux/spinlock.h>
> +#include <linux/types.h>
> +#include <kvm/iodev.h>
> +
> +#define VGIC_V3_MAX_CPUS	255
> +#define VGIC_V2_MAX_CPUS	8
> +#define VGIC_NR_IRQS_LEGACY     256
> +#define VGIC_NR_SGIS		16
> +#define VGIC_NR_PPIS		16
> +#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
> +#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
> +#define VGIC_MAX_SPI		1019
> +#define VGIC_MAX_RESERVED	1023
> +#define VGIC_MIN_LPI		8192
> +
> +enum vgic_type {
> +	VGIC_V2,		/* Good ol' GICv2 */
> +	VGIC_V3,		/* New fancy GICv3 */
> +};
> +
> +/* same for all guests, as depending only on the _host's_ GIC model */
> +struct vgic_global {
> +	/* type of the host GIC */
> +	enum vgic_type		type;
> +
> +	/* Physical address of vgic virtual cpu interface */
> +	phys_addr_t		vcpu_base;
> +
> +	/* virtual control interface mapping */
> +	void __iomem		*vctrl_base;
> +
> +	/* Number of implemented list registers */
> +	int			nr_lr;
> +
> +	/* Maintenance IRQ number */

nit: this is the physial INTID, right?

> +	unsigned int		maint_irq;
> +
> +	/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
> +	int			max_gic_vcpus;
> +
> +	/* Only needed for the legacy KVM_CREATE_IRQCHIP */
> +	bool			can_emulate_gicv2;
> +};
> +
> +extern struct vgic_global kvm_vgic_global_state;
> +
> +#define VGIC_V2_MAX_LRS		(1 << 6)
> +#define VGIC_V3_MAX_LRS		16
> +#define VGIC_V3_LR_INDEX(lr)	(VGIC_V3_MAX_LRS - 1 - lr)
> +
> +enum vgic_irq_config {
> +	VGIC_CONFIG_EDGE = 0,
> +	VGIC_CONFIG_LEVEL
> +};
> +
> +struct vgic_irq {
> +	spinlock_t irq_lock;		/* Protects the content of the struct */
> +	struct list_head ap_list;
> +
> +	struct kvm_vcpu *vcpu;		/* SGIs and PPIs: The VCPU
> +					 * SPIs and LPIs: The VCPU whose ap_list
> +					 * on which this is queued.

nit: s/on which this is queued/this is queued on/

> +					 */
> +
> +	struct kvm_vcpu *target_vcpu;	/* The VCPU that this interrupt should
> +					 * be send to, as a result of the

nit: s/send/sent/

> +					 * targets reg (v2) or the
> +					 * affinity reg (v3).
> +					 */
> +
> +	u32 intid;			/* Guest visible INTID */
> +	bool pending;
> +	bool line_level;		/* Level only */
> +	bool soft_pending;		/* Level only */
> +	bool active;			/* not used for LPIs */
> +	bool enabled;
> +	bool hw;			/* Tied to HW IRQ */
> +	u32 hwintid;			/* HW INTID number */
> +	union {
> +		u8 targets;			/* GICv2 target VCPUs mask */
> +		u32 mpidr;			/* GICv3 target VCPU */
> +	};
> +	u8 source;			/* GICv2 SGIs only */
> +	u8 priority;
> +	enum vgic_irq_config config;	/* Level or edge */
> +};
> +
> +struct vgic_dist {
> +	bool			in_kernel;
> +	bool			ready;
> +
> +	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
> +	u32			vgic_model;
> +
> +	int			nr_spis;
> +
> +	/* TODO: Consider moving to global state */
> +	/* Virtual control interface mapping */
> +	void __iomem		*vctrl_base;
> +
> +	/* base addresses in guest physical address space: */
> +	gpa_t			vgic_dist_base;		/* distributor */
> +	union {
> +		/* either a GICv2 CPU interface */
> +		gpa_t			vgic_cpu_base;
> +		/* or a number of GICv3 redistributor regions */
> +		gpa_t			vgic_redist_base;
> +	};
> +
> +	/* distributor enabled */
> +	bool			enabled;
> +
> +	struct vgic_irq		*spis;
> +};
> +
> +struct vgic_v2_cpu_if {
> +	u32		vgic_hcr;
> +	u32		vgic_vmcr;
> +	u32		vgic_misr;	/* Saved only */
> +	u64		vgic_eisr;	/* Saved only */
> +	u64		vgic_elrsr;	/* Saved only */
> +	u32		vgic_apr;
> +	u32		vgic_lr[VGIC_V2_MAX_LRS];
> +};
> +
> +struct vgic_v3_cpu_if {
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +	u32		vgic_hcr;
> +	u32		vgic_vmcr;
> +	u32		vgic_sre;	/* Restored only, change ignored */
> +	u32		vgic_misr;	/* Saved only */
> +	u32		vgic_eisr;	/* Saved only */
> +	u32		vgic_elrsr;	/* Saved only */
> +	u32		vgic_ap0r[4];
> +	u32		vgic_ap1r[4];
> +	u64		vgic_lr[VGIC_V3_MAX_LRS];
> +#endif
> +};
> +
> +struct vgic_cpu {
> +	/* CPU vif control registers for world switch */
> +	union {
> +		struct vgic_v2_cpu_if	vgic_v2;
> +		struct vgic_v3_cpu_if	vgic_v3;
> +	};
> +
> +	unsigned int used_lrs;
> +	struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
> +
> +	spinlock_t ap_list_lock;	/* Protects the ap_list */
> +
> +	/*
> +	 * List of IRQs that this VCPU should consider because they are either
> +	 * Active or Pending (hence the name; AP list), or because they recently
> +	 * were one of the two and need to be migrated off this list to another
> +	 * VCPU.
> +	 */
> +	struct list_head ap_list_head;
> +
> +	u64 live_lrs;
> +};
> +
> +#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> +#define vgic_initialized(k)	(false)
> +#define vgic_ready(k)		((k)->arch.vgic.ready)
> +#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
> +			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))

this should really be a static inline at this point.

> +
> +/**
> + * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
> + *
> + * The host's GIC naturally limits the maximum amount of VCPUs a guest
> + * can use.
> + */
> +static inline int kvm_vgic_get_max_vcpus(void)
> +{
> +	return kvm_vgic_global_state.max_gic_vcpus;
> +}
> +
> +#endif /* __ASM_ARM_KVM_VGIC_VGIC_H */
> -- 
> 2.7.3
> 

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

* [PATCH v3 13/55] KVM: arm/arm64: vgic-new: Add data structure definitions
@ 2016-05-12 12:12     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 12:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:26AM +0100, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Add a new header file for the new and improved GIC implementation.
> The big change is that we now have a struct vgic_irq per IRQ instead
> of spreading all the information over various bitmaps.
> 
> We include this new header conditionally from within the old header
> file for the time being to avoid touching all the users.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changes RFC .. v1:
> - adapt to 4.6-rc (adding live_lrs member)
> - elaborate on ap_list usage
> 
> Changes v1 .. v2:
> - change data type of dist->enabled to bool
> 
>  include/kvm/arm_vgic.h  |   5 ++
>  include/kvm/vgic/vgic.h | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 206 insertions(+)
>  create mode 100644 include/kvm/vgic/vgic.h
> 
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index c14ff77..d406f8e 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -19,6 +19,10 @@
>  #ifndef __ASM_ARM_KVM_VGIC_H
>  #define __ASM_ARM_KVM_VGIC_H
>  
> +#ifdef CONFIG_KVM_NEW_VGIC
> +#include <kvm/vgic/vgic.h>
> +#else
> +
>  #include <linux/kernel.h>
>  #include <linux/kvm.h>
>  #include <linux/irqreturn.h>
> @@ -366,4 +370,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>  }
>  #endif
>  
> +#endif	/* old VGIC include */
>  #endif
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> new file mode 100644
> index 0000000..39933ee
> --- /dev/null
> +++ b/include/kvm/vgic/vgic.h
> @@ -0,0 +1,201 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef __ASM_ARM_KVM_VGIC_VGIC_H
> +#define __ASM_ARM_KVM_VGIC_VGIC_H
> +
> +#include <linux/kernel.h>
> +#include <linux/kvm.h>
> +#include <linux/irqreturn.h>
> +#include <linux/spinlock.h>
> +#include <linux/types.h>
> +#include <kvm/iodev.h>
> +
> +#define VGIC_V3_MAX_CPUS	255
> +#define VGIC_V2_MAX_CPUS	8
> +#define VGIC_NR_IRQS_LEGACY     256
> +#define VGIC_NR_SGIS		16
> +#define VGIC_NR_PPIS		16
> +#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
> +#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
> +#define VGIC_MAX_SPI		1019
> +#define VGIC_MAX_RESERVED	1023
> +#define VGIC_MIN_LPI		8192
> +
> +enum vgic_type {
> +	VGIC_V2,		/* Good ol' GICv2 */
> +	VGIC_V3,		/* New fancy GICv3 */
> +};
> +
> +/* same for all guests, as depending only on the _host's_ GIC model */
> +struct vgic_global {
> +	/* type of the host GIC */
> +	enum vgic_type		type;
> +
> +	/* Physical address of vgic virtual cpu interface */
> +	phys_addr_t		vcpu_base;
> +
> +	/* virtual control interface mapping */
> +	void __iomem		*vctrl_base;
> +
> +	/* Number of implemented list registers */
> +	int			nr_lr;
> +
> +	/* Maintenance IRQ number */

nit: this is the physial INTID, right?

> +	unsigned int		maint_irq;
> +
> +	/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
> +	int			max_gic_vcpus;
> +
> +	/* Only needed for the legacy KVM_CREATE_IRQCHIP */
> +	bool			can_emulate_gicv2;
> +};
> +
> +extern struct vgic_global kvm_vgic_global_state;
> +
> +#define VGIC_V2_MAX_LRS		(1 << 6)
> +#define VGIC_V3_MAX_LRS		16
> +#define VGIC_V3_LR_INDEX(lr)	(VGIC_V3_MAX_LRS - 1 - lr)
> +
> +enum vgic_irq_config {
> +	VGIC_CONFIG_EDGE = 0,
> +	VGIC_CONFIG_LEVEL
> +};
> +
> +struct vgic_irq {
> +	spinlock_t irq_lock;		/* Protects the content of the struct */
> +	struct list_head ap_list;
> +
> +	struct kvm_vcpu *vcpu;		/* SGIs and PPIs: The VCPU
> +					 * SPIs and LPIs: The VCPU whose ap_list
> +					 * on which this is queued.

nit: s/on which this is queued/this is queued on/

> +					 */
> +
> +	struct kvm_vcpu *target_vcpu;	/* The VCPU that this interrupt should
> +					 * be send to, as a result of the

nit: s/send/sent/

> +					 * targets reg (v2) or the
> +					 * affinity reg (v3).
> +					 */
> +
> +	u32 intid;			/* Guest visible INTID */
> +	bool pending;
> +	bool line_level;		/* Level only */
> +	bool soft_pending;		/* Level only */
> +	bool active;			/* not used for LPIs */
> +	bool enabled;
> +	bool hw;			/* Tied to HW IRQ */
> +	u32 hwintid;			/* HW INTID number */
> +	union {
> +		u8 targets;			/* GICv2 target VCPUs mask */
> +		u32 mpidr;			/* GICv3 target VCPU */
> +	};
> +	u8 source;			/* GICv2 SGIs only */
> +	u8 priority;
> +	enum vgic_irq_config config;	/* Level or edge */
> +};
> +
> +struct vgic_dist {
> +	bool			in_kernel;
> +	bool			ready;
> +
> +	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
> +	u32			vgic_model;
> +
> +	int			nr_spis;
> +
> +	/* TODO: Consider moving to global state */
> +	/* Virtual control interface mapping */
> +	void __iomem		*vctrl_base;
> +
> +	/* base addresses in guest physical address space: */
> +	gpa_t			vgic_dist_base;		/* distributor */
> +	union {
> +		/* either a GICv2 CPU interface */
> +		gpa_t			vgic_cpu_base;
> +		/* or a number of GICv3 redistributor regions */
> +		gpa_t			vgic_redist_base;
> +	};
> +
> +	/* distributor enabled */
> +	bool			enabled;
> +
> +	struct vgic_irq		*spis;
> +};
> +
> +struct vgic_v2_cpu_if {
> +	u32		vgic_hcr;
> +	u32		vgic_vmcr;
> +	u32		vgic_misr;	/* Saved only */
> +	u64		vgic_eisr;	/* Saved only */
> +	u64		vgic_elrsr;	/* Saved only */
> +	u32		vgic_apr;
> +	u32		vgic_lr[VGIC_V2_MAX_LRS];
> +};
> +
> +struct vgic_v3_cpu_if {
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +	u32		vgic_hcr;
> +	u32		vgic_vmcr;
> +	u32		vgic_sre;	/* Restored only, change ignored */
> +	u32		vgic_misr;	/* Saved only */
> +	u32		vgic_eisr;	/* Saved only */
> +	u32		vgic_elrsr;	/* Saved only */
> +	u32		vgic_ap0r[4];
> +	u32		vgic_ap1r[4];
> +	u64		vgic_lr[VGIC_V3_MAX_LRS];
> +#endif
> +};
> +
> +struct vgic_cpu {
> +	/* CPU vif control registers for world switch */
> +	union {
> +		struct vgic_v2_cpu_if	vgic_v2;
> +		struct vgic_v3_cpu_if	vgic_v3;
> +	};
> +
> +	unsigned int used_lrs;
> +	struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
> +
> +	spinlock_t ap_list_lock;	/* Protects the ap_list */
> +
> +	/*
> +	 * List of IRQs that this VCPU should consider because they are either
> +	 * Active or Pending (hence the name; AP list), or because they recently
> +	 * were one of the two and need to be migrated off this list to another
> +	 * VCPU.
> +	 */
> +	struct list_head ap_list_head;
> +
> +	u64 live_lrs;
> +};
> +
> +#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> +#define vgic_initialized(k)	(false)
> +#define vgic_ready(k)		((k)->arch.vgic.ready)
> +#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
> +			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))

this should really be a static inline at this point.

> +
> +/**
> + * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
> + *
> + * The host's GIC naturally limits the maximum amount of VCPUs a guest
> + * can use.
> + */
> +static inline int kvm_vgic_get_max_vcpus(void)
> +{
> +	return kvm_vgic_global_state.max_gic_vcpus;
> +}
> +
> +#endif /* __ASM_ARM_KVM_VGIC_VGIC_H */
> -- 
> 2.7.3
> 

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

* Re: [PATCH v3 13/55] KVM: arm/arm64: vgic-new: Add data structure definitions
  2016-05-12 12:12     ` Christoffer Dall
@ 2016-05-12 12:17       ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-12 12:17 UTC (permalink / raw)
  To: Christoffer Dall, Andre Przywara; +Cc: linux-arm-kernel, kvmarm, kvm

On 12/05/16 13:12, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:26AM +0100, Andre Przywara wrote:
>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>
>> Add a new header file for the new and improved GIC implementation.
>> The big change is that we now have a struct vgic_irq per IRQ instead
>> of spreading all the information over various bitmaps.
>>
>> We include this new header conditionally from within the old header
>> file for the time being to avoid touching all the users.
>>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changes RFC .. v1:
>> - adapt to 4.6-rc (adding live_lrs member)
>> - elaborate on ap_list usage
>>
>> Changes v1 .. v2:
>> - change data type of dist->enabled to bool
>>
>>  include/kvm/arm_vgic.h  |   5 ++
>>  include/kvm/vgic/vgic.h | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 206 insertions(+)
>>  create mode 100644 include/kvm/vgic/vgic.h
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index c14ff77..d406f8e 100644
>> --- a/include/kvm/arm_vgic.h
>> +++ b/include/kvm/arm_vgic.h
>> @@ -19,6 +19,10 @@
>>  #ifndef __ASM_ARM_KVM_VGIC_H
>>  #define __ASM_ARM_KVM_VGIC_H
>>  
>> +#ifdef CONFIG_KVM_NEW_VGIC
>> +#include <kvm/vgic/vgic.h>
>> +#else
>> +
>>  #include <linux/kernel.h>
>>  #include <linux/kvm.h>
>>  #include <linux/irqreturn.h>
>> @@ -366,4 +370,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>>  }
>>  #endif
>>  
>> +#endif	/* old VGIC include */
>>  #endif
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> new file mode 100644
>> index 0000000..39933ee
>> --- /dev/null
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -0,0 +1,201 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +#ifndef __ASM_ARM_KVM_VGIC_VGIC_H
>> +#define __ASM_ARM_KVM_VGIC_VGIC_H
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/kvm.h>
>> +#include <linux/irqreturn.h>
>> +#include <linux/spinlock.h>
>> +#include <linux/types.h>
>> +#include <kvm/iodev.h>
>> +
>> +#define VGIC_V3_MAX_CPUS	255
>> +#define VGIC_V2_MAX_CPUS	8
>> +#define VGIC_NR_IRQS_LEGACY     256
>> +#define VGIC_NR_SGIS		16
>> +#define VGIC_NR_PPIS		16
>> +#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
>> +#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
>> +#define VGIC_MAX_SPI		1019
>> +#define VGIC_MAX_RESERVED	1023
>> +#define VGIC_MIN_LPI		8192
>> +
>> +enum vgic_type {
>> +	VGIC_V2,		/* Good ol' GICv2 */
>> +	VGIC_V3,		/* New fancy GICv3 */
>> +};
>> +
>> +/* same for all guests, as depending only on the _host's_ GIC model */
>> +struct vgic_global {
>> +	/* type of the host GIC */
>> +	enum vgic_type		type;
>> +
>> +	/* Physical address of vgic virtual cpu interface */
>> +	phys_addr_t		vcpu_base;
>> +
>> +	/* virtual control interface mapping */
>> +	void __iomem		*vctrl_base;
>> +
>> +	/* Number of implemented list registers */
>> +	int			nr_lr;
>> +
>> +	/* Maintenance IRQ number */
> 
> nit: this is the physial INTID, right?
> 
>> +	unsigned int		maint_irq;

No, this is the actual Linux IRQ number.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 13/55] KVM: arm/arm64: vgic-new: Add data structure definitions
@ 2016-05-12 12:17       ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-12 12:17 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/05/16 13:12, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:26AM +0100, Andre Przywara wrote:
>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>
>> Add a new header file for the new and improved GIC implementation.
>> The big change is that we now have a struct vgic_irq per IRQ instead
>> of spreading all the information over various bitmaps.
>>
>> We include this new header conditionally from within the old header
>> file for the time being to avoid touching all the users.
>>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changes RFC .. v1:
>> - adapt to 4.6-rc (adding live_lrs member)
>> - elaborate on ap_list usage
>>
>> Changes v1 .. v2:
>> - change data type of dist->enabled to bool
>>
>>  include/kvm/arm_vgic.h  |   5 ++
>>  include/kvm/vgic/vgic.h | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 206 insertions(+)
>>  create mode 100644 include/kvm/vgic/vgic.h
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index c14ff77..d406f8e 100644
>> --- a/include/kvm/arm_vgic.h
>> +++ b/include/kvm/arm_vgic.h
>> @@ -19,6 +19,10 @@
>>  #ifndef __ASM_ARM_KVM_VGIC_H
>>  #define __ASM_ARM_KVM_VGIC_H
>>  
>> +#ifdef CONFIG_KVM_NEW_VGIC
>> +#include <kvm/vgic/vgic.h>
>> +#else
>> +
>>  #include <linux/kernel.h>
>>  #include <linux/kvm.h>
>>  #include <linux/irqreturn.h>
>> @@ -366,4 +370,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>>  }
>>  #endif
>>  
>> +#endif	/* old VGIC include */
>>  #endif
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> new file mode 100644
>> index 0000000..39933ee
>> --- /dev/null
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -0,0 +1,201 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +#ifndef __ASM_ARM_KVM_VGIC_VGIC_H
>> +#define __ASM_ARM_KVM_VGIC_VGIC_H
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/kvm.h>
>> +#include <linux/irqreturn.h>
>> +#include <linux/spinlock.h>
>> +#include <linux/types.h>
>> +#include <kvm/iodev.h>
>> +
>> +#define VGIC_V3_MAX_CPUS	255
>> +#define VGIC_V2_MAX_CPUS	8
>> +#define VGIC_NR_IRQS_LEGACY     256
>> +#define VGIC_NR_SGIS		16
>> +#define VGIC_NR_PPIS		16
>> +#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
>> +#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
>> +#define VGIC_MAX_SPI		1019
>> +#define VGIC_MAX_RESERVED	1023
>> +#define VGIC_MIN_LPI		8192
>> +
>> +enum vgic_type {
>> +	VGIC_V2,		/* Good ol' GICv2 */
>> +	VGIC_V3,		/* New fancy GICv3 */
>> +};
>> +
>> +/* same for all guests, as depending only on the _host's_ GIC model */
>> +struct vgic_global {
>> +	/* type of the host GIC */
>> +	enum vgic_type		type;
>> +
>> +	/* Physical address of vgic virtual cpu interface */
>> +	phys_addr_t		vcpu_base;
>> +
>> +	/* virtual control interface mapping */
>> +	void __iomem		*vctrl_base;
>> +
>> +	/* Number of implemented list registers */
>> +	int			nr_lr;
>> +
>> +	/* Maintenance IRQ number */
> 
> nit: this is the physial INTID, right?
> 
>> +	unsigned int		maint_irq;

No, this is the actual Linux IRQ number.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 36/55] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-12 12:21     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 12:21 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 06, 2016 at 11:45:49AM +0100, Andre Przywara wrote:
> Since GICv3 supports much more than the 8 CPUs the GICv2 ITARGETSR
> register can handle, the new IROUTER register covers the whole range
> of possible target (V)CPUs by using the same MPIDR that the cores
> report themselves.
> In addition to translating this MPIDR into a vcpu pointer we store
> the originally written value as well. The architecture allows to
> write any values into the register, which must be read back as written.
> 
> Since we don't support affinity level 3, we don't need to take care
> about the upper word of this 64-bit register, which simplifies the
> handling a bit.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - fold in and simplify vgic_v3_irq_change_affinity
> 
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 65 +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 64 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index 48fba9c..3bcc2c4 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -86,6 +86,69 @@ static u32 compress_mpidr(unsigned long mpidr)
>  	return ret;
>  }
>  
> +static unsigned long decompress_mpidr(u32 value)
> +{
> +	unsigned long mpidr;
> +
> +	mpidr  = ((value >>  0) & 0xFF) << MPIDR_LEVEL_SHIFT(0);
> +	mpidr |= ((value >>  8) & 0xFF) << MPIDR_LEVEL_SHIFT(1);
> +	mpidr |= ((value >> 16) & 0xFF) << MPIDR_LEVEL_SHIFT(2);
> +	mpidr |= (u64)((value >> 24) & 0xFF) << MPIDR_LEVEL_SHIFT(3);
> +
> +	return mpidr;
> +}
> +
> +static unsigned long vgic_mmio_read_irouter(struct kvm_vcpu *vcpu,
> +					    gpa_t addr, unsigned int len)
> +{
> +	int intid = (addr & 0x1fff) / 8;
> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
> +	unsigned long mpidr;
> +
> +	if (!irq)
> +		return 0;
> +
> +	mpidr = decompress_mpidr(irq->mpidr);

I'm unsure here; do we ned a READ_ONCE() in lieu taking the lock or are
we guaranteed that this is a single memory access even with compiler
inlining etc.?

> +	return extract_bytes(mpidr, addr & 7, len);
> +}
> +
> +static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len,
> +				    unsigned long val)
> +{
> +	int intid = (addr & 0x1fff) / 8;
> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
> +	unsigned long mask = 0xffffffff;	/* upper word is WI */
> +	u64 mpidr;
> +
> +	if (!irq)
> +		return;
> +
> +	/*
> +	 * There are only two supported options:
> +	 * (1) aligned 64-bit access
> +	 * (2) aligned 32-bit access
> +	 *
> +	 * TODO: make this check generic and move it to dispatch_...()
> +	 */
> +	if (len != 4 && len != 8)
> +		return;
> +
> +
> +	/* The upper word is WI for us since we don't implement Aff3. */
> +	if (addr & 4)
> +		return;
> +
> +	spin_lock(&irq->irq_lock);
> +
> +	mpidr = decompress_mpidr(irq->mpidr);
> +	mpidr = (mpidr & ~mask) | (val & mask);
> +	irq->mpidr = compress_mpidr(mpidr);
> +	irq->target_vcpu = kvm_mpidr_to_vcpu(vcpu->kvm, mpidr);

this is weird because it doesn't preserve read-as-written semantics but
allows a guest to write something into the RES0 field and read that back
in the Aff3 field...

> +
> +	spin_unlock(&irq->irq_lock);
> +}
> +
>  static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
>  					      gpa_t addr, unsigned int len)
>  {
> @@ -174,7 +237,7 @@ static const struct vgic_register_region vgic_v3_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
> +		vgic_mmio_read_irouter, vgic_mmio_write_irouter, 64),
>  	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>  		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
>  };
> -- 
> 2.7.3
> 

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

* [PATCH v3 36/55] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
@ 2016-05-12 12:21     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 12:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:49AM +0100, Andre Przywara wrote:
> Since GICv3 supports much more than the 8 CPUs the GICv2 ITARGETSR
> register can handle, the new IROUTER register covers the whole range
> of possible target (V)CPUs by using the same MPIDR that the cores
> report themselves.
> In addition to translating this MPIDR into a vcpu pointer we store
> the originally written value as well. The architecture allows to
> write any values into the register, which must be read back as written.
> 
> Since we don't support affinity level 3, we don't need to take care
> about the upper word of this 64-bit register, which simplifies the
> handling a bit.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - fold in and simplify vgic_v3_irq_change_affinity
> 
> Changelog v1 .. v2:
> - adapt to new MMIO framework
> 
>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 65 +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 64 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index 48fba9c..3bcc2c4 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -86,6 +86,69 @@ static u32 compress_mpidr(unsigned long mpidr)
>  	return ret;
>  }
>  
> +static unsigned long decompress_mpidr(u32 value)
> +{
> +	unsigned long mpidr;
> +
> +	mpidr  = ((value >>  0) & 0xFF) << MPIDR_LEVEL_SHIFT(0);
> +	mpidr |= ((value >>  8) & 0xFF) << MPIDR_LEVEL_SHIFT(1);
> +	mpidr |= ((value >> 16) & 0xFF) << MPIDR_LEVEL_SHIFT(2);
> +	mpidr |= (u64)((value >> 24) & 0xFF) << MPIDR_LEVEL_SHIFT(3);
> +
> +	return mpidr;
> +}
> +
> +static unsigned long vgic_mmio_read_irouter(struct kvm_vcpu *vcpu,
> +					    gpa_t addr, unsigned int len)
> +{
> +	int intid = (addr & 0x1fff) / 8;
> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
> +	unsigned long mpidr;
> +
> +	if (!irq)
> +		return 0;
> +
> +	mpidr = decompress_mpidr(irq->mpidr);

I'm unsure here; do we ned a READ_ONCE() in lieu taking the lock or are
we guaranteed that this is a single memory access even with compiler
inlining etc.?

> +	return extract_bytes(mpidr, addr & 7, len);
> +}
> +
> +static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
> +				    gpa_t addr, unsigned int len,
> +				    unsigned long val)
> +{
> +	int intid = (addr & 0x1fff) / 8;
> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
> +	unsigned long mask = 0xffffffff;	/* upper word is WI */
> +	u64 mpidr;
> +
> +	if (!irq)
> +		return;
> +
> +	/*
> +	 * There are only two supported options:
> +	 * (1) aligned 64-bit access
> +	 * (2) aligned 32-bit access
> +	 *
> +	 * TODO: make this check generic and move it to dispatch_...()
> +	 */
> +	if (len != 4 && len != 8)
> +		return;
> +
> +
> +	/* The upper word is WI for us since we don't implement Aff3. */
> +	if (addr & 4)
> +		return;
> +
> +	spin_lock(&irq->irq_lock);
> +
> +	mpidr = decompress_mpidr(irq->mpidr);
> +	mpidr = (mpidr & ~mask) | (val & mask);
> +	irq->mpidr = compress_mpidr(mpidr);
> +	irq->target_vcpu = kvm_mpidr_to_vcpu(vcpu->kvm, mpidr);

this is weird because it doesn't preserve read-as-written semantics but
allows a guest to write something into the RES0 field and read that back
in the Aff3 field...

> +
> +	spin_unlock(&irq->irq_lock);
> +}
> +
>  static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
>  					      gpa_t addr, unsigned int len)
>  {
> @@ -174,7 +237,7 @@ static const struct vgic_register_region vgic_v3_dist_registers[] = {
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGRPMODR,
>  		vgic_mmio_read_raz, vgic_mmio_write_wi, 1),
>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IROUTER,
> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 64),
> +		vgic_mmio_read_irouter, vgic_mmio_write_irouter, 64),
>  	REGISTER_DESC_WITH_LENGTH(GICD_IDREGS,
>  		vgic_mmio_read_v3_idregs, vgic_mmio_write_wi, 48),
>  };
> -- 
> 2.7.3
> 

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

* Re: [PATCH v3 13/55] KVM: arm/arm64: vgic-new: Add data structure definitions
  2016-05-12 12:17       ` Marc Zyngier
@ 2016-05-12 12:23         ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 12:23 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: linux-arm-kernel, Andre Przywara, kvmarm, kvm

On Thu, May 12, 2016 at 01:17:38PM +0100, Marc Zyngier wrote:
> On 12/05/16 13:12, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:26AM +0100, Andre Przywara wrote:
> >> From: Christoffer Dall <christoffer.dall@linaro.org>
> >>
> >> Add a new header file for the new and improved GIC implementation.
> >> The big change is that we now have a struct vgic_irq per IRQ instead
> >> of spreading all the information over various bitmaps.
> >>
> >> We include this new header conditionally from within the old header
> >> file for the time being to avoid touching all the users.
> >>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changes RFC .. v1:
> >> - adapt to 4.6-rc (adding live_lrs member)
> >> - elaborate on ap_list usage
> >>
> >> Changes v1 .. v2:
> >> - change data type of dist->enabled to bool
> >>
> >>  include/kvm/arm_vgic.h  |   5 ++
> >>  include/kvm/vgic/vgic.h | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
> >>  2 files changed, 206 insertions(+)
> >>  create mode 100644 include/kvm/vgic/vgic.h
> >>
> >> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> >> index c14ff77..d406f8e 100644
> >> --- a/include/kvm/arm_vgic.h
> >> +++ b/include/kvm/arm_vgic.h
> >> @@ -19,6 +19,10 @@
> >>  #ifndef __ASM_ARM_KVM_VGIC_H
> >>  #define __ASM_ARM_KVM_VGIC_H
> >>  
> >> +#ifdef CONFIG_KVM_NEW_VGIC
> >> +#include <kvm/vgic/vgic.h>
> >> +#else
> >> +
> >>  #include <linux/kernel.h>
> >>  #include <linux/kvm.h>
> >>  #include <linux/irqreturn.h>
> >> @@ -366,4 +370,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
> >>  }
> >>  #endif
> >>  
> >> +#endif	/* old VGIC include */
> >>  #endif
> >> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >> new file mode 100644
> >> index 0000000..39933ee
> >> --- /dev/null
> >> +++ b/include/kvm/vgic/vgic.h
> >> @@ -0,0 +1,201 @@
> >> +/*
> >> + * Copyright (C) 2015, 2016 ARM Ltd.
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License version 2 as
> >> + * published by the Free Software Foundation.
> >> + *
> >> + * This program is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >> + * GNU General Public License for more details.
> >> + *
> >> + * You should have received a copy of the GNU General Public License
> >> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> >> + */
> >> +#ifndef __ASM_ARM_KVM_VGIC_VGIC_H
> >> +#define __ASM_ARM_KVM_VGIC_VGIC_H
> >> +
> >> +#include <linux/kernel.h>
> >> +#include <linux/kvm.h>
> >> +#include <linux/irqreturn.h>
> >> +#include <linux/spinlock.h>
> >> +#include <linux/types.h>
> >> +#include <kvm/iodev.h>
> >> +
> >> +#define VGIC_V3_MAX_CPUS	255
> >> +#define VGIC_V2_MAX_CPUS	8
> >> +#define VGIC_NR_IRQS_LEGACY     256
> >> +#define VGIC_NR_SGIS		16
> >> +#define VGIC_NR_PPIS		16
> >> +#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
> >> +#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
> >> +#define VGIC_MAX_SPI		1019
> >> +#define VGIC_MAX_RESERVED	1023
> >> +#define VGIC_MIN_LPI		8192
> >> +
> >> +enum vgic_type {
> >> +	VGIC_V2,		/* Good ol' GICv2 */
> >> +	VGIC_V3,		/* New fancy GICv3 */
> >> +};
> >> +
> >> +/* same for all guests, as depending only on the _host's_ GIC model */
> >> +struct vgic_global {
> >> +	/* type of the host GIC */
> >> +	enum vgic_type		type;
> >> +
> >> +	/* Physical address of vgic virtual cpu interface */
> >> +	phys_addr_t		vcpu_base;
> >> +
> >> +	/* virtual control interface mapping */
> >> +	void __iomem		*vctrl_base;
> >> +
> >> +	/* Number of implemented list registers */
> >> +	int			nr_lr;
> >> +
> >> +	/* Maintenance IRQ number */
> > 
> > nit: this is the physial INTID, right?
> > 
> >> +	unsigned int		maint_irq;
> 
> No, this is the actual Linux IRQ number.
> 
oh right, it's set by irq_of_parse_and_map.

My bad,
-Christoffer

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

* [PATCH v3 13/55] KVM: arm/arm64: vgic-new: Add data structure definitions
@ 2016-05-12 12:23         ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 12:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 12, 2016 at 01:17:38PM +0100, Marc Zyngier wrote:
> On 12/05/16 13:12, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:26AM +0100, Andre Przywara wrote:
> >> From: Christoffer Dall <christoffer.dall@linaro.org>
> >>
> >> Add a new header file for the new and improved GIC implementation.
> >> The big change is that we now have a struct vgic_irq per IRQ instead
> >> of spreading all the information over various bitmaps.
> >>
> >> We include this new header conditionally from within the old header
> >> file for the time being to avoid touching all the users.
> >>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changes RFC .. v1:
> >> - adapt to 4.6-rc (adding live_lrs member)
> >> - elaborate on ap_list usage
> >>
> >> Changes v1 .. v2:
> >> - change data type of dist->enabled to bool
> >>
> >>  include/kvm/arm_vgic.h  |   5 ++
> >>  include/kvm/vgic/vgic.h | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
> >>  2 files changed, 206 insertions(+)
> >>  create mode 100644 include/kvm/vgic/vgic.h
> >>
> >> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> >> index c14ff77..d406f8e 100644
> >> --- a/include/kvm/arm_vgic.h
> >> +++ b/include/kvm/arm_vgic.h
> >> @@ -19,6 +19,10 @@
> >>  #ifndef __ASM_ARM_KVM_VGIC_H
> >>  #define __ASM_ARM_KVM_VGIC_H
> >>  
> >> +#ifdef CONFIG_KVM_NEW_VGIC
> >> +#include <kvm/vgic/vgic.h>
> >> +#else
> >> +
> >>  #include <linux/kernel.h>
> >>  #include <linux/kvm.h>
> >>  #include <linux/irqreturn.h>
> >> @@ -366,4 +370,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
> >>  }
> >>  #endif
> >>  
> >> +#endif	/* old VGIC include */
> >>  #endif
> >> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >> new file mode 100644
> >> index 0000000..39933ee
> >> --- /dev/null
> >> +++ b/include/kvm/vgic/vgic.h
> >> @@ -0,0 +1,201 @@
> >> +/*
> >> + * Copyright (C) 2015, 2016 ARM Ltd.
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License version 2 as
> >> + * published by the Free Software Foundation.
> >> + *
> >> + * This program is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >> + * GNU General Public License for more details.
> >> + *
> >> + * You should have received a copy of the GNU General Public License
> >> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> >> + */
> >> +#ifndef __ASM_ARM_KVM_VGIC_VGIC_H
> >> +#define __ASM_ARM_KVM_VGIC_VGIC_H
> >> +
> >> +#include <linux/kernel.h>
> >> +#include <linux/kvm.h>
> >> +#include <linux/irqreturn.h>
> >> +#include <linux/spinlock.h>
> >> +#include <linux/types.h>
> >> +#include <kvm/iodev.h>
> >> +
> >> +#define VGIC_V3_MAX_CPUS	255
> >> +#define VGIC_V2_MAX_CPUS	8
> >> +#define VGIC_NR_IRQS_LEGACY     256
> >> +#define VGIC_NR_SGIS		16
> >> +#define VGIC_NR_PPIS		16
> >> +#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
> >> +#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
> >> +#define VGIC_MAX_SPI		1019
> >> +#define VGIC_MAX_RESERVED	1023
> >> +#define VGIC_MIN_LPI		8192
> >> +
> >> +enum vgic_type {
> >> +	VGIC_V2,		/* Good ol' GICv2 */
> >> +	VGIC_V3,		/* New fancy GICv3 */
> >> +};
> >> +
> >> +/* same for all guests, as depending only on the _host's_ GIC model */
> >> +struct vgic_global {
> >> +	/* type of the host GIC */
> >> +	enum vgic_type		type;
> >> +
> >> +	/* Physical address of vgic virtual cpu interface */
> >> +	phys_addr_t		vcpu_base;
> >> +
> >> +	/* virtual control interface mapping */
> >> +	void __iomem		*vctrl_base;
> >> +
> >> +	/* Number of implemented list registers */
> >> +	int			nr_lr;
> >> +
> >> +	/* Maintenance IRQ number */
> > 
> > nit: this is the physial INTID, right?
> > 
> >> +	unsigned int		maint_irq;
> 
> No, this is the actual Linux IRQ number.
> 
oh right, it's set by irq_of_parse_and_map.

My bad,
-Christoffer

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

* Re: [PATCH v3 33/55] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
  2016-05-12 11:47     ` Christoffer Dall
@ 2016-05-12 12:33       ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-12 12:33 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 12/05/16 12:47, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:46AM +0100, Andre Przywara wrote:
>> As in the GICv2 emulation we handle those three registers in one
>> function.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - kick VCPUs if distributor gets enabled
>>
>> Changelog v1 .. v2:
>> - rewrite write handler to use switch statement
>>
>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 50 +++++++++++++++++++++++++++++++++++++++-
>>  virt/kvm/arm/vgic/vgic.h         |  2 ++
>>  2 files changed, 51 insertions(+), 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> index 06c7ec5..5f4558c 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> @@ -22,6 +22,54 @@
>>  #include "vgic.h"
>>  #include "vgic-mmio.h"
>>  
>> +static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
>> +					    gpa_t addr, unsigned int len)
>> +{
>> +	u32 value = 0;
>> +
>> +	switch (addr & 0x0c) {
>> +	case GICD_CTLR:
>> +		if (vcpu->kvm->arch.vgic.enabled)
>> +			value |= GICD_CTLR_ENABLE_SS_G1;
>> +		value |= GICD_CTLR_ARE_NS | GICD_CTLR_DS;
>> +		break;
>> +	case GICD_TYPER:
>> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +		value = (value >> 5) - 1;
>> +		value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
>> +		break;
>> +	case GICD_IIDR:
>> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
>> +		break;
>> +	default:
>> +		return 0;
>> +	}
>> +
>> +	return extract_bytes(value, addr & 3, len);
> 
> why do we return extract_bytes here?  This register can only be accessed
> in full with a 32-bit aligned access, right?

... which we only ensure since last night.
So: yes, I think this can go.
Will fix it.

> 
>> +}
>> +
>> +static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
>> +				    gpa_t addr, unsigned int len,
>> +				    unsigned long val)
>> +{
>> +	switch (addr & 0x0c) {
>> +	case GICD_CTLR:
>> +		if (!(addr & 1)) {
> 
> obviously same question as on the v2 counterpart

Noted, will be fixed.

Cheers,
Andre.

> 
>> +			struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>> +			bool was_enabled = dist->enabled;
>> +
>> +			dist->enabled = val & GICD_CTLR_ENABLE_SS_G1;
>> +
>> +			if (!was_enabled && dist->enabled)
>> +				vgic_kick_vcpus(vcpu->kvm);
>> +		}
>> +		break;
>> +	case GICD_TYPER:
>> +	case GICD_IIDR:
>> +		return;
>> +	}
>> +}
>> +
>>  /*
>>   * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
>>   * redistributors, while SPIs are covered by registers in the distributor
>> @@ -46,7 +94,7 @@
>>  
>>  static const struct vgic_register_region vgic_v3_dist_registers[] = {
>>  	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
>> +		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 39a8a65..635e2e2 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -19,6 +19,8 @@
>>  #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
>>  #define IMPLEMENTER_ARM		0x43b
>>  
>> +#define INTERRUPT_ID_BITS_SPIS	10
>> +
>>  #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
>>  
>>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> -- 
>> 2.7.3
>>
> 

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

* [PATCH v3 33/55] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers
@ 2016-05-12 12:33       ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-12 12:33 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 12/05/16 12:47, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:46AM +0100, Andre Przywara wrote:
>> As in the GICv2 emulation we handle those three registers in one
>> function.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - kick VCPUs if distributor gets enabled
>>
>> Changelog v1 .. v2:
>> - rewrite write handler to use switch statement
>>
>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 50 +++++++++++++++++++++++++++++++++++++++-
>>  virt/kvm/arm/vgic/vgic.h         |  2 ++
>>  2 files changed, 51 insertions(+), 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> index 06c7ec5..5f4558c 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> @@ -22,6 +22,54 @@
>>  #include "vgic.h"
>>  #include "vgic-mmio.h"
>>  
>> +static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
>> +					    gpa_t addr, unsigned int len)
>> +{
>> +	u32 value = 0;
>> +
>> +	switch (addr & 0x0c) {
>> +	case GICD_CTLR:
>> +		if (vcpu->kvm->arch.vgic.enabled)
>> +			value |= GICD_CTLR_ENABLE_SS_G1;
>> +		value |= GICD_CTLR_ARE_NS | GICD_CTLR_DS;
>> +		break;
>> +	case GICD_TYPER:
>> +		value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +		value = (value >> 5) - 1;
>> +		value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
>> +		break;
>> +	case GICD_IIDR:
>> +		value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
>> +		break;
>> +	default:
>> +		return 0;
>> +	}
>> +
>> +	return extract_bytes(value, addr & 3, len);
> 
> why do we return extract_bytes here?  This register can only be accessed
> in full with a 32-bit aligned access, right?

... which we only ensure since last night.
So: yes, I think this can go.
Will fix it.

> 
>> +}
>> +
>> +static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
>> +				    gpa_t addr, unsigned int len,
>> +				    unsigned long val)
>> +{
>> +	switch (addr & 0x0c) {
>> +	case GICD_CTLR:
>> +		if (!(addr & 1)) {
> 
> obviously same question as on the v2 counterpart

Noted, will be fixed.

Cheers,
Andre.

> 
>> +			struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
>> +			bool was_enabled = dist->enabled;
>> +
>> +			dist->enabled = val & GICD_CTLR_ENABLE_SS_G1;
>> +
>> +			if (!was_enabled && dist->enabled)
>> +				vgic_kick_vcpus(vcpu->kvm);
>> +		}
>> +		break;
>> +	case GICD_TYPER:
>> +	case GICD_IIDR:
>> +		return;
>> +	}
>> +}
>> +
>>  /*
>>   * The GICv3 per-IRQ registers are split to control PPIs and SGIs in the
>>   * redistributors, while SPIs are covered by registers in the distributor
>> @@ -46,7 +94,7 @@
>>  
>>  static const struct vgic_register_region vgic_v3_dist_registers[] = {
>>  	REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>> -		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
>> +		vgic_mmio_read_v3_misc, vgic_mmio_write_v3_misc, 16),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_IGROUPR,
>>  		vgic_mmio_read_rao, vgic_mmio_write_wi, 1),
>>  	REGISTER_DESC_WITH_BITS_PER_IRQ_SHARED(GICD_ISENABLER,
>> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
>> index 39a8a65..635e2e2 100644
>> --- a/virt/kvm/arm/vgic/vgic.h
>> +++ b/virt/kvm/arm/vgic/vgic.h
>> @@ -19,6 +19,8 @@
>>  #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
>>  #define IMPLEMENTER_ARM		0x43b
>>  
>> +#define INTERRUPT_ID_BITS_SPIS	10
>> +
>>  #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
>>  
>>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>> -- 
>> 2.7.3
>>
> 

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

* Re: [PATCH v3 35/55] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
  2016-05-12 12:12     ` Christoffer Dall
@ 2016-05-12 12:37       ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-12 12:37 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 12/05/16 13:12, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:48AM +0100, Andre Przywara wrote:
>> We implement the only one ID register that is required by the
>> architecture, also this is the one that Linux actually checks.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog v1 .. v2:
>> - adapt to new MMIO framework
>>
>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 20 ++++++++++++++++++--
>>  1 file changed, 18 insertions(+), 2 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> index d137242..48fba9c 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> @@ -110,6 +110,22 @@ static unsigned long vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
>>  	return extract_bytes(value, addr & 3, len);
>>  }
>>  
>> +static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
>> +					      gpa_t addr, unsigned int len)
>> +{
>> +	u32 regnr = (addr & 0x3f) - (GICD_IDREGS & 0x3f);
> 
> this regnr thing is confusing, because it's not an index, it's an
> address offset.
> 
> why can't you do:
> 
> 	switch (addr & 0xffff) {
> 	case GICD_PIDR2:
> 	}

Makes sense. This was a leftover from the time I had subtraction instead
of masking for the IRQ number determination.
Will fix it.

Thanks,
Andre.

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

* [PATCH v3 35/55] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler
@ 2016-05-12 12:37       ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-12 12:37 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 12/05/16 13:12, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:48AM +0100, Andre Przywara wrote:
>> We implement the only one ID register that is required by the
>> architecture, also this is the one that Linux actually checks.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog v1 .. v2:
>> - adapt to new MMIO framework
>>
>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 20 ++++++++++++++++++--
>>  1 file changed, 18 insertions(+), 2 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> index d137242..48fba9c 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> @@ -110,6 +110,22 @@ static unsigned long vgic_mmio_read_v3r_iidr(struct kvm_vcpu *vcpu,
>>  	return extract_bytes(value, addr & 3, len);
>>  }
>>  
>> +static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu,
>> +					      gpa_t addr, unsigned int len)
>> +{
>> +	u32 regnr = (addr & 0x3f) - (GICD_IDREGS & 0x3f);
> 
> this regnr thing is confusing, because it's not an index, it's an
> address offset.
> 
> why can't you do:
> 
> 	switch (addr & 0xffff) {
> 	case GICD_PIDR2:
> 	}

Makes sense. This was a leftover from the time I had subtraction instead
of masking for the IRQ number determination.
Will fix it.

Thanks,
Andre.

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

* Re: [PATCH v3 36/55] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
  2016-05-12 12:21     ` Christoffer Dall
@ 2016-05-12 12:37       ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-12 12:37 UTC (permalink / raw)
  To: Christoffer Dall, Andre Przywara
  Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

On 12/05/16 13:21, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:49AM +0100, Andre Przywara wrote:
>> Since GICv3 supports much more than the 8 CPUs the GICv2 ITARGETSR
>> register can handle, the new IROUTER register covers the whole range
>> of possible target (V)CPUs by using the same MPIDR that the cores
>> report themselves.
>> In addition to translating this MPIDR into a vcpu pointer we store
>> the originally written value as well. The architecture allows to
>> write any values into the register, which must be read back as written.
>>
>> Since we don't support affinity level 3, we don't need to take care
>> about the upper word of this 64-bit register, which simplifies the
>> handling a bit.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - fold in and simplify vgic_v3_irq_change_affinity
>>
>> Changelog v1 .. v2:
>> - adapt to new MMIO framework
>>
>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 65 +++++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 64 insertions(+), 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> index 48fba9c..3bcc2c4 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> @@ -86,6 +86,69 @@ static u32 compress_mpidr(unsigned long mpidr)
>>  	return ret;
>>  }
>>  
>> +static unsigned long decompress_mpidr(u32 value)
>> +{
>> +	unsigned long mpidr;
>> +
>> +	mpidr  = ((value >>  0) & 0xFF) << MPIDR_LEVEL_SHIFT(0);
>> +	mpidr |= ((value >>  8) & 0xFF) << MPIDR_LEVEL_SHIFT(1);
>> +	mpidr |= ((value >> 16) & 0xFF) << MPIDR_LEVEL_SHIFT(2);
>> +	mpidr |= (u64)((value >> 24) & 0xFF) << MPIDR_LEVEL_SHIFT(3);
>> +
>> +	return mpidr;
>> +}
>> +
>> +static unsigned long vgic_mmio_read_irouter(struct kvm_vcpu *vcpu,
>> +					    gpa_t addr, unsigned int len)
>> +{
>> +	int intid = (addr & 0x1fff) / 8;
>> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
>> +	unsigned long mpidr;
>> +
>> +	if (!irq)
>> +		return 0;
>> +
>> +	mpidr = decompress_mpidr(irq->mpidr);
> 
> I'm unsure here; do we ned a READ_ONCE() in lieu taking the lock or are
> we guaranteed that this is a single memory access even with compiler
> inlining etc.?

I can't imagine the compiler being stupid enough to read this multiple
times, but better safe than sorry. +1 for READ_ONCE().

> 
>> +	return extract_bytes(mpidr, addr & 7, len);
>> +}
>> +
>> +static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
>> +				    gpa_t addr, unsigned int len,
>> +				    unsigned long val)
>> +{
>> +	int intid = (addr & 0x1fff) / 8;
>> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
>> +	unsigned long mask = 0xffffffff;	/* upper word is WI */
>> +	u64 mpidr;
>> +
>> +	if (!irq)
>> +		return;
>> +
>> +	/*
>> +	 * There are only two supported options:
>> +	 * (1) aligned 64-bit access
>> +	 * (2) aligned 32-bit access
>> +	 *
>> +	 * TODO: make this check generic and move it to dispatch_...()
>> +	 */
>> +	if (len != 4 && len != 8)
>> +		return;
>> +
>> +
>> +	/* The upper word is WI for us since we don't implement Aff3. */
>> +	if (addr & 4)
>> +		return;
>> +
>> +	spin_lock(&irq->irq_lock);
>> +
>> +	mpidr = decompress_mpidr(irq->mpidr);
>> +	mpidr = (mpidr & ~mask) | (val & mask);
>> +	irq->mpidr = compress_mpidr(mpidr);
>> +	irq->target_vcpu = kvm_mpidr_to_vcpu(vcpu->kvm, mpidr);
> 
> this is weird because it doesn't preserve read-as-written semantics but
> allows a guest to write something into the RES0 field and read that back
> in the Aff3 field...

I don't see how we get this RES0/Aff3 mixup, but I can see other issues:

>> +	unsigned long mask = 0xffffffff;	/* upper word is WI */

followed by:

>> +	mpidr = (mpidr & ~mask) | (val & mask);

is not going to preserve the top bits on 32bit (assuming we could
perform a 64bit access on 32bit, but still). Also, the mask preserves
the IRM bit, which is wrong (we don't support 1-of-n distribution).

Why don't we just have

	mpidr = val & GENMASK_ULL(23, 0);

and let's be done with it? I must be missing something about this whole
Aff3 thing...

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 36/55] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
@ 2016-05-12 12:37       ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-12 12:37 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/05/16 13:21, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:49AM +0100, Andre Przywara wrote:
>> Since GICv3 supports much more than the 8 CPUs the GICv2 ITARGETSR
>> register can handle, the new IROUTER register covers the whole range
>> of possible target (V)CPUs by using the same MPIDR that the cores
>> report themselves.
>> In addition to translating this MPIDR into a vcpu pointer we store
>> the originally written value as well. The architecture allows to
>> write any values into the register, which must be read back as written.
>>
>> Since we don't support affinity level 3, we don't need to take care
>> about the upper word of this 64-bit register, which simplifies the
>> handling a bit.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changelog RFC..v1:
>> - fold in and simplify vgic_v3_irq_change_affinity
>>
>> Changelog v1 .. v2:
>> - adapt to new MMIO framework
>>
>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 65 +++++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 64 insertions(+), 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> index 48fba9c..3bcc2c4 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>> @@ -86,6 +86,69 @@ static u32 compress_mpidr(unsigned long mpidr)
>>  	return ret;
>>  }
>>  
>> +static unsigned long decompress_mpidr(u32 value)
>> +{
>> +	unsigned long mpidr;
>> +
>> +	mpidr  = ((value >>  0) & 0xFF) << MPIDR_LEVEL_SHIFT(0);
>> +	mpidr |= ((value >>  8) & 0xFF) << MPIDR_LEVEL_SHIFT(1);
>> +	mpidr |= ((value >> 16) & 0xFF) << MPIDR_LEVEL_SHIFT(2);
>> +	mpidr |= (u64)((value >> 24) & 0xFF) << MPIDR_LEVEL_SHIFT(3);
>> +
>> +	return mpidr;
>> +}
>> +
>> +static unsigned long vgic_mmio_read_irouter(struct kvm_vcpu *vcpu,
>> +					    gpa_t addr, unsigned int len)
>> +{
>> +	int intid = (addr & 0x1fff) / 8;
>> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
>> +	unsigned long mpidr;
>> +
>> +	if (!irq)
>> +		return 0;
>> +
>> +	mpidr = decompress_mpidr(irq->mpidr);
> 
> I'm unsure here; do we ned a READ_ONCE() in lieu taking the lock or are
> we guaranteed that this is a single memory access even with compiler
> inlining etc.?

I can't imagine the compiler being stupid enough to read this multiple
times, but better safe than sorry. +1 for READ_ONCE().

> 
>> +	return extract_bytes(mpidr, addr & 7, len);
>> +}
>> +
>> +static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
>> +				    gpa_t addr, unsigned int len,
>> +				    unsigned long val)
>> +{
>> +	int intid = (addr & 0x1fff) / 8;
>> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
>> +	unsigned long mask = 0xffffffff;	/* upper word is WI */
>> +	u64 mpidr;
>> +
>> +	if (!irq)
>> +		return;
>> +
>> +	/*
>> +	 * There are only two supported options:
>> +	 * (1) aligned 64-bit access
>> +	 * (2) aligned 32-bit access
>> +	 *
>> +	 * TODO: make this check generic and move it to dispatch_...()
>> +	 */
>> +	if (len != 4 && len != 8)
>> +		return;
>> +
>> +
>> +	/* The upper word is WI for us since we don't implement Aff3. */
>> +	if (addr & 4)
>> +		return;
>> +
>> +	spin_lock(&irq->irq_lock);
>> +
>> +	mpidr = decompress_mpidr(irq->mpidr);
>> +	mpidr = (mpidr & ~mask) | (val & mask);
>> +	irq->mpidr = compress_mpidr(mpidr);
>> +	irq->target_vcpu = kvm_mpidr_to_vcpu(vcpu->kvm, mpidr);
> 
> this is weird because it doesn't preserve read-as-written semantics but
> allows a guest to write something into the RES0 field and read that back
> in the Aff3 field...

I don't see how we get this RES0/Aff3 mixup, but I can see other issues:

>> +	unsigned long mask = 0xffffffff;	/* upper word is WI */

followed by:

>> +	mpidr = (mpidr & ~mask) | (val & mask);

is not going to preserve the top bits on 32bit (assuming we could
perform a 64bit access on 32bit, but still). Also, the mask preserves
the IRM bit, which is wrong (we don't support 1-of-n distribution).

Why don't we just have

	mpidr = val & GENMASK_ULL(23, 0);

and let's be done with it? I must be missing something about this whole
Aff3 thing...

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 37/55] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-12 12:40     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 12:40 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 06, 2016 at 11:45:50AM +0100, Andre Przywara wrote:
> In contrast to GICv2 SGIs in a GICv3 implementation are not triggered
> by a MMIO write, but with a system register write. KVM knows about
> that register already, we just need to implement the handler and wire
> it up to the core KVM/ARM code.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - add comment about SGI_AFFINITY_LEVEL macro
> 
>  include/kvm/vgic/vgic.h          |   8 +++
>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 106 +++++++++++++++++++++++++++++++++++++++
>  2 files changed, 114 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 4ec1270..2c43eb8 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -209,6 +209,14 @@ bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
>  void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
>  void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
>  
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
> +#else
> +static inline void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
> +{
> +}
> +#endif
> +
>  /**
>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>   *
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index 3bcc2c4..af12592 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -356,3 +356,109 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
>  
>  	return ret;
>  }
> +
> +/*
> + * Compare a given affinity (level 1-3 and a level 0 mask, from the SGI
> + * generation register ICC_SGI1R_EL1) with a given VCPU.
> + * If the VCPU's MPIDR matches, return the level0 affinity, otherwise
> + * return -1.
> + */
> +static int match_mpidr(u64 sgi_aff, u16 sgi_cpu_mask, struct kvm_vcpu *vcpu)
> +{
> +	unsigned long affinity;
> +	int level0;
> +
> +	/*
> +	 * Split the current VCPU's MPIDR into affinity level 0 and the
> +	 * rest as this is what we have to compare against.
> +	 */
> +	affinity = kvm_vcpu_get_mpidr_aff(vcpu);
> +	level0 = MPIDR_AFFINITY_LEVEL(affinity, 0);
> +	affinity &= ~MPIDR_LEVEL_MASK;
> +
> +	/* bail out if the upper three levels don't match */
> +	if (sgi_aff != affinity)
> +		return -1;
> +
> +	/* Is this VCPU's bit set in the mask ? */
> +	if (!(sgi_cpu_mask & BIT(level0)))
> +		return -1;
> +
> +	return level0;
> +}
> +
> +/*
> + * The ICC_SGI* registers encode the affinity differently from the MPIDR,
> + * so provide a wrapper to use the existing defines to isolate a certain
> + * affinity level.
> + */
> +#define SGI_AFFINITY_LEVEL(reg, level) \
> +	((((reg) & ICC_SGI1R_AFFINITY_## level ##_MASK) \
> +	>> ICC_SGI1R_AFFINITY_## level ##_SHIFT) << MPIDR_LEVEL_SHIFT(level))

Do we really prefer this over (untested):

	static inline u64 decode_sgi_affinity(u64 reg)
	{
		u64 aff1, aff2, aff3;

		aff1 = (reg & ICC_SGI1R_AFFINITY_1_MASK) >> ICC_SGI1R_AFFINITY_1_SHIFT;
		aff2 = (reg & ICC_SGI1R_AFFINITY_2_MASK) >> ICC_SGI1R_AFFINITY_2_SHIFT;
		aff3 = (reg & ICC_SGI1R_AFFINITY_3_MASK) >> ICC_SGI1R_AFFINITY_3_SHIFT;

		return (aff1 << MPIDR_LEVEL_SHIFT(1)) |
		       (aff2 << MPIDR_LEVEL_SHIFT(2)) |
		       (aff3 << MPIDR_LEVEL_SHIFT(3));
	}

> +
> +/**
> + * vgic_v3_dispatch_sgi - handle SGI requests from VCPUs
> + * @vcpu: The VCPU requesting a SGI
> + * @reg: The value written into the ICC_SGI1R_EL1 register by that VCPU
> + *
> + * With GICv3 (and ARE=1) CPUs trigger SGIs by writing to a system register.
> + * This will trap in sys_regs.c and call this function.
> + * This ICC_SGI1R_EL1 register contains the upper three affinity levels of the
> + * target processors as well as a bitmask of 16 Aff0 CPUs.
> + * If the interrupt routing mode bit is not set, we iterate over all VCPUs to
> + * check for matching ones. If this bit is set, we signal all, but not the
> + * calling VCPU.
> + */
> +void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
> +{
> +	struct kvm *kvm = vcpu->kvm;
> +	struct kvm_vcpu *c_vcpu;
> +	u16 target_cpus;
> +	u64 mpidr;
> +	int sgi, c;
> +	int vcpu_id = vcpu->vcpu_id;
> +	bool broadcast;
> +
> +	sgi = (reg & ICC_SGI1R_SGI_ID_MASK) >> ICC_SGI1R_SGI_ID_SHIFT;
> +	broadcast = reg & BIT(ICC_SGI1R_IRQ_ROUTING_MODE_BIT);
> +	target_cpus = (reg & ICC_SGI1R_TARGET_LIST_MASK) >> ICC_SGI1R_TARGET_LIST_SHIFT;
> +	mpidr = SGI_AFFINITY_LEVEL(reg, 3);
> +	mpidr |= SGI_AFFINITY_LEVEL(reg, 2);
> +	mpidr |= SGI_AFFINITY_LEVEL(reg, 1);
> +
> +	/*
> +	 * We iterate over all VCPUs to find the MPIDRs matching the request.
> +	 * If we have handled one CPU, we clear its bit to detect early
> +	 * if we are already finished. This avoids iterating through all
> +	 * VCPUs when most of the times we just signal a single VCPU.
> +	 */
> +	kvm_for_each_vcpu(c, c_vcpu, kvm) {
> +		struct vgic_irq *irq;
> +
> +		/* Exit early if we have dealt with all requested CPUs */
> +		if (!broadcast && target_cpus == 0)
> +			break;
> +
> +		/* Don't signal the calling VCPU */
> +		if (broadcast && c == vcpu_id)
> +			continue;
> +
> +		if (!broadcast) {
> +			int level0;
> +
> +			level0 = match_mpidr(mpidr, target_cpus, c_vcpu);
> +			if (level0 == -1)
> +				continue;
> +
> +			/* remove this matching VCPU from the mask */
> +			target_cpus &= ~BIT(level0);
> +		}
> +
> +		irq = vgic_get_irq(vcpu->kvm, c_vcpu, sgi);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->pending = true;
> +
> +		vgic_queue_irq_unlock(vcpu->kvm, irq);
> +	}
> +}
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

otherwise:

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

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

* [PATCH v3 37/55] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler
@ 2016-05-12 12:40     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 12:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:50AM +0100, Andre Przywara wrote:
> In contrast to GICv2 SGIs in a GICv3 implementation are not triggered
> by a MMIO write, but with a system register write. KVM knows about
> that register already, we just need to implement the handler and wire
> it up to the core KVM/ARM code.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - add comment about SGI_AFFINITY_LEVEL macro
> 
>  include/kvm/vgic/vgic.h          |   8 +++
>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 106 +++++++++++++++++++++++++++++++++++++++
>  2 files changed, 114 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 4ec1270..2c43eb8 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -209,6 +209,14 @@ bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
>  void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
>  void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
>  
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
> +#else
> +static inline void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
> +{
> +}
> +#endif
> +
>  /**
>   * kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
>   *
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> index 3bcc2c4..af12592 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> @@ -356,3 +356,109 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
>  
>  	return ret;
>  }
> +
> +/*
> + * Compare a given affinity (level 1-3 and a level 0 mask, from the SGI
> + * generation register ICC_SGI1R_EL1) with a given VCPU.
> + * If the VCPU's MPIDR matches, return the level0 affinity, otherwise
> + * return -1.
> + */
> +static int match_mpidr(u64 sgi_aff, u16 sgi_cpu_mask, struct kvm_vcpu *vcpu)
> +{
> +	unsigned long affinity;
> +	int level0;
> +
> +	/*
> +	 * Split the current VCPU's MPIDR into affinity level 0 and the
> +	 * rest as this is what we have to compare against.
> +	 */
> +	affinity = kvm_vcpu_get_mpidr_aff(vcpu);
> +	level0 = MPIDR_AFFINITY_LEVEL(affinity, 0);
> +	affinity &= ~MPIDR_LEVEL_MASK;
> +
> +	/* bail out if the upper three levels don't match */
> +	if (sgi_aff != affinity)
> +		return -1;
> +
> +	/* Is this VCPU's bit set in the mask ? */
> +	if (!(sgi_cpu_mask & BIT(level0)))
> +		return -1;
> +
> +	return level0;
> +}
> +
> +/*
> + * The ICC_SGI* registers encode the affinity differently from the MPIDR,
> + * so provide a wrapper to use the existing defines to isolate a certain
> + * affinity level.
> + */
> +#define SGI_AFFINITY_LEVEL(reg, level) \
> +	((((reg) & ICC_SGI1R_AFFINITY_## level ##_MASK) \
> +	>> ICC_SGI1R_AFFINITY_## level ##_SHIFT) << MPIDR_LEVEL_SHIFT(level))

Do we really prefer this over (untested):

	static inline u64 decode_sgi_affinity(u64 reg)
	{
		u64 aff1, aff2, aff3;

		aff1 = (reg & ICC_SGI1R_AFFINITY_1_MASK) >> ICC_SGI1R_AFFINITY_1_SHIFT;
		aff2 = (reg & ICC_SGI1R_AFFINITY_2_MASK) >> ICC_SGI1R_AFFINITY_2_SHIFT;
		aff3 = (reg & ICC_SGI1R_AFFINITY_3_MASK) >> ICC_SGI1R_AFFINITY_3_SHIFT;

		return (aff1 << MPIDR_LEVEL_SHIFT(1)) |
		       (aff2 << MPIDR_LEVEL_SHIFT(2)) |
		       (aff3 << MPIDR_LEVEL_SHIFT(3));
	}

> +
> +/**
> + * vgic_v3_dispatch_sgi - handle SGI requests from VCPUs
> + * @vcpu: The VCPU requesting a SGI
> + * @reg: The value written into the ICC_SGI1R_EL1 register by that VCPU
> + *
> + * With GICv3 (and ARE=1) CPUs trigger SGIs by writing to a system register.
> + * This will trap in sys_regs.c and call this function.
> + * This ICC_SGI1R_EL1 register contains the upper three affinity levels of the
> + * target processors as well as a bitmask of 16 Aff0 CPUs.
> + * If the interrupt routing mode bit is not set, we iterate over all VCPUs to
> + * check for matching ones. If this bit is set, we signal all, but not the
> + * calling VCPU.
> + */
> +void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
> +{
> +	struct kvm *kvm = vcpu->kvm;
> +	struct kvm_vcpu *c_vcpu;
> +	u16 target_cpus;
> +	u64 mpidr;
> +	int sgi, c;
> +	int vcpu_id = vcpu->vcpu_id;
> +	bool broadcast;
> +
> +	sgi = (reg & ICC_SGI1R_SGI_ID_MASK) >> ICC_SGI1R_SGI_ID_SHIFT;
> +	broadcast = reg & BIT(ICC_SGI1R_IRQ_ROUTING_MODE_BIT);
> +	target_cpus = (reg & ICC_SGI1R_TARGET_LIST_MASK) >> ICC_SGI1R_TARGET_LIST_SHIFT;
> +	mpidr = SGI_AFFINITY_LEVEL(reg, 3);
> +	mpidr |= SGI_AFFINITY_LEVEL(reg, 2);
> +	mpidr |= SGI_AFFINITY_LEVEL(reg, 1);
> +
> +	/*
> +	 * We iterate over all VCPUs to find the MPIDRs matching the request.
> +	 * If we have handled one CPU, we clear its bit to detect early
> +	 * if we are already finished. This avoids iterating through all
> +	 * VCPUs when most of the times we just signal a single VCPU.
> +	 */
> +	kvm_for_each_vcpu(c, c_vcpu, kvm) {
> +		struct vgic_irq *irq;
> +
> +		/* Exit early if we have dealt with all requested CPUs */
> +		if (!broadcast && target_cpus == 0)
> +			break;
> +
> +		/* Don't signal the calling VCPU */
> +		if (broadcast && c == vcpu_id)
> +			continue;
> +
> +		if (!broadcast) {
> +			int level0;
> +
> +			level0 = match_mpidr(mpidr, target_cpus, c_vcpu);
> +			if (level0 == -1)
> +				continue;
> +
> +			/* remove this matching VCPU from the mask */
> +			target_cpus &= ~BIT(level0);
> +		}
> +
> +		irq = vgic_get_irq(vcpu->kvm, c_vcpu, sgi);
> +
> +		spin_lock(&irq->irq_lock);
> +		irq->pending = true;
> +
> +		vgic_queue_irq_unlock(vcpu->kvm, irq);
> +	}
> +}
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

otherwise:

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

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

* Re: [PATCH v3 13/55] KVM: arm/arm64: vgic-new: Add data structure definitions
  2016-05-12 12:12     ` Christoffer Dall
@ 2016-05-12 13:25       ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-12 13:25 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 12/05/16 13:12, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:26AM +0100, Andre Przywara wrote:
>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>
>> Add a new header file for the new and improved GIC implementation.
>> The big change is that we now have a struct vgic_irq per IRQ instead
>> of spreading all the information over various bitmaps.
>>
>> We include this new header conditionally from within the old header
>> file for the time being to avoid touching all the users.
>>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changes RFC .. v1:
>> - adapt to 4.6-rc (adding live_lrs member)
>> - elaborate on ap_list usage
>>
>> Changes v1 .. v2:
>> - change data type of dist->enabled to bool
>>
>>  include/kvm/arm_vgic.h  |   5 ++
>>  include/kvm/vgic/vgic.h | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 206 insertions(+)
>>  create mode 100644 include/kvm/vgic/vgic.h
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index c14ff77..d406f8e 100644
>> --- a/include/kvm/arm_vgic.h
>> +++ b/include/kvm/arm_vgic.h
>> @@ -19,6 +19,10 @@
>>  #ifndef __ASM_ARM_KVM_VGIC_H
>>  #define __ASM_ARM_KVM_VGIC_H
>>  
>> +#ifdef CONFIG_KVM_NEW_VGIC
>> +#include <kvm/vgic/vgic.h>
>> +#else
>> +
>>  #include <linux/kernel.h>
>>  #include <linux/kvm.h>
>>  #include <linux/irqreturn.h>
>> @@ -366,4 +370,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>>  }
>>  #endif
>>  
>> +#endif	/* old VGIC include */
>>  #endif
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> new file mode 100644
>> index 0000000..39933ee
>> --- /dev/null
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -0,0 +1,201 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +#ifndef __ASM_ARM_KVM_VGIC_VGIC_H
>> +#define __ASM_ARM_KVM_VGIC_VGIC_H
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/kvm.h>
>> +#include <linux/irqreturn.h>
>> +#include <linux/spinlock.h>
>> +#include <linux/types.h>
>> +#include <kvm/iodev.h>
>> +
>> +#define VGIC_V3_MAX_CPUS	255
>> +#define VGIC_V2_MAX_CPUS	8
>> +#define VGIC_NR_IRQS_LEGACY     256
>> +#define VGIC_NR_SGIS		16
>> +#define VGIC_NR_PPIS		16
>> +#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
>> +#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
>> +#define VGIC_MAX_SPI		1019
>> +#define VGIC_MAX_RESERVED	1023
>> +#define VGIC_MIN_LPI		8192
>> +
>> +enum vgic_type {
>> +	VGIC_V2,		/* Good ol' GICv2 */
>> +	VGIC_V3,		/* New fancy GICv3 */
>> +};
>> +
>> +/* same for all guests, as depending only on the _host's_ GIC model */
>> +struct vgic_global {
>> +	/* type of the host GIC */
>> +	enum vgic_type		type;
>> +
>> +	/* Physical address of vgic virtual cpu interface */
>> +	phys_addr_t		vcpu_base;
>> +
>> +	/* virtual control interface mapping */
>> +	void __iomem		*vctrl_base;
>> +
>> +	/* Number of implemented list registers */
>> +	int			nr_lr;
>> +
>> +	/* Maintenance IRQ number */
> 
> nit: this is the physial INTID, right?
> 
>> +	unsigned int		maint_irq;
>> +
>> +	/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
>> +	int			max_gic_vcpus;
>> +
>> +	/* Only needed for the legacy KVM_CREATE_IRQCHIP */
>> +	bool			can_emulate_gicv2;
>> +};
>> +
>> +extern struct vgic_global kvm_vgic_global_state;
>> +
>> +#define VGIC_V2_MAX_LRS		(1 << 6)
>> +#define VGIC_V3_MAX_LRS		16
>> +#define VGIC_V3_LR_INDEX(lr)	(VGIC_V3_MAX_LRS - 1 - lr)
>> +
>> +enum vgic_irq_config {
>> +	VGIC_CONFIG_EDGE = 0,
>> +	VGIC_CONFIG_LEVEL
>> +};
>> +
>> +struct vgic_irq {
>> +	spinlock_t irq_lock;		/* Protects the content of the struct */
>> +	struct list_head ap_list;
>> +
>> +	struct kvm_vcpu *vcpu;		/* SGIs and PPIs: The VCPU
>> +					 * SPIs and LPIs: The VCPU whose ap_list
>> +					 * on which this is queued.
> 
> nit: s/on which this is queued/this is queued on/
> 
>> +					 */
>> +
>> +	struct kvm_vcpu *target_vcpu;	/* The VCPU that this interrupt should
>> +					 * be send to, as a result of the
> 
> nit: s/send/sent/

Both fixed.

>> +					 * targets reg (v2) or the
>> +					 * affinity reg (v3).
>> +					 */
>> +
>> +	u32 intid;			/* Guest visible INTID */
>> +	bool pending;
>> +	bool line_level;		/* Level only */
>> +	bool soft_pending;		/* Level only */
>> +	bool active;			/* not used for LPIs */
>> +	bool enabled;
>> +	bool hw;			/* Tied to HW IRQ */
>> +	u32 hwintid;			/* HW INTID number */
>> +	union {
>> +		u8 targets;			/* GICv2 target VCPUs mask */
>> +		u32 mpidr;			/* GICv3 target VCPU */
>> +	};
>> +	u8 source;			/* GICv2 SGIs only */
>> +	u8 priority;
>> +	enum vgic_irq_config config;	/* Level or edge */
>> +};
>> +
>> +struct vgic_dist {
>> +	bool			in_kernel;
>> +	bool			ready;
>> +
>> +	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
>> +	u32			vgic_model;
>> +
>> +	int			nr_spis;
>> +
>> +	/* TODO: Consider moving to global state */
>> +	/* Virtual control interface mapping */
>> +	void __iomem		*vctrl_base;
>> +
>> +	/* base addresses in guest physical address space: */
>> +	gpa_t			vgic_dist_base;		/* distributor */
>> +	union {
>> +		/* either a GICv2 CPU interface */
>> +		gpa_t			vgic_cpu_base;
>> +		/* or a number of GICv3 redistributor regions */
>> +		gpa_t			vgic_redist_base;
>> +	};
>> +
>> +	/* distributor enabled */
>> +	bool			enabled;
>> +
>> +	struct vgic_irq		*spis;
>> +};
>> +
>> +struct vgic_v2_cpu_if {
>> +	u32		vgic_hcr;
>> +	u32		vgic_vmcr;
>> +	u32		vgic_misr;	/* Saved only */
>> +	u64		vgic_eisr;	/* Saved only */
>> +	u64		vgic_elrsr;	/* Saved only */
>> +	u32		vgic_apr;
>> +	u32		vgic_lr[VGIC_V2_MAX_LRS];
>> +};
>> +
>> +struct vgic_v3_cpu_if {
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +	u32		vgic_hcr;
>> +	u32		vgic_vmcr;
>> +	u32		vgic_sre;	/* Restored only, change ignored */
>> +	u32		vgic_misr;	/* Saved only */
>> +	u32		vgic_eisr;	/* Saved only */
>> +	u32		vgic_elrsr;	/* Saved only */
>> +	u32		vgic_ap0r[4];
>> +	u32		vgic_ap1r[4];
>> +	u64		vgic_lr[VGIC_V3_MAX_LRS];
>> +#endif
>> +};
>> +
>> +struct vgic_cpu {
>> +	/* CPU vif control registers for world switch */
>> +	union {
>> +		struct vgic_v2_cpu_if	vgic_v2;
>> +		struct vgic_v3_cpu_if	vgic_v3;
>> +	};
>> +
>> +	unsigned int used_lrs;
>> +	struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
>> +
>> +	spinlock_t ap_list_lock;	/* Protects the ap_list */
>> +
>> +	/*
>> +	 * List of IRQs that this VCPU should consider because they are either
>> +	 * Active or Pending (hence the name; AP list), or because they recently
>> +	 * were one of the two and need to be migrated off this list to another
>> +	 * VCPU.
>> +	 */
>> +	struct list_head ap_list_head;
>> +
>> +	u64 live_lrs;
>> +};
>> +
>> +#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>> +#define vgic_initialized(k)	(false)
>> +#define vgic_ready(k)		((k)->arch.vgic.ready)
>> +#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>> +			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
> 
> this should really be a static inline at this point.

I think I tried this at the very beginning and it doesn't work. I get:

In file included from include/kvm/arm_vgic.h:23:0,
                 from arch/arm64/include/asm/kvm_host.h:39,
                 from include/linux/kvm_host.h:36,
                 from arch/arm64/kernel/asm-offsets.c:24:
include/kvm/vgic/vgic.h: In function 'vgic_valid_spi':
include/kvm/vgic/vgic.h:232:13: error: dereferencing pointer to
incomplete type 'struct kvm'
   (irq < kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS);
             ^
./Kbuild:80: recipe for target 'arch/arm64/kernel/asm-offsets.s' failed
make[3]: *** [arch/arm64/kernel/asm-offsets.s] Error 1

Is this because asm-offsets.s includes this file and struct kvm is
opaque at this point?
Or is my brain totally GICed by now?

Cheers,
Andre.

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

* [PATCH v3 13/55] KVM: arm/arm64: vgic-new: Add data structure definitions
@ 2016-05-12 13:25       ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-12 13:25 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 12/05/16 13:12, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:26AM +0100, Andre Przywara wrote:
>> From: Christoffer Dall <christoffer.dall@linaro.org>
>>
>> Add a new header file for the new and improved GIC implementation.
>> The big change is that we now have a struct vgic_irq per IRQ instead
>> of spreading all the information over various bitmaps.
>>
>> We include this new header conditionally from within the old header
>> file for the time being to avoid touching all the users.
>>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> Changes RFC .. v1:
>> - adapt to 4.6-rc (adding live_lrs member)
>> - elaborate on ap_list usage
>>
>> Changes v1 .. v2:
>> - change data type of dist->enabled to bool
>>
>>  include/kvm/arm_vgic.h  |   5 ++
>>  include/kvm/vgic/vgic.h | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 206 insertions(+)
>>  create mode 100644 include/kvm/vgic/vgic.h
>>
>> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
>> index c14ff77..d406f8e 100644
>> --- a/include/kvm/arm_vgic.h
>> +++ b/include/kvm/arm_vgic.h
>> @@ -19,6 +19,10 @@
>>  #ifndef __ASM_ARM_KVM_VGIC_H
>>  #define __ASM_ARM_KVM_VGIC_H
>>  
>> +#ifdef CONFIG_KVM_NEW_VGIC
>> +#include <kvm/vgic/vgic.h>
>> +#else
>> +
>>  #include <linux/kernel.h>
>>  #include <linux/kvm.h>
>>  #include <linux/irqreturn.h>
>> @@ -366,4 +370,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
>>  }
>>  #endif
>>  
>> +#endif	/* old VGIC include */
>>  #endif
>> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
>> new file mode 100644
>> index 0000000..39933ee
>> --- /dev/null
>> +++ b/include/kvm/vgic/vgic.h
>> @@ -0,0 +1,201 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +#ifndef __ASM_ARM_KVM_VGIC_VGIC_H
>> +#define __ASM_ARM_KVM_VGIC_VGIC_H
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/kvm.h>
>> +#include <linux/irqreturn.h>
>> +#include <linux/spinlock.h>
>> +#include <linux/types.h>
>> +#include <kvm/iodev.h>
>> +
>> +#define VGIC_V3_MAX_CPUS	255
>> +#define VGIC_V2_MAX_CPUS	8
>> +#define VGIC_NR_IRQS_LEGACY     256
>> +#define VGIC_NR_SGIS		16
>> +#define VGIC_NR_PPIS		16
>> +#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
>> +#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
>> +#define VGIC_MAX_SPI		1019
>> +#define VGIC_MAX_RESERVED	1023
>> +#define VGIC_MIN_LPI		8192
>> +
>> +enum vgic_type {
>> +	VGIC_V2,		/* Good ol' GICv2 */
>> +	VGIC_V3,		/* New fancy GICv3 */
>> +};
>> +
>> +/* same for all guests, as depending only on the _host's_ GIC model */
>> +struct vgic_global {
>> +	/* type of the host GIC */
>> +	enum vgic_type		type;
>> +
>> +	/* Physical address of vgic virtual cpu interface */
>> +	phys_addr_t		vcpu_base;
>> +
>> +	/* virtual control interface mapping */
>> +	void __iomem		*vctrl_base;
>> +
>> +	/* Number of implemented list registers */
>> +	int			nr_lr;
>> +
>> +	/* Maintenance IRQ number */
> 
> nit: this is the physial INTID, right?
> 
>> +	unsigned int		maint_irq;
>> +
>> +	/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
>> +	int			max_gic_vcpus;
>> +
>> +	/* Only needed for the legacy KVM_CREATE_IRQCHIP */
>> +	bool			can_emulate_gicv2;
>> +};
>> +
>> +extern struct vgic_global kvm_vgic_global_state;
>> +
>> +#define VGIC_V2_MAX_LRS		(1 << 6)
>> +#define VGIC_V3_MAX_LRS		16
>> +#define VGIC_V3_LR_INDEX(lr)	(VGIC_V3_MAX_LRS - 1 - lr)
>> +
>> +enum vgic_irq_config {
>> +	VGIC_CONFIG_EDGE = 0,
>> +	VGIC_CONFIG_LEVEL
>> +};
>> +
>> +struct vgic_irq {
>> +	spinlock_t irq_lock;		/* Protects the content of the struct */
>> +	struct list_head ap_list;
>> +
>> +	struct kvm_vcpu *vcpu;		/* SGIs and PPIs: The VCPU
>> +					 * SPIs and LPIs: The VCPU whose ap_list
>> +					 * on which this is queued.
> 
> nit: s/on which this is queued/this is queued on/
> 
>> +					 */
>> +
>> +	struct kvm_vcpu *target_vcpu;	/* The VCPU that this interrupt should
>> +					 * be send to, as a result of the
> 
> nit: s/send/sent/

Both fixed.

>> +					 * targets reg (v2) or the
>> +					 * affinity reg (v3).
>> +					 */
>> +
>> +	u32 intid;			/* Guest visible INTID */
>> +	bool pending;
>> +	bool line_level;		/* Level only */
>> +	bool soft_pending;		/* Level only */
>> +	bool active;			/* not used for LPIs */
>> +	bool enabled;
>> +	bool hw;			/* Tied to HW IRQ */
>> +	u32 hwintid;			/* HW INTID number */
>> +	union {
>> +		u8 targets;			/* GICv2 target VCPUs mask */
>> +		u32 mpidr;			/* GICv3 target VCPU */
>> +	};
>> +	u8 source;			/* GICv2 SGIs only */
>> +	u8 priority;
>> +	enum vgic_irq_config config;	/* Level or edge */
>> +};
>> +
>> +struct vgic_dist {
>> +	bool			in_kernel;
>> +	bool			ready;
>> +
>> +	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
>> +	u32			vgic_model;
>> +
>> +	int			nr_spis;
>> +
>> +	/* TODO: Consider moving to global state */
>> +	/* Virtual control interface mapping */
>> +	void __iomem		*vctrl_base;
>> +
>> +	/* base addresses in guest physical address space: */
>> +	gpa_t			vgic_dist_base;		/* distributor */
>> +	union {
>> +		/* either a GICv2 CPU interface */
>> +		gpa_t			vgic_cpu_base;
>> +		/* or a number of GICv3 redistributor regions */
>> +		gpa_t			vgic_redist_base;
>> +	};
>> +
>> +	/* distributor enabled */
>> +	bool			enabled;
>> +
>> +	struct vgic_irq		*spis;
>> +};
>> +
>> +struct vgic_v2_cpu_if {
>> +	u32		vgic_hcr;
>> +	u32		vgic_vmcr;
>> +	u32		vgic_misr;	/* Saved only */
>> +	u64		vgic_eisr;	/* Saved only */
>> +	u64		vgic_elrsr;	/* Saved only */
>> +	u32		vgic_apr;
>> +	u32		vgic_lr[VGIC_V2_MAX_LRS];
>> +};
>> +
>> +struct vgic_v3_cpu_if {
>> +#ifdef CONFIG_KVM_ARM_VGIC_V3
>> +	u32		vgic_hcr;
>> +	u32		vgic_vmcr;
>> +	u32		vgic_sre;	/* Restored only, change ignored */
>> +	u32		vgic_misr;	/* Saved only */
>> +	u32		vgic_eisr;	/* Saved only */
>> +	u32		vgic_elrsr;	/* Saved only */
>> +	u32		vgic_ap0r[4];
>> +	u32		vgic_ap1r[4];
>> +	u64		vgic_lr[VGIC_V3_MAX_LRS];
>> +#endif
>> +};
>> +
>> +struct vgic_cpu {
>> +	/* CPU vif control registers for world switch */
>> +	union {
>> +		struct vgic_v2_cpu_if	vgic_v2;
>> +		struct vgic_v3_cpu_if	vgic_v3;
>> +	};
>> +
>> +	unsigned int used_lrs;
>> +	struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
>> +
>> +	spinlock_t ap_list_lock;	/* Protects the ap_list */
>> +
>> +	/*
>> +	 * List of IRQs that this VCPU should consider because they are either
>> +	 * Active or Pending (hence the name; AP list), or because they recently
>> +	 * were one of the two and need to be migrated off this list to another
>> +	 * VCPU.
>> +	 */
>> +	struct list_head ap_list_head;
>> +
>> +	u64 live_lrs;
>> +};
>> +
>> +#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
>> +#define vgic_initialized(k)	(false)
>> +#define vgic_ready(k)		((k)->arch.vgic.ready)
>> +#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>> +			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
> 
> this should really be a static inline at this point.

I think I tried this at the very beginning and it doesn't work. I get:

In file included from include/kvm/arm_vgic.h:23:0,
                 from arch/arm64/include/asm/kvm_host.h:39,
                 from include/linux/kvm_host.h:36,
                 from arch/arm64/kernel/asm-offsets.c:24:
include/kvm/vgic/vgic.h: In function 'vgic_valid_spi':
include/kvm/vgic/vgic.h:232:13: error: dereferencing pointer to
incomplete type 'struct kvm'
   (irq < kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS);
             ^
./Kbuild:80: recipe for target 'arch/arm64/kernel/asm-offsets.s' failed
make[3]: *** [arch/arm64/kernel/asm-offsets.s] Error 1

Is this because asm-offsets.s includes this file and struct kvm is
opaque at this point?
Or is my brain totally GICed by now?

Cheers,
Andre.

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

* Re: [PATCH v3 36/55] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
  2016-05-12 12:37       ` Marc Zyngier
@ 2016-05-12 13:41         ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 13:41 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: Andre Przywara, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Thu, May 12, 2016 at 01:37:57PM +0100, Marc Zyngier wrote:
> On 12/05/16 13:21, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:49AM +0100, Andre Przywara wrote:
> >> Since GICv3 supports much more than the 8 CPUs the GICv2 ITARGETSR
> >> register can handle, the new IROUTER register covers the whole range
> >> of possible target (V)CPUs by using the same MPIDR that the cores
> >> report themselves.
> >> In addition to translating this MPIDR into a vcpu pointer we store
> >> the originally written value as well. The architecture allows to
> >> write any values into the register, which must be read back as written.
> >>
> >> Since we don't support affinity level 3, we don't need to take care
> >> about the upper word of this 64-bit register, which simplifies the
> >> handling a bit.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changelog RFC..v1:
> >> - fold in and simplify vgic_v3_irq_change_affinity
> >>
> >> Changelog v1 .. v2:
> >> - adapt to new MMIO framework
> >>
> >>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 65 +++++++++++++++++++++++++++++++++++++++-
> >>  1 file changed, 64 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> >> index 48fba9c..3bcc2c4 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> >> @@ -86,6 +86,69 @@ static u32 compress_mpidr(unsigned long mpidr)
> >>  	return ret;
> >>  }
> >>  
> >> +static unsigned long decompress_mpidr(u32 value)
> >> +{
> >> +	unsigned long mpidr;
> >> +
> >> +	mpidr  = ((value >>  0) & 0xFF) << MPIDR_LEVEL_SHIFT(0);
> >> +	mpidr |= ((value >>  8) & 0xFF) << MPIDR_LEVEL_SHIFT(1);
> >> +	mpidr |= ((value >> 16) & 0xFF) << MPIDR_LEVEL_SHIFT(2);
> >> +	mpidr |= (u64)((value >> 24) & 0xFF) << MPIDR_LEVEL_SHIFT(3);
> >> +
> >> +	return mpidr;
> >> +}
> >> +
> >> +static unsigned long vgic_mmio_read_irouter(struct kvm_vcpu *vcpu,
> >> +					    gpa_t addr, unsigned int len)
> >> +{
> >> +	int intid = (addr & 0x1fff) / 8;
> >> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
> >> +	unsigned long mpidr;
> >> +
> >> +	if (!irq)
> >> +		return 0;
> >> +
> >> +	mpidr = decompress_mpidr(irq->mpidr);
> > 
> > I'm unsure here; do we ned a READ_ONCE() in lieu taking the lock or are
> > we guaranteed that this is a single memory access even with compiler
> > inlining etc.?
> 
> I can't imagine the compiler being stupid enough to read this multiple
> times, but better safe than sorry. +1 for READ_ONCE().
> 
> > 
> >> +	return extract_bytes(mpidr, addr & 7, len);
> >> +}
> >> +
> >> +static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
> >> +				    gpa_t addr, unsigned int len,
> >> +				    unsigned long val)
> >> +{
> >> +	int intid = (addr & 0x1fff) / 8;
> >> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
> >> +	unsigned long mask = 0xffffffff;	/* upper word is WI */
> >> +	u64 mpidr;
> >> +
> >> +	if (!irq)
> >> +		return;
> >> +
> >> +	/*
> >> +	 * There are only two supported options:
> >> +	 * (1) aligned 64-bit access
> >> +	 * (2) aligned 32-bit access
> >> +	 *
> >> +	 * TODO: make this check generic and move it to dispatch_...()
> >> +	 */
> >> +	if (len != 4 && len != 8)
> >> +		return;
> >> +
> >> +
> >> +	/* The upper word is WI for us since we don't implement Aff3. */
> >> +	if (addr & 4)
> >> +		return;
> >> +
> >> +	spin_lock(&irq->irq_lock);
> >> +
> >> +	mpidr = decompress_mpidr(irq->mpidr);
> >> +	mpidr = (mpidr & ~mask) | (val & mask);
> >> +	irq->mpidr = compress_mpidr(mpidr);
> >> +	irq->target_vcpu = kvm_mpidr_to_vcpu(vcpu->kvm, mpidr);
> > 
> > this is weird because it doesn't preserve read-as-written semantics but
> > allows a guest to write something into the RES0 field and read that back
> > in the Aff3 field...
> 
> I don't see how we get this RES0/Aff3 mixup, but I can see other issues:
> 
oh, never mind, compress_mpidr expects aff3 in bits[39:32] and throws
the rest away.

/me hides under table.

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

* [PATCH v3 36/55] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
@ 2016-05-12 13:41         ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 13:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 12, 2016 at 01:37:57PM +0100, Marc Zyngier wrote:
> On 12/05/16 13:21, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:49AM +0100, Andre Przywara wrote:
> >> Since GICv3 supports much more than the 8 CPUs the GICv2 ITARGETSR
> >> register can handle, the new IROUTER register covers the whole range
> >> of possible target (V)CPUs by using the same MPIDR that the cores
> >> report themselves.
> >> In addition to translating this MPIDR into a vcpu pointer we store
> >> the originally written value as well. The architecture allows to
> >> write any values into the register, which must be read back as written.
> >>
> >> Since we don't support affinity level 3, we don't need to take care
> >> about the upper word of this 64-bit register, which simplifies the
> >> handling a bit.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changelog RFC..v1:
> >> - fold in and simplify vgic_v3_irq_change_affinity
> >>
> >> Changelog v1 .. v2:
> >> - adapt to new MMIO framework
> >>
> >>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 65 +++++++++++++++++++++++++++++++++++++++-
> >>  1 file changed, 64 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> >> index 48fba9c..3bcc2c4 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
> >> @@ -86,6 +86,69 @@ static u32 compress_mpidr(unsigned long mpidr)
> >>  	return ret;
> >>  }
> >>  
> >> +static unsigned long decompress_mpidr(u32 value)
> >> +{
> >> +	unsigned long mpidr;
> >> +
> >> +	mpidr  = ((value >>  0) & 0xFF) << MPIDR_LEVEL_SHIFT(0);
> >> +	mpidr |= ((value >>  8) & 0xFF) << MPIDR_LEVEL_SHIFT(1);
> >> +	mpidr |= ((value >> 16) & 0xFF) << MPIDR_LEVEL_SHIFT(2);
> >> +	mpidr |= (u64)((value >> 24) & 0xFF) << MPIDR_LEVEL_SHIFT(3);
> >> +
> >> +	return mpidr;
> >> +}
> >> +
> >> +static unsigned long vgic_mmio_read_irouter(struct kvm_vcpu *vcpu,
> >> +					    gpa_t addr, unsigned int len)
> >> +{
> >> +	int intid = (addr & 0x1fff) / 8;
> >> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
> >> +	unsigned long mpidr;
> >> +
> >> +	if (!irq)
> >> +		return 0;
> >> +
> >> +	mpidr = decompress_mpidr(irq->mpidr);
> > 
> > I'm unsure here; do we ned a READ_ONCE() in lieu taking the lock or are
> > we guaranteed that this is a single memory access even with compiler
> > inlining etc.?
> 
> I can't imagine the compiler being stupid enough to read this multiple
> times, but better safe than sorry. +1 for READ_ONCE().
> 
> > 
> >> +	return extract_bytes(mpidr, addr & 7, len);
> >> +}
> >> +
> >> +static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
> >> +				    gpa_t addr, unsigned int len,
> >> +				    unsigned long val)
> >> +{
> >> +	int intid = (addr & 0x1fff) / 8;
> >> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
> >> +	unsigned long mask = 0xffffffff;	/* upper word is WI */
> >> +	u64 mpidr;
> >> +
> >> +	if (!irq)
> >> +		return;
> >> +
> >> +	/*
> >> +	 * There are only two supported options:
> >> +	 * (1) aligned 64-bit access
> >> +	 * (2) aligned 32-bit access
> >> +	 *
> >> +	 * TODO: make this check generic and move it to dispatch_...()
> >> +	 */
> >> +	if (len != 4 && len != 8)
> >> +		return;
> >> +
> >> +
> >> +	/* The upper word is WI for us since we don't implement Aff3. */
> >> +	if (addr & 4)
> >> +		return;
> >> +
> >> +	spin_lock(&irq->irq_lock);
> >> +
> >> +	mpidr = decompress_mpidr(irq->mpidr);
> >> +	mpidr = (mpidr & ~mask) | (val & mask);
> >> +	irq->mpidr = compress_mpidr(mpidr);
> >> +	irq->target_vcpu = kvm_mpidr_to_vcpu(vcpu->kvm, mpidr);
> > 
> > this is weird because it doesn't preserve read-as-written semantics but
> > allows a guest to write something into the RES0 field and read that back
> > in the Aff3 field...
> 
> I don't see how we get this RES0/Aff3 mixup, but I can see other issues:
> 
oh, never mind, compress_mpidr expects aff3 in bits[39:32] and throws
the rest away.

/me hides under table.

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

* Re: [PATCH v3 13/55] KVM: arm/arm64: vgic-new: Add data structure definitions
  2016-05-12 13:25       ` Andre Przywara
@ 2016-05-12 13:48         ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 13:48 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Thu, May 12, 2016 at 02:25:23PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 12/05/16 13:12, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:26AM +0100, Andre Przywara wrote:
> >> From: Christoffer Dall <christoffer.dall@linaro.org>
> >>
> >> Add a new header file for the new and improved GIC implementation.
> >> The big change is that we now have a struct vgic_irq per IRQ instead
> >> of spreading all the information over various bitmaps.
> >>
> >> We include this new header conditionally from within the old header
> >> file for the time being to avoid touching all the users.
> >>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changes RFC .. v1:
> >> - adapt to 4.6-rc (adding live_lrs member)
> >> - elaborate on ap_list usage
> >>
> >> Changes v1 .. v2:
> >> - change data type of dist->enabled to bool
> >>
> >>  include/kvm/arm_vgic.h  |   5 ++
> >>  include/kvm/vgic/vgic.h | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
> >>  2 files changed, 206 insertions(+)
> >>  create mode 100644 include/kvm/vgic/vgic.h
> >>
> >> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> >> index c14ff77..d406f8e 100644
> >> --- a/include/kvm/arm_vgic.h
> >> +++ b/include/kvm/arm_vgic.h
> >> @@ -19,6 +19,10 @@
> >>  #ifndef __ASM_ARM_KVM_VGIC_H
> >>  #define __ASM_ARM_KVM_VGIC_H
> >>  
> >> +#ifdef CONFIG_KVM_NEW_VGIC
> >> +#include <kvm/vgic/vgic.h>
> >> +#else
> >> +
> >>  #include <linux/kernel.h>
> >>  #include <linux/kvm.h>
> >>  #include <linux/irqreturn.h>
> >> @@ -366,4 +370,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
> >>  }
> >>  #endif
> >>  
> >> +#endif	/* old VGIC include */
> >>  #endif
> >> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >> new file mode 100644
> >> index 0000000..39933ee
> >> --- /dev/null
> >> +++ b/include/kvm/vgic/vgic.h
> >> @@ -0,0 +1,201 @@
> >> +/*
> >> + * Copyright (C) 2015, 2016 ARM Ltd.
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License version 2 as
> >> + * published by the Free Software Foundation.
> >> + *
> >> + * This program is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >> + * GNU General Public License for more details.
> >> + *
> >> + * You should have received a copy of the GNU General Public License
> >> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> >> + */
> >> +#ifndef __ASM_ARM_KVM_VGIC_VGIC_H
> >> +#define __ASM_ARM_KVM_VGIC_VGIC_H
> >> +
> >> +#include <linux/kernel.h>
> >> +#include <linux/kvm.h>
> >> +#include <linux/irqreturn.h>
> >> +#include <linux/spinlock.h>
> >> +#include <linux/types.h>
> >> +#include <kvm/iodev.h>
> >> +
> >> +#define VGIC_V3_MAX_CPUS	255
> >> +#define VGIC_V2_MAX_CPUS	8
> >> +#define VGIC_NR_IRQS_LEGACY     256
> >> +#define VGIC_NR_SGIS		16
> >> +#define VGIC_NR_PPIS		16
> >> +#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
> >> +#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
> >> +#define VGIC_MAX_SPI		1019
> >> +#define VGIC_MAX_RESERVED	1023
> >> +#define VGIC_MIN_LPI		8192
> >> +
> >> +enum vgic_type {
> >> +	VGIC_V2,		/* Good ol' GICv2 */
> >> +	VGIC_V3,		/* New fancy GICv3 */
> >> +};
> >> +
> >> +/* same for all guests, as depending only on the _host's_ GIC model */
> >> +struct vgic_global {
> >> +	/* type of the host GIC */
> >> +	enum vgic_type		type;
> >> +
> >> +	/* Physical address of vgic virtual cpu interface */
> >> +	phys_addr_t		vcpu_base;
> >> +
> >> +	/* virtual control interface mapping */
> >> +	void __iomem		*vctrl_base;
> >> +
> >> +	/* Number of implemented list registers */
> >> +	int			nr_lr;
> >> +
> >> +	/* Maintenance IRQ number */
> > 
> > nit: this is the physial INTID, right?
> > 
> >> +	unsigned int		maint_irq;
> >> +
> >> +	/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
> >> +	int			max_gic_vcpus;
> >> +
> >> +	/* Only needed for the legacy KVM_CREATE_IRQCHIP */
> >> +	bool			can_emulate_gicv2;
> >> +};
> >> +
> >> +extern struct vgic_global kvm_vgic_global_state;
> >> +
> >> +#define VGIC_V2_MAX_LRS		(1 << 6)
> >> +#define VGIC_V3_MAX_LRS		16
> >> +#define VGIC_V3_LR_INDEX(lr)	(VGIC_V3_MAX_LRS - 1 - lr)
> >> +
> >> +enum vgic_irq_config {
> >> +	VGIC_CONFIG_EDGE = 0,
> >> +	VGIC_CONFIG_LEVEL
> >> +};
> >> +
> >> +struct vgic_irq {
> >> +	spinlock_t irq_lock;		/* Protects the content of the struct */
> >> +	struct list_head ap_list;
> >> +
> >> +	struct kvm_vcpu *vcpu;		/* SGIs and PPIs: The VCPU
> >> +					 * SPIs and LPIs: The VCPU whose ap_list
> >> +					 * on which this is queued.
> > 
> > nit: s/on which this is queued/this is queued on/
> > 
> >> +					 */
> >> +
> >> +	struct kvm_vcpu *target_vcpu;	/* The VCPU that this interrupt should
> >> +					 * be send to, as a result of the
> > 
> > nit: s/send/sent/
> 
> Both fixed.
> 
> >> +					 * targets reg (v2) or the
> >> +					 * affinity reg (v3).
> >> +					 */
> >> +
> >> +	u32 intid;			/* Guest visible INTID */
> >> +	bool pending;
> >> +	bool line_level;		/* Level only */
> >> +	bool soft_pending;		/* Level only */
> >> +	bool active;			/* not used for LPIs */
> >> +	bool enabled;
> >> +	bool hw;			/* Tied to HW IRQ */
> >> +	u32 hwintid;			/* HW INTID number */
> >> +	union {
> >> +		u8 targets;			/* GICv2 target VCPUs mask */
> >> +		u32 mpidr;			/* GICv3 target VCPU */
> >> +	};
> >> +	u8 source;			/* GICv2 SGIs only */
> >> +	u8 priority;
> >> +	enum vgic_irq_config config;	/* Level or edge */
> >> +};
> >> +
> >> +struct vgic_dist {
> >> +	bool			in_kernel;
> >> +	bool			ready;
> >> +
> >> +	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
> >> +	u32			vgic_model;
> >> +
> >> +	int			nr_spis;
> >> +
> >> +	/* TODO: Consider moving to global state */
> >> +	/* Virtual control interface mapping */
> >> +	void __iomem		*vctrl_base;
> >> +
> >> +	/* base addresses in guest physical address space: */
> >> +	gpa_t			vgic_dist_base;		/* distributor */
> >> +	union {
> >> +		/* either a GICv2 CPU interface */
> >> +		gpa_t			vgic_cpu_base;
> >> +		/* or a number of GICv3 redistributor regions */
> >> +		gpa_t			vgic_redist_base;
> >> +	};
> >> +
> >> +	/* distributor enabled */
> >> +	bool			enabled;
> >> +
> >> +	struct vgic_irq		*spis;
> >> +};
> >> +
> >> +struct vgic_v2_cpu_if {
> >> +	u32		vgic_hcr;
> >> +	u32		vgic_vmcr;
> >> +	u32		vgic_misr;	/* Saved only */
> >> +	u64		vgic_eisr;	/* Saved only */
> >> +	u64		vgic_elrsr;	/* Saved only */
> >> +	u32		vgic_apr;
> >> +	u32		vgic_lr[VGIC_V2_MAX_LRS];
> >> +};
> >> +
> >> +struct vgic_v3_cpu_if {
> >> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> >> +	u32		vgic_hcr;
> >> +	u32		vgic_vmcr;
> >> +	u32		vgic_sre;	/* Restored only, change ignored */
> >> +	u32		vgic_misr;	/* Saved only */
> >> +	u32		vgic_eisr;	/* Saved only */
> >> +	u32		vgic_elrsr;	/* Saved only */
> >> +	u32		vgic_ap0r[4];
> >> +	u32		vgic_ap1r[4];
> >> +	u64		vgic_lr[VGIC_V3_MAX_LRS];
> >> +#endif
> >> +};
> >> +
> >> +struct vgic_cpu {
> >> +	/* CPU vif control registers for world switch */
> >> +	union {
> >> +		struct vgic_v2_cpu_if	vgic_v2;
> >> +		struct vgic_v3_cpu_if	vgic_v3;
> >> +	};
> >> +
> >> +	unsigned int used_lrs;
> >> +	struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
> >> +
> >> +	spinlock_t ap_list_lock;	/* Protects the ap_list */
> >> +
> >> +	/*
> >> +	 * List of IRQs that this VCPU should consider because they are either
> >> +	 * Active or Pending (hence the name; AP list), or because they recently
> >> +	 * were one of the two and need to be migrated off this list to another
> >> +	 * VCPU.
> >> +	 */
> >> +	struct list_head ap_list_head;
> >> +
> >> +	u64 live_lrs;
> >> +};
> >> +
> >> +#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> >> +#define vgic_initialized(k)	(false)
> >> +#define vgic_ready(k)		((k)->arch.vgic.ready)
> >> +#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
> >> +			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
> > 
> > this should really be a static inline at this point.
> 
> I think I tried this at the very beginning and it doesn't work. I get:
> 
> In file included from include/kvm/arm_vgic.h:23:0,
>                  from arch/arm64/include/asm/kvm_host.h:39,
>                  from include/linux/kvm_host.h:36,
>                  from arch/arm64/kernel/asm-offsets.c:24:
> include/kvm/vgic/vgic.h: In function 'vgic_valid_spi':
> include/kvm/vgic/vgic.h:232:13: error: dereferencing pointer to
> incomplete type 'struct kvm'
>    (irq < kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS);
>              ^
> ./Kbuild:80: recipe for target 'arch/arm64/kernel/asm-offsets.s' failed
> make[3]: *** [arch/arm64/kernel/asm-offsets.s] Error 1
> 
> Is this because asm-offsets.s includes this file and struct kvm is
> opaque at this point?

Probably, but in this case, never mind, we can rework that another time.

> Or is my brain totally GICed by now?
> 

Haha, I definitely feel GICed!

-Christoffer

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

* [PATCH v3 13/55] KVM: arm/arm64: vgic-new: Add data structure definitions
@ 2016-05-12 13:48         ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 13:48 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 12, 2016 at 02:25:23PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 12/05/16 13:12, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:26AM +0100, Andre Przywara wrote:
> >> From: Christoffer Dall <christoffer.dall@linaro.org>
> >>
> >> Add a new header file for the new and improved GIC implementation.
> >> The big change is that we now have a struct vgic_irq per IRQ instead
> >> of spreading all the information over various bitmaps.
> >>
> >> We include this new header conditionally from within the old header
> >> file for the time being to avoid touching all the users.
> >>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> Changes RFC .. v1:
> >> - adapt to 4.6-rc (adding live_lrs member)
> >> - elaborate on ap_list usage
> >>
> >> Changes v1 .. v2:
> >> - change data type of dist->enabled to bool
> >>
> >>  include/kvm/arm_vgic.h  |   5 ++
> >>  include/kvm/vgic/vgic.h | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
> >>  2 files changed, 206 insertions(+)
> >>  create mode 100644 include/kvm/vgic/vgic.h
> >>
> >> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> >> index c14ff77..d406f8e 100644
> >> --- a/include/kvm/arm_vgic.h
> >> +++ b/include/kvm/arm_vgic.h
> >> @@ -19,6 +19,10 @@
> >>  #ifndef __ASM_ARM_KVM_VGIC_H
> >>  #define __ASM_ARM_KVM_VGIC_H
> >>  
> >> +#ifdef CONFIG_KVM_NEW_VGIC
> >> +#include <kvm/vgic/vgic.h>
> >> +#else
> >> +
> >>  #include <linux/kernel.h>
> >>  #include <linux/kvm.h>
> >>  #include <linux/irqreturn.h>
> >> @@ -366,4 +370,5 @@ static inline int vgic_v3_probe(struct device_node *vgic_node,
> >>  }
> >>  #endif
> >>  
> >> +#endif	/* old VGIC include */
> >>  #endif
> >> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> >> new file mode 100644
> >> index 0000000..39933ee
> >> --- /dev/null
> >> +++ b/include/kvm/vgic/vgic.h
> >> @@ -0,0 +1,201 @@
> >> +/*
> >> + * Copyright (C) 2015, 2016 ARM Ltd.
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License version 2 as
> >> + * published by the Free Software Foundation.
> >> + *
> >> + * This program is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >> + * GNU General Public License for more details.
> >> + *
> >> + * You should have received a copy of the GNU General Public License
> >> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> >> + */
> >> +#ifndef __ASM_ARM_KVM_VGIC_VGIC_H
> >> +#define __ASM_ARM_KVM_VGIC_VGIC_H
> >> +
> >> +#include <linux/kernel.h>
> >> +#include <linux/kvm.h>
> >> +#include <linux/irqreturn.h>
> >> +#include <linux/spinlock.h>
> >> +#include <linux/types.h>
> >> +#include <kvm/iodev.h>
> >> +
> >> +#define VGIC_V3_MAX_CPUS	255
> >> +#define VGIC_V2_MAX_CPUS	8
> >> +#define VGIC_NR_IRQS_LEGACY     256
> >> +#define VGIC_NR_SGIS		16
> >> +#define VGIC_NR_PPIS		16
> >> +#define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
> >> +#define VGIC_MAX_PRIVATE	(VGIC_NR_PRIVATE_IRQS - 1)
> >> +#define VGIC_MAX_SPI		1019
> >> +#define VGIC_MAX_RESERVED	1023
> >> +#define VGIC_MIN_LPI		8192
> >> +
> >> +enum vgic_type {
> >> +	VGIC_V2,		/* Good ol' GICv2 */
> >> +	VGIC_V3,		/* New fancy GICv3 */
> >> +};
> >> +
> >> +/* same for all guests, as depending only on the _host's_ GIC model */
> >> +struct vgic_global {
> >> +	/* type of the host GIC */
> >> +	enum vgic_type		type;
> >> +
> >> +	/* Physical address of vgic virtual cpu interface */
> >> +	phys_addr_t		vcpu_base;
> >> +
> >> +	/* virtual control interface mapping */
> >> +	void __iomem		*vctrl_base;
> >> +
> >> +	/* Number of implemented list registers */
> >> +	int			nr_lr;
> >> +
> >> +	/* Maintenance IRQ number */
> > 
> > nit: this is the physial INTID, right?
> > 
> >> +	unsigned int		maint_irq;
> >> +
> >> +	/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
> >> +	int			max_gic_vcpus;
> >> +
> >> +	/* Only needed for the legacy KVM_CREATE_IRQCHIP */
> >> +	bool			can_emulate_gicv2;
> >> +};
> >> +
> >> +extern struct vgic_global kvm_vgic_global_state;
> >> +
> >> +#define VGIC_V2_MAX_LRS		(1 << 6)
> >> +#define VGIC_V3_MAX_LRS		16
> >> +#define VGIC_V3_LR_INDEX(lr)	(VGIC_V3_MAX_LRS - 1 - lr)
> >> +
> >> +enum vgic_irq_config {
> >> +	VGIC_CONFIG_EDGE = 0,
> >> +	VGIC_CONFIG_LEVEL
> >> +};
> >> +
> >> +struct vgic_irq {
> >> +	spinlock_t irq_lock;		/* Protects the content of the struct */
> >> +	struct list_head ap_list;
> >> +
> >> +	struct kvm_vcpu *vcpu;		/* SGIs and PPIs: The VCPU
> >> +					 * SPIs and LPIs: The VCPU whose ap_list
> >> +					 * on which this is queued.
> > 
> > nit: s/on which this is queued/this is queued on/
> > 
> >> +					 */
> >> +
> >> +	struct kvm_vcpu *target_vcpu;	/* The VCPU that this interrupt should
> >> +					 * be send to, as a result of the
> > 
> > nit: s/send/sent/
> 
> Both fixed.
> 
> >> +					 * targets reg (v2) or the
> >> +					 * affinity reg (v3).
> >> +					 */
> >> +
> >> +	u32 intid;			/* Guest visible INTID */
> >> +	bool pending;
> >> +	bool line_level;		/* Level only */
> >> +	bool soft_pending;		/* Level only */
> >> +	bool active;			/* not used for LPIs */
> >> +	bool enabled;
> >> +	bool hw;			/* Tied to HW IRQ */
> >> +	u32 hwintid;			/* HW INTID number */
> >> +	union {
> >> +		u8 targets;			/* GICv2 target VCPUs mask */
> >> +		u32 mpidr;			/* GICv3 target VCPU */
> >> +	};
> >> +	u8 source;			/* GICv2 SGIs only */
> >> +	u8 priority;
> >> +	enum vgic_irq_config config;	/* Level or edge */
> >> +};
> >> +
> >> +struct vgic_dist {
> >> +	bool			in_kernel;
> >> +	bool			ready;
> >> +
> >> +	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
> >> +	u32			vgic_model;
> >> +
> >> +	int			nr_spis;
> >> +
> >> +	/* TODO: Consider moving to global state */
> >> +	/* Virtual control interface mapping */
> >> +	void __iomem		*vctrl_base;
> >> +
> >> +	/* base addresses in guest physical address space: */
> >> +	gpa_t			vgic_dist_base;		/* distributor */
> >> +	union {
> >> +		/* either a GICv2 CPU interface */
> >> +		gpa_t			vgic_cpu_base;
> >> +		/* or a number of GICv3 redistributor regions */
> >> +		gpa_t			vgic_redist_base;
> >> +	};
> >> +
> >> +	/* distributor enabled */
> >> +	bool			enabled;
> >> +
> >> +	struct vgic_irq		*spis;
> >> +};
> >> +
> >> +struct vgic_v2_cpu_if {
> >> +	u32		vgic_hcr;
> >> +	u32		vgic_vmcr;
> >> +	u32		vgic_misr;	/* Saved only */
> >> +	u64		vgic_eisr;	/* Saved only */
> >> +	u64		vgic_elrsr;	/* Saved only */
> >> +	u32		vgic_apr;
> >> +	u32		vgic_lr[VGIC_V2_MAX_LRS];
> >> +};
> >> +
> >> +struct vgic_v3_cpu_if {
> >> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> >> +	u32		vgic_hcr;
> >> +	u32		vgic_vmcr;
> >> +	u32		vgic_sre;	/* Restored only, change ignored */
> >> +	u32		vgic_misr;	/* Saved only */
> >> +	u32		vgic_eisr;	/* Saved only */
> >> +	u32		vgic_elrsr;	/* Saved only */
> >> +	u32		vgic_ap0r[4];
> >> +	u32		vgic_ap1r[4];
> >> +	u64		vgic_lr[VGIC_V3_MAX_LRS];
> >> +#endif
> >> +};
> >> +
> >> +struct vgic_cpu {
> >> +	/* CPU vif control registers for world switch */
> >> +	union {
> >> +		struct vgic_v2_cpu_if	vgic_v2;
> >> +		struct vgic_v3_cpu_if	vgic_v3;
> >> +	};
> >> +
> >> +	unsigned int used_lrs;
> >> +	struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
> >> +
> >> +	spinlock_t ap_list_lock;	/* Protects the ap_list */
> >> +
> >> +	/*
> >> +	 * List of IRQs that this VCPU should consider because they are either
> >> +	 * Active or Pending (hence the name; AP list), or because they recently
> >> +	 * were one of the two and need to be migrated off this list to another
> >> +	 * VCPU.
> >> +	 */
> >> +	struct list_head ap_list_head;
> >> +
> >> +	u64 live_lrs;
> >> +};
> >> +
> >> +#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> >> +#define vgic_initialized(k)	(false)
> >> +#define vgic_ready(k)		((k)->arch.vgic.ready)
> >> +#define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
> >> +			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
> > 
> > this should really be a static inline at this point.
> 
> I think I tried this at the very beginning and it doesn't work. I get:
> 
> In file included from include/kvm/arm_vgic.h:23:0,
>                  from arch/arm64/include/asm/kvm_host.h:39,
>                  from include/linux/kvm_host.h:36,
>                  from arch/arm64/kernel/asm-offsets.c:24:
> include/kvm/vgic/vgic.h: In function 'vgic_valid_spi':
> include/kvm/vgic/vgic.h:232:13: error: dereferencing pointer to
> incomplete type 'struct kvm'
>    (irq < kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS);
>              ^
> ./Kbuild:80: recipe for target 'arch/arm64/kernel/asm-offsets.s' failed
> make[3]: *** [arch/arm64/kernel/asm-offsets.s] Error 1
> 
> Is this because asm-offsets.s includes this file and struct kvm is
> opaque at this point?

Probably, but in this case, never mind, we can rework that another time.

> Or is my brain totally GICed by now?
> 

Haha, I definitely feel GICed!

-Christoffer

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

* Re: [PATCH v3 36/55] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
  2016-05-12 12:37       ` Marc Zyngier
@ 2016-05-12 14:00         ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-12 14:00 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

Hi,

On 12/05/16 13:37, Marc Zyngier wrote:
> On 12/05/16 13:21, Christoffer Dall wrote:
>> On Fri, May 06, 2016 at 11:45:49AM +0100, Andre Przywara wrote:
>>> Since GICv3 supports much more than the 8 CPUs the GICv2 ITARGETSR
>>> register can handle, the new IROUTER register covers the whole range
>>> of possible target (V)CPUs by using the same MPIDR that the cores
>>> report themselves.
>>> In addition to translating this MPIDR into a vcpu pointer we store
>>> the originally written value as well. The architecture allows to
>>> write any values into the register, which must be read back as written.
>>>
>>> Since we don't support affinity level 3, we don't need to take care
>>> about the upper word of this 64-bit register, which simplifies the
>>> handling a bit.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>> Changelog RFC..v1:
>>> - fold in and simplify vgic_v3_irq_change_affinity
>>>
>>> Changelog v1 .. v2:
>>> - adapt to new MMIO framework
>>>
>>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 65 +++++++++++++++++++++++++++++++++++++++-
>>>  1 file changed, 64 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>> index 48fba9c..3bcc2c4 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>> @@ -86,6 +86,69 @@ static u32 compress_mpidr(unsigned long mpidr)
>>>  	return ret;
>>>  }
>>>  
>>> +static unsigned long decompress_mpidr(u32 value)
>>> +{
>>> +	unsigned long mpidr;
>>> +
>>> +	mpidr  = ((value >>  0) & 0xFF) << MPIDR_LEVEL_SHIFT(0);
>>> +	mpidr |= ((value >>  8) & 0xFF) << MPIDR_LEVEL_SHIFT(1);
>>> +	mpidr |= ((value >> 16) & 0xFF) << MPIDR_LEVEL_SHIFT(2);
>>> +	mpidr |= (u64)((value >> 24) & 0xFF) << MPIDR_LEVEL_SHIFT(3);
>>> +
>>> +	return mpidr;
>>> +}
>>> +
>>> +static unsigned long vgic_mmio_read_irouter(struct kvm_vcpu *vcpu,
>>> +					    gpa_t addr, unsigned int len)
>>> +{
>>> +	int intid = (addr & 0x1fff) / 8;
>>> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
>>> +	unsigned long mpidr;
>>> +
>>> +	if (!irq)
>>> +		return 0;
>>> +
>>> +	mpidr = decompress_mpidr(irq->mpidr);
>>
>> I'm unsure here; do we ned a READ_ONCE() in lieu taking the lock or are
>> we guaranteed that this is a single memory access even with compiler
>> inlining etc.?
> 
> I can't imagine the compiler being stupid enough to read this multiple
> times, but better safe than sorry. +1 for READ_ONCE().
> 
>>
>>> +	return extract_bytes(mpidr, addr & 7, len);
>>> +}
>>> +
>>> +static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
>>> +				    gpa_t addr, unsigned int len,
>>> +				    unsigned long val)
>>> +{
>>> +	int intid = (addr & 0x1fff) / 8;
>>> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
>>> +	unsigned long mask = 0xffffffff;	/* upper word is WI */
>>> +	u64 mpidr;
>>> +
>>> +	if (!irq)
>>> +		return;
>>> +
>>> +	/*
>>> +	 * There are only two supported options:
>>> +	 * (1) aligned 64-bit access
>>> +	 * (2) aligned 32-bit access
>>> +	 *
>>> +	 * TODO: make this check generic and move it to dispatch_...()
>>> +	 */
>>> +	if (len != 4 && len != 8)
>>> +		return;
>>> +
>>> +
>>> +	/* The upper word is WI for us since we don't implement Aff3. */
>>> +	if (addr & 4)
>>> +		return;
>>> +
>>> +	spin_lock(&irq->irq_lock);
>>> +
>>> +	mpidr = decompress_mpidr(irq->mpidr);
>>> +	mpidr = (mpidr & ~mask) | (val & mask);
>>> +	irq->mpidr = compress_mpidr(mpidr);
>>> +	irq->target_vcpu = kvm_mpidr_to_vcpu(vcpu->kvm, mpidr);
>>
>> this is weird because it doesn't preserve read-as-written semantics but
>> allows a guest to write something into the RES0 field and read that back
>> in the Aff3 field...

Technically Aff3 is not RES0, even if the A3V bit is cleared.
The A3V bit just disables Aff3 on the CPU interface side, specifically
for ICC_SGI0R_EL1 & friends.
I think we agreed some time ago that we have to support read-as-written
for this register and don't forward this IRQ if the MPIDR is not valid,
as the spec demands.

> I don't see how we get this RES0/Aff3 mixup, but I can see other issues:
> 
>>> +	unsigned long mask = 0xffffffff;	/* upper word is WI */
> 
> followed by:
> 
>>> +	mpidr = (mpidr & ~mask) | (val & mask);
> 
> is not going to preserve the top bits on 32bit (assuming we could
> perform a 64bit access on 32bit, but still).

Which would be fixed by making mask a u64?

> Also, the mask preserves
> the IRM bit, which is wrong (we don't support 1-of-n distribution).

Agreed on this.

> 
> Why don't we just have
> 
> 	mpidr = val & GENMASK_ULL(23, 0);
> 
> and let's be done with it? I must be missing something about this whole
> Aff3 thing...

Well, this would be a simple solution if we don't have to preserve bogus
MPIDRs.
The spec is a bit vague here:
"For each interrupt, a GIC implementation might support fewer than 256
values for an affinity level. In this case, some bits of the
corresponding affinity level field might be RO."

Not sure if this can apply to _all_ bits of an affinity level or not.

I think the key question is: do we need to preserve any MPIDR value
written into this register?

Cheers,
Andre.

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

* [PATCH v3 36/55] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
@ 2016-05-12 14:00         ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-12 14:00 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 12/05/16 13:37, Marc Zyngier wrote:
> On 12/05/16 13:21, Christoffer Dall wrote:
>> On Fri, May 06, 2016 at 11:45:49AM +0100, Andre Przywara wrote:
>>> Since GICv3 supports much more than the 8 CPUs the GICv2 ITARGETSR
>>> register can handle, the new IROUTER register covers the whole range
>>> of possible target (V)CPUs by using the same MPIDR that the cores
>>> report themselves.
>>> In addition to translating this MPIDR into a vcpu pointer we store
>>> the originally written value as well. The architecture allows to
>>> write any values into the register, which must be read back as written.
>>>
>>> Since we don't support affinity level 3, we don't need to take care
>>> about the upper word of this 64-bit register, which simplifies the
>>> handling a bit.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>> Changelog RFC..v1:
>>> - fold in and simplify vgic_v3_irq_change_affinity
>>>
>>> Changelog v1 .. v2:
>>> - adapt to new MMIO framework
>>>
>>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 65 +++++++++++++++++++++++++++++++++++++++-
>>>  1 file changed, 64 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>> index 48fba9c..3bcc2c4 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>> @@ -86,6 +86,69 @@ static u32 compress_mpidr(unsigned long mpidr)
>>>  	return ret;
>>>  }
>>>  
>>> +static unsigned long decompress_mpidr(u32 value)
>>> +{
>>> +	unsigned long mpidr;
>>> +
>>> +	mpidr  = ((value >>  0) & 0xFF) << MPIDR_LEVEL_SHIFT(0);
>>> +	mpidr |= ((value >>  8) & 0xFF) << MPIDR_LEVEL_SHIFT(1);
>>> +	mpidr |= ((value >> 16) & 0xFF) << MPIDR_LEVEL_SHIFT(2);
>>> +	mpidr |= (u64)((value >> 24) & 0xFF) << MPIDR_LEVEL_SHIFT(3);
>>> +
>>> +	return mpidr;
>>> +}
>>> +
>>> +static unsigned long vgic_mmio_read_irouter(struct kvm_vcpu *vcpu,
>>> +					    gpa_t addr, unsigned int len)
>>> +{
>>> +	int intid = (addr & 0x1fff) / 8;
>>> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
>>> +	unsigned long mpidr;
>>> +
>>> +	if (!irq)
>>> +		return 0;
>>> +
>>> +	mpidr = decompress_mpidr(irq->mpidr);
>>
>> I'm unsure here; do we ned a READ_ONCE() in lieu taking the lock or are
>> we guaranteed that this is a single memory access even with compiler
>> inlining etc.?
> 
> I can't imagine the compiler being stupid enough to read this multiple
> times, but better safe than sorry. +1 for READ_ONCE().
> 
>>
>>> +	return extract_bytes(mpidr, addr & 7, len);
>>> +}
>>> +
>>> +static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
>>> +				    gpa_t addr, unsigned int len,
>>> +				    unsigned long val)
>>> +{
>>> +	int intid = (addr & 0x1fff) / 8;
>>> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
>>> +	unsigned long mask = 0xffffffff;	/* upper word is WI */
>>> +	u64 mpidr;
>>> +
>>> +	if (!irq)
>>> +		return;
>>> +
>>> +	/*
>>> +	 * There are only two supported options:
>>> +	 * (1) aligned 64-bit access
>>> +	 * (2) aligned 32-bit access
>>> +	 *
>>> +	 * TODO: make this check generic and move it to dispatch_...()
>>> +	 */
>>> +	if (len != 4 && len != 8)
>>> +		return;
>>> +
>>> +
>>> +	/* The upper word is WI for us since we don't implement Aff3. */
>>> +	if (addr & 4)
>>> +		return;
>>> +
>>> +	spin_lock(&irq->irq_lock);
>>> +
>>> +	mpidr = decompress_mpidr(irq->mpidr);
>>> +	mpidr = (mpidr & ~mask) | (val & mask);
>>> +	irq->mpidr = compress_mpidr(mpidr);
>>> +	irq->target_vcpu = kvm_mpidr_to_vcpu(vcpu->kvm, mpidr);
>>
>> this is weird because it doesn't preserve read-as-written semantics but
>> allows a guest to write something into the RES0 field and read that back
>> in the Aff3 field...

Technically Aff3 is not RES0, even if the A3V bit is cleared.
The A3V bit just disables Aff3 on the CPU interface side, specifically
for ICC_SGI0R_EL1 & friends.
I think we agreed some time ago that we have to support read-as-written
for this register and don't forward this IRQ if the MPIDR is not valid,
as the spec demands.

> I don't see how we get this RES0/Aff3 mixup, but I can see other issues:
> 
>>> +	unsigned long mask = 0xffffffff;	/* upper word is WI */
> 
> followed by:
> 
>>> +	mpidr = (mpidr & ~mask) | (val & mask);
> 
> is not going to preserve the top bits on 32bit (assuming we could
> perform a 64bit access on 32bit, but still).

Which would be fixed by making mask a u64?

> Also, the mask preserves
> the IRM bit, which is wrong (we don't support 1-of-n distribution).

Agreed on this.

> 
> Why don't we just have
> 
> 	mpidr = val & GENMASK_ULL(23, 0);
> 
> and let's be done with it? I must be missing something about this whole
> Aff3 thing...

Well, this would be a simple solution if we don't have to preserve bogus
MPIDRs.
The spec is a bit vague here:
"For each interrupt, a GIC implementation might support fewer than 256
values for an affinity level. In this case, some bits of the
corresponding affinity level field might be RO."

Not sure if this can apply to _all_ bits of an affinity level or not.

I think the key question is: do we need to preserve any MPIDR value
written into this register?

Cheers,
Andre.

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

* Re: [PATCH v3 36/55] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
  2016-05-12 14:00         ` Andre Przywara
@ 2016-05-12 14:20           ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-12 14:20 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall
  Cc: linux-arm-kernel, kvmarm, kvm, Eric Auger

On 12/05/16 15:00, Andre Przywara wrote:
> Hi,
> 
> On 12/05/16 13:37, Marc Zyngier wrote:
>> On 12/05/16 13:21, Christoffer Dall wrote:
>>> On Fri, May 06, 2016 at 11:45:49AM +0100, Andre Przywara wrote:
>>>> Since GICv3 supports much more than the 8 CPUs the GICv2 ITARGETSR
>>>> register can handle, the new IROUTER register covers the whole range
>>>> of possible target (V)CPUs by using the same MPIDR that the cores
>>>> report themselves.
>>>> In addition to translating this MPIDR into a vcpu pointer we store
>>>> the originally written value as well. The architecture allows to
>>>> write any values into the register, which must be read back as written.
>>>>
>>>> Since we don't support affinity level 3, we don't need to take care
>>>> about the upper word of this 64-bit register, which simplifies the
>>>> handling a bit.
>>>>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>> Changelog RFC..v1:
>>>> - fold in and simplify vgic_v3_irq_change_affinity
>>>>
>>>> Changelog v1 .. v2:
>>>> - adapt to new MMIO framework
>>>>
>>>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 65 +++++++++++++++++++++++++++++++++++++++-
>>>>  1 file changed, 64 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>>> index 48fba9c..3bcc2c4 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>>> @@ -86,6 +86,69 @@ static u32 compress_mpidr(unsigned long mpidr)
>>>>  	return ret;
>>>>  }
>>>>  
>>>> +static unsigned long decompress_mpidr(u32 value)
>>>> +{
>>>> +	unsigned long mpidr;
>>>> +
>>>> +	mpidr  = ((value >>  0) & 0xFF) << MPIDR_LEVEL_SHIFT(0);
>>>> +	mpidr |= ((value >>  8) & 0xFF) << MPIDR_LEVEL_SHIFT(1);
>>>> +	mpidr |= ((value >> 16) & 0xFF) << MPIDR_LEVEL_SHIFT(2);
>>>> +	mpidr |= (u64)((value >> 24) & 0xFF) << MPIDR_LEVEL_SHIFT(3);
>>>> +
>>>> +	return mpidr;
>>>> +}
>>>> +
>>>> +static unsigned long vgic_mmio_read_irouter(struct kvm_vcpu *vcpu,
>>>> +					    gpa_t addr, unsigned int len)
>>>> +{
>>>> +	int intid = (addr & 0x1fff) / 8;
>>>> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
>>>> +	unsigned long mpidr;
>>>> +
>>>> +	if (!irq)
>>>> +		return 0;
>>>> +
>>>> +	mpidr = decompress_mpidr(irq->mpidr);
>>>
>>> I'm unsure here; do we ned a READ_ONCE() in lieu taking the lock or are
>>> we guaranteed that this is a single memory access even with compiler
>>> inlining etc.?
>>
>> I can't imagine the compiler being stupid enough to read this multiple
>> times, but better safe than sorry. +1 for READ_ONCE().
>>
>>>
>>>> +	return extract_bytes(mpidr, addr & 7, len);
>>>> +}
>>>> +
>>>> +static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
>>>> +				    gpa_t addr, unsigned int len,
>>>> +				    unsigned long val)
>>>> +{
>>>> +	int intid = (addr & 0x1fff) / 8;
>>>> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
>>>> +	unsigned long mask = 0xffffffff;	/* upper word is WI */
>>>> +	u64 mpidr;
>>>> +
>>>> +	if (!irq)
>>>> +		return;
>>>> +
>>>> +	/*
>>>> +	 * There are only two supported options:
>>>> +	 * (1) aligned 64-bit access
>>>> +	 * (2) aligned 32-bit access
>>>> +	 *
>>>> +	 * TODO: make this check generic and move it to dispatch_...()
>>>> +	 */
>>>> +	if (len != 4 && len != 8)
>>>> +		return;
>>>> +
>>>> +
>>>> +	/* The upper word is WI for us since we don't implement Aff3. */
>>>> +	if (addr & 4)
>>>> +		return;
>>>> +
>>>> +	spin_lock(&irq->irq_lock);
>>>> +
>>>> +	mpidr = decompress_mpidr(irq->mpidr);
>>>> +	mpidr = (mpidr & ~mask) | (val & mask);
>>>> +	irq->mpidr = compress_mpidr(mpidr);
>>>> +	irq->target_vcpu = kvm_mpidr_to_vcpu(vcpu->kvm, mpidr);
>>>
>>> this is weird because it doesn't preserve read-as-written semantics but
>>> allows a guest to write something into the RES0 field and read that back
>>> in the Aff3 field...
> 
> Technically Aff3 is not RES0, even if the A3V bit is cleared.
> The A3V bit just disables Aff3 on the CPU interface side, specifically
> for ICC_SGI0R_EL1 & friends.
> I think we agreed some time ago that we have to support read-as-written
> for this register and don't forward this IRQ if the MPIDR is not valid,
> as the spec demands.
> 
>> I don't see how we get this RES0/Aff3 mixup, but I can see other issues:
>>
>>>> +	unsigned long mask = 0xffffffff;	/* upper word is WI */
>>
>> followed by:
>>
>>>> +	mpidr = (mpidr & ~mask) | (val & mask);
>>
>> is not going to preserve the top bits on 32bit (assuming we could
>> perform a 64bit access on 32bit, but still).
> 
> Which would be fixed by making mask a u64?
> 
>> Also, the mask preserves
>> the IRM bit, which is wrong (we don't support 1-of-n distribution).
> 
> Agreed on this.
> 
>>
>> Why don't we just have
>>
>> 	mpidr = val & GENMASK_ULL(23, 0);
>>
>> and let's be done with it? I must be missing something about this whole
>> Aff3 thing...
> 
> Well, this would be a simple solution if we don't have to preserve bogus
> MPIDRs.
> The spec is a bit vague here:
> "For each interrupt, a GIC implementation might support fewer than 256
> values for an affinity level. In this case, some bits of the
> corresponding affinity level field might be RO."
> 
> Not sure if this can apply to _all_ bits of an affinity level or not.

I believe it does. Take GIC500 for example: it only implements Aff0
(only 8 cores) and Aff1 (32 clusters). Not even Aff2.

> I think the key question is: do we need to preserve any MPIDR value
> written into this register?

I can't see why. What's the point of storing something you can't even
address? Knowing the HW guys, they'd hate to have precious gates just to
serve as an external brain pack for the SW dudes.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 36/55] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers
@ 2016-05-12 14:20           ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-12 14:20 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/05/16 15:00, Andre Przywara wrote:
> Hi,
> 
> On 12/05/16 13:37, Marc Zyngier wrote:
>> On 12/05/16 13:21, Christoffer Dall wrote:
>>> On Fri, May 06, 2016 at 11:45:49AM +0100, Andre Przywara wrote:
>>>> Since GICv3 supports much more than the 8 CPUs the GICv2 ITARGETSR
>>>> register can handle, the new IROUTER register covers the whole range
>>>> of possible target (V)CPUs by using the same MPIDR that the cores
>>>> report themselves.
>>>> In addition to translating this MPIDR into a vcpu pointer we store
>>>> the originally written value as well. The architecture allows to
>>>> write any values into the register, which must be read back as written.
>>>>
>>>> Since we don't support affinity level 3, we don't need to take care
>>>> about the upper word of this 64-bit register, which simplifies the
>>>> handling a bit.
>>>>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> ---
>>>> Changelog RFC..v1:
>>>> - fold in and simplify vgic_v3_irq_change_affinity
>>>>
>>>> Changelog v1 .. v2:
>>>> - adapt to new MMIO framework
>>>>
>>>>  virt/kvm/arm/vgic/vgic-mmio-v3.c | 65 +++++++++++++++++++++++++++++++++++++++-
>>>>  1 file changed, 64 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>>> index 48fba9c..3bcc2c4 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
>>>> @@ -86,6 +86,69 @@ static u32 compress_mpidr(unsigned long mpidr)
>>>>  	return ret;
>>>>  }
>>>>  
>>>> +static unsigned long decompress_mpidr(u32 value)
>>>> +{
>>>> +	unsigned long mpidr;
>>>> +
>>>> +	mpidr  = ((value >>  0) & 0xFF) << MPIDR_LEVEL_SHIFT(0);
>>>> +	mpidr |= ((value >>  8) & 0xFF) << MPIDR_LEVEL_SHIFT(1);
>>>> +	mpidr |= ((value >> 16) & 0xFF) << MPIDR_LEVEL_SHIFT(2);
>>>> +	mpidr |= (u64)((value >> 24) & 0xFF) << MPIDR_LEVEL_SHIFT(3);
>>>> +
>>>> +	return mpidr;
>>>> +}
>>>> +
>>>> +static unsigned long vgic_mmio_read_irouter(struct kvm_vcpu *vcpu,
>>>> +					    gpa_t addr, unsigned int len)
>>>> +{
>>>> +	int intid = (addr & 0x1fff) / 8;
>>>> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
>>>> +	unsigned long mpidr;
>>>> +
>>>> +	if (!irq)
>>>> +		return 0;
>>>> +
>>>> +	mpidr = decompress_mpidr(irq->mpidr);
>>>
>>> I'm unsure here; do we ned a READ_ONCE() in lieu taking the lock or are
>>> we guaranteed that this is a single memory access even with compiler
>>> inlining etc.?
>>
>> I can't imagine the compiler being stupid enough to read this multiple
>> times, but better safe than sorry. +1 for READ_ONCE().
>>
>>>
>>>> +	return extract_bytes(mpidr, addr & 7, len);
>>>> +}
>>>> +
>>>> +static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
>>>> +				    gpa_t addr, unsigned int len,
>>>> +				    unsigned long val)
>>>> +{
>>>> +	int intid = (addr & 0x1fff) / 8;
>>>> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
>>>> +	unsigned long mask = 0xffffffff;	/* upper word is WI */
>>>> +	u64 mpidr;
>>>> +
>>>> +	if (!irq)
>>>> +		return;
>>>> +
>>>> +	/*
>>>> +	 * There are only two supported options:
>>>> +	 * (1) aligned 64-bit access
>>>> +	 * (2) aligned 32-bit access
>>>> +	 *
>>>> +	 * TODO: make this check generic and move it to dispatch_...()
>>>> +	 */
>>>> +	if (len != 4 && len != 8)
>>>> +		return;
>>>> +
>>>> +
>>>> +	/* The upper word is WI for us since we don't implement Aff3. */
>>>> +	if (addr & 4)
>>>> +		return;
>>>> +
>>>> +	spin_lock(&irq->irq_lock);
>>>> +
>>>> +	mpidr = decompress_mpidr(irq->mpidr);
>>>> +	mpidr = (mpidr & ~mask) | (val & mask);
>>>> +	irq->mpidr = compress_mpidr(mpidr);
>>>> +	irq->target_vcpu = kvm_mpidr_to_vcpu(vcpu->kvm, mpidr);
>>>
>>> this is weird because it doesn't preserve read-as-written semantics but
>>> allows a guest to write something into the RES0 field and read that back
>>> in the Aff3 field...
> 
> Technically Aff3 is not RES0, even if the A3V bit is cleared.
> The A3V bit just disables Aff3 on the CPU interface side, specifically
> for ICC_SGI0R_EL1 & friends.
> I think we agreed some time ago that we have to support read-as-written
> for this register and don't forward this IRQ if the MPIDR is not valid,
> as the spec demands.
> 
>> I don't see how we get this RES0/Aff3 mixup, but I can see other issues:
>>
>>>> +	unsigned long mask = 0xffffffff;	/* upper word is WI */
>>
>> followed by:
>>
>>>> +	mpidr = (mpidr & ~mask) | (val & mask);
>>
>> is not going to preserve the top bits on 32bit (assuming we could
>> perform a 64bit access on 32bit, but still).
> 
> Which would be fixed by making mask a u64?
> 
>> Also, the mask preserves
>> the IRM bit, which is wrong (we don't support 1-of-n distribution).
> 
> Agreed on this.
> 
>>
>> Why don't we just have
>>
>> 	mpidr = val & GENMASK_ULL(23, 0);
>>
>> and let's be done with it? I must be missing something about this whole
>> Aff3 thing...
> 
> Well, this would be a simple solution if we don't have to preserve bogus
> MPIDRs.
> The spec is a bit vague here:
> "For each interrupt, a GIC implementation might support fewer than 256
> values for an affinity level. In this case, some bits of the
> corresponding affinity level field might be RO."
> 
> Not sure if this can apply to _all_ bits of an affinity level or not.

I believe it does. Take GIC500 for example: it only implements Aff0
(only 8 cores) and Aff1 (32 clusters). Not even Aff2.

> I think the key question is: do we need to preserve any MPIDR value
> written into this register?

I can't see why. What's the point of storing something you can't even
address? Knowing the HW guys, they'd hate to have precious gates just to
serve as an external brain pack for the SW dudes.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 17/55] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
  2016-05-12 11:46     ` Christoffer Dall
@ 2016-05-12 15:08       ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-12 15:08 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 12/05/16 12:46, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:30AM +0100, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Implement the framework for syncing IRQs between our emulation and
>> the list registers, which represent the guest's view of IRQs.
>> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
>> which gets called on guest entry and exit.
>> The code talking to the actual GICv2/v3 hardware is added in the
>> following patches.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
> 
> [...]
> 
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index 4fb20fd..c6f8b9b 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
> 
> [...]
> 
>> +
>> +/* Requires the VCPU's ap_list_lock to be held. */
>> +static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	struct vgic_irq *irq;
>> +	int count = 0;
>> +
>> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
>> +
>> +	if (unlikely(!vcpu->kvm->arch.vgic.enabled))
>> +		goto out_clean;
> 
> 
> I know I said I reviewed this, but thinking about this more carefully,
> doesn't the enable bit actually tell us if forwarding of pending
> interrupts is enabled, but not whether or not the vgic exists?
> 
> So you could imagine a guest that turns off the GIC, but still has
> active interrupts that it wants to disable/EOI, in the case of
> shutdown/reboot for example, or is this architecturally not allowed?

I guess you are right, the spec talks only about GICD.CTLR[Enable]
controlling the forwarding of pending interrupts to the CPU interface.
If you don't want interrupts at all, I guess you disable the CPU interface.

So we just don't put pending IRQs in the LR, but only active ones.
I am coding this right now.

Cheers,
Andre

> 
> If it is, then we should, at least theoretically, still forward active
> interrupts in LRs despite the enabled bit being clear, but modify the
> oracle to take the global enable bit into account.
> 
> Thanks,
> -Christoffer

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

* [PATCH v3 17/55] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework
@ 2016-05-12 15:08       ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-12 15:08 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 12/05/16 12:46, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:30AM +0100, Andre Przywara wrote:
>> From: Marc Zyngier <marc.zyngier@arm.com>
>>
>> Implement the framework for syncing IRQs between our emulation and
>> the list registers, which represent the guest's view of IRQs.
>> This is done in kvm_vgic_flush_hwstate and kvm_vgic_sync_hwstate,
>> which gets called on guest entry and exit.
>> The code talking to the actual GICv2/v3 hardware is added in the
>> following patches.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
> 
> [...]
> 
>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>> index 4fb20fd..c6f8b9b 100644
>> --- a/virt/kvm/arm/vgic/vgic.c
>> +++ b/virt/kvm/arm/vgic/vgic.c
> 
> [...]
> 
>> +
>> +/* Requires the VCPU's ap_list_lock to be held. */
>> +static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
>> +{
>> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
>> +	struct vgic_irq *irq;
>> +	int count = 0;
>> +
>> +	DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
>> +
>> +	if (unlikely(!vcpu->kvm->arch.vgic.enabled))
>> +		goto out_clean;
> 
> 
> I know I said I reviewed this, but thinking about this more carefully,
> doesn't the enable bit actually tell us if forwarding of pending
> interrupts is enabled, but not whether or not the vgic exists?
> 
> So you could imagine a guest that turns off the GIC, but still has
> active interrupts that it wants to disable/EOI, in the case of
> shutdown/reboot for example, or is this architecturally not allowed?

I guess you are right, the spec talks only about GICD.CTLR[Enable]
controlling the forwarding of pending interrupts to the CPU interface.
If you don't want interrupts at all, I guess you disable the CPU interface.

So we just don't put pending IRQs in the LR, but only active ones.
I am coding this right now.

Cheers,
Andre

> 
> If it is, then we should, at least theoretically, still forward active
> interrupts in LRs despite the enabled bit being clear, but modify the
> oracle to take the global enable bit into account.
> 
> Thanks,
> -Christoffer

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

* Re: [PATCH v3 43/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-12 18:30     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 18:30 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:45:56AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> This patch implements the switches for KVM_DEV_ARM_VGIC_GRP_DIST_REGS
> and KVM_DEV_ARM_VGIC_GRP_CPU_REGS API which allows the userspace to
> access VGIC registers.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 53 +++++++++++++++++++++++++++++++++++--
>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 34 ++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h            |  1 +
>  3 files changed, 86 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index 0189c13..c952f6f 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -252,6 +252,21 @@ void kvm_register_vgic_device(unsigned long type)
>  	}
>  }
>  
> +/** vgic_attr_regs_access: allows user space to read/write VGIC registers
> + *
> + * @dev: kvm device handle
> + * @attr: kvm device attribute
> + * @reg: address the value is read or written
> + * @is_write: write flag
> + *
> + */
> +static int vgic_attr_regs_access(struct kvm_device *dev,
> +				 struct kvm_device_attr *attr,
> +				 u32 *reg, bool is_write)
> +{
> +	return -ENXIO;
> +}
> +
>  /* V2 ops */
>  
>  static int vgic_v2_set_attr(struct kvm_device *dev,
> @@ -260,8 +275,23 @@ static int vgic_v2_set_attr(struct kvm_device *dev,
>  	int ret;
>  
>  	ret = vgic_set_common_attr(dev, attr);
> -	return ret;
> +	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;
> +
> +		if (get_user(reg, uaddr))
> +			return -EFAULT;
>  
> +		return vgic_attr_regs_access(dev, attr, &reg, true);
> +	}
> +	}
> +
> +	return -ENXIO;
>  }
>  
>  static int vgic_v2_get_attr(struct kvm_device *dev,
> @@ -270,7 +300,23 @@ static int vgic_v2_get_attr(struct kvm_device *dev,
>  	int ret;
>  
>  	ret = vgic_get_common_attr(dev, attr);
> -	return ret;
> +	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 = 0;
> +
> +		ret = vgic_attr_regs_access(dev, attr, &reg, false);
> +		if (ret)
> +			return ret;
> +		return put_user(reg, uaddr);
> +	}
> +	}
> +
> +	return -ENXIO;
>  }
>  
>  static int vgic_v2_has_attr(struct kvm_device *dev,
> @@ -284,6 +330,9 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
>  			return 0;
>  		}
>  		break;
> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> +	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> +		return vgic_v2_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 8006ac0..cf8fee9 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -246,3 +246,37 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
>  
>  	return SZ_4K;
>  }
> +
> +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;
> +
> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> +		regions = vgic_v2_dist_registers;
> +		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
> +		break;
> +	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> +		return -ENXIO;		/* TODO: describe CPU i/f regs also */
> +	default:
> +		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;

should we check if addr is word-aligned ?

> +	}
> +
> +	return -ENXIO;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index c44ee01..a4397f9 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -36,6 +36,7 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>  void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
>  void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
> +int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
>  int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
>  			     enum vgic_type);
>  
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v3 43/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
@ 2016-05-12 18:30     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 18:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:56AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> This patch implements the switches for KVM_DEV_ARM_VGIC_GRP_DIST_REGS
> and KVM_DEV_ARM_VGIC_GRP_CPU_REGS API which allows the userspace to
> access VGIC registers.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 53 +++++++++++++++++++++++++++++++++++--
>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 34 ++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h            |  1 +
>  3 files changed, 86 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index 0189c13..c952f6f 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -252,6 +252,21 @@ void kvm_register_vgic_device(unsigned long type)
>  	}
>  }
>  
> +/** vgic_attr_regs_access: allows user space to read/write VGIC registers
> + *
> + * @dev: kvm device handle
> + * @attr: kvm device attribute
> + * @reg: address the value is read or written
> + * @is_write: write flag
> + *
> + */
> +static int vgic_attr_regs_access(struct kvm_device *dev,
> +				 struct kvm_device_attr *attr,
> +				 u32 *reg, bool is_write)
> +{
> +	return -ENXIO;
> +}
> +
>  /* V2 ops */
>  
>  static int vgic_v2_set_attr(struct kvm_device *dev,
> @@ -260,8 +275,23 @@ static int vgic_v2_set_attr(struct kvm_device *dev,
>  	int ret;
>  
>  	ret = vgic_set_common_attr(dev, attr);
> -	return ret;
> +	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;
> +
> +		if (get_user(reg, uaddr))
> +			return -EFAULT;
>  
> +		return vgic_attr_regs_access(dev, attr, &reg, true);
> +	}
> +	}
> +
> +	return -ENXIO;
>  }
>  
>  static int vgic_v2_get_attr(struct kvm_device *dev,
> @@ -270,7 +300,23 @@ static int vgic_v2_get_attr(struct kvm_device *dev,
>  	int ret;
>  
>  	ret = vgic_get_common_attr(dev, attr);
> -	return ret;
> +	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 = 0;
> +
> +		ret = vgic_attr_regs_access(dev, attr, &reg, false);
> +		if (ret)
> +			return ret;
> +		return put_user(reg, uaddr);
> +	}
> +	}
> +
> +	return -ENXIO;
>  }
>  
>  static int vgic_v2_has_attr(struct kvm_device *dev,
> @@ -284,6 +330,9 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
>  			return 0;
>  		}
>  		break;
> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> +	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> +		return vgic_v2_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 8006ac0..cf8fee9 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -246,3 +246,37 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
>  
>  	return SZ_4K;
>  }
> +
> +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;
> +
> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> +		regions = vgic_v2_dist_registers;
> +		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
> +		break;
> +	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> +		return -ENXIO;		/* TODO: describe CPU i/f regs also */
> +	default:
> +		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;

should we check if addr is word-aligned ?

> +	}
> +
> +	return -ENXIO;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index c44ee01..a4397f9 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -36,6 +36,7 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
>  void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
>  void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
> +int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
>  int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
>  			     enum vgic_type);
>  
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v3 45/55] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-12 18:41     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 18:41 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:45:58AM +0100, Andre Przywara wrote:
> Userland may want to save and restore the state of the in-kernel VGIC,
> so we provide the code which takes a userland request and translate
> that into calls to our MMIO framework.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 50 ++++++++++++++++++++++++++++++++++++-
>  1 file changed, 49 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index c952f6f..bb33af8 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -264,7 +264,55 @@ static int vgic_attr_regs_access(struct kvm_device *dev,

come to think of it, this is GICv2 specific right?

why don't we call it vgic_v2_attr_regs_access then?

and should it really live in this file?

>  				 struct kvm_device_attr *attr,
>  				 u32 *reg, bool is_write)
>  {
> -	return -ENXIO;
> +	gpa_t addr;
> +	int cpuid, ret, c;
> +	struct kvm_vcpu *vcpu, *tmp_vcpu;
> +
> +	cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >>
> +		 KVM_DEV_ARM_VGIC_CPUID_SHIFT;
> +	vcpu = kvm_get_vcpu(dev->kvm, cpuid);
> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
> +
> +	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;
> +	}
> +
> +	/*
> +	 * 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().
> +	 */

eh, I don't see us grabbing any vgic->lock (does that still exist?)
here?

> +	kvm_for_each_vcpu(c, tmp_vcpu, dev->kvm) {
> +		if (unlikely(tmp_vcpu->cpu != -1)) {
> +			ret = -EBUSY;
> +			goto out;
> +		}
> +	}
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> +		ret = -EINVAL;
> +		break;
> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> +		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +out:
> +	mutex_unlock(&dev->kvm->lock);
> +	return ret;
>  }
>  
>  /* V2 ops */
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Thanks,
-Christoffer

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

* [PATCH v3 45/55] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
@ 2016-05-12 18:41     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 18:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:58AM +0100, Andre Przywara wrote:
> Userland may want to save and restore the state of the in-kernel VGIC,
> so we provide the code which takes a userland request and translate
> that into calls to our MMIO framework.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 50 ++++++++++++++++++++++++++++++++++++-
>  1 file changed, 49 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index c952f6f..bb33af8 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -264,7 +264,55 @@ static int vgic_attr_regs_access(struct kvm_device *dev,

come to think of it, this is GICv2 specific right?

why don't we call it vgic_v2_attr_regs_access then?

and should it really live in this file?

>  				 struct kvm_device_attr *attr,
>  				 u32 *reg, bool is_write)
>  {
> -	return -ENXIO;
> +	gpa_t addr;
> +	int cpuid, ret, c;
> +	struct kvm_vcpu *vcpu, *tmp_vcpu;
> +
> +	cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >>
> +		 KVM_DEV_ARM_VGIC_CPUID_SHIFT;
> +	vcpu = kvm_get_vcpu(dev->kvm, cpuid);
> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
> +
> +	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;
> +	}
> +
> +	/*
> +	 * 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().
> +	 */

eh, I don't see us grabbing any vgic->lock (does that still exist?)
here?

> +	kvm_for_each_vcpu(c, tmp_vcpu, dev->kvm) {
> +		if (unlikely(tmp_vcpu->cpu != -1)) {
> +			ret = -EBUSY;
> +			goto out;
> +		}
> +	}
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> +		ret = -EINVAL;
> +		break;
> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> +		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +out:
> +	mutex_unlock(&dev->kvm->lock);
> +	return ret;
>  }
>  
>  /* V2 ops */
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Thanks,
-Christoffer

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

* Re: [PATCH v3 46/55] KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-12 18:43     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 18:43 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:45:59AM +0100, Andre Przywara wrote:
> Since the GIC CPU interface is always virtualized by the hardware,
> we don't have CPU interface state information readily available in our
> emulation if userland wants to save or restore it.
> Fortunately the GIC hypervisor interface provides the VMCR register to
> access the required virtual CPU interface bits.
> Provide wrappers for GICv2 and GICv3 hosts to have access to this
> register.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog v2 .. v3:
> - remove exported v2/v3 selector functions (as per Marc's patch)
> 
>  include/kvm/vgic/vgic.h     |  7 +++++++
>  virt/kvm/arm/vgic/vgic-v2.c | 29 +++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c | 22 ++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h    | 14 ++++++++++++++
>  4 files changed, 72 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 73cab36..cfc3640 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -171,6 +171,13 @@ struct vgic_v3_cpu_if {
>  #endif
>  };
>  
> +struct vgic_vmcr {
> +	u32	ctlr;
> +	u32	abpr;
> +	u32	bpr;
> +	u32	pmr;
> +};
> +

is this going to be used outside the vgic code?

otherwise it could go in virt/kvm/arm/vgic/vgic.h instead?

>  struct vgic_cpu {
>  	/* CPU vif control registers for world switch */
>  	union {
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 4cee616..70cac63 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -176,3 +176,32 @@ void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
>  {
>  	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
>  }
> +
> +void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
> +{
> +	u32 vmcr;
> +
> +	vmcr  = (vmcrp->ctlr << GICH_VMCR_CTRL_SHIFT) & GICH_VMCR_CTRL_MASK;
> +	vmcr |= (vmcrp->abpr << GICH_VMCR_ALIAS_BINPOINT_SHIFT) &
> +		GICH_VMCR_ALIAS_BINPOINT_MASK;
> +	vmcr |= (vmcrp->bpr << GICH_VMCR_BINPOINT_SHIFT) &
> +		GICH_VMCR_BINPOINT_MASK;
> +	vmcr |= (vmcrp->pmr << GICH_VMCR_PRIMASK_SHIFT) &
> +		GICH_VMCR_PRIMASK_MASK;
> +
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = vmcr;
> +}
> +
> +void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
> +{
> +	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr;
> +
> +	vmcrp->ctlr = (vmcr & GICH_VMCR_CTRL_MASK) >>
> +			GICH_VMCR_CTRL_SHIFT;
> +	vmcrp->abpr = (vmcr & GICH_VMCR_ALIAS_BINPOINT_MASK) >>
> +			GICH_VMCR_ALIAS_BINPOINT_SHIFT;
> +	vmcrp->bpr  = (vmcr & GICH_VMCR_BINPOINT_MASK) >>
> +			GICH_VMCR_BINPOINT_SHIFT;
> +	vmcrp->pmr  = (vmcr & GICH_VMCR_PRIMASK_MASK) >>
> +			GICH_VMCR_PRIMASK_SHIFT;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 43d1dd7..dca52b3 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -166,3 +166,25 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
>  {
>  	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = 0;
>  }
> +
> +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;
> +	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;
> +
> +	vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
> +}
> +
> +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;
> +	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;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index bc5750e..5260d23 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -39,6 +39,8 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>  int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
>  int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			 int offset, u32 *val);
> +void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> +void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
>  			     enum vgic_type);
>  
> @@ -48,6 +50,8 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
>  void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
> +void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> +void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
>  #else
>  static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> @@ -71,6 +75,16 @@ static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>  {
>  }
>  
> +static inline
> +void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> +{
> +}
> +
> +static inline
> +void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> +{
> +}
> +
>  static inline int vgic_register_redist_iodevs(struct kvm *kvm,
>  					      gpa_t dist_base_address)
>  {
> -- 
> 2.7.3
> 

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

* [PATCH v3 46/55] KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors
@ 2016-05-12 18:43     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 18:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:59AM +0100, Andre Przywara wrote:
> Since the GIC CPU interface is always virtualized by the hardware,
> we don't have CPU interface state information readily available in our
> emulation if userland wants to save or restore it.
> Fortunately the GIC hypervisor interface provides the VMCR register to
> access the required virtual CPU interface bits.
> Provide wrappers for GICv2 and GICv3 hosts to have access to this
> register.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog v2 .. v3:
> - remove exported v2/v3 selector functions (as per Marc's patch)
> 
>  include/kvm/vgic/vgic.h     |  7 +++++++
>  virt/kvm/arm/vgic/vgic-v2.c | 29 +++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c | 22 ++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h    | 14 ++++++++++++++
>  4 files changed, 72 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 73cab36..cfc3640 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -171,6 +171,13 @@ struct vgic_v3_cpu_if {
>  #endif
>  };
>  
> +struct vgic_vmcr {
> +	u32	ctlr;
> +	u32	abpr;
> +	u32	bpr;
> +	u32	pmr;
> +};
> +

is this going to be used outside the vgic code?

otherwise it could go in virt/kvm/arm/vgic/vgic.h instead?

>  struct vgic_cpu {
>  	/* CPU vif control registers for world switch */
>  	union {
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 4cee616..70cac63 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -176,3 +176,32 @@ void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
>  {
>  	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = 0;
>  }
> +
> +void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
> +{
> +	u32 vmcr;
> +
> +	vmcr  = (vmcrp->ctlr << GICH_VMCR_CTRL_SHIFT) & GICH_VMCR_CTRL_MASK;
> +	vmcr |= (vmcrp->abpr << GICH_VMCR_ALIAS_BINPOINT_SHIFT) &
> +		GICH_VMCR_ALIAS_BINPOINT_MASK;
> +	vmcr |= (vmcrp->bpr << GICH_VMCR_BINPOINT_SHIFT) &
> +		GICH_VMCR_BINPOINT_MASK;
> +	vmcr |= (vmcrp->pmr << GICH_VMCR_PRIMASK_SHIFT) &
> +		GICH_VMCR_PRIMASK_MASK;
> +
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = vmcr;
> +}
> +
> +void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
> +{
> +	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr;
> +
> +	vmcrp->ctlr = (vmcr & GICH_VMCR_CTRL_MASK) >>
> +			GICH_VMCR_CTRL_SHIFT;
> +	vmcrp->abpr = (vmcr & GICH_VMCR_ALIAS_BINPOINT_MASK) >>
> +			GICH_VMCR_ALIAS_BINPOINT_SHIFT;
> +	vmcrp->bpr  = (vmcr & GICH_VMCR_BINPOINT_MASK) >>
> +			GICH_VMCR_BINPOINT_SHIFT;
> +	vmcrp->pmr  = (vmcr & GICH_VMCR_PRIMASK_MASK) >>
> +			GICH_VMCR_PRIMASK_SHIFT;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 43d1dd7..dca52b3 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -166,3 +166,25 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
>  {
>  	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = 0;
>  }
> +
> +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;
> +	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;
> +
> +	vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
> +}
> +
> +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;
> +	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;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index bc5750e..5260d23 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -39,6 +39,8 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>  int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
>  int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			 int offset, u32 *val);
> +void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> +void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
>  			     enum vgic_type);
>  
> @@ -48,6 +50,8 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
>  void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
> +void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> +void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
>  #else
>  static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> @@ -71,6 +75,16 @@ static inline void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>  {
>  }
>  
> +static inline
> +void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> +{
> +}
> +
> +static inline
> +void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> +{
> +}
> +
>  static inline int vgic_register_redist_iodevs(struct kvm *kvm,
>  					      gpa_t dist_base_address)
>  {
> -- 
> 2.7.3
> 

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

* Re: [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
  2016-05-06 10:46   ` Andre Przywara
@ 2016-05-12 18:47     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 18:47 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:46:00AM +0100, Andre Przywara wrote:
> Using the VMCR accessors we provide access to GIC CPU interface state
> to userland by wiring it up to the existing userland interface.
> [Marc: move and make VMCR accessors static, streamline MMIO handlers]

does this mean Marc did this and serves as credit or is it a lost
reminder?

> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
> Changelog v2 .. v3:
> - total rework, moving into vgic-mmio-v2.c
> - move vmcr accessor wrapper functions into this file
> - use the register description table for CPU i/f registers as well
> - add RAZ/WI handling for the active priority registers
> - streamline MMIO handler functions
> 
>  virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h            |   2 +
>  3 files changed, 107 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index bb33af8..2122ff2 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
>  
>  	switch (attr->group) {
>  	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> -		ret = -EINVAL;
> +		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
>  		break;
>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>  		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index c453e6f..0060539 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -206,6 +206,84 @@ 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. */
> +static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
> +					   gpa_t addr, unsigned int len)
> +{
> +	struct vgic_vmcr vmcr;
> +	u32 val;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +
> +	switch (addr & 0xff) {
> +	case GIC_CPU_CTRL:
> +		val = vmcr.ctlr;
> +		break;
> +	case GIC_CPU_PRIMASK:
> +		val = vmcr.pmr;
> +		break;
> +	case GIC_CPU_BINPOINT:
> +		val = vmcr.bpr;
> +		break;
> +	case GIC_CPU_ALIAS_BINPOINT:
> +		val = vmcr.abpr;
> +		break;
> +	case GIC_CPU_IDENT:
> +		val = ((PRODUCT_ID_KVM << 20) |
> +		       (GICC_ARCH_VERSION_V2 << 16) |
> +		       IMPLEMENTER_ARM);
> +		break;
> +	default:
> +		return 0;
> +	}
> +
> +	return extract_bytes(val, addr & 3, len);

I don't think we allow anything than a full 32-bit aligned accesses
from userspace - we shouldn't at least.

> +}
> +
> +static void vgic_mmio_write_vcpuif(struct kvm_vcpu *vcpu,
> +				   gpa_t addr, unsigned int len,
> +				   unsigned long val)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +
> +	switch (addr & 0xff) {
> +	case GIC_CPU_CTRL:
> +		vmcr.ctlr = val;
> +		break;
> +	case GIC_CPU_PRIMASK:
> +		vmcr.pmr = val;
> +		break;
> +	case GIC_CPU_BINPOINT:
> +		vmcr.bpr = val;
> +		break;
> +	case GIC_CPU_ALIAS_BINPOINT:
> +		vmcr.abpr = val;
> +		break;
> +	}
> +
> +	vgic_set_vmcr(vcpu, &vmcr);
> +}
> +
>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -237,6 +315,21 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
>  };
>  
> +static const struct vgic_register_region vgic_v2_cpu_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_CTRL,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_PRIMASK,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_BINPOINT,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_ALIAS_BINPOINT,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_ACTIVEPRIO,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_IDENT,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +};
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
>  {
>  	dev->regions = vgic_v2_dist_registers;
> @@ -306,6 +399,17 @@ static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>  	return ret;
>  }
>  
> +int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +			  int offset, u32 *val)
> +{
> +	struct vgic_io_device dev = {
> +		.regions = vgic_v2_cpu_registers,
> +		.nr_regions = ARRAY_SIZE(vgic_v2_cpu_registers),
> +	};
> +
> +	return vgic_uaccess(vcpu, &dev, is_write, offset, val);
> +}
> +
>  int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			 int offset, u32 *val)
>  {
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 5260d23..7a69955 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -39,6 +39,8 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>  int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
>  int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			 int offset, u32 *val);
> +int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +			  int offset, u32 *val);
>  void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
> -- 
> 2.7.3
> 

Thanks,
-Christoffer

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

* [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
@ 2016-05-12 18:47     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 18:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:46:00AM +0100, Andre Przywara wrote:
> Using the VMCR accessors we provide access to GIC CPU interface state
> to userland by wiring it up to the existing userland interface.
> [Marc: move and make VMCR accessors static, streamline MMIO handlers]

does this mean Marc did this and serves as credit or is it a lost
reminder?

> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
> Changelog v2 .. v3:
> - total rework, moving into vgic-mmio-v2.c
> - move vmcr accessor wrapper functions into this file
> - use the register description table for CPU i/f registers as well
> - add RAZ/WI handling for the active priority registers
> - streamline MMIO handler functions
> 
>  virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h            |   2 +
>  3 files changed, 107 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index bb33af8..2122ff2 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
>  
>  	switch (attr->group) {
>  	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> -		ret = -EINVAL;
> +		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
>  		break;
>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>  		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> index c453e6f..0060539 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> @@ -206,6 +206,84 @@ 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. */
> +static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
> +					   gpa_t addr, unsigned int len)
> +{
> +	struct vgic_vmcr vmcr;
> +	u32 val;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +
> +	switch (addr & 0xff) {
> +	case GIC_CPU_CTRL:
> +		val = vmcr.ctlr;
> +		break;
> +	case GIC_CPU_PRIMASK:
> +		val = vmcr.pmr;
> +		break;
> +	case GIC_CPU_BINPOINT:
> +		val = vmcr.bpr;
> +		break;
> +	case GIC_CPU_ALIAS_BINPOINT:
> +		val = vmcr.abpr;
> +		break;
> +	case GIC_CPU_IDENT:
> +		val = ((PRODUCT_ID_KVM << 20) |
> +		       (GICC_ARCH_VERSION_V2 << 16) |
> +		       IMPLEMENTER_ARM);
> +		break;
> +	default:
> +		return 0;
> +	}
> +
> +	return extract_bytes(val, addr & 3, len);

I don't think we allow anything than a full 32-bit aligned accesses
from userspace - we shouldn't at least.

> +}
> +
> +static void vgic_mmio_write_vcpuif(struct kvm_vcpu *vcpu,
> +				   gpa_t addr, unsigned int len,
> +				   unsigned long val)
> +{
> +	struct vgic_vmcr vmcr;
> +
> +	vgic_get_vmcr(vcpu, &vmcr);
> +
> +	switch (addr & 0xff) {
> +	case GIC_CPU_CTRL:
> +		vmcr.ctlr = val;
> +		break;
> +	case GIC_CPU_PRIMASK:
> +		vmcr.pmr = val;
> +		break;
> +	case GIC_CPU_BINPOINT:
> +		vmcr.bpr = val;
> +		break;
> +	case GIC_CPU_ALIAS_BINPOINT:
> +		vmcr.abpr = val;
> +		break;
> +	}
> +
> +	vgic_set_vmcr(vcpu, &vmcr);
> +}
> +
>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  	REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
>  		vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12),
> @@ -237,6 +315,21 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>  		vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16),
>  };
>  
> +static const struct vgic_register_region vgic_v2_cpu_registers[] = {
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_CTRL,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_PRIMASK,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_BINPOINT,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_ALIAS_BINPOINT,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_ACTIVEPRIO,
> +		vgic_mmio_read_raz, vgic_mmio_write_wi, 16),
> +	REGISTER_DESC_WITH_LENGTH(GIC_CPU_IDENT,
> +		vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif, 4),
> +};
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
>  {
>  	dev->regions = vgic_v2_dist_registers;
> @@ -306,6 +399,17 @@ static int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
>  	return ret;
>  }
>  
> +int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +			  int offset, u32 *val)
> +{
> +	struct vgic_io_device dev = {
> +		.regions = vgic_v2_cpu_registers,
> +		.nr_regions = ARRAY_SIZE(vgic_v2_cpu_registers),
> +	};
> +
> +	return vgic_uaccess(vcpu, &dev, is_write, offset, val);
> +}
> +
>  int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			 int offset, u32 *val)
>  {
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 5260d23..7a69955 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -39,6 +39,8 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
>  int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
>  int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			 int offset, u32 *val);
> +int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
> +			  int offset, u32 *val);
>  void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
> -- 
> 2.7.3
> 

Thanks,
-Christoffer

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

* Re: [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
  2016-05-12 18:47     ` Christoffer Dall
@ 2016-05-12 18:52       ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-12 18:52 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 12/05/16 19:47, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:46:00AM +0100, Andre Przywara wrote:
>> Using the VMCR accessors we provide access to GIC CPU interface state
>> to userland by wiring it up to the existing userland interface.
>> [Marc: move and make VMCR accessors static, streamline MMIO handlers]
> 
> does this mean Marc did this and serves as credit or is it a lost
> reminder?

It was meant as credit. I thought that is the usual annotation for this?

>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>> Changelog v2 .. v3:
>> - total rework, moving into vgic-mmio-v2.c
>> - move vmcr accessor wrapper functions into this file
>> - use the register description table for CPU i/f registers as well
>> - add RAZ/WI handling for the active priority registers
>> - streamline MMIO handler functions
>>
>>  virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.h            |   2 +
>>  3 files changed, 107 insertions(+), 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> index bb33af8..2122ff2 100644
>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> @@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
>>  
>>  	switch (attr->group) {
>>  	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
>> -		ret = -EINVAL;
>> +		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
>>  		break;
>>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>>  		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index c453e6f..0060539 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -206,6 +206,84 @@ 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. */
>> +static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
>> +					   gpa_t addr, unsigned int len)
>> +{
>> +	struct vgic_vmcr vmcr;
>> +	u32 val;
>> +
>> +	vgic_get_vmcr(vcpu, &vmcr);
>> +
>> +	switch (addr & 0xff) {
>> +	case GIC_CPU_CTRL:
>> +		val = vmcr.ctlr;
>> +		break;
>> +	case GIC_CPU_PRIMASK:
>> +		val = vmcr.pmr;
>> +		break;
>> +	case GIC_CPU_BINPOINT:
>> +		val = vmcr.bpr;
>> +		break;
>> +	case GIC_CPU_ALIAS_BINPOINT:
>> +		val = vmcr.abpr;
>> +		break;
>> +	case GIC_CPU_IDENT:
>> +		val = ((PRODUCT_ID_KVM << 20) |
>> +		       (GICC_ARCH_VERSION_V2 << 16) |
>> +		       IMPLEMENTER_ARM);
>> +		break;
>> +	default:
>> +		return 0;
>> +	}
>> +
>> +	return extract_bytes(val, addr & 3, len);
> 
> I don't think we allow anything than a full 32-bit aligned accesses
> from userspace - we shouldn't at least.

Indeed - I think userland was always 32-bit only. And since last night
we even enforce this. So potentially there are more extract_bytes()
calls that can go.

Cheers,
Andre.

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

* [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
@ 2016-05-12 18:52       ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-12 18:52 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 12/05/16 19:47, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:46:00AM +0100, Andre Przywara wrote:
>> Using the VMCR accessors we provide access to GIC CPU interface state
>> to userland by wiring it up to the existing userland interface.
>> [Marc: move and make VMCR accessors static, streamline MMIO handlers]
> 
> does this mean Marc did this and serves as credit or is it a lost
> reminder?

It was meant as credit. I thought that is the usual annotation for this?

>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>> Changelog v2 .. v3:
>> - total rework, moving into vgic-mmio-v2.c
>> - move vmcr accessor wrapper functions into this file
>> - use the register description table for CPU i/f registers as well
>> - add RAZ/WI handling for the active priority registers
>> - streamline MMIO handler functions
>>
>>  virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.h            |   2 +
>>  3 files changed, 107 insertions(+), 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> index bb33af8..2122ff2 100644
>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> @@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
>>  
>>  	switch (attr->group) {
>>  	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
>> -		ret = -EINVAL;
>> +		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
>>  		break;
>>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>>  		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> index c453e6f..0060539 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -206,6 +206,84 @@ 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. */
>> +static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
>> +					   gpa_t addr, unsigned int len)
>> +{
>> +	struct vgic_vmcr vmcr;
>> +	u32 val;
>> +
>> +	vgic_get_vmcr(vcpu, &vmcr);
>> +
>> +	switch (addr & 0xff) {
>> +	case GIC_CPU_CTRL:
>> +		val = vmcr.ctlr;
>> +		break;
>> +	case GIC_CPU_PRIMASK:
>> +		val = vmcr.pmr;
>> +		break;
>> +	case GIC_CPU_BINPOINT:
>> +		val = vmcr.bpr;
>> +		break;
>> +	case GIC_CPU_ALIAS_BINPOINT:
>> +		val = vmcr.abpr;
>> +		break;
>> +	case GIC_CPU_IDENT:
>> +		val = ((PRODUCT_ID_KVM << 20) |
>> +		       (GICC_ARCH_VERSION_V2 << 16) |
>> +		       IMPLEMENTER_ARM);
>> +		break;
>> +	default:
>> +		return 0;
>> +	}
>> +
>> +	return extract_bytes(val, addr & 3, len);
> 
> I don't think we allow anything than a full 32-bit aligned accesses
> from userspace - we shouldn't at least.

Indeed - I think userland was always 32-bit only. And since last night
we even enforce this. So potentially there are more extract_bytes()
calls that can go.

Cheers,
Andre.

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

* Re: [PATCH v3 48/55] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
  2016-05-06 10:46   ` Andre Przywara
@ 2016-05-12 19:00     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 19:00 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:46:01AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> Implements kvm_vgic_hyp_init and vgic_probe function.
> 
> The vgic_global struct is enriched with new fields populated
> by those functions.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog v1 .. v2:
> - rename vgic_init.c to vgic-init.c
> 
> Changelog v2 .. v3:
> - include kvm/arm_vgic.h instead of kvm/vgic/vgic.h
> - move ich_vtr_el2 variable into probe function
> 
>  include/kvm/vgic/vgic.h       |   1 +
>  virt/kvm/arm/vgic/vgic-init.c | 122 ++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v2.c   |  90 +++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c   |  73 +++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h      |   7 +++
>  5 files changed, 293 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-init.c
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index cfc3640..d144e3d 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -202,6 +202,7 @@ struct vgic_cpu {
>  };
>  
>  int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
> +int kvm_vgic_hyp_init(void);
>  
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  			bool level);
> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> new file mode 100644
> index 0000000..f10997b
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-init.c
> @@ -0,0 +1,122 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/uaccess.h>
> +#include <linux/interrupt.h>
> +#include <linux/cpu.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/kvm_host.h>
> +#include <kvm/arm_vgic.h>
> +#include <asm/kvm_mmu.h>
> +#include "vgic.h"
> +
> +/* GENERIC PROBE */
> +
> +static void vgic_init_maintenance_interrupt(void *info)
> +{
> +	enable_percpu_irq(kvm_vgic_global_state.maint_irq, 0);
> +}
> +
> +static int vgic_cpu_notify(struct notifier_block *self,
> +			   unsigned long action, void *cpu)
> +{
> +	switch (action) {
> +	case CPU_STARTING:
> +	case CPU_STARTING_FROZEN:
> +		vgic_init_maintenance_interrupt(NULL);
> +		break;
> +	case CPU_DYING:
> +	case CPU_DYING_FROZEN:
> +		disable_percpu_irq(kvm_vgic_global_state.maint_irq);
> +		break;
> +	}
> +
> +	return NOTIFY_OK;
> +}
> +
> +static struct notifier_block vgic_cpu_nb = {
> +	.notifier_call = vgic_cpu_notify,
> +};
> +
> +static irqreturn_t vgic_maintenance_handler(int irq, void *data)
> +{
> +	/*
> +	 * We cannot rely on the vgic maintenance interrupt to be
> +	 * delivered synchronously. This means we can only use it to
> +	 * exit the VM, and we perform the handling of EOIed
> +	 * interrupts on the exit path (see vgic_process_maintenance).
> +	 */
> +	return IRQ_HANDLED;
> +}
> +
> +static const struct of_device_id vgic_ids[] = {
> +	{ .compatible = "arm,cortex-a15-gic",	.data = vgic_v2_probe, },
> +	{ .compatible = "arm,cortex-a7-gic",	.data = vgic_v2_probe, },
> +	{ .compatible = "arm,gic-400",		.data = vgic_v2_probe, },
> +	{ .compatible = "arm,gic-v3",		.data = vgic_v3_probe, },
> +	{},
> +};
> +
> +/**
> + * kvm_vgic_hyp_init: populates the kvm_vgic_global_state variable
> + * according to the host GIC model. Accordingly calls either
> + * vgic_v2/v3_probe which registers the KVM_DEVICE that can be
> + * instantiated by a guest later on .
> + */
> +int kvm_vgic_hyp_init(void)
> +{
> +	const struct of_device_id *matched_id;
> +	const int (*vgic_probe)(struct device_node *);
> +	struct device_node *vgic_node;
> +	int ret;
> +
> +	vgic_node = of_find_matching_node_and_match(NULL,
> +						    vgic_ids, &matched_id);
> +	if (!vgic_node) {
> +		kvm_err("error: no compatible GIC node found\n");
> +		return -ENODEV;
> +	}
> +
> +	vgic_probe = matched_id->data;
> +	ret = vgic_probe(vgic_node);
> +	if (ret)
> +		return ret;
> +
> +	ret = request_percpu_irq(kvm_vgic_global_state.maint_irq,
> +				 vgic_maintenance_handler,
> +				 "vgic", kvm_get_running_vcpus());
> +	if (ret) {
> +		kvm_err("Cannot register interrupt %d\n",
> +			kvm_vgic_global_state.maint_irq);
> +		return ret;
> +	}
> +
> +	ret = __register_cpu_notifier(&vgic_cpu_nb);
> +	if (ret) {
> +		kvm_err("Cannot register vgic CPU notifier\n");
> +		goto out_free_irq;
> +	}
> +
> +	on_each_cpu(vgic_init_maintenance_interrupt, NULL, 1);
> +
> +	return 0;
> +
> +out_free_irq:
> +	free_percpu_irq(kvm_vgic_global_state.maint_irq,
> +			kvm_get_running_vcpus());
> +	return ret;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 70cac63..91b69a4 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -17,6 +17,11 @@
>  #include <linux/irqchip/arm-gic.h>
>  #include <linux/kvm.h>
>  #include <linux/kvm_host.h>
> +#include <kvm/arm_vgic.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <asm/kvm_mmu.h>
>  
>  #include "vgic.h"
>  
> @@ -205,3 +210,88 @@ void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  	vmcrp->pmr  = (vmcr & GICH_VMCR_PRIMASK_MASK) >>
>  			GICH_VMCR_PRIMASK_SHIFT;
>  }
> +
> +/**
> + * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
> + * @node:	pointer to the DT node
> + *
> + * Returns 0 if a GICv2 has been found, returns an error code otherwise
> + */
> +int vgic_v2_probe(struct device_node *vgic_node)
> +{
> +	int ret;
> +	struct resource vctrl_res;
> +	struct resource vcpu_res;
> +
> +	kvm_vgic_global_state.maint_irq = irq_of_parse_and_map(vgic_node, 0);
> +	if (!kvm_vgic_global_state.maint_irq) {
> +		kvm_err("error getting vgic maintenance irq from DT\n");
> +		ret = -ENXIO;
> +		goto out;
> +	}
> +
> +	ret = of_address_to_resource(vgic_node, 2, &vctrl_res);
> +	if (ret) {
> +		kvm_err("Cannot obtain GICH resource\n");
> +		goto out;
> +	}
> +
> +	kvm_vgic_global_state.vctrl_base = of_iomap(vgic_node, 2);
> +	if (!kvm_vgic_global_state.vctrl_base) {
> +		kvm_err("Cannot ioremap GICH\n");
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +
> +	kvm_vgic_global_state.nr_lr =
> +		readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VTR);
> +	kvm_vgic_global_state.nr_lr = (kvm_vgic_global_state.nr_lr & 0x3f) + 1;

could we please do:
	vtr = readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VTR);
	kvm_vgic_global_state.nr_lr = (vtr & 0x3f) + 1;

instead?

> +
> +	ret = create_hyp_io_mappings(kvm_vgic_global_state.vctrl_base,
> +				     kvm_vgic_global_state.vctrl_base +
> +					 resource_size(&vctrl_res),
> +				     vctrl_res.start);
> +	if (ret) {
> +		kvm_err("Cannot map VCTRL into hyp\n");
> +		goto out_unmap;
> +	}
> +
> +	if (of_address_to_resource(vgic_node, 3, &vcpu_res)) {
> +		kvm_err("Cannot obtain GICV resource\n");
> +		ret = -ENXIO;
> +		goto out_unmap;
> +	}
> +
> +	if (!PAGE_ALIGNED(vcpu_res.start)) {
> +		kvm_err("GICV physical address 0x%llx not page aligned\n",
> +			(unsigned long long)vcpu_res.start);
> +		ret = -ENXIO;
> +		goto out_unmap;
> +	}
> +
> +	if (!PAGE_ALIGNED(resource_size(&vcpu_res))) {
> +		kvm_err("GICV size 0x%llx not a multiple of page size 0x%lx\n",
> +			(unsigned long long)resource_size(&vcpu_res),
> +			PAGE_SIZE);
> +		ret = -ENXIO;
> +		goto out_unmap;
> +	}
> +
> +	kvm_vgic_global_state.can_emulate_gicv2 = true;
> +	kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
> +
> +	kvm_vgic_global_state.vcpu_base = vcpu_res.start;
> +
> +	kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
> +		 vctrl_res.start, kvm_vgic_global_state.maint_irq);
> +
> +	kvm_vgic_global_state.type = VGIC_V2;
> +	kvm_vgic_global_state.max_gic_vcpus = VGIC_V2_MAX_CPUS;
> +	goto out;
> +
> +out_unmap:
> +	iounmap(kvm_vgic_global_state.vctrl_base);
> +out:
> +	of_node_put(vgic_node);
> +	return ret;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index dca52b3..48b0bb7 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -15,6 +15,12 @@
>  #include <linux/irqchip/arm-gic-v3.h>
>  #include <linux/kvm.h>
>  #include <linux/kvm_host.h>
> +#include <kvm/arm_vgic.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <asm/kvm_mmu.h>
> +#include <asm/kvm_asm.h>
>  
>  #include "vgic.h"
>  
> @@ -188,3 +194,70 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  	vmcrp->bpr  = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
>  	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
>  }
> +
> +/**
> + * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
> + * @node:	pointer to the DT node
> + *
> + * Returns 0 if a GICv3 has been found, returns an error code otherwise
> + */
> +int vgic_v3_probe(struct device_node *vgic_node)
> +{
> +	u32 ich_vtr_el2;
> +	u32 gicv_idx;
> +	int ret = 0;
> +	struct resource vcpu_res;
> +
> +	kvm_vgic_global_state.maint_irq = irq_of_parse_and_map(vgic_node, 0);
> +	if (!kvm_vgic_global_state.maint_irq) {
> +		kvm_err("error getting vgic maintenance irq from DT\n");
> +		ret = -ENXIO;
> +		goto out;
> +	}
> +
> +	ich_vtr_el2 = kvm_call_hyp(__vgic_v3_get_ich_vtr_el2);
> +
> +	/*
> +	 * The ListRegs field is 5 bits, but there is a architectural
> +	 * maximum of 16 list registers. Just ignore bit 4...
> +	 */
> +	kvm_vgic_global_state.nr_lr = (ich_vtr_el2 & 0xf) + 1;
> +	kvm_vgic_global_state.can_emulate_gicv2 = false;
> +
> +	if (of_property_read_u32(vgic_node, "#redistributor-regions",
> +				 &gicv_idx))
> +		gicv_idx = 1;
> +
> +	gicv_idx += 3; /* Also skip GICD, GICC, GICH */
> +	if (of_address_to_resource(vgic_node, gicv_idx, &vcpu_res)) {
> +		kvm_info("GICv3: no GICV resource entry\n");
> +		kvm_vgic_global_state.vcpu_base = 0;
> +	} else if (!PAGE_ALIGNED(vcpu_res.start)) {
> +		pr_warn("GICV physical address 0x%llx not page aligned\n",
> +			(unsigned long long)vcpu_res.start);
> +		kvm_vgic_global_state.vcpu_base = 0;
> +	} else if (!PAGE_ALIGNED(resource_size(&vcpu_res))) {
> +		pr_warn("GICV size 0x%llx not a multiple of page size 0x%lx\n",
> +			(unsigned long long)resource_size(&vcpu_res),
> +			PAGE_SIZE);
> +		kvm_vgic_global_state.vcpu_base = 0;
> +	} else {
> +		kvm_vgic_global_state.vcpu_base = vcpu_res.start;
> +		kvm_vgic_global_state.can_emulate_gicv2 = true;
> +		kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
> +	}
> +	if (kvm_vgic_global_state.vcpu_base == 0)
> +		kvm_info("disabling GICv2 emulation\n");
> +	kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V3);
> +
> +	kvm_vgic_global_state.vctrl_base = NULL;
> +	kvm_vgic_global_state.type = VGIC_V3;
> +	kvm_vgic_global_state.max_gic_vcpus = VGIC_V3_MAX_CPUS;
> +
> +	kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
> +		 vcpu_res.start, kvm_vgic_global_state.maint_irq);
> +
> +out:
> +	of_node_put(vgic_node);
> +	return ret;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 7a69955..e49b1df 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -43,6 +43,7 @@ int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			  int offset, u32 *val);
>  void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> +int vgic_v2_probe(struct device_node *vgic_node);
>  int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
>  			     enum vgic_type);
>  
> @@ -54,6 +55,7 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
>  void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> +int vgic_v3_probe(struct device_node *vgic_node);
>  int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
>  #else
>  static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> @@ -87,6 +89,11 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>  {
>  }
>  
> +static inline int vgic_v3_probe(struct device_node *vgic_node)
> +{
> +	return -ENODEV;
> +}
> +
>  static inline int vgic_register_redist_iodevs(struct kvm *kvm,
>  					      gpa_t dist_base_address)
>  {
> -- 
> 2.7.3
> 
> --

I think we need to change this behavior to use the gic_kvm_info
structure populated by Julien's patches now and in kvmarm/next for the
next version of the series, and then I'll review that part properly.
Thoughts?

Thanks,
-Christoffer

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

* [PATCH v3 48/55] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
@ 2016-05-12 19:00     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 19:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:46:01AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> Implements kvm_vgic_hyp_init and vgic_probe function.
> 
> The vgic_global struct is enriched with new fields populated
> by those functions.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog v1 .. v2:
> - rename vgic_init.c to vgic-init.c
> 
> Changelog v2 .. v3:
> - include kvm/arm_vgic.h instead of kvm/vgic/vgic.h
> - move ich_vtr_el2 variable into probe function
> 
>  include/kvm/vgic/vgic.h       |   1 +
>  virt/kvm/arm/vgic/vgic-init.c | 122 ++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v2.c   |  90 +++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c   |  73 +++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h      |   7 +++
>  5 files changed, 293 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-init.c
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index cfc3640..d144e3d 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -202,6 +202,7 @@ struct vgic_cpu {
>  };
>  
>  int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
> +int kvm_vgic_hyp_init(void);
>  
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  			bool level);
> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> new file mode 100644
> index 0000000..f10997b
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-init.c
> @@ -0,0 +1,122 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/uaccess.h>
> +#include <linux/interrupt.h>
> +#include <linux/cpu.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/kvm_host.h>
> +#include <kvm/arm_vgic.h>
> +#include <asm/kvm_mmu.h>
> +#include "vgic.h"
> +
> +/* GENERIC PROBE */
> +
> +static void vgic_init_maintenance_interrupt(void *info)
> +{
> +	enable_percpu_irq(kvm_vgic_global_state.maint_irq, 0);
> +}
> +
> +static int vgic_cpu_notify(struct notifier_block *self,
> +			   unsigned long action, void *cpu)
> +{
> +	switch (action) {
> +	case CPU_STARTING:
> +	case CPU_STARTING_FROZEN:
> +		vgic_init_maintenance_interrupt(NULL);
> +		break;
> +	case CPU_DYING:
> +	case CPU_DYING_FROZEN:
> +		disable_percpu_irq(kvm_vgic_global_state.maint_irq);
> +		break;
> +	}
> +
> +	return NOTIFY_OK;
> +}
> +
> +static struct notifier_block vgic_cpu_nb = {
> +	.notifier_call = vgic_cpu_notify,
> +};
> +
> +static irqreturn_t vgic_maintenance_handler(int irq, void *data)
> +{
> +	/*
> +	 * We cannot rely on the vgic maintenance interrupt to be
> +	 * delivered synchronously. This means we can only use it to
> +	 * exit the VM, and we perform the handling of EOIed
> +	 * interrupts on the exit path (see vgic_process_maintenance).
> +	 */
> +	return IRQ_HANDLED;
> +}
> +
> +static const struct of_device_id vgic_ids[] = {
> +	{ .compatible = "arm,cortex-a15-gic",	.data = vgic_v2_probe, },
> +	{ .compatible = "arm,cortex-a7-gic",	.data = vgic_v2_probe, },
> +	{ .compatible = "arm,gic-400",		.data = vgic_v2_probe, },
> +	{ .compatible = "arm,gic-v3",		.data = vgic_v3_probe, },
> +	{},
> +};
> +
> +/**
> + * kvm_vgic_hyp_init: populates the kvm_vgic_global_state variable
> + * according to the host GIC model. Accordingly calls either
> + * vgic_v2/v3_probe which registers the KVM_DEVICE that can be
> + * instantiated by a guest later on .
> + */
> +int kvm_vgic_hyp_init(void)
> +{
> +	const struct of_device_id *matched_id;
> +	const int (*vgic_probe)(struct device_node *);
> +	struct device_node *vgic_node;
> +	int ret;
> +
> +	vgic_node = of_find_matching_node_and_match(NULL,
> +						    vgic_ids, &matched_id);
> +	if (!vgic_node) {
> +		kvm_err("error: no compatible GIC node found\n");
> +		return -ENODEV;
> +	}
> +
> +	vgic_probe = matched_id->data;
> +	ret = vgic_probe(vgic_node);
> +	if (ret)
> +		return ret;
> +
> +	ret = request_percpu_irq(kvm_vgic_global_state.maint_irq,
> +				 vgic_maintenance_handler,
> +				 "vgic", kvm_get_running_vcpus());
> +	if (ret) {
> +		kvm_err("Cannot register interrupt %d\n",
> +			kvm_vgic_global_state.maint_irq);
> +		return ret;
> +	}
> +
> +	ret = __register_cpu_notifier(&vgic_cpu_nb);
> +	if (ret) {
> +		kvm_err("Cannot register vgic CPU notifier\n");
> +		goto out_free_irq;
> +	}
> +
> +	on_each_cpu(vgic_init_maintenance_interrupt, NULL, 1);
> +
> +	return 0;
> +
> +out_free_irq:
> +	free_percpu_irq(kvm_vgic_global_state.maint_irq,
> +			kvm_get_running_vcpus());
> +	return ret;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 70cac63..91b69a4 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -17,6 +17,11 @@
>  #include <linux/irqchip/arm-gic.h>
>  #include <linux/kvm.h>
>  #include <linux/kvm_host.h>
> +#include <kvm/arm_vgic.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <asm/kvm_mmu.h>
>  
>  #include "vgic.h"
>  
> @@ -205,3 +210,88 @@ void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  	vmcrp->pmr  = (vmcr & GICH_VMCR_PRIMASK_MASK) >>
>  			GICH_VMCR_PRIMASK_SHIFT;
>  }
> +
> +/**
> + * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
> + * @node:	pointer to the DT node
> + *
> + * Returns 0 if a GICv2 has been found, returns an error code otherwise
> + */
> +int vgic_v2_probe(struct device_node *vgic_node)
> +{
> +	int ret;
> +	struct resource vctrl_res;
> +	struct resource vcpu_res;
> +
> +	kvm_vgic_global_state.maint_irq = irq_of_parse_and_map(vgic_node, 0);
> +	if (!kvm_vgic_global_state.maint_irq) {
> +		kvm_err("error getting vgic maintenance irq from DT\n");
> +		ret = -ENXIO;
> +		goto out;
> +	}
> +
> +	ret = of_address_to_resource(vgic_node, 2, &vctrl_res);
> +	if (ret) {
> +		kvm_err("Cannot obtain GICH resource\n");
> +		goto out;
> +	}
> +
> +	kvm_vgic_global_state.vctrl_base = of_iomap(vgic_node, 2);
> +	if (!kvm_vgic_global_state.vctrl_base) {
> +		kvm_err("Cannot ioremap GICH\n");
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +
> +	kvm_vgic_global_state.nr_lr =
> +		readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VTR);
> +	kvm_vgic_global_state.nr_lr = (kvm_vgic_global_state.nr_lr & 0x3f) + 1;

could we please do:
	vtr = readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VTR);
	kvm_vgic_global_state.nr_lr = (vtr & 0x3f) + 1;

instead?

> +
> +	ret = create_hyp_io_mappings(kvm_vgic_global_state.vctrl_base,
> +				     kvm_vgic_global_state.vctrl_base +
> +					 resource_size(&vctrl_res),
> +				     vctrl_res.start);
> +	if (ret) {
> +		kvm_err("Cannot map VCTRL into hyp\n");
> +		goto out_unmap;
> +	}
> +
> +	if (of_address_to_resource(vgic_node, 3, &vcpu_res)) {
> +		kvm_err("Cannot obtain GICV resource\n");
> +		ret = -ENXIO;
> +		goto out_unmap;
> +	}
> +
> +	if (!PAGE_ALIGNED(vcpu_res.start)) {
> +		kvm_err("GICV physical address 0x%llx not page aligned\n",
> +			(unsigned long long)vcpu_res.start);
> +		ret = -ENXIO;
> +		goto out_unmap;
> +	}
> +
> +	if (!PAGE_ALIGNED(resource_size(&vcpu_res))) {
> +		kvm_err("GICV size 0x%llx not a multiple of page size 0x%lx\n",
> +			(unsigned long long)resource_size(&vcpu_res),
> +			PAGE_SIZE);
> +		ret = -ENXIO;
> +		goto out_unmap;
> +	}
> +
> +	kvm_vgic_global_state.can_emulate_gicv2 = true;
> +	kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
> +
> +	kvm_vgic_global_state.vcpu_base = vcpu_res.start;
> +
> +	kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
> +		 vctrl_res.start, kvm_vgic_global_state.maint_irq);
> +
> +	kvm_vgic_global_state.type = VGIC_V2;
> +	kvm_vgic_global_state.max_gic_vcpus = VGIC_V2_MAX_CPUS;
> +	goto out;
> +
> +out_unmap:
> +	iounmap(kvm_vgic_global_state.vctrl_base);
> +out:
> +	of_node_put(vgic_node);
> +	return ret;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index dca52b3..48b0bb7 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -15,6 +15,12 @@
>  #include <linux/irqchip/arm-gic-v3.h>
>  #include <linux/kvm.h>
>  #include <linux/kvm_host.h>
> +#include <kvm/arm_vgic.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <asm/kvm_mmu.h>
> +#include <asm/kvm_asm.h>
>  
>  #include "vgic.h"
>  
> @@ -188,3 +194,70 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  	vmcrp->bpr  = (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
>  	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
>  }
> +
> +/**
> + * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
> + * @node:	pointer to the DT node
> + *
> + * Returns 0 if a GICv3 has been found, returns an error code otherwise
> + */
> +int vgic_v3_probe(struct device_node *vgic_node)
> +{
> +	u32 ich_vtr_el2;
> +	u32 gicv_idx;
> +	int ret = 0;
> +	struct resource vcpu_res;
> +
> +	kvm_vgic_global_state.maint_irq = irq_of_parse_and_map(vgic_node, 0);
> +	if (!kvm_vgic_global_state.maint_irq) {
> +		kvm_err("error getting vgic maintenance irq from DT\n");
> +		ret = -ENXIO;
> +		goto out;
> +	}
> +
> +	ich_vtr_el2 = kvm_call_hyp(__vgic_v3_get_ich_vtr_el2);
> +
> +	/*
> +	 * The ListRegs field is 5 bits, but there is a architectural
> +	 * maximum of 16 list registers. Just ignore bit 4...
> +	 */
> +	kvm_vgic_global_state.nr_lr = (ich_vtr_el2 & 0xf) + 1;
> +	kvm_vgic_global_state.can_emulate_gicv2 = false;
> +
> +	if (of_property_read_u32(vgic_node, "#redistributor-regions",
> +				 &gicv_idx))
> +		gicv_idx = 1;
> +
> +	gicv_idx += 3; /* Also skip GICD, GICC, GICH */
> +	if (of_address_to_resource(vgic_node, gicv_idx, &vcpu_res)) {
> +		kvm_info("GICv3: no GICV resource entry\n");
> +		kvm_vgic_global_state.vcpu_base = 0;
> +	} else if (!PAGE_ALIGNED(vcpu_res.start)) {
> +		pr_warn("GICV physical address 0x%llx not page aligned\n",
> +			(unsigned long long)vcpu_res.start);
> +		kvm_vgic_global_state.vcpu_base = 0;
> +	} else if (!PAGE_ALIGNED(resource_size(&vcpu_res))) {
> +		pr_warn("GICV size 0x%llx not a multiple of page size 0x%lx\n",
> +			(unsigned long long)resource_size(&vcpu_res),
> +			PAGE_SIZE);
> +		kvm_vgic_global_state.vcpu_base = 0;
> +	} else {
> +		kvm_vgic_global_state.vcpu_base = vcpu_res.start;
> +		kvm_vgic_global_state.can_emulate_gicv2 = true;
> +		kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
> +	}
> +	if (kvm_vgic_global_state.vcpu_base == 0)
> +		kvm_info("disabling GICv2 emulation\n");
> +	kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V3);
> +
> +	kvm_vgic_global_state.vctrl_base = NULL;
> +	kvm_vgic_global_state.type = VGIC_V3;
> +	kvm_vgic_global_state.max_gic_vcpus = VGIC_V3_MAX_CPUS;
> +
> +	kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
> +		 vcpu_res.start, kvm_vgic_global_state.maint_irq);
> +
> +out:
> +	of_node_put(vgic_node);
> +	return ret;
> +}
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index 7a69955..e49b1df 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -43,6 +43,7 @@ int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			  int offset, u32 *val);
>  void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> +int vgic_v2_probe(struct device_node *vgic_node);
>  int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
>  			     enum vgic_type);
>  
> @@ -54,6 +55,7 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
>  void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> +int vgic_v3_probe(struct device_node *vgic_node);
>  int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
>  #else
>  static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> @@ -87,6 +89,11 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>  {
>  }
>  
> +static inline int vgic_v3_probe(struct device_node *vgic_node)
> +{
> +	return -ENODEV;
> +}
> +
>  static inline int vgic_register_redist_iodevs(struct kvm *kvm,
>  					      gpa_t dist_base_address)
>  {
> -- 
> 2.7.3
> 
> --

I think we need to change this behavior to use the gic_kvm_info
structure populated by Julien's patches now and in kvmarm/next for the
next version of the series, and then I'll review that part properly.
Thoughts?

Thanks,
-Christoffer

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

* Re: [PATCH v3 49/55] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create
  2016-05-06 10:46   ` Andre Przywara
@ 2016-05-12 19:08     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 19:08 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 06, 2016 at 11:46:02AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> This patch implements the vgic_creation function which is
> called on CREATE_IRQCHIP VM IOCTL (v2 only) or KVM_CREATE_DEVICE
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h       |  1 +
>  virt/kvm/arm/vgic/vgic-init.c | 84 +++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 85 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index d144e3d..899b7b7 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -202,6 +202,7 @@ struct vgic_cpu {
>  };
>  
>  int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
> +int kvm_vgic_create(struct kvm *kvm, u32 type);
>  int kvm_vgic_hyp_init(void);
>  
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> index f10997b..a150363 100644
> --- a/virt/kvm/arm/vgic/vgic-init.c
> +++ b/virt/kvm/arm/vgic/vgic-init.c
> @@ -24,6 +24,90 @@
>  #include <asm/kvm_mmu.h>
>  #include "vgic.h"
>  
> +/* CREATION */
> +
> +/**
> + * kvm_vgic_create: triggered by the instantiation of the VGIC device by
> + * user space, either through the legacy ARM specific VM IOCTL (CREATE_IRQCHIP)

nit: is KVM_CREATE_IRQCHIP ARM specific or are we talking about the ARM
implementation of a generic ioctl?

> + * or through the generic VM IOCTL, KVM_CREATE_DEVICE API.
> + * Completion can be tested by irqchip_in_kernel

s/Completion can be tested by irqchip_in_kernel/
  irqchip_in_kernel() tells you if this function succeeded or not/

> + */
> +int kvm_vgic_create(struct kvm *kvm, u32 type)
> +{
> +	int i, vcpu_lock_idx = -1, ret;
> +	struct kvm_vcpu *vcpu;
> +
> +	mutex_lock(&kvm->lock);
> +
> +	if (irqchip_in_kernel(kvm)) {
> +		ret = -EEXIST;
> +		goto out;
> +	}
> +
> +	/*
> +	 * This function is also called by the KVM_CREATE_IRQCHIP handler,
> +	 * which had no chance yet to check the availability of the GICv2
> +	 * emulation. So check this here again. KVM_CREATE_DEVICE does
> +	 * the proper checks already.
> +	 */
> +	if (type == KVM_DEV_TYPE_ARM_VGIC_V2 &&
> +		!kvm_vgic_global_state.can_emulate_gicv2) {
> +		ret = -ENODEV;
> +		goto out;
> +	}
> +
> +	/*
> +	 * Any time a vcpu is run, vcpu_load is called which tries to grab the
> +	 * vcpu->mutex.  By grabbing the vcpu->mutex of all VCPUs we ensure
> +	 * that no other VCPUs are run while we create the vgic.
> +	 */
> +	ret = -EBUSY;
> +	kvm_for_each_vcpu(i, vcpu, kvm) {
> +		if (!mutex_trylock(&vcpu->mutex))
> +			goto out_unlock;
> +		vcpu_lock_idx = i;
> +	}
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm) {
> +		if (vcpu->arch.has_run_once)
> +			goto out_unlock;
> +	}
> +	ret = 0;
> +
> +	if (type == KVM_DEV_TYPE_ARM_VGIC_V2)
> +		kvm->arch.max_vcpus = VGIC_V2_MAX_CPUS;
> +	else
> +		kvm->arch.max_vcpus = VGIC_V3_MAX_CPUS;
> +
> +	if (atomic_read(&kvm->online_vcpus) > kvm->arch.max_vcpus) {
> +		ret = -E2BIG;
> +		goto out_unlock;
> +	}
> +
> +	kvm->arch.vgic.in_kernel = true;
> +	kvm->arch.vgic.vgic_model = type;
> +
> +	/*
> +	 * kvm_vgic_global_state.vctrl_base is set on vgic probe (kvm_arch_init)
> +	 * it is stored in distributor struct for asm save/restore purpose

we don't have any assembly code anymore, so could we simply export the
global state to __hyp code?

> +	 */
> +	kvm->arch.vgic.vctrl_base = kvm_vgic_global_state.vctrl_base;
> +
> +	kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
> +	kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
> +	kvm->arch.vgic.vgic_redist_base = VGIC_ADDR_UNDEF;
> +
> +out_unlock:
> +	for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
> +		vcpu = kvm_get_vcpu(kvm, vcpu_lock_idx);
> +		mutex_unlock(&vcpu->mutex);
> +	}
> +
> +out:
> +	mutex_unlock(&kvm->lock);
> +	return ret;
> +}
> +
>  /* GENERIC PROBE */
>  
>  static void vgic_init_maintenance_interrupt(void *info)
> -- 
> 2.7.3
> 

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

* [PATCH v3 49/55] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create
@ 2016-05-12 19:08     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 19:08 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:46:02AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> This patch implements the vgic_creation function which is
> called on CREATE_IRQCHIP VM IOCTL (v2 only) or KVM_CREATE_DEVICE
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h       |  1 +
>  virt/kvm/arm/vgic/vgic-init.c | 84 +++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 85 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index d144e3d..899b7b7 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -202,6 +202,7 @@ struct vgic_cpu {
>  };
>  
>  int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
> +int kvm_vgic_create(struct kvm *kvm, u32 type);
>  int kvm_vgic_hyp_init(void);
>  
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> index f10997b..a150363 100644
> --- a/virt/kvm/arm/vgic/vgic-init.c
> +++ b/virt/kvm/arm/vgic/vgic-init.c
> @@ -24,6 +24,90 @@
>  #include <asm/kvm_mmu.h>
>  #include "vgic.h"
>  
> +/* CREATION */
> +
> +/**
> + * kvm_vgic_create: triggered by the instantiation of the VGIC device by
> + * user space, either through the legacy ARM specific VM IOCTL (CREATE_IRQCHIP)

nit: is KVM_CREATE_IRQCHIP ARM specific or are we talking about the ARM
implementation of a generic ioctl?

> + * or through the generic VM IOCTL, KVM_CREATE_DEVICE API.
> + * Completion can be tested by irqchip_in_kernel

s/Completion can be tested by irqchip_in_kernel/
  irqchip_in_kernel() tells you if this function succeeded or not/

> + */
> +int kvm_vgic_create(struct kvm *kvm, u32 type)
> +{
> +	int i, vcpu_lock_idx = -1, ret;
> +	struct kvm_vcpu *vcpu;
> +
> +	mutex_lock(&kvm->lock);
> +
> +	if (irqchip_in_kernel(kvm)) {
> +		ret = -EEXIST;
> +		goto out;
> +	}
> +
> +	/*
> +	 * This function is also called by the KVM_CREATE_IRQCHIP handler,
> +	 * which had no chance yet to check the availability of the GICv2
> +	 * emulation. So check this here again. KVM_CREATE_DEVICE does
> +	 * the proper checks already.
> +	 */
> +	if (type == KVM_DEV_TYPE_ARM_VGIC_V2 &&
> +		!kvm_vgic_global_state.can_emulate_gicv2) {
> +		ret = -ENODEV;
> +		goto out;
> +	}
> +
> +	/*
> +	 * Any time a vcpu is run, vcpu_load is called which tries to grab the
> +	 * vcpu->mutex.  By grabbing the vcpu->mutex of all VCPUs we ensure
> +	 * that no other VCPUs are run while we create the vgic.
> +	 */
> +	ret = -EBUSY;
> +	kvm_for_each_vcpu(i, vcpu, kvm) {
> +		if (!mutex_trylock(&vcpu->mutex))
> +			goto out_unlock;
> +		vcpu_lock_idx = i;
> +	}
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm) {
> +		if (vcpu->arch.has_run_once)
> +			goto out_unlock;
> +	}
> +	ret = 0;
> +
> +	if (type == KVM_DEV_TYPE_ARM_VGIC_V2)
> +		kvm->arch.max_vcpus = VGIC_V2_MAX_CPUS;
> +	else
> +		kvm->arch.max_vcpus = VGIC_V3_MAX_CPUS;
> +
> +	if (atomic_read(&kvm->online_vcpus) > kvm->arch.max_vcpus) {
> +		ret = -E2BIG;
> +		goto out_unlock;
> +	}
> +
> +	kvm->arch.vgic.in_kernel = true;
> +	kvm->arch.vgic.vgic_model = type;
> +
> +	/*
> +	 * kvm_vgic_global_state.vctrl_base is set on vgic probe (kvm_arch_init)
> +	 * it is stored in distributor struct for asm save/restore purpose

we don't have any assembly code anymore, so could we simply export the
global state to __hyp code?

> +	 */
> +	kvm->arch.vgic.vctrl_base = kvm_vgic_global_state.vctrl_base;
> +
> +	kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
> +	kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
> +	kvm->arch.vgic.vgic_redist_base = VGIC_ADDR_UNDEF;
> +
> +out_unlock:
> +	for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
> +		vcpu = kvm_get_vcpu(kvm, vcpu_lock_idx);
> +		mutex_unlock(&vcpu->mutex);
> +	}
> +
> +out:
> +	mutex_unlock(&kvm->lock);
> +	return ret;
> +}
> +
>  /* GENERIC PROBE */
>  
>  static void vgic_init_maintenance_interrupt(void *info)
> -- 
> 2.7.3
> 

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

* Re: [PATCH v3 45/55] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
  2016-05-12 18:41     ` Christoffer Dall
@ 2016-05-12 19:10       ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-12 19:10 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 12/05/16 19:41, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:58AM +0100, Andre Przywara wrote:
>> Userland may want to save and restore the state of the in-kernel VGIC,
>> so we provide the code which takes a userland request and translate
>> that into calls to our MMIO framework.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic-kvm-device.c | 50 ++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 49 insertions(+), 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> index c952f6f..bb33af8 100644
>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> @@ -264,7 +264,55 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
> 
> come to think of it, this is GICv2 specific right?
> 
> why don't we call it vgic_v2_attr_regs_access then?
> 
> and should it really live in this file?

Mmmh, at the moment every userland access is v2 specific, but
potentially this function should cover GICv3 as well, I think. We might
need some adjustments once this will be implemented, but in general I
don't see anything too v2 specific in here?

>>  				 struct kvm_device_attr *attr,
>>  				 u32 *reg, bool is_write)
>>  {
>> -	return -ENXIO;
>> +	gpa_t addr;
>> +	int cpuid, ret, c;
>> +	struct kvm_vcpu *vcpu, *tmp_vcpu;
>> +
>> +	cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >>
>> +		 KVM_DEV_ARM_VGIC_CPUID_SHIFT;
>> +	vcpu = kvm_get_vcpu(dev->kvm, cpuid);
>> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
>> +
>> +	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;
>> +	}
>> +
>> +	/*
>> +	 * 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().
>> +	 */
> 
> eh, I don't see us grabbing any vgic->lock (does that still exist?)
> here?

Yeah, that scared me the other day too.
In fact I think we cannot guarantee this requirement anymore with our
existing locks - but maybe we can pause the guest explicitly as we do
now for the clear-active handler?

Cheers,
Andre.

>> +	kvm_for_each_vcpu(c, tmp_vcpu, dev->kvm) {
>> +		if (unlikely(tmp_vcpu->cpu != -1)) {
>> +			ret = -EBUSY;
>> +			goto out;
>> +		}
>> +	}
>> +
>> +	switch (attr->group) {
>> +	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
>> +		ret = -EINVAL;
>> +		break;
>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>> +		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
>> +		break;
>> +	default:
>> +		ret = -EINVAL;
>> +		break;
>> +	}
>> +
>> +out:
>> +	mutex_unlock(&dev->kvm->lock);
>> +	return ret;
>>  }
>>  
>>  /* V2 ops */
>> -- 
>> 2.7.3
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe kvm" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> Thanks,
> -Christoffer
> 

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

* [PATCH v3 45/55] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
@ 2016-05-12 19:10       ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-12 19:10 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 12/05/16 19:41, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:58AM +0100, Andre Przywara wrote:
>> Userland may want to save and restore the state of the in-kernel VGIC,
>> so we provide the code which takes a userland request and translate
>> that into calls to our MMIO framework.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic-kvm-device.c | 50 ++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 49 insertions(+), 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> index c952f6f..bb33af8 100644
>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> @@ -264,7 +264,55 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
> 
> come to think of it, this is GICv2 specific right?
> 
> why don't we call it vgic_v2_attr_regs_access then?
> 
> and should it really live in this file?

Mmmh, at the moment every userland access is v2 specific, but
potentially this function should cover GICv3 as well, I think. We might
need some adjustments once this will be implemented, but in general I
don't see anything too v2 specific in here?

>>  				 struct kvm_device_attr *attr,
>>  				 u32 *reg, bool is_write)
>>  {
>> -	return -ENXIO;
>> +	gpa_t addr;
>> +	int cpuid, ret, c;
>> +	struct kvm_vcpu *vcpu, *tmp_vcpu;
>> +
>> +	cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >>
>> +		 KVM_DEV_ARM_VGIC_CPUID_SHIFT;
>> +	vcpu = kvm_get_vcpu(dev->kvm, cpuid);
>> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
>> +
>> +	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;
>> +	}
>> +
>> +	/*
>> +	 * 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().
>> +	 */
> 
> eh, I don't see us grabbing any vgic->lock (does that still exist?)
> here?

Yeah, that scared me the other day too.
In fact I think we cannot guarantee this requirement anymore with our
existing locks - but maybe we can pause the guest explicitly as we do
now for the clear-active handler?

Cheers,
Andre.

>> +	kvm_for_each_vcpu(c, tmp_vcpu, dev->kvm) {
>> +		if (unlikely(tmp_vcpu->cpu != -1)) {
>> +			ret = -EBUSY;
>> +			goto out;
>> +		}
>> +	}
>> +
>> +	switch (attr->group) {
>> +	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
>> +		ret = -EINVAL;
>> +		break;
>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>> +		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
>> +		break;
>> +	default:
>> +		ret = -EINVAL;
>> +		break;
>> +	}
>> +
>> +out:
>> +	mutex_unlock(&dev->kvm->lock);
>> +	return ret;
>>  }
>>  
>>  /* V2 ops */
>> -- 
>> 2.7.3
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe kvm" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> Thanks,
> -Christoffer
> 

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

* Re: [PATCH v3 50/55] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
  2016-05-06 10:46   ` Andre Przywara
@ 2016-05-12 19:25     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 19:25 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 06, 2016 at 11:46:03AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> This patch allocates and initializes the data structures used
> to model the vgic distributor and virtual cpu interfaces. At that
> stage the number of IRQs and number of virtual CPUs is frozen.
> 
> The following early_init functions are kept since they are called from
> arm.c. However they may disappear in subsequent patches since
> they are void.
> 
> vgic_[v2|v3]_enable still is stubbed at this stage.

I suggest deleting the last two paragraphs.

> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - initialize v2/v3 default CPU affinities explicitly
> 
> Changelog v1 .. v2:
> - move lazy_init() into vgic_update_irq_pending()
> 
>  include/kvm/vgic/vgic.h       |   7 +-
>  virt/kvm/arm/vgic/vgic-init.c | 213 ++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v2.c   |   5 +
>  virt/kvm/arm/vgic/vgic-v3.c   |   5 +
>  virt/kvm/arm/vgic/vgic.c      |   4 +
>  virt/kvm/arm/vgic/vgic.h      |   8 ++
>  6 files changed, 241 insertions(+), 1 deletion(-)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 899b7b7..538078a 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -119,6 +119,7 @@ struct vgic_io_device {
>  struct vgic_dist {
>  	bool			in_kernel;
>  	bool			ready;
> +	bool			initialized;
>  
>  	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
>  	u32			vgic_model;
> @@ -202,7 +203,11 @@ struct vgic_cpu {
>  };
>  
>  int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
> +void kvm_vgic_early_init(struct kvm *kvm);
>  int kvm_vgic_create(struct kvm *kvm, u32 type);
> +void kvm_vgic_destroy(struct kvm *kvm);
> +void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
> +void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
>  int kvm_vgic_hyp_init(void);
>  
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> @@ -211,7 +216,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
>  
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> -#define vgic_initialized(k)	(false)
> +#define vgic_initialized(k)	((k)->arch.vgic.initialized)
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
>  #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> index a150363..3f9c137 100644
> --- a/virt/kvm/arm/vgic/vgic-init.c
> +++ b/virt/kvm/arm/vgic/vgic-init.c
> @@ -24,6 +24,42 @@
>  #include <asm/kvm_mmu.h>
>  #include "vgic.h"
>  
> +/*
> + * Initialization rules: there are multiple stages to the vgic
> + * initialization, both for the distributor and the CPU interfaces.
> + *
> + * Distributor:
> + *
> + * - kvm_vgic_early_init(): initialization of static data that doesn't
> + *   depend on any sizing information or emulation type. No allocation
> + *   is allowed there.
> + *
> + * - vgic_init(): allocation and initialization of the generic data
> + *   structures that depend on sizing information (number of CPUs,
> + *   number of interrupts). Also initializes the vcpu specific data
> + *   structures. Can be executed lazily for GICv2.
> + *
> + * CPU Interface:
> + *
> + * - kvm_vgic_cpu_early_init(): initialization of static data that
> + *   doesn't depend on any sizing information or emulation type. No
> + *   allocation is allowed there.
> + */
> +
> +/* EARLY INIT */
> +
> +/*
> + * Those 2 functions should not be needed anymore but they
> + * still are called from arm.c
> + */
> +void kvm_vgic_early_init(struct kvm *kvm)
> +{
> +}
> +
> +void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu)
> +{
> +}
> +
>  /* CREATION */
>  
>  /**
> @@ -108,6 +144,183 @@ out:
>  	return ret;
>  }
>  
> +/* INIT/DESTROY */
> +
> +/**
> + * kvm_vgic_dist_init: initialize the dist data structures
> + * @kvm: kvm struct pointer
> + * @nr_spis: number of spis, frozen by caller
> + */
> +int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)

is this ever called from outside this file?

If not, why is it not static?

> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
> +	int i;
> +
> +	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
> +	if (!dist->spis)
> +		return  -ENOMEM;
> +
> +	/*
> +	 * In following code we do not take the irq struct lock since
> +	 * no other action on irq structs can happen while the VGIC is
> +	 * not initialized yet:
> +	 * injection requires (VGICV3) or does (VGIC2) initialization.
> +	 * MMIO access triggers init.

I don't understand these two last lines of comment?

> +	 */
> +	for (i = 0; i < nr_spis; i++) {
> +		struct vgic_irq *irq = &dist->spis[i];
> +
> +		irq->intid = i + VGIC_NR_PRIVATE_IRQS;
> +		INIT_LIST_HEAD(&irq->ap_list);
> +		spin_lock_init(&irq->irq_lock);
> +		irq->vcpu = NULL;
> +		irq->target_vcpu = vcpu0;
> +		if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
> +			irq->targets = 0;
> +		else
> +			irq->mpidr = 0;
> +	}
> +	return 0;
> +}
> +
> +/**
> + * kvm_vgic_vcpu_init: initialize the vcpu data structures and
> + * enable the VCPU interface
> + * @kvm: kvm struct pointer
> + */
> +void kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)

same here

> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	int i;
> +
> +	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
> +	spin_lock_init(&vgic_cpu->ap_list_lock);
> +
> +	/*
> +	 * Enable and configure all SGIs to be edge-triggered and
> +	 * configure all PPIs as level-triggered.
> +	 */
> +	for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
> +		struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
> +
> +		INIT_LIST_HEAD(&irq->ap_list);
> +		spin_lock_init(&irq->irq_lock);
> +		irq->intid = i;
> +		irq->vcpu = NULL;
> +		irq->target_vcpu = vcpu;
> +		irq->targets = 1U << vcpu->vcpu_id;
> +		if (vgic_irq_is_sgi(i)) {
> +			/* SGIs */
> +			irq->enabled = 1;
> +			irq->config = VGIC_CONFIG_EDGE;
> +		} else {
> +			/* PPIs */
> +			irq->config = VGIC_CONFIG_LEVEL;
> +		}
> +	}
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_enable(vcpu);
> +	else
> +		vgic_v3_enable(vcpu);
> +}
> +
> +/*
> + * vgic_init: allocates and initializes dist and vcpu data structures
> + * depending on two dimensioning parameters:
> + * - the number of spis
> + * - the number of vcpus
> + * The function is generally called when nr_spis has been explicitly set
> + * by the guest through the KVM DEVICE API. If not nr_spis is set to 256.
> + * Completion can be tested by vgic_initialized

s/Completion can be tested by vgic_initialized/
  vgic_initialized() returns true when this function has succeeded/

> + * Must be called with kvm->lock held!
> + */
> +int vgic_init(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	struct kvm_vcpu *vcpu;
> +	int ret = 0, i;
> +
> +	if (vgic_initialized(kvm))
> +		return 0;
> +
> +	/* freeze the number of spis */
> +	if (!dist->nr_spis)
> +		dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;
> +
> +	ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
> +	if (ret)
> +		goto out;
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm)
> +		kvm_vgic_vcpu_init(vcpu);
> +
> +	dist->initialized = true;
> +out:
> +	return ret;
> +}
> +
> +static void kvm_vgic_dist_destroy(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +
> +	mutex_lock(&kvm->lock);
> +
> +	dist->ready = false;
> +	dist->initialized = false;
> +
> +	kfree(dist->spis);
> +	kfree(dist->redist_iodevs);
> +	dist->nr_spis = 0;
> +
> +	mutex_unlock(&kvm->lock);
> +}
> +
> +void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +
> +	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);

this is actually not the state prior to initialization, so is this
really required?

> +}
> +
> +void kvm_vgic_destroy(struct kvm *kvm)
> +{
> +	struct kvm_vcpu *vcpu;
> +	int i;
> +
> +	kvm_vgic_dist_destroy(kvm);
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm)
> +		kvm_vgic_vcpu_destroy(vcpu);
> +}
> +
> +/**
> + * Lazy init only is allowed if the GIC exposed to the guest is a GICV2.
> + * GICV3 must be explicitly initialized by the guest using the
> + * KVM_DEV_ARM_VGIC_GRP_CTRL KVM_DEVICE group

nit: period after group.

> + */
> +int vgic_lazy_init(struct kvm *kvm)
> +{
> +	int ret = 0;
> +
> +	if (unlikely(!vgic_initialized(kvm))) {
> +		/*
> +		 * We only provide the automatic initialization of the VGIC
> +		 * for the legacy case of a GICv2. Any other type must
> +		 * be explicitly initialized once setup with the respective
> +		 * KVM device call.
> +		 */
> +		if (kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2)
> +			return -EBUSY;
> +
> +		mutex_lock(&kvm->lock);
> +		ret = vgic_init(kvm);
> +		mutex_unlock(&kvm->lock);
> +	}
> +
> +	return ret;
> +}
> +
>  /* GENERIC PROBE */
>  
>  static void vgic_init_maintenance_interrupt(void *info)
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 91b69a4..48aa877 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -211,6 +211,11 @@ void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  			GICH_VMCR_PRIMASK_SHIFT;
>  }
>  
> +/* not yet implemented */
> +void vgic_v2_enable(struct kvm_vcpu *vcpu)
> +{
> +}
> +
>  /**
>   * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
>   * @node:	pointer to the DT node
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 48b0bb7..7cab5b9 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -195,6 +195,11 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
>  }
>  
> +/* not yet implemented */
> +void vgic_v3_enable(struct kvm_vcpu *vcpu)
> +{
> +}
> +
>  /**
>   * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
>   * @node:	pointer to the DT node
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 5355de6..068389a 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -255,6 +255,10 @@ static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
>  
>  	trace_vgic_update_irq_pending(cpuid, intid, level);
>  
> +	ret = vgic_lazy_init(kvm);
> +	if (ret)
> +		return ret;
> +
>  	vcpu = kvm_get_vcpu(kvm, cpuid);
>  	if (!vcpu && intid < VGIC_NR_PRIVATE_IRQS)
>  		return -EINVAL;
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index e49b1df..cad04eb 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -43,6 +43,7 @@ int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			  int offset, u32 *val);
>  void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> +void vgic_v2_enable(struct kvm_vcpu *vcpu);
>  int vgic_v2_probe(struct device_node *vgic_node);
>  int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
>  			     enum vgic_type);
> @@ -55,6 +56,7 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
>  void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> +void vgic_v3_enable(struct kvm_vcpu *vcpu);
>  int vgic_v3_probe(struct device_node *vgic_node);
>  int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
>  #else
> @@ -89,6 +91,10 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>  {
>  }
>  
> +static inline void vgic_v3_enable(struct kvm_vcpu *vcpu)
> +{
> +}
> +
>  static inline int vgic_v3_probe(struct device_node *vgic_node)
>  {
>  	return -ENODEV;
> @@ -102,5 +108,7 @@ static inline int vgic_register_redist_iodevs(struct kvm *kvm,
>  #endif
>  
>  void kvm_register_vgic_device(unsigned long type);
> +int vgic_lazy_init(struct kvm *kvm);
> +int vgic_init(struct kvm *kvm);
>  
>  #endif
> -- 
> 2.7.3
> 
> --

The cosmetic comments notwithstanding:

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

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

* [PATCH v3 50/55] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
@ 2016-05-12 19:25     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 19:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:46:03AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> This patch allocates and initializes the data structures used
> to model the vgic distributor and virtual cpu interfaces. At that
> stage the number of IRQs and number of virtual CPUs is frozen.
> 
> The following early_init functions are kept since they are called from
> arm.c. However they may disappear in subsequent patches since
> they are void.
> 
> vgic_[v2|v3]_enable still is stubbed at this stage.

I suggest deleting the last two paragraphs.

> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - initialize v2/v3 default CPU affinities explicitly
> 
> Changelog v1 .. v2:
> - move lazy_init() into vgic_update_irq_pending()
> 
>  include/kvm/vgic/vgic.h       |   7 +-
>  virt/kvm/arm/vgic/vgic-init.c | 213 ++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v2.c   |   5 +
>  virt/kvm/arm/vgic/vgic-v3.c   |   5 +
>  virt/kvm/arm/vgic/vgic.c      |   4 +
>  virt/kvm/arm/vgic/vgic.h      |   8 ++
>  6 files changed, 241 insertions(+), 1 deletion(-)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 899b7b7..538078a 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -119,6 +119,7 @@ struct vgic_io_device {
>  struct vgic_dist {
>  	bool			in_kernel;
>  	bool			ready;
> +	bool			initialized;
>  
>  	/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
>  	u32			vgic_model;
> @@ -202,7 +203,11 @@ struct vgic_cpu {
>  };
>  
>  int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
> +void kvm_vgic_early_init(struct kvm *kvm);
>  int kvm_vgic_create(struct kvm *kvm, u32 type);
> +void kvm_vgic_destroy(struct kvm *kvm);
> +void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
> +void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
>  int kvm_vgic_hyp_init(void);
>  
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> @@ -211,7 +216,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
>  
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> -#define vgic_initialized(k)	(false)
> +#define vgic_initialized(k)	((k)->arch.vgic.initialized)
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
>  #define vgic_valid_spi(k, i)	(((i) >= VGIC_NR_PRIVATE_IRQS) && \
>  			((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> index a150363..3f9c137 100644
> --- a/virt/kvm/arm/vgic/vgic-init.c
> +++ b/virt/kvm/arm/vgic/vgic-init.c
> @@ -24,6 +24,42 @@
>  #include <asm/kvm_mmu.h>
>  #include "vgic.h"
>  
> +/*
> + * Initialization rules: there are multiple stages to the vgic
> + * initialization, both for the distributor and the CPU interfaces.
> + *
> + * Distributor:
> + *
> + * - kvm_vgic_early_init(): initialization of static data that doesn't
> + *   depend on any sizing information or emulation type. No allocation
> + *   is allowed there.
> + *
> + * - vgic_init(): allocation and initialization of the generic data
> + *   structures that depend on sizing information (number of CPUs,
> + *   number of interrupts). Also initializes the vcpu specific data
> + *   structures. Can be executed lazily for GICv2.
> + *
> + * CPU Interface:
> + *
> + * - kvm_vgic_cpu_early_init(): initialization of static data that
> + *   doesn't depend on any sizing information or emulation type. No
> + *   allocation is allowed there.
> + */
> +
> +/* EARLY INIT */
> +
> +/*
> + * Those 2 functions should not be needed anymore but they
> + * still are called from arm.c
> + */
> +void kvm_vgic_early_init(struct kvm *kvm)
> +{
> +}
> +
> +void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu)
> +{
> +}
> +
>  /* CREATION */
>  
>  /**
> @@ -108,6 +144,183 @@ out:
>  	return ret;
>  }
>  
> +/* INIT/DESTROY */
> +
> +/**
> + * kvm_vgic_dist_init: initialize the dist data structures
> + * @kvm: kvm struct pointer
> + * @nr_spis: number of spis, frozen by caller
> + */
> +int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)

is this ever called from outside this file?

If not, why is it not static?

> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
> +	int i;
> +
> +	dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
> +	if (!dist->spis)
> +		return  -ENOMEM;
> +
> +	/*
> +	 * In following code we do not take the irq struct lock since
> +	 * no other action on irq structs can happen while the VGIC is
> +	 * not initialized yet:
> +	 * injection requires (VGICV3) or does (VGIC2) initialization.
> +	 * MMIO access triggers init.

I don't understand these two last lines of comment?

> +	 */
> +	for (i = 0; i < nr_spis; i++) {
> +		struct vgic_irq *irq = &dist->spis[i];
> +
> +		irq->intid = i + VGIC_NR_PRIVATE_IRQS;
> +		INIT_LIST_HEAD(&irq->ap_list);
> +		spin_lock_init(&irq->irq_lock);
> +		irq->vcpu = NULL;
> +		irq->target_vcpu = vcpu0;
> +		if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
> +			irq->targets = 0;
> +		else
> +			irq->mpidr = 0;
> +	}
> +	return 0;
> +}
> +
> +/**
> + * kvm_vgic_vcpu_init: initialize the vcpu data structures and
> + * enable the VCPU interface
> + * @kvm: kvm struct pointer
> + */
> +void kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)

same here

> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +	int i;
> +
> +	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
> +	spin_lock_init(&vgic_cpu->ap_list_lock);
> +
> +	/*
> +	 * Enable and configure all SGIs to be edge-triggered and
> +	 * configure all PPIs as level-triggered.
> +	 */
> +	for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
> +		struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
> +
> +		INIT_LIST_HEAD(&irq->ap_list);
> +		spin_lock_init(&irq->irq_lock);
> +		irq->intid = i;
> +		irq->vcpu = NULL;
> +		irq->target_vcpu = vcpu;
> +		irq->targets = 1U << vcpu->vcpu_id;
> +		if (vgic_irq_is_sgi(i)) {
> +			/* SGIs */
> +			irq->enabled = 1;
> +			irq->config = VGIC_CONFIG_EDGE;
> +		} else {
> +			/* PPIs */
> +			irq->config = VGIC_CONFIG_LEVEL;
> +		}
> +	}
> +	if (kvm_vgic_global_state.type == VGIC_V2)
> +		vgic_v2_enable(vcpu);
> +	else
> +		vgic_v3_enable(vcpu);
> +}
> +
> +/*
> + * vgic_init: allocates and initializes dist and vcpu data structures
> + * depending on two dimensioning parameters:
> + * - the number of spis
> + * - the number of vcpus
> + * The function is generally called when nr_spis has been explicitly set
> + * by the guest through the KVM DEVICE API. If not nr_spis is set to 256.
> + * Completion can be tested by vgic_initialized

s/Completion can be tested by vgic_initialized/
  vgic_initialized() returns true when this function has succeeded/

> + * Must be called with kvm->lock held!
> + */
> +int vgic_init(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	struct kvm_vcpu *vcpu;
> +	int ret = 0, i;
> +
> +	if (vgic_initialized(kvm))
> +		return 0;
> +
> +	/* freeze the number of spis */
> +	if (!dist->nr_spis)
> +		dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;
> +
> +	ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
> +	if (ret)
> +		goto out;
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm)
> +		kvm_vgic_vcpu_init(vcpu);
> +
> +	dist->initialized = true;
> +out:
> +	return ret;
> +}
> +
> +static void kvm_vgic_dist_destroy(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +
> +	mutex_lock(&kvm->lock);
> +
> +	dist->ready = false;
> +	dist->initialized = false;
> +
> +	kfree(dist->spis);
> +	kfree(dist->redist_iodevs);
> +	dist->nr_spis = 0;
> +
> +	mutex_unlock(&kvm->lock);
> +}
> +
> +void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
> +
> +	INIT_LIST_HEAD(&vgic_cpu->ap_list_head);

this is actually not the state prior to initialization, so is this
really required?

> +}
> +
> +void kvm_vgic_destroy(struct kvm *kvm)
> +{
> +	struct kvm_vcpu *vcpu;
> +	int i;
> +
> +	kvm_vgic_dist_destroy(kvm);
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm)
> +		kvm_vgic_vcpu_destroy(vcpu);
> +}
> +
> +/**
> + * Lazy init only is allowed if the GIC exposed to the guest is a GICV2.
> + * GICV3 must be explicitly initialized by the guest using the
> + * KVM_DEV_ARM_VGIC_GRP_CTRL KVM_DEVICE group

nit: period after group.

> + */
> +int vgic_lazy_init(struct kvm *kvm)
> +{
> +	int ret = 0;
> +
> +	if (unlikely(!vgic_initialized(kvm))) {
> +		/*
> +		 * We only provide the automatic initialization of the VGIC
> +		 * for the legacy case of a GICv2. Any other type must
> +		 * be explicitly initialized once setup with the respective
> +		 * KVM device call.
> +		 */
> +		if (kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2)
> +			return -EBUSY;
> +
> +		mutex_lock(&kvm->lock);
> +		ret = vgic_init(kvm);
> +		mutex_unlock(&kvm->lock);
> +	}
> +
> +	return ret;
> +}
> +
>  /* GENERIC PROBE */
>  
>  static void vgic_init_maintenance_interrupt(void *info)
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 91b69a4..48aa877 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -211,6 +211,11 @@ void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  			GICH_VMCR_PRIMASK_SHIFT;
>  }
>  
> +/* not yet implemented */
> +void vgic_v2_enable(struct kvm_vcpu *vcpu)
> +{
> +}
> +
>  /**
>   * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
>   * @node:	pointer to the DT node
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 48b0bb7..7cab5b9 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -195,6 +195,11 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
>  }
>  
> +/* not yet implemented */
> +void vgic_v3_enable(struct kvm_vcpu *vcpu)
> +{
> +}
> +
>  /**
>   * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
>   * @node:	pointer to the DT node
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 5355de6..068389a 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -255,6 +255,10 @@ static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
>  
>  	trace_vgic_update_irq_pending(cpuid, intid, level);
>  
> +	ret = vgic_lazy_init(kvm);
> +	if (ret)
> +		return ret;
> +
>  	vcpu = kvm_get_vcpu(kvm, cpuid);
>  	if (!vcpu && intid < VGIC_NR_PRIVATE_IRQS)
>  		return -EINVAL;
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index e49b1df..cad04eb 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -43,6 +43,7 @@ int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write,
>  			  int offset, u32 *val);
>  void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> +void vgic_v2_enable(struct kvm_vcpu *vcpu);
>  int vgic_v2_probe(struct device_node *vgic_node);
>  int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
>  			     enum vgic_type);
> @@ -55,6 +56,7 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
>  void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
> +void vgic_v3_enable(struct kvm_vcpu *vcpu);
>  int vgic_v3_probe(struct device_node *vgic_node);
>  int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
>  #else
> @@ -89,6 +91,10 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
>  {
>  }
>  
> +static inline void vgic_v3_enable(struct kvm_vcpu *vcpu)
> +{
> +}
> +
>  static inline int vgic_v3_probe(struct device_node *vgic_node)
>  {
>  	return -ENODEV;
> @@ -102,5 +108,7 @@ static inline int vgic_register_redist_iodevs(struct kvm *kvm,
>  #endif
>  
>  void kvm_register_vgic_device(unsigned long type);
> +int vgic_lazy_init(struct kvm *kvm);
> +int vgic_init(struct kvm *kvm);
>  
>  #endif
> -- 
> 2.7.3
> 
> --

The cosmetic comments notwithstanding:

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

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

* Re: [PATCH v3 51/55] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources
  2016-05-06 10:46   ` Andre Przywara
@ 2016-05-12 19:28     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 19:28 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:46:04AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> map_resources is the last initialization step. It is executed on
> 1st VCPU run. At that stage the code checks the userspace has provided
> the base addresses for the relevant VGIC regions, which depend on
> the type of VGIC that is exposed to the guest.
> 
> The function also forces the vgic_init if it has not been executed yet
> (only allowed for VGIC v2).
> 
> for GICv2, The VGIC CPU interface is mapped onto the GIC virtual CPU
> interface.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h       |  1 +
>  virt/kvm/arm/vgic/vgic-init.c | 27 +++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v2.c   | 47 +++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c   | 44 ++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h      |  7 +++++++
>  5 files changed, 126 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 538078a..07c3011 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -208,6 +208,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type);
>  void kvm_vgic_destroy(struct kvm *kvm);
>  void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
>  void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
> +int kvm_vgic_map_resources(struct kvm *kvm);
>  int kvm_vgic_hyp_init(void);
>  
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> index 3f9c137..7fefb12 100644
> --- a/virt/kvm/arm/vgic/vgic-init.c
> +++ b/virt/kvm/arm/vgic/vgic-init.c
> @@ -321,6 +321,33 @@ int vgic_lazy_init(struct kvm *kvm)
>  	return ret;
>  }
>  
> +/* RESOURCE MAPPING */
> +
> +/**
> + * Map the MMIO regions depending on the VGIC model exposed to the guest
> + * called on the first VCPU run.
> + * Also map the virtual CPU interface into the VM.
> + * v2/v3 derivatives call vgic_init if not already done.
> + * Completion can be tested by vgic_ready

s/Completion can be tested by vgic_ready/
 vgic_ready() returns true if this function has succeeded/

> + */
> +int kvm_vgic_map_resources(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	int ret = 0;
> +
> +	mutex_lock(&kvm->lock);
> +	if (!irqchip_in_kernel(kvm))
> +		goto out;
> +
> +	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
> +		ret = vgic_v2_map_resources(kvm);
> +	else
> +		ret = vgic_v3_map_resources(kvm);
> +out:
> +	mutex_unlock(&kvm->lock);
> +	return ret;
> +}
> +
>  /* GENERIC PROBE */
>  
>  static void vgic_init_maintenance_interrupt(void *info)
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 48aa877..1e411f5 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -216,6 +216,53 @@ void vgic_v2_enable(struct kvm_vcpu *vcpu)
>  {
>  }
>  
> +int vgic_v2_map_resources(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	int ret = 0;
> +
> +	if (vgic_ready(kvm))
> +		goto out;
> +
> +	if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base) ||
> +	    IS_VGIC_ADDR_UNDEF(dist->vgic_cpu_base)) {
> +		kvm_err("Need to set vgic cpu and dist addresses first\n");
> +		ret = -ENXIO;
> +		goto out;
> +	}
> +
> +	/*
> +	 * Initialize the vgic if this hasn't already been done on demand by
> +	 * accessing the vgic state from userspace.
> +	 */
> +	ret = vgic_init(kvm);
> +	if (ret) {
> +		kvm_err("Unable to initialize VGIC dynamic data structures\n");
> +		goto out;
> +	}
> +
> +	ret = vgic_register_dist_iodev(kvm, dist->vgic_dist_base, VGIC_V2);
> +	if (ret) {
> +		kvm_err("Unable to register VGIC MMIO regions\n");
> +		goto out;
> +	}
> +
> +	ret = kvm_phys_addr_ioremap(kvm, dist->vgic_cpu_base,
> +				    kvm_vgic_global_state.vcpu_base,
> +				    KVM_VGIC_V2_CPU_SIZE, true);
> +	if (ret) {
> +		kvm_err("Unable to remap VGIC CPU to VCPU\n");
> +		goto out;
> +	}
> +
> +	dist->ready = true;
> +
> +out:
> +	if (ret)
> +		kvm_vgic_destroy(kvm);
> +	return ret;
> +}
> +
>  /**
>   * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
>   * @node:	pointer to the DT node
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 7cab5b9..4bfd42a 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -200,6 +200,50 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
>  {
>  }
>  
> +int vgic_v3_map_resources(struct kvm *kvm)
> +{
> +	int ret = 0;
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +
> +	if (vgic_ready(kvm))
> +		goto out;
> +
> +	if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base) ||
> +	    IS_VGIC_ADDR_UNDEF(dist->vgic_redist_base)) {
> +		kvm_err("Need to set vgic distributor addresses first\n");
> +		ret = -ENXIO;
> +		goto out;
> +	}
> +
> +	/*
> +	 * For a VGICv3 we require the userland to explicitly initialize
> +	 * the VGIC before we need to use it.
> +	 */
> +	if (!vgic_initialized(kvm)) {
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	ret = vgic_register_dist_iodev(kvm, dist->vgic_dist_base, VGIC_V3);
> +	if (ret) {
> +		kvm_err("Unable to register VGICv3 dist MMIO regions\n");
> +		goto out;
> +	}
> +
> +	ret = vgic_register_redist_iodevs(kvm, dist->vgic_redist_base);
> +	if (ret) {
> +		kvm_err("Unable to register VGICv3 redist MMIO regions\n");
> +		goto out;
> +	}
> +
> +	dist->ready = true;
> +
> +out:
> +	if (ret)
> +		kvm_vgic_destroy(kvm);
> +	return ret;
> +}
> +
>  /**
>   * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
>   * @node:	pointer to the DT node
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index cad04eb..5c7dc99 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -45,6 +45,7 @@ void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v2_enable(struct kvm_vcpu *vcpu);
>  int vgic_v2_probe(struct device_node *vgic_node);
> +int vgic_v2_map_resources(struct kvm *kvm);
>  int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
>  			     enum vgic_type);
>  
> @@ -58,6 +59,7 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v3_enable(struct kvm_vcpu *vcpu);
>  int vgic_v3_probe(struct device_node *vgic_node);
> +int vgic_v3_map_resources(struct kvm *kvm);
>  int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
>  #else
>  static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> @@ -100,6 +102,11 @@ static inline int vgic_v3_probe(struct device_node *vgic_node)
>  	return -ENODEV;
>  }
>  
> +static inline int vgic_v3_map_resources(struct kvm *kvm)
> +{
> +	return -ENODEV;
> +}
> +
>  static inline int vgic_register_redist_iodevs(struct kvm *kvm,
>  					      gpa_t dist_base_address)
>  {
> -- 
> 2.7.3
> 
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

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

* [PATCH v3 51/55] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources
@ 2016-05-12 19:28     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 19:28 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:46:04AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> map_resources is the last initialization step. It is executed on
> 1st VCPU run. At that stage the code checks the userspace has provided
> the base addresses for the relevant VGIC regions, which depend on
> the type of VGIC that is exposed to the guest.
> 
> The function also forces the vgic_init if it has not been executed yet
> (only allowed for VGIC v2).
> 
> for GICv2, The VGIC CPU interface is mapped onto the GIC virtual CPU
> interface.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h       |  1 +
>  virt/kvm/arm/vgic/vgic-init.c | 27 +++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v2.c   | 47 +++++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c   | 44 ++++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h      |  7 +++++++
>  5 files changed, 126 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 538078a..07c3011 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -208,6 +208,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type);
>  void kvm_vgic_destroy(struct kvm *kvm);
>  void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
>  void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
> +int kvm_vgic_map_resources(struct kvm *kvm);
>  int kvm_vgic_hyp_init(void);
>  
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
> index 3f9c137..7fefb12 100644
> --- a/virt/kvm/arm/vgic/vgic-init.c
> +++ b/virt/kvm/arm/vgic/vgic-init.c
> @@ -321,6 +321,33 @@ int vgic_lazy_init(struct kvm *kvm)
>  	return ret;
>  }
>  
> +/* RESOURCE MAPPING */
> +
> +/**
> + * Map the MMIO regions depending on the VGIC model exposed to the guest
> + * called on the first VCPU run.
> + * Also map the virtual CPU interface into the VM.
> + * v2/v3 derivatives call vgic_init if not already done.
> + * Completion can be tested by vgic_ready

s/Completion can be tested by vgic_ready/
 vgic_ready() returns true if this function has succeeded/

> + */
> +int kvm_vgic_map_resources(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	int ret = 0;
> +
> +	mutex_lock(&kvm->lock);
> +	if (!irqchip_in_kernel(kvm))
> +		goto out;
> +
> +	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2)
> +		ret = vgic_v2_map_resources(kvm);
> +	else
> +		ret = vgic_v3_map_resources(kvm);
> +out:
> +	mutex_unlock(&kvm->lock);
> +	return ret;
> +}
> +
>  /* GENERIC PROBE */
>  
>  static void vgic_init_maintenance_interrupt(void *info)
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 48aa877..1e411f5 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -216,6 +216,53 @@ void vgic_v2_enable(struct kvm_vcpu *vcpu)
>  {
>  }
>  
> +int vgic_v2_map_resources(struct kvm *kvm)
> +{
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +	int ret = 0;
> +
> +	if (vgic_ready(kvm))
> +		goto out;
> +
> +	if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base) ||
> +	    IS_VGIC_ADDR_UNDEF(dist->vgic_cpu_base)) {
> +		kvm_err("Need to set vgic cpu and dist addresses first\n");
> +		ret = -ENXIO;
> +		goto out;
> +	}
> +
> +	/*
> +	 * Initialize the vgic if this hasn't already been done on demand by
> +	 * accessing the vgic state from userspace.
> +	 */
> +	ret = vgic_init(kvm);
> +	if (ret) {
> +		kvm_err("Unable to initialize VGIC dynamic data structures\n");
> +		goto out;
> +	}
> +
> +	ret = vgic_register_dist_iodev(kvm, dist->vgic_dist_base, VGIC_V2);
> +	if (ret) {
> +		kvm_err("Unable to register VGIC MMIO regions\n");
> +		goto out;
> +	}
> +
> +	ret = kvm_phys_addr_ioremap(kvm, dist->vgic_cpu_base,
> +				    kvm_vgic_global_state.vcpu_base,
> +				    KVM_VGIC_V2_CPU_SIZE, true);
> +	if (ret) {
> +		kvm_err("Unable to remap VGIC CPU to VCPU\n");
> +		goto out;
> +	}
> +
> +	dist->ready = true;
> +
> +out:
> +	if (ret)
> +		kvm_vgic_destroy(kvm);
> +	return ret;
> +}
> +
>  /**
>   * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
>   * @node:	pointer to the DT node
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 7cab5b9..4bfd42a 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -200,6 +200,50 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
>  {
>  }
>  
> +int vgic_v3_map_resources(struct kvm *kvm)
> +{
> +	int ret = 0;
> +	struct vgic_dist *dist = &kvm->arch.vgic;
> +
> +	if (vgic_ready(kvm))
> +		goto out;
> +
> +	if (IS_VGIC_ADDR_UNDEF(dist->vgic_dist_base) ||
> +	    IS_VGIC_ADDR_UNDEF(dist->vgic_redist_base)) {
> +		kvm_err("Need to set vgic distributor addresses first\n");
> +		ret = -ENXIO;
> +		goto out;
> +	}
> +
> +	/*
> +	 * For a VGICv3 we require the userland to explicitly initialize
> +	 * the VGIC before we need to use it.
> +	 */
> +	if (!vgic_initialized(kvm)) {
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	ret = vgic_register_dist_iodev(kvm, dist->vgic_dist_base, VGIC_V3);
> +	if (ret) {
> +		kvm_err("Unable to register VGICv3 dist MMIO regions\n");
> +		goto out;
> +	}
> +
> +	ret = vgic_register_redist_iodevs(kvm, dist->vgic_redist_base);
> +	if (ret) {
> +		kvm_err("Unable to register VGICv3 redist MMIO regions\n");
> +		goto out;
> +	}
> +
> +	dist->ready = true;
> +
> +out:
> +	if (ret)
> +		kvm_vgic_destroy(kvm);
> +	return ret;
> +}
> +
>  /**
>   * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
>   * @node:	pointer to the DT node
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index cad04eb..5c7dc99 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -45,6 +45,7 @@ void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v2_enable(struct kvm_vcpu *vcpu);
>  int vgic_v2_probe(struct device_node *vgic_node);
> +int vgic_v2_map_resources(struct kvm *kvm);
>  int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
>  			     enum vgic_type);
>  
> @@ -58,6 +59,7 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v3_enable(struct kvm_vcpu *vcpu);
>  int vgic_v3_probe(struct device_node *vgic_node);
> +int vgic_v3_map_resources(struct kvm *kvm);
>  int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
>  #else
>  static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
> @@ -100,6 +102,11 @@ static inline int vgic_v3_probe(struct device_node *vgic_node)
>  	return -ENODEV;
>  }
>  
> +static inline int vgic_v3_map_resources(struct kvm *kvm)
> +{
> +	return -ENODEV;
> +}
> +
>  static inline int vgic_register_redist_iodevs(struct kvm *kvm,
>  					      gpa_t dist_base_address)
>  {
> -- 
> 2.7.3
> 
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

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

* Re: [PATCH v3 52/55] KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable
  2016-05-06 10:46   ` Andre Przywara
@ 2016-05-12 19:30     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 19:30 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:46:05AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> Enable the VGIC operation by properly initialising the registers
> in the hypervisor GIC interface.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-v2.c | 11 ++++++++++-
>  virt/kvm/arm/vgic/vgic-v3.c | 23 ++++++++++++++++++++++-
>  2 files changed, 32 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 1e411f5..4493593 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -211,9 +211,18 @@ void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  			GICH_VMCR_PRIMASK_SHIFT;
>  }
>  
> -/* not yet implemented */
>  void vgic_v2_enable(struct kvm_vcpu *vcpu)
>  {
> +	/*
> +	 * By forcing VMCR to zero, the GIC will restore the binary
> +	 * points to their reset values. Anything else resets to zero
> +	 * anyway.
> +	 */
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = 0;
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr = ~0;
> +
> +	/* Get the show on the road... */
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr = GICH_HCR_EN;
>  }
>  
>  int vgic_v2_map_resources(struct kvm *kvm)
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 4bfd42a..6d7422f 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -195,9 +195,30 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
>  }
>  
> -/* not yet implemented */
>  void vgic_v3_enable(struct kvm_vcpu *vcpu)
>  {
> +	struct vgic_v3_cpu_if *vgic_v3 = &vcpu->arch.vgic_cpu.vgic_v3;
> +
> +	/*
> +	 * By forcing VMCR to zero, the GIC will restore the binary
> +	 * points to their reset values. Anything else resets to zero
> +	 * anyway.
> +	 */
> +	vgic_v3->vgic_vmcr = 0;
> +	vgic_v3->vgic_elrsr = ~0;
> +
> +	/*
> +	 * If we are emulating a GICv3, we do it in an non-GICv2-compatible
> +	 * way, so we force SRE to 1 to demonstrate this to the guest.
> +	 * This goes with the spec allowing the value to be RAO/WI.
> +	 */
> +	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +		vgic_v3->vgic_sre = ICC_SRE_EL1_SRE;
> +	else
> +		vgic_v3->vgic_sre = 0;
> +
> +	/* Get the show on the road... */
> +	vgic_v3->vgic_hcr = ICH_HCR_EN;
>  }
>  
>  int vgic_v3_map_resources(struct kvm *kvm)
> -- 
> 2.7.3
> 

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

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

* [PATCH v3 52/55] KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable
@ 2016-05-12 19:30     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 19:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:46:05AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> Enable the VGIC operation by properly initialising the registers
> in the hypervisor GIC interface.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-v2.c | 11 ++++++++++-
>  virt/kvm/arm/vgic/vgic-v3.c | 23 ++++++++++++++++++++++-
>  2 files changed, 32 insertions(+), 2 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 1e411f5..4493593 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -211,9 +211,18 @@ void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  			GICH_VMCR_PRIMASK_SHIFT;
>  }
>  
> -/* not yet implemented */
>  void vgic_v2_enable(struct kvm_vcpu *vcpu)
>  {
> +	/*
> +	 * By forcing VMCR to zero, the GIC will restore the binary
> +	 * points to their reset values. Anything else resets to zero
> +	 * anyway.
> +	 */
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = 0;
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr = ~0;
> +
> +	/* Get the show on the road... */
> +	vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr = GICH_HCR_EN;
>  }
>  
>  int vgic_v2_map_resources(struct kvm *kvm)
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 4bfd42a..6d7422f 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -195,9 +195,30 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
>  	vmcrp->pmr  = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
>  }
>  
> -/* not yet implemented */
>  void vgic_v3_enable(struct kvm_vcpu *vcpu)
>  {
> +	struct vgic_v3_cpu_if *vgic_v3 = &vcpu->arch.vgic_cpu.vgic_v3;
> +
> +	/*
> +	 * By forcing VMCR to zero, the GIC will restore the binary
> +	 * points to their reset values. Anything else resets to zero
> +	 * anyway.
> +	 */
> +	vgic_v3->vgic_vmcr = 0;
> +	vgic_v3->vgic_elrsr = ~0;
> +
> +	/*
> +	 * If we are emulating a GICv3, we do it in an non-GICv2-compatible
> +	 * way, so we force SRE to 1 to demonstrate this to the guest.
> +	 * This goes with the spec allowing the value to be RAO/WI.
> +	 */
> +	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
> +		vgic_v3->vgic_sre = ICC_SRE_EL1_SRE;
> +	else
> +		vgic_v3->vgic_sre = 0;
> +
> +	/* Get the show on the road... */
> +	vgic_v3->vgic_hcr = ICH_HCR_EN;
>  }
>  
>  int vgic_v3_map_resources(struct kvm *kvm)
> -- 
> 2.7.3
> 

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

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

* Re: [PATCH v3 53/55] KVM: arm/arm64: vgic-new: Wire up irqfd injection
  2016-05-06 10:46   ` Andre Przywara
@ 2016-05-12 19:33     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 19:33 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:46:06AM +0100, Andre Przywara wrote:
> Connect to the new VGIC to the irqfd framework, so that we can
> inject IRQs.
> GSI routing and MSI routing is not yet implemented.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-irqfd.c | 52 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 52 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-irqfd.c
> 
> diff --git a/virt/kvm/arm/vgic/vgic-irqfd.c b/virt/kvm/arm/vgic/vgic-irqfd.c
> new file mode 100644
> index 0000000..c675513
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-irqfd.c
> @@ -0,0 +1,52 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <trace/events/kvm.h>
> +
> +int kvm_irq_map_gsi(struct kvm *kvm,
> +		    struct kvm_kernel_irq_routing_entry *entries,
> +		    int gsi)
> +{
> +	return 0;
> +}
> +
> +int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned int irqchip,
> +			 unsigned int pin)
> +{
> +	return pin;
> +}
> +
> +int kvm_set_irq(struct kvm *kvm, int irq_source_id,
> +		u32 irq, int level, bool line_status)
> +{
> +	unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS;
> +
> +	trace_kvm_set_irq(irq, level, irq_source_id);
> +
> +	BUG_ON(!vgic_initialized(kvm));
> +
> +	return kvm_vgic_inject_irq(kvm, 0, spi, level);
> +}
> +
> +/* MSI not implemented yet */
> +int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
> +		struct kvm *kvm, int irq_source_id,
> +		int level, bool line_status)
> +{
> +	return 0;
> +}
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

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

* [PATCH v3 53/55] KVM: arm/arm64: vgic-new: Wire up irqfd injection
@ 2016-05-12 19:33     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 19:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:46:06AM +0100, Andre Przywara wrote:
> Connect to the new VGIC to the irqfd framework, so that we can
> inject IRQs.
> GSI routing and MSI routing is not yet implemented.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-irqfd.c | 52 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 52 insertions(+)
>  create mode 100644 virt/kvm/arm/vgic/vgic-irqfd.c
> 
> diff --git a/virt/kvm/arm/vgic/vgic-irqfd.c b/virt/kvm/arm/vgic/vgic-irqfd.c
> new file mode 100644
> index 0000000..c675513
> --- /dev/null
> +++ b/virt/kvm/arm/vgic/vgic-irqfd.c
> @@ -0,0 +1,52 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/kvm.h>
> +#include <linux/kvm_host.h>
> +#include <trace/events/kvm.h>
> +
> +int kvm_irq_map_gsi(struct kvm *kvm,
> +		    struct kvm_kernel_irq_routing_entry *entries,
> +		    int gsi)
> +{
> +	return 0;
> +}
> +
> +int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned int irqchip,
> +			 unsigned int pin)
> +{
> +	return pin;
> +}
> +
> +int kvm_set_irq(struct kvm *kvm, int irq_source_id,
> +		u32 irq, int level, bool line_status)
> +{
> +	unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS;
> +
> +	trace_kvm_set_irq(irq, level, irq_source_id);
> +
> +	BUG_ON(!vgic_initialized(kvm));
> +
> +	return kvm_vgic_inject_irq(kvm, 0, spi, level);
> +}
> +
> +/* MSI not implemented yet */
> +int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
> +		struct kvm *kvm, int irq_source_id,
> +		int level, bool line_status)
> +{
> +	return 0;
> +}
> -- 
> 2.7.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

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

* Re: [PATCH v3 54/55] KVM: arm/arm64: vgic-new: implement mapped IRQ handling
  2016-05-06 10:46   ` Andre Przywara
@ 2016-05-12 19:36     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 19:36 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:46:07AM +0100, Andre Przywara wrote:
> We now store the mapped hardware IRQ number in our struct, so we
> don't need the irq_phys_map for the new VGIC.
> Implement the hardware IRQ mapping on top of the reworked arch
> timer interface.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - adapt to new arch_timer mapped IRQ interface
> - implement inject_mapped_irq() as a macro (since it is identical to
>   the "un-mapped" IRQ implementation)
> 
> Changelog v1 .. v2:
> - replace inject_mapped_irq() macro with a separate implementation,
>   which only allows mapped IRQs to be injected via this interface
> 
>  include/kvm/vgic/vgic.h  |  5 +++++
>  virt/kvm/arm/vgic/vgic.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 55 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 07c3011..64aca0c 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -213,6 +213,11 @@ int kvm_vgic_hyp_init(void);
>  
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  			bool level);
> +int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			       bool level);
> +int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, u32 virt_irq, u32 phys_irq);
> +int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq);
> +bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
>  
>  int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
>  
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 068389a..3f854c5 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -310,6 +310,44 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
>  }
>  
> +int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			       bool level)
> +{
> +	return vgic_update_irq_pending(kvm, cpuid, intid, level, true);
> +}
> +
> +int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, u32 virt_irq, u32 phys_irq)
> +{
> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
> +
> +	BUG_ON(!irq);
> +
> +	spin_lock(&irq->irq_lock);
> +
> +	irq->hw = true;
> +	irq->hwintid = phys_irq;
> +
> +	spin_unlock(&irq->irq_lock);
> +
> +	return 0;
> +}
> +
> +int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq)
> +{
> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
> +
> +	BUG_ON(!irq);
> +
> +	spin_lock(&irq->irq_lock);
> +
> +	irq->hw = false;
> +	irq->hwintid = 0;
> +
> +	spin_unlock(&irq->irq_lock);
> +
> +	return 0;
> +}
> +
>  /**
>   * vgic_prune_ap_list - Remove non-relevant interrupts from the list
>   *
> @@ -563,3 +601,15 @@ void vgic_kick_vcpus(struct kvm *kvm)
>  			kvm_vcpu_kick(vcpu);
>  	}
>  }
> +
> +bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq)
> +{
> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
> +	bool map_is_active;
> +
> +	spin_lock(&irq->irq_lock);
> +	map_is_active = irq->hw && irq->active;
> +	spin_unlock(&irq->irq_lock);
> +
> +	return map_is_active;
> +}
> -- 
> 2.7.3
> 

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

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

* [PATCH v3 54/55] KVM: arm/arm64: vgic-new: implement mapped IRQ handling
@ 2016-05-12 19:36     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 19:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:46:07AM +0100, Andre Przywara wrote:
> We now store the mapped hardware IRQ number in our struct, so we
> don't need the irq_phys_map for the new VGIC.
> Implement the hardware IRQ mapping on top of the reworked arch
> timer interface.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Changelog RFC..v1:
> - adapt to new arch_timer mapped IRQ interface
> - implement inject_mapped_irq() as a macro (since it is identical to
>   the "un-mapped" IRQ implementation)
> 
> Changelog v1 .. v2:
> - replace inject_mapped_irq() macro with a separate implementation,
>   which only allows mapped IRQs to be injected via this interface
> 
>  include/kvm/vgic/vgic.h  |  5 +++++
>  virt/kvm/arm/vgic/vgic.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 55 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 07c3011..64aca0c 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -213,6 +213,11 @@ int kvm_vgic_hyp_init(void);
>  
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  			bool level);
> +int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			       bool level);
> +int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, u32 virt_irq, u32 phys_irq);
> +int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq);
> +bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
>  
>  int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
>  
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 068389a..3f854c5 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -310,6 +310,44 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  	return vgic_update_irq_pending(kvm, cpuid, intid, level, false);
>  }
>  
> +int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
> +			       bool level)
> +{
> +	return vgic_update_irq_pending(kvm, cpuid, intid, level, true);
> +}
> +
> +int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, u32 virt_irq, u32 phys_irq)
> +{
> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
> +
> +	BUG_ON(!irq);
> +
> +	spin_lock(&irq->irq_lock);
> +
> +	irq->hw = true;
> +	irq->hwintid = phys_irq;
> +
> +	spin_unlock(&irq->irq_lock);
> +
> +	return 0;
> +}
> +
> +int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq)
> +{
> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
> +
> +	BUG_ON(!irq);
> +
> +	spin_lock(&irq->irq_lock);
> +
> +	irq->hw = false;
> +	irq->hwintid = 0;
> +
> +	spin_unlock(&irq->irq_lock);
> +
> +	return 0;
> +}
> +
>  /**
>   * vgic_prune_ap_list - Remove non-relevant interrupts from the list
>   *
> @@ -563,3 +601,15 @@ void vgic_kick_vcpus(struct kvm *kvm)
>  			kvm_vcpu_kick(vcpu);
>  	}
>  }
> +
> +bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq)
> +{
> +	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, virt_irq);
> +	bool map_is_active;
> +
> +	spin_lock(&irq->irq_lock);
> +	map_is_active = irq->hw && irq->active;
> +	spin_unlock(&irq->irq_lock);
> +
> +	return map_is_active;
> +}
> -- 
> 2.7.3
> 

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

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

* Re: [PATCH v2] KVM: arm/arm64: vgic-new: fix overlap check for device addresses
  2016-05-10 17:18           ` Andre Przywara
@ 2016-05-12 19:43             ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 19:43 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Tue, May 10, 2016 at 06:18:46PM +0100, Andre Przywara wrote:
> When userland sets the base addresses for the GIC register frames,
> the kernel tries to make sure that the regions for the distributor and
> the one for the CPU interface or the redistributors do not overlap.
> Currently this check only works properly for GICv2.
> For a GICv3 we need the number of VCPUs to compute the size of the
> redistributor region, which we only know for sure at init time.
> So move the overlap check from kvm_vgic_addr() to the model specific
> map_resources() implementation.
> This also allows us to simplify the existing checking code a bit.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Hi,
> 
> so another rework, now hopefully really covering GICv3 properly.
> For consistency I also moved the GICv2 check to init time. This is
> a slightly different behaviour, but shouldn't make a difference, as
> the init call can fail as well - for instance if no addresses have been
> set up at all.
> 
> Cheers,
> Andre.
> 
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 50 ++++++++-----------------------------
>  virt/kvm/arm/vgic/vgic-v2.c         | 22 ++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c         | 27 ++++++++++++++++++++
>  3 files changed, 60 insertions(+), 39 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index 2122ff2..9e736a7 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -19,43 +19,19 @@
>  #include <asm/kvm_mmu.h>
>  #include "vgic.h"
>  
> -/* common helpers */
> -
> -static int vgic_ioaddr_overlap(struct kvm *kvm)
> -{
> -	phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;
> -	phys_addr_t cpu = kvm->arch.vgic.vgic_cpu_base;
> -
> -	if (IS_VGIC_ADDR_UNDEF(dist) || IS_VGIC_ADDR_UNDEF(cpu))
> -		return 0;
> -	if ((dist <= cpu && dist + KVM_VGIC_V2_DIST_SIZE > cpu) ||
> -	    (cpu <= dist && cpu + KVM_VGIC_V2_CPU_SIZE > dist))
> -		return -EBUSY;
> -	return 0;
> -}
> -
> -static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
> -			      phys_addr_t addr, phys_addr_t size)
> +static int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
> +			     phys_addr_t addr, phys_addr_t alignment)
>  {
> -	int ret;
> -
>  	if (addr & ~KVM_PHYS_MASK)
>  		return -E2BIG;
>  
> -	if (addr & (SZ_4K - 1))
> +	if (!IS_ALIGNED(addr, alignment))
>  		return -EINVAL;
>  
>  	if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
>  		return -EEXIST;
> -	if (addr + size < addr)
> -		return -EINVAL;
> -
> -	*ioaddr = addr;
> -	ret = vgic_ioaddr_overlap(kvm);
> -	if (ret)
> -		*ioaddr = VGIC_ADDR_UNDEF;
>  
> -	return ret;
> +	return 0;
>  }
>  
>  /**
> @@ -70,40 +46,38 @@ static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
>   * interface in the VM physical address space.  These addresses are properties
>   * of the emulated core/SoC and therefore user space initially knows this
>   * information.
> + * Check them for sanity (alignment, double assignment). We can't check for
> + * overlapping regions in case of a virtual GICv3 here, since we don't know
> + * the number of VCPUs yet, so we defer this check to map_resources().
>   */
>  int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
>  {
>  	int r = 0;
>  	struct vgic_dist *vgic = &kvm->arch.vgic;
>  	int type_needed;
> -	phys_addr_t *addr_ptr, block_size;
> -	phys_addr_t alignment;
> +	phys_addr_t *addr_ptr, alignment;
>  
>  	mutex_lock(&kvm->lock);
>  	switch (type) {
>  	case KVM_VGIC_V2_ADDR_TYPE_DIST:
>  		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
>  		addr_ptr = &vgic->vgic_dist_base;
> -		block_size = KVM_VGIC_V2_DIST_SIZE;
>  		alignment = SZ_4K;
>  		break;
>  	case KVM_VGIC_V2_ADDR_TYPE_CPU:
>  		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
>  		addr_ptr = &vgic->vgic_cpu_base;
> -		block_size = KVM_VGIC_V2_CPU_SIZE;
>  		alignment = SZ_4K;
>  		break;
>  #ifdef CONFIG_KVM_ARM_VGIC_V3
>  	case KVM_VGIC_V3_ADDR_TYPE_DIST:
>  		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
>  		addr_ptr = &vgic->vgic_dist_base;
> -		block_size = KVM_VGIC_V3_DIST_SIZE;
>  		alignment = SZ_64K;
>  		break;
>  	case KVM_VGIC_V3_ADDR_TYPE_REDIST:
>  		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
>  		addr_ptr = &vgic->vgic_redist_base;
> -		block_size = KVM_VGIC_V3_REDIST_SIZE;
>  		alignment = SZ_64K;
>  		break;
>  #endif
> @@ -118,11 +92,9 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
>  	}
>  
>  	if (write) {
> -		if (!IS_ALIGNED(*addr, alignment))
> -			r = -EINVAL;
> -		else
> -			r = vgic_ioaddr_assign(kvm, addr_ptr,
> -					       *addr, block_size);
> +		r = vgic_check_ioaddr(kvm, addr_ptr, *addr, alignment);
> +		if (!r)
> +			*addr_ptr = *addr;
>  	} else {
>  		*addr = *addr_ptr;
>  	}
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 4493593..fe6e3bd 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -225,6 +225,22 @@ void vgic_v2_enable(struct kvm_vcpu *vcpu)
>  	vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr = GICH_HCR_EN;
>  }
>  
> +/* check for overlapping regions and for regions crossing the end of memory */
> +static bool vgic_check_addresses(gpa_t dist_base, gpa_t cpu_base)
> +{
> +	if (dist_base + KVM_VGIC_V2_DIST_SIZE < dist_base)
> +		return false;
> +	if (cpu_base + KVM_VGIC_V2_CPU_SIZE < cpu_base)
> +		return false;
> +
> +	if (dist_base + KVM_VGIC_V2_DIST_SIZE <= cpu_base)
> +		return true;
> +	if (cpu_base + KVM_VGIC_V2_CPU_SIZE <= dist_base)
> +		return true;
> +
> +	return false;
> +}
> +
>  int vgic_v2_map_resources(struct kvm *kvm)
>  {
>  	struct vgic_dist *dist = &kvm->arch.vgic;
> @@ -240,6 +256,12 @@ int vgic_v2_map_resources(struct kvm *kvm)
>  		goto out;
>  	}
>  
> +	if (!vgic_check_addresses(dist->vgic_dist_base, dist->vgic_cpu_base)) {
> +		kvm_err("VGIC CPU and dist frames overlap\n");
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
>  	/*
>  	 * Initialize the vgic if this hasn't already been done on demand by
>  	 * accessing the vgic state from userspace.
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 6d7422f..fa444a7 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -221,6 +221,27 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
>  	vgic_v3->vgic_hcr = ICH_HCR_EN;
>  }
>  
> +/* check for overlapping regions and for regions crossing the end of memory */
> +static bool vgic_check_addresses(struct kvm *kvm)
> +{
> +	struct vgic_dist *d = &kvm->arch.vgic;
> +	gpa_t redist_size = KVM_VGIC_V3_REDIST_SIZE;
> +
> +	redist_size = KVM_VGIC_V3_REDIST_SIZE * atomic_read(&kvm->online_vcpus);

this looks horrible IMHO, you can fit the full calculations on exactly
80 chars, which must be a sign of what was supposed to happen ;)

> +
> +	if (d->vgic_dist_base + KVM_VGIC_V3_DIST_SIZE < d->vgic_dist_base)
> +		return false;
> +	if (d->vgic_redist_base + redist_size < d->vgic_redist_base)
> +		return false;
> +
> +	if (d->vgic_dist_base + KVM_VGIC_V3_DIST_SIZE <= d->vgic_redist_base)
> +		return true;
> +	if (d->vgic_redist_base + redist_size <= d->vgic_dist_base)
> +		return true;
> +
> +	return false;
> +}
> +
>  int vgic_v3_map_resources(struct kvm *kvm)
>  {
>  	int ret = 0;
> @@ -236,6 +257,12 @@ int vgic_v3_map_resources(struct kvm *kvm)
>  		goto out;
>  	}
>  
> +	if (!vgic_check_addresses(kvm)) {
> +		kvm_err("VGIC redist and dist frames overlap\n");
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
>  	/*
>  	 * For a VGICv3 we require the userland to explicitly initialize
>  	 * the VGIC before we need to use it.
> -- 
> 2.7.3
> 

I would have named the check_addresses functions with the specific vgic
version, but anyhow:

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

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

* [PATCH v2] KVM: arm/arm64: vgic-new: fix overlap check for device addresses
@ 2016-05-12 19:43             ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-12 19:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 10, 2016 at 06:18:46PM +0100, Andre Przywara wrote:
> When userland sets the base addresses for the GIC register frames,
> the kernel tries to make sure that the regions for the distributor and
> the one for the CPU interface or the redistributors do not overlap.
> Currently this check only works properly for GICv2.
> For a GICv3 we need the number of VCPUs to compute the size of the
> redistributor region, which we only know for sure at init time.
> So move the overlap check from kvm_vgic_addr() to the model specific
> map_resources() implementation.
> This also allows us to simplify the existing checking code a bit.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Hi,
> 
> so another rework, now hopefully really covering GICv3 properly.
> For consistency I also moved the GICv2 check to init time. This is
> a slightly different behaviour, but shouldn't make a difference, as
> the init call can fail as well - for instance if no addresses have been
> set up at all.
> 
> Cheers,
> Andre.
> 
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 50 ++++++++-----------------------------
>  virt/kvm/arm/vgic/vgic-v2.c         | 22 ++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c         | 27 ++++++++++++++++++++
>  3 files changed, 60 insertions(+), 39 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index 2122ff2..9e736a7 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -19,43 +19,19 @@
>  #include <asm/kvm_mmu.h>
>  #include "vgic.h"
>  
> -/* common helpers */
> -
> -static int vgic_ioaddr_overlap(struct kvm *kvm)
> -{
> -	phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;
> -	phys_addr_t cpu = kvm->arch.vgic.vgic_cpu_base;
> -
> -	if (IS_VGIC_ADDR_UNDEF(dist) || IS_VGIC_ADDR_UNDEF(cpu))
> -		return 0;
> -	if ((dist <= cpu && dist + KVM_VGIC_V2_DIST_SIZE > cpu) ||
> -	    (cpu <= dist && cpu + KVM_VGIC_V2_CPU_SIZE > dist))
> -		return -EBUSY;
> -	return 0;
> -}
> -
> -static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
> -			      phys_addr_t addr, phys_addr_t size)
> +static int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
> +			     phys_addr_t addr, phys_addr_t alignment)
>  {
> -	int ret;
> -
>  	if (addr & ~KVM_PHYS_MASK)
>  		return -E2BIG;
>  
> -	if (addr & (SZ_4K - 1))
> +	if (!IS_ALIGNED(addr, alignment))
>  		return -EINVAL;
>  
>  	if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
>  		return -EEXIST;
> -	if (addr + size < addr)
> -		return -EINVAL;
> -
> -	*ioaddr = addr;
> -	ret = vgic_ioaddr_overlap(kvm);
> -	if (ret)
> -		*ioaddr = VGIC_ADDR_UNDEF;
>  
> -	return ret;
> +	return 0;
>  }
>  
>  /**
> @@ -70,40 +46,38 @@ static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
>   * interface in the VM physical address space.  These addresses are properties
>   * of the emulated core/SoC and therefore user space initially knows this
>   * information.
> + * Check them for sanity (alignment, double assignment). We can't check for
> + * overlapping regions in case of a virtual GICv3 here, since we don't know
> + * the number of VCPUs yet, so we defer this check to map_resources().
>   */
>  int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
>  {
>  	int r = 0;
>  	struct vgic_dist *vgic = &kvm->arch.vgic;
>  	int type_needed;
> -	phys_addr_t *addr_ptr, block_size;
> -	phys_addr_t alignment;
> +	phys_addr_t *addr_ptr, alignment;
>  
>  	mutex_lock(&kvm->lock);
>  	switch (type) {
>  	case KVM_VGIC_V2_ADDR_TYPE_DIST:
>  		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
>  		addr_ptr = &vgic->vgic_dist_base;
> -		block_size = KVM_VGIC_V2_DIST_SIZE;
>  		alignment = SZ_4K;
>  		break;
>  	case KVM_VGIC_V2_ADDR_TYPE_CPU:
>  		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
>  		addr_ptr = &vgic->vgic_cpu_base;
> -		block_size = KVM_VGIC_V2_CPU_SIZE;
>  		alignment = SZ_4K;
>  		break;
>  #ifdef CONFIG_KVM_ARM_VGIC_V3
>  	case KVM_VGIC_V3_ADDR_TYPE_DIST:
>  		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
>  		addr_ptr = &vgic->vgic_dist_base;
> -		block_size = KVM_VGIC_V3_DIST_SIZE;
>  		alignment = SZ_64K;
>  		break;
>  	case KVM_VGIC_V3_ADDR_TYPE_REDIST:
>  		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
>  		addr_ptr = &vgic->vgic_redist_base;
> -		block_size = KVM_VGIC_V3_REDIST_SIZE;
>  		alignment = SZ_64K;
>  		break;
>  #endif
> @@ -118,11 +92,9 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
>  	}
>  
>  	if (write) {
> -		if (!IS_ALIGNED(*addr, alignment))
> -			r = -EINVAL;
> -		else
> -			r = vgic_ioaddr_assign(kvm, addr_ptr,
> -					       *addr, block_size);
> +		r = vgic_check_ioaddr(kvm, addr_ptr, *addr, alignment);
> +		if (!r)
> +			*addr_ptr = *addr;
>  	} else {
>  		*addr = *addr_ptr;
>  	}
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 4493593..fe6e3bd 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -225,6 +225,22 @@ void vgic_v2_enable(struct kvm_vcpu *vcpu)
>  	vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr = GICH_HCR_EN;
>  }
>  
> +/* check for overlapping regions and for regions crossing the end of memory */
> +static bool vgic_check_addresses(gpa_t dist_base, gpa_t cpu_base)
> +{
> +	if (dist_base + KVM_VGIC_V2_DIST_SIZE < dist_base)
> +		return false;
> +	if (cpu_base + KVM_VGIC_V2_CPU_SIZE < cpu_base)
> +		return false;
> +
> +	if (dist_base + KVM_VGIC_V2_DIST_SIZE <= cpu_base)
> +		return true;
> +	if (cpu_base + KVM_VGIC_V2_CPU_SIZE <= dist_base)
> +		return true;
> +
> +	return false;
> +}
> +
>  int vgic_v2_map_resources(struct kvm *kvm)
>  {
>  	struct vgic_dist *dist = &kvm->arch.vgic;
> @@ -240,6 +256,12 @@ int vgic_v2_map_resources(struct kvm *kvm)
>  		goto out;
>  	}
>  
> +	if (!vgic_check_addresses(dist->vgic_dist_base, dist->vgic_cpu_base)) {
> +		kvm_err("VGIC CPU and dist frames overlap\n");
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
>  	/*
>  	 * Initialize the vgic if this hasn't already been done on demand by
>  	 * accessing the vgic state from userspace.
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 6d7422f..fa444a7 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -221,6 +221,27 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
>  	vgic_v3->vgic_hcr = ICH_HCR_EN;
>  }
>  
> +/* check for overlapping regions and for regions crossing the end of memory */
> +static bool vgic_check_addresses(struct kvm *kvm)
> +{
> +	struct vgic_dist *d = &kvm->arch.vgic;
> +	gpa_t redist_size = KVM_VGIC_V3_REDIST_SIZE;
> +
> +	redist_size = KVM_VGIC_V3_REDIST_SIZE * atomic_read(&kvm->online_vcpus);

this looks horrible IMHO, you can fit the full calculations on exactly
80 chars, which must be a sign of what was supposed to happen ;)

> +
> +	if (d->vgic_dist_base + KVM_VGIC_V3_DIST_SIZE < d->vgic_dist_base)
> +		return false;
> +	if (d->vgic_redist_base + redist_size < d->vgic_redist_base)
> +		return false;
> +
> +	if (d->vgic_dist_base + KVM_VGIC_V3_DIST_SIZE <= d->vgic_redist_base)
> +		return true;
> +	if (d->vgic_redist_base + redist_size <= d->vgic_dist_base)
> +		return true;
> +
> +	return false;
> +}
> +
>  int vgic_v3_map_resources(struct kvm *kvm)
>  {
>  	int ret = 0;
> @@ -236,6 +257,12 @@ int vgic_v3_map_resources(struct kvm *kvm)
>  		goto out;
>  	}
>  
> +	if (!vgic_check_addresses(kvm)) {
> +		kvm_err("VGIC redist and dist frames overlap\n");
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
>  	/*
>  	 * For a VGICv3 we require the userland to explicitly initialize
>  	 * the VGIC before we need to use it.
> -- 
> 2.7.3
> 

I would have named the check_addresses functions with the specific vgic
version, but anyhow:

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

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

* Re: [PATCH v3 45/55] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
  2016-05-12 19:10       ` Andre Przywara
@ 2016-05-13  7:51         ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13  7:51 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Thu, May 12, 2016 at 08:10:21PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 12/05/16 19:41, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:58AM +0100, Andre Przywara wrote:
> >> Userland may want to save and restore the state of the in-kernel VGIC,
> >> so we provide the code which takes a userland request and translate
> >> that into calls to our MMIO framework.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  virt/kvm/arm/vgic/vgic-kvm-device.c | 50 ++++++++++++++++++++++++++++++++++++-
> >>  1 file changed, 49 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >> index c952f6f..bb33af8 100644
> >> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> >> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >> @@ -264,7 +264,55 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
> > 
> > come to think of it, this is GICv2 specific right?
> > 
> > why don't we call it vgic_v2_attr_regs_access then?
> > 
> > and should it really live in this file?
> 
> Mmmh, at the moment every userland access is v2 specific, but
> potentially this function should cover GICv3 as well, I think. We might
> need some adjustments once this will be implemented, but in general I
> don't see anything too v2 specific in here?


the defines being used below are v2 specific and it's going to stay that
way.  But ok, if you think it will be reworked to cater for both v2 and
v3, fine.

> 
> >>  				 struct kvm_device_attr *attr,
> >>  				 u32 *reg, bool is_write)
> >>  {
> >> -	return -ENXIO;
> >> +	gpa_t addr;
> >> +	int cpuid, ret, c;
> >> +	struct kvm_vcpu *vcpu, *tmp_vcpu;
> >> +
> >> +	cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >>
> >> +		 KVM_DEV_ARM_VGIC_CPUID_SHIFT;
> >> +	vcpu = kvm_get_vcpu(dev->kvm, cpuid);
> >> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
> >> +
> >> +	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;
> >> +	}
> >> +
> >> +	/*
> >> +	 * 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().
> >> +	 */
> > 
> > eh, I don't see us grabbing any vgic->lock (does that still exist?)
> > here?
> 
> Yeah, that scared me the other day too.
> In fact I think we cannot guarantee this requirement anymore with our
> existing locks - but maybe we can pause the guest explicitly as we do
> now for the clear-active handler?
> 

I think that should work, yes.

Even if you're doing a restore of the state before actually running your
VCPUs, the make all requests wouldn't do anything and your VCPUs would
block in the early part of the run loop.  They will call
first_run_init() though, but I can't easily make that out to be a
problem.

An alternative is to do something similar to kvm_vgic_create(), perhaps
factor out that logic, which grabs the mutexes of all vcpus.

-Christoffer

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

* [PATCH v3 45/55] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
@ 2016-05-13  7:51         ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13  7:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 12, 2016 at 08:10:21PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 12/05/16 19:41, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:58AM +0100, Andre Przywara wrote:
> >> Userland may want to save and restore the state of the in-kernel VGIC,
> >> so we provide the code which takes a userland request and translate
> >> that into calls to our MMIO framework.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  virt/kvm/arm/vgic/vgic-kvm-device.c | 50 ++++++++++++++++++++++++++++++++++++-
> >>  1 file changed, 49 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >> index c952f6f..bb33af8 100644
> >> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> >> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >> @@ -264,7 +264,55 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
> > 
> > come to think of it, this is GICv2 specific right?
> > 
> > why don't we call it vgic_v2_attr_regs_access then?
> > 
> > and should it really live in this file?
> 
> Mmmh, at the moment every userland access is v2 specific, but
> potentially this function should cover GICv3 as well, I think. We might
> need some adjustments once this will be implemented, but in general I
> don't see anything too v2 specific in here?


the defines being used below are v2 specific and it's going to stay that
way.  But ok, if you think it will be reworked to cater for both v2 and
v3, fine.

> 
> >>  				 struct kvm_device_attr *attr,
> >>  				 u32 *reg, bool is_write)
> >>  {
> >> -	return -ENXIO;
> >> +	gpa_t addr;
> >> +	int cpuid, ret, c;
> >> +	struct kvm_vcpu *vcpu, *tmp_vcpu;
> >> +
> >> +	cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >>
> >> +		 KVM_DEV_ARM_VGIC_CPUID_SHIFT;
> >> +	vcpu = kvm_get_vcpu(dev->kvm, cpuid);
> >> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
> >> +
> >> +	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;
> >> +	}
> >> +
> >> +	/*
> >> +	 * 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().
> >> +	 */
> > 
> > eh, I don't see us grabbing any vgic->lock (does that still exist?)
> > here?
> 
> Yeah, that scared me the other day too.
> In fact I think we cannot guarantee this requirement anymore with our
> existing locks - but maybe we can pause the guest explicitly as we do
> now for the clear-active handler?
> 

I think that should work, yes.

Even if you're doing a restore of the state before actually running your
VCPUs, the make all requests wouldn't do anything and your VCPUs would
block in the early part of the run loop.  They will call
first_run_init() though, but I can't easily make that out to be a
problem.

An alternative is to do something similar to kvm_vgic_create(), perhaps
factor out that logic, which grabs the mutexes of all vcpus.

-Christoffer

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

* Re: [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
  2016-05-12 18:52       ` Andre Przywara
@ 2016-05-13  7:53         ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13  7:53 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Thu, May 12, 2016 at 07:52:38PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 12/05/16 19:47, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:46:00AM +0100, Andre Przywara wrote:
> >> Using the VMCR accessors we provide access to GIC CPU interface state
> >> to userland by wiring it up to the existing userland interface.
> >> [Marc: move and make VMCR accessors static, streamline MMIO handlers]
> > 
> > does this mean Marc did this and serves as credit or is it a lost
> > reminder?
> 
> It was meant as credit. I thought that is the usual annotation for this?
> 

I'm not sure if that's the usual way, I read it as a reminder, but it's
not too important.  Mostly wanting to make sure we're not forgetting
some todo item.

> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> ---
> >> Changelog v2 .. v3:
> >> - total rework, moving into vgic-mmio-v2.c
> >> - move vmcr accessor wrapper functions into this file
> >> - use the register description table for CPU i/f registers as well
> >> - add RAZ/WI handling for the active priority registers
> >> - streamline MMIO handler functions
> >>
> >>  virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
> >>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic.h            |   2 +
> >>  3 files changed, 107 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >> index bb33af8..2122ff2 100644
> >> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> >> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >> @@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
> >>  
> >>  	switch (attr->group) {
> >>  	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> >> -		ret = -EINVAL;
> >> +		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
> >>  		break;
> >>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> >>  		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> index c453e6f..0060539 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> @@ -206,6 +206,84 @@ 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. */
> >> +static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
> >> +					   gpa_t addr, unsigned int len)
> >> +{
> >> +	struct vgic_vmcr vmcr;
> >> +	u32 val;
> >> +
> >> +	vgic_get_vmcr(vcpu, &vmcr);
> >> +
> >> +	switch (addr & 0xff) {
> >> +	case GIC_CPU_CTRL:
> >> +		val = vmcr.ctlr;
> >> +		break;
> >> +	case GIC_CPU_PRIMASK:
> >> +		val = vmcr.pmr;
> >> +		break;
> >> +	case GIC_CPU_BINPOINT:
> >> +		val = vmcr.bpr;
> >> +		break;
> >> +	case GIC_CPU_ALIAS_BINPOINT:
> >> +		val = vmcr.abpr;
> >> +		break;
> >> +	case GIC_CPU_IDENT:
> >> +		val = ((PRODUCT_ID_KVM << 20) |
> >> +		       (GICC_ARCH_VERSION_V2 << 16) |
> >> +		       IMPLEMENTER_ARM);
> >> +		break;
> >> +	default:
> >> +		return 0;
> >> +	}
> >> +
> >> +	return extract_bytes(val, addr & 3, len);
> > 
> > I don't think we allow anything than a full 32-bit aligned accesses
> > from userspace - we shouldn't at least.
> 
> Indeed - I think userland was always 32-bit only. And since last night
> we even enforce this. So potentially there are more extract_bytes()
> calls that can go.
> 
Right.

-Christoffer

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

* [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
@ 2016-05-13  7:53         ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13  7:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 12, 2016 at 07:52:38PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 12/05/16 19:47, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:46:00AM +0100, Andre Przywara wrote:
> >> Using the VMCR accessors we provide access to GIC CPU interface state
> >> to userland by wiring it up to the existing userland interface.
> >> [Marc: move and make VMCR accessors static, streamline MMIO handlers]
> > 
> > does this mean Marc did this and serves as credit or is it a lost
> > reminder?
> 
> It was meant as credit. I thought that is the usual annotation for this?
> 

I'm not sure if that's the usual way, I read it as a reminder, but it's
not too important.  Mostly wanting to make sure we're not forgetting
some todo item.

> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> ---
> >> Changelog v2 .. v3:
> >> - total rework, moving into vgic-mmio-v2.c
> >> - move vmcr accessor wrapper functions into this file
> >> - use the register description table for CPU i/f registers as well
> >> - add RAZ/WI handling for the active priority registers
> >> - streamline MMIO handler functions
> >>
> >>  virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
> >>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
> >>  virt/kvm/arm/vgic/vgic.h            |   2 +
> >>  3 files changed, 107 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >> index bb33af8..2122ff2 100644
> >> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> >> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >> @@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
> >>  
> >>  	switch (attr->group) {
> >>  	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> >> -		ret = -EINVAL;
> >> +		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
> >>  		break;
> >>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> >>  		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
> >> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> index c453e6f..0060539 100644
> >> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >> @@ -206,6 +206,84 @@ 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. */
> >> +static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
> >> +					   gpa_t addr, unsigned int len)
> >> +{
> >> +	struct vgic_vmcr vmcr;
> >> +	u32 val;
> >> +
> >> +	vgic_get_vmcr(vcpu, &vmcr);
> >> +
> >> +	switch (addr & 0xff) {
> >> +	case GIC_CPU_CTRL:
> >> +		val = vmcr.ctlr;
> >> +		break;
> >> +	case GIC_CPU_PRIMASK:
> >> +		val = vmcr.pmr;
> >> +		break;
> >> +	case GIC_CPU_BINPOINT:
> >> +		val = vmcr.bpr;
> >> +		break;
> >> +	case GIC_CPU_ALIAS_BINPOINT:
> >> +		val = vmcr.abpr;
> >> +		break;
> >> +	case GIC_CPU_IDENT:
> >> +		val = ((PRODUCT_ID_KVM << 20) |
> >> +		       (GICC_ARCH_VERSION_V2 << 16) |
> >> +		       IMPLEMENTER_ARM);
> >> +		break;
> >> +	default:
> >> +		return 0;
> >> +	}
> >> +
> >> +	return extract_bytes(val, addr & 3, len);
> > 
> > I don't think we allow anything than a full 32-bit aligned accesses
> > from userspace - we shouldn't at least.
> 
> Indeed - I think userland was always 32-bit only. And since last night
> we even enforce this. So potentially there are more extract_bytes()
> calls that can go.
> 
Right.

-Christoffer

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

* Re: [PATCH v3 38/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-13 10:11     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13 10:11 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 06, 2016 at 11:45:51AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> This patch introduces the skeleton for the KVM device operations
> associated to KVM_DEV_TYPE_ARM_VGIC_V2 and KVM_DEV_TYPE_ARM_VGIC_V3.
> 
> At that stage kvm_vgic_create is stubbed.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

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

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

* [PATCH v3 38/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration
@ 2016-05-13 10:11     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13 10:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:51AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> This patch introduces the skeleton for the KVM device operations
> associated to KVM_DEV_TYPE_ARM_VGIC_V2 and KVM_DEV_TYPE_ARM_VGIC_V3.
> 
> At that stage kvm_vgic_create is stubbed.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

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

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

* Re: [PATCH v3 39/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-13 10:11     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13 10:11 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 06, 2016 at 11:45:52AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> This patch implements the KVM_DEV_ARM_VGIC_GRP_NR_IRQS group. This
> modality is supported by both VGIC V2 and V3 KVM device as will be
> other groups, hence the introduction of common helpers.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 83 +++++++++++++++++++++++++++++++++++--
>  1 file changed, 79 insertions(+), 4 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index ff332f3..05ff925 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -15,9 +15,69 @@
>   */
>  #include <linux/kvm_host.h>
>  #include <kvm/arm_vgic.h>
> +#include <linux/uaccess.h>
> +#include "vgic.h"
>  
>  /* common helpers */
>  
> +static int vgic_set_common_attr(struct kvm_device *dev,
> +				struct kvm_device_attr *attr)
> +{
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
> +		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
> +		u32 val;
> +		int ret = 0;
> +
> +		if (get_user(val, uaddr))
> +			return -EFAULT;
> +
> +		/*
> +		 * We require:
> +		 * - at least 32 SPIs on top of the 16 SGIs and 16 PPIs
> +		 * - at most 1024 interrupts
> +		 * - a multiple of 32 interrupts
> +		 */
> +		if (val < (VGIC_NR_PRIVATE_IRQS + 32) ||
> +		    val > VGIC_MAX_RESERVED ||
> +		    (val & 31))
> +			return -EINVAL;
> +
> +		mutex_lock(&dev->kvm->lock);
> +
> +		if (vgic_ready(dev->kvm) || dev->kvm->arch.vgic.nr_spis)
> +			ret = -EBUSY;
> +		else
> +			dev->kvm->arch.vgic.nr_spis =
> +				val - VGIC_NR_PRIVATE_IRQS;
> +
> +		mutex_unlock(&dev->kvm->lock);
> +
> +		return ret;
> +	}
> +	}
> +
> +	return -ENXIO;
> +}
> +
> +static int vgic_get_common_attr(struct kvm_device *dev,
> +				struct kvm_device_attr *attr)
> +{
> +	int r = -ENXIO;
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
> +		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
> +
> +		r = put_user(dev->kvm->arch.vgic.nr_spis +
> +			     VGIC_NR_PRIVATE_IRQS, uaddr);
> +		break;
> +	}
> +	}
> +
> +	return r;
> +}
> +
>  static int vgic_create(struct kvm_device *dev, u32 type)
>  {
>  	return kvm_vgic_create(dev->kvm, type);
> @@ -49,18 +109,29 @@ void kvm_register_vgic_device(unsigned long type)
>  static int vgic_v2_set_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
> -	return -ENXIO;
> +	int ret;
> +
> +	ret = vgic_set_common_attr(dev, attr);
> +	return ret;
> +
>  }
>  
>  static int vgic_v2_get_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
> -	return -ENXIO;
> +	int ret;
> +
> +	ret = vgic_get_common_attr(dev, attr);
> +	return ret;
>  }
>  
>  static int vgic_v2_has_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
> +		return 0;
> +	}
>  	return -ENXIO;
>  }
>  
> @@ -80,18 +151,22 @@ struct kvm_device_ops kvm_arm_vgic_v2_ops = {
>  static int vgic_v3_set_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
> -	return -ENXIO;
> +	return vgic_set_common_attr(dev, attr);
>  }
>  
>  static int vgic_v3_get_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
> -	return -ENXIO;
> +	return vgic_get_common_attr(dev, attr);
>  }
>  
>  static int vgic_v3_has_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
> +		return 0;
> +	}
>  	return -ENXIO;
>  }
>  
> -- 
> 2.7.3
> 

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

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

* [PATCH v3 39/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS
@ 2016-05-13 10:11     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13 10:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:52AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> This patch implements the KVM_DEV_ARM_VGIC_GRP_NR_IRQS group. This
> modality is supported by both VGIC V2 and V3 KVM device as will be
> other groups, hence the introduction of common helpers.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 83 +++++++++++++++++++++++++++++++++++--
>  1 file changed, 79 insertions(+), 4 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index ff332f3..05ff925 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -15,9 +15,69 @@
>   */
>  #include <linux/kvm_host.h>
>  #include <kvm/arm_vgic.h>
> +#include <linux/uaccess.h>
> +#include "vgic.h"
>  
>  /* common helpers */
>  
> +static int vgic_set_common_attr(struct kvm_device *dev,
> +				struct kvm_device_attr *attr)
> +{
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
> +		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
> +		u32 val;
> +		int ret = 0;
> +
> +		if (get_user(val, uaddr))
> +			return -EFAULT;
> +
> +		/*
> +		 * We require:
> +		 * - at least 32 SPIs on top of the 16 SGIs and 16 PPIs
> +		 * - at most 1024 interrupts
> +		 * - a multiple of 32 interrupts
> +		 */
> +		if (val < (VGIC_NR_PRIVATE_IRQS + 32) ||
> +		    val > VGIC_MAX_RESERVED ||
> +		    (val & 31))
> +			return -EINVAL;
> +
> +		mutex_lock(&dev->kvm->lock);
> +
> +		if (vgic_ready(dev->kvm) || dev->kvm->arch.vgic.nr_spis)
> +			ret = -EBUSY;
> +		else
> +			dev->kvm->arch.vgic.nr_spis =
> +				val - VGIC_NR_PRIVATE_IRQS;
> +
> +		mutex_unlock(&dev->kvm->lock);
> +
> +		return ret;
> +	}
> +	}
> +
> +	return -ENXIO;
> +}
> +
> +static int vgic_get_common_attr(struct kvm_device *dev,
> +				struct kvm_device_attr *attr)
> +{
> +	int r = -ENXIO;
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
> +		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
> +
> +		r = put_user(dev->kvm->arch.vgic.nr_spis +
> +			     VGIC_NR_PRIVATE_IRQS, uaddr);
> +		break;
> +	}
> +	}
> +
> +	return r;
> +}
> +
>  static int vgic_create(struct kvm_device *dev, u32 type)
>  {
>  	return kvm_vgic_create(dev->kvm, type);
> @@ -49,18 +109,29 @@ void kvm_register_vgic_device(unsigned long type)
>  static int vgic_v2_set_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
> -	return -ENXIO;
> +	int ret;
> +
> +	ret = vgic_set_common_attr(dev, attr);
> +	return ret;
> +
>  }
>  
>  static int vgic_v2_get_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
> -	return -ENXIO;
> +	int ret;
> +
> +	ret = vgic_get_common_attr(dev, attr);
> +	return ret;
>  }
>  
>  static int vgic_v2_has_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
> +		return 0;
> +	}
>  	return -ENXIO;
>  }
>  
> @@ -80,18 +151,22 @@ struct kvm_device_ops kvm_arm_vgic_v2_ops = {
>  static int vgic_v3_set_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
> -	return -ENXIO;
> +	return vgic_set_common_attr(dev, attr);
>  }
>  
>  static int vgic_v3_get_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
> -	return -ENXIO;
> +	return vgic_get_common_attr(dev, attr);
>  }
>  
>  static int vgic_v3_has_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
> +		return 0;
> +	}
>  	return -ENXIO;
>  }
>  
> -- 
> 2.7.3
> 

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

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

* Re: [PATCH v3 40/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-13 10:11     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13 10:11 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:45:53AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> This patch implements the KVM_DEV_ARM_VGIC_GRP_CTRL group API
> featuring KVM_DEV_ARM_VGIC_CTRL_INIT attribute. The vgic_init
> function is not yet implemented though.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 22 ++++++++++++++++++++++
>  1 file changed, 22 insertions(+)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index 05ff925..e153f12 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -23,6 +23,8 @@
>  static int vgic_set_common_attr(struct kvm_device *dev,
>  				struct kvm_device_attr *attr)
>  {
> +	int r;
> +
>  	switch (attr->group) {
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
>  		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
> @@ -55,6 +57,16 @@ static int vgic_set_common_attr(struct kvm_device *dev,
>  
>  		return ret;
>  	}
> +	case KVM_DEV_ARM_VGIC_GRP_CTRL: {
> +		switch (attr->attr) {
> +		case KVM_DEV_ARM_VGIC_CTRL_INIT:
> +			mutex_lock(&dev->kvm->lock);
> +			r = vgic_init(dev->kvm);
> +			mutex_unlock(&dev->kvm->lock);
> +			return r;
> +		}
> +		break;
> +	}
>  	}
>  
>  	return -ENXIO;
> @@ -131,6 +143,11 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
>  	switch (attr->group) {
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>  		return 0;
> +	case KVM_DEV_ARM_VGIC_GRP_CTRL:
> +		switch (attr->attr) {
> +		case KVM_DEV_ARM_VGIC_CTRL_INIT:
> +			return 0;
> +		}
>  	}
>  	return -ENXIO;
>  }
> @@ -166,6 +183,11 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
>  	switch (attr->group) {
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>  		return 0;
> +	case KVM_DEV_ARM_VGIC_GRP_CTRL:
> +		switch (attr->attr) {
> +		case KVM_DEV_ARM_VGIC_CTRL_INIT:
> +			return 0;
> +		}
>  	}
>  	return -ENXIO;
>  }
> -- 
> 2.7.3
> 
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

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

* [PATCH v3 40/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL
@ 2016-05-13 10:11     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13 10:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:53AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> This patch implements the KVM_DEV_ARM_VGIC_GRP_CTRL group API
> featuring KVM_DEV_ARM_VGIC_CTRL_INIT attribute. The vgic_init
> function is not yet implemented though.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 22 ++++++++++++++++++++++
>  1 file changed, 22 insertions(+)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index 05ff925..e153f12 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -23,6 +23,8 @@
>  static int vgic_set_common_attr(struct kvm_device *dev,
>  				struct kvm_device_attr *attr)
>  {
> +	int r;
> +
>  	switch (attr->group) {
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
>  		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
> @@ -55,6 +57,16 @@ static int vgic_set_common_attr(struct kvm_device *dev,
>  
>  		return ret;
>  	}
> +	case KVM_DEV_ARM_VGIC_GRP_CTRL: {
> +		switch (attr->attr) {
> +		case KVM_DEV_ARM_VGIC_CTRL_INIT:
> +			mutex_lock(&dev->kvm->lock);
> +			r = vgic_init(dev->kvm);
> +			mutex_unlock(&dev->kvm->lock);
> +			return r;
> +		}
> +		break;
> +	}
>  	}
>  
>  	return -ENXIO;
> @@ -131,6 +143,11 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
>  	switch (attr->group) {
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>  		return 0;
> +	case KVM_DEV_ARM_VGIC_GRP_CTRL:
> +		switch (attr->attr) {
> +		case KVM_DEV_ARM_VGIC_CTRL_INIT:
> +			return 0;
> +		}
>  	}
>  	return -ENXIO;
>  }
> @@ -166,6 +183,11 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
>  	switch (attr->group) {
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>  		return 0;
> +	case KVM_DEV_ARM_VGIC_GRP_CTRL:
> +		switch (attr->attr) {
> +		case KVM_DEV_ARM_VGIC_CTRL_INIT:
> +			return 0;
> +		}
>  	}
>  	return -ENXIO;
>  }
> -- 
> 2.7.3
> 
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

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

* Re: [PATCH v3 41/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-13 10:12     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13 10:12 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 06, 2016 at 11:45:54AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> kvm_vgic_addr is used by the userspace to set the base address of
> the following register regions, as seen by the guest:
> - distributor(v2 and v3),
> - re-distributors (v3),
> - CPU interface (v2).
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h             |   2 +
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 112 ++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h            |   3 +
>  3 files changed, 117 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 2c43eb8..73cab36 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -194,6 +194,8 @@ struct vgic_cpu {
>  	u64 live_lrs;
>  };
>  
> +int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
> +
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  			bool level);
>  
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index e153f12..493e941 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -16,10 +16,122 @@
>  #include <linux/kvm_host.h>
>  #include <kvm/arm_vgic.h>
>  #include <linux/uaccess.h>
> +#include <asm/kvm_mmu.h>
>  #include "vgic.h"
>  
>  /* common helpers */
>  
> +static int vgic_ioaddr_overlap(struct kvm *kvm)
> +{
> +	phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;
> +	phys_addr_t cpu = kvm->arch.vgic.vgic_cpu_base;
> +
> +	if (IS_VGIC_ADDR_UNDEF(dist) || IS_VGIC_ADDR_UNDEF(cpu))
> +		return 0;
> +	if ((dist <= cpu && dist + KVM_VGIC_V2_DIST_SIZE > cpu) ||
> +	    (cpu <= dist && cpu + KVM_VGIC_V2_CPU_SIZE > dist))
> +		return -EBUSY;
> +	return 0;
> +}
> +
> +static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
> +			      phys_addr_t addr, phys_addr_t size)
> +{
> +	int ret;
> +
> +	if (addr & ~KVM_PHYS_MASK)
> +		return -E2BIG;
> +
> +	if (addr & (SZ_4K - 1))
> +		return -EINVAL;
> +
> +	if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
> +		return -EEXIST;
> +	if (addr + size < addr)
> +		return -EINVAL;
> +
> +	*ioaddr = addr;
> +	ret = vgic_ioaddr_overlap(kvm);
> +	if (ret)
> +		*ioaddr = VGIC_ADDR_UNDEF;
> +
> +	return ret;
> +}
> +
> +/**
> + * kvm_vgic_addr - set or get vgic VM base addresses
> + * @kvm:   pointer to the vm struct
> + * @type:  the VGIC addr type, one of KVM_VGIC_V[23]_ADDR_TYPE_XXX
> + * @addr:  pointer to address value
> + * @write: if true set the address in the VM address space, if false read the
> + *          address
> + *
> + * Set or get the vgic base addresses for the distributor and the virtual CPU
> + * interface in the VM physical address space.  These addresses are properties
> + * of the emulated core/SoC and therefore user space initially knows this
> + * information.
> + */
> +int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
> +{
> +	int r = 0;
> +	struct vgic_dist *vgic = &kvm->arch.vgic;
> +	int type_needed;
> +	phys_addr_t *addr_ptr, block_size;
> +	phys_addr_t alignment;
> +
> +	mutex_lock(&kvm->lock);
> +	switch (type) {
> +	case KVM_VGIC_V2_ADDR_TYPE_DIST:
> +		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
> +		addr_ptr = &vgic->vgic_dist_base;
> +		block_size = KVM_VGIC_V2_DIST_SIZE;
> +		alignment = SZ_4K;
> +		break;
> +	case KVM_VGIC_V2_ADDR_TYPE_CPU:
> +		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
> +		addr_ptr = &vgic->vgic_cpu_base;
> +		block_size = KVM_VGIC_V2_CPU_SIZE;
> +		alignment = SZ_4K;
> +		break;
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +	case KVM_VGIC_V3_ADDR_TYPE_DIST:
> +		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
> +		addr_ptr = &vgic->vgic_dist_base;
> +		block_size = KVM_VGIC_V3_DIST_SIZE;
> +		alignment = SZ_64K;
> +		break;
> +	case KVM_VGIC_V3_ADDR_TYPE_REDIST:
> +		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
> +		addr_ptr = &vgic->vgic_redist_base;
> +		block_size = KVM_VGIC_V3_REDIST_SIZE;
> +		alignment = SZ_64K;
> +		break;
> +#endif
> +	default:
> +		r = -ENODEV;
> +		goto out;
> +	}
> +
> +	if (vgic->vgic_model != type_needed) {
> +		r = -ENODEV;
> +		goto out;
> +	}
> +
> +	if (write) {
> +		if (!IS_ALIGNED(*addr, alignment))
> +			r = -EINVAL;
> +		else
> +			r = vgic_ioaddr_assign(kvm, addr_ptr,
> +					       *addr, block_size);
> +	} else {
> +		*addr = *addr_ptr;
> +	}
> +
> +out:
> +	mutex_unlock(&kvm->lock);
> +	return r;
> +}
> +
>  static int vgic_set_common_attr(struct kvm_device *dev,
>  				struct kvm_device_attr *attr)
>  {
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index e7c66a5..c44ee01 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -19,6 +19,9 @@
>  #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
>  #define IMPLEMENTER_ARM		0x43b
>  
> +#define VGIC_ADDR_UNDEF		(-1)
> +#define IS_VGIC_ADDR_UNDEF(_x)  ((_x) == VGIC_ADDR_UNDEF)
> +
>  #define INTERRUPT_ID_BITS_SPIS	10
>  
>  #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
> -- 
> 2.7.3
> 
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

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

* [PATCH v3 41/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr
@ 2016-05-13 10:12     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13 10:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:54AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> kvm_vgic_addr is used by the userspace to set the base address of
> the following register regions, as seen by the guest:
> - distributor(v2 and v3),
> - re-distributors (v3),
> - CPU interface (v2).
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/vgic/vgic.h             |   2 +
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 112 ++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h            |   3 +
>  3 files changed, 117 insertions(+)
> 
> diff --git a/include/kvm/vgic/vgic.h b/include/kvm/vgic/vgic.h
> index 2c43eb8..73cab36 100644
> --- a/include/kvm/vgic/vgic.h
> +++ b/include/kvm/vgic/vgic.h
> @@ -194,6 +194,8 @@ struct vgic_cpu {
>  	u64 live_lrs;
>  };
>  
> +int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
> +
>  int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
>  			bool level);
>  
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index e153f12..493e941 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -16,10 +16,122 @@
>  #include <linux/kvm_host.h>
>  #include <kvm/arm_vgic.h>
>  #include <linux/uaccess.h>
> +#include <asm/kvm_mmu.h>
>  #include "vgic.h"
>  
>  /* common helpers */
>  
> +static int vgic_ioaddr_overlap(struct kvm *kvm)
> +{
> +	phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;
> +	phys_addr_t cpu = kvm->arch.vgic.vgic_cpu_base;
> +
> +	if (IS_VGIC_ADDR_UNDEF(dist) || IS_VGIC_ADDR_UNDEF(cpu))
> +		return 0;
> +	if ((dist <= cpu && dist + KVM_VGIC_V2_DIST_SIZE > cpu) ||
> +	    (cpu <= dist && cpu + KVM_VGIC_V2_CPU_SIZE > dist))
> +		return -EBUSY;
> +	return 0;
> +}
> +
> +static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
> +			      phys_addr_t addr, phys_addr_t size)
> +{
> +	int ret;
> +
> +	if (addr & ~KVM_PHYS_MASK)
> +		return -E2BIG;
> +
> +	if (addr & (SZ_4K - 1))
> +		return -EINVAL;
> +
> +	if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
> +		return -EEXIST;
> +	if (addr + size < addr)
> +		return -EINVAL;
> +
> +	*ioaddr = addr;
> +	ret = vgic_ioaddr_overlap(kvm);
> +	if (ret)
> +		*ioaddr = VGIC_ADDR_UNDEF;
> +
> +	return ret;
> +}
> +
> +/**
> + * kvm_vgic_addr - set or get vgic VM base addresses
> + * @kvm:   pointer to the vm struct
> + * @type:  the VGIC addr type, one of KVM_VGIC_V[23]_ADDR_TYPE_XXX
> + * @addr:  pointer to address value
> + * @write: if true set the address in the VM address space, if false read the
> + *          address
> + *
> + * Set or get the vgic base addresses for the distributor and the virtual CPU
> + * interface in the VM physical address space.  These addresses are properties
> + * of the emulated core/SoC and therefore user space initially knows this
> + * information.
> + */
> +int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
> +{
> +	int r = 0;
> +	struct vgic_dist *vgic = &kvm->arch.vgic;
> +	int type_needed;
> +	phys_addr_t *addr_ptr, block_size;
> +	phys_addr_t alignment;
> +
> +	mutex_lock(&kvm->lock);
> +	switch (type) {
> +	case KVM_VGIC_V2_ADDR_TYPE_DIST:
> +		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
> +		addr_ptr = &vgic->vgic_dist_base;
> +		block_size = KVM_VGIC_V2_DIST_SIZE;
> +		alignment = SZ_4K;
> +		break;
> +	case KVM_VGIC_V2_ADDR_TYPE_CPU:
> +		type_needed = KVM_DEV_TYPE_ARM_VGIC_V2;
> +		addr_ptr = &vgic->vgic_cpu_base;
> +		block_size = KVM_VGIC_V2_CPU_SIZE;
> +		alignment = SZ_4K;
> +		break;
> +#ifdef CONFIG_KVM_ARM_VGIC_V3
> +	case KVM_VGIC_V3_ADDR_TYPE_DIST:
> +		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
> +		addr_ptr = &vgic->vgic_dist_base;
> +		block_size = KVM_VGIC_V3_DIST_SIZE;
> +		alignment = SZ_64K;
> +		break;
> +	case KVM_VGIC_V3_ADDR_TYPE_REDIST:
> +		type_needed = KVM_DEV_TYPE_ARM_VGIC_V3;
> +		addr_ptr = &vgic->vgic_redist_base;
> +		block_size = KVM_VGIC_V3_REDIST_SIZE;
> +		alignment = SZ_64K;
> +		break;
> +#endif
> +	default:
> +		r = -ENODEV;
> +		goto out;
> +	}
> +
> +	if (vgic->vgic_model != type_needed) {
> +		r = -ENODEV;
> +		goto out;
> +	}
> +
> +	if (write) {
> +		if (!IS_ALIGNED(*addr, alignment))
> +			r = -EINVAL;
> +		else
> +			r = vgic_ioaddr_assign(kvm, addr_ptr,
> +					       *addr, block_size);
> +	} else {
> +		*addr = *addr_ptr;
> +	}
> +
> +out:
> +	mutex_unlock(&kvm->lock);
> +	return r;
> +}
> +
>  static int vgic_set_common_attr(struct kvm_device *dev,
>  				struct kvm_device_attr *attr)
>  {
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index e7c66a5..c44ee01 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -19,6 +19,9 @@
>  #define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
>  #define IMPLEMENTER_ARM		0x43b
>  
> +#define VGIC_ADDR_UNDEF		(-1)
> +#define IS_VGIC_ADDR_UNDEF(_x)  ((_x) == VGIC_ADDR_UNDEF)
> +
>  #define INTERRUPT_ID_BITS_SPIS	10
>  
>  #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
> -- 
> 2.7.3
> 
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

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

* Re: [PATCH v3 42/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-13 10:12     ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13 10:12 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 06, 2016 at 11:45:55AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> This patch implements the KVM_DEV_ARM_VGIC_GRP_ADDR group which
> enables to set the base address of GIC regions as seen by the guest.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 38 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 38 insertions(+)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index 493e941..0189c13 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -138,6 +138,17 @@ static int vgic_set_common_attr(struct kvm_device *dev,
>  	int r;
>  
>  	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_ADDR: {
> +		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
> +		u64 addr;
> +		unsigned long type = (unsigned long)attr->attr;
> +
> +		if (copy_from_user(&addr, uaddr, sizeof(addr)))
> +			return -EFAULT;
> +
> +		r = kvm_vgic_addr(dev->kvm, type, &addr, true);
> +		return (r == -ENODEV) ? -ENXIO : r;
> +	}
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
>  		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
>  		u32 val;
> @@ -190,6 +201,19 @@ static int vgic_get_common_attr(struct kvm_device *dev,
>  	int r = -ENXIO;
>  
>  	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_ADDR: {
> +		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
> +		u64 addr;
> +		unsigned long type = (unsigned long)attr->attr;
> +
> +		r = kvm_vgic_addr(dev->kvm, type, &addr, false);
> +		if (r)
> +			return (r == -ENODEV) ? -ENXIO : r;
> +
> +		if (copy_to_user(uaddr, &addr, sizeof(addr)))
> +			return -EFAULT;
> +		break;
> +	}
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
>  		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
>  
> @@ -253,6 +277,13 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
>  	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_ADDR:
> +		switch (attr->attr) {
> +		case KVM_VGIC_V2_ADDR_TYPE_DIST:
> +		case KVM_VGIC_V2_ADDR_TYPE_CPU:
> +			return 0;
> +		}
> +		break;
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>  		return 0;
>  	case KVM_DEV_ARM_VGIC_GRP_CTRL:
> @@ -293,6 +324,13 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
>  	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_ADDR:
> +		switch (attr->attr) {
> +		case KVM_VGIC_V3_ADDR_TYPE_DIST:
> +		case KVM_VGIC_V3_ADDR_TYPE_REDIST:
> +			return 0;
> +		}
> +		break;
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>  		return 0;
>  	case KVM_DEV_ARM_VGIC_GRP_CTRL:
> -- 
> 2.7.3
> 
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

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

* [PATCH v3 42/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR
@ 2016-05-13 10:12     ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13 10:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 06, 2016 at 11:45:55AM +0100, Andre Przywara wrote:
> From: Eric Auger <eric.auger@linaro.org>
> 
> This patch implements the KVM_DEV_ARM_VGIC_GRP_ADDR group which
> enables to set the base address of GIC regions as seen by the guest.
> 
> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-kvm-device.c | 38 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 38 insertions(+)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> index 493e941..0189c13 100644
> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> @@ -138,6 +138,17 @@ static int vgic_set_common_attr(struct kvm_device *dev,
>  	int r;
>  
>  	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_ADDR: {
> +		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
> +		u64 addr;
> +		unsigned long type = (unsigned long)attr->attr;
> +
> +		if (copy_from_user(&addr, uaddr, sizeof(addr)))
> +			return -EFAULT;
> +
> +		r = kvm_vgic_addr(dev->kvm, type, &addr, true);
> +		return (r == -ENODEV) ? -ENXIO : r;
> +	}
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
>  		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
>  		u32 val;
> @@ -190,6 +201,19 @@ static int vgic_get_common_attr(struct kvm_device *dev,
>  	int r = -ENXIO;
>  
>  	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_ADDR: {
> +		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
> +		u64 addr;
> +		unsigned long type = (unsigned long)attr->attr;
> +
> +		r = kvm_vgic_addr(dev->kvm, type, &addr, false);
> +		if (r)
> +			return (r == -ENODEV) ? -ENXIO : r;
> +
> +		if (copy_to_user(uaddr, &addr, sizeof(addr)))
> +			return -EFAULT;
> +		break;
> +	}
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
>  		u32 __user *uaddr = (u32 __user *)(long)attr->addr;
>  
> @@ -253,6 +277,13 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
>  	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_ADDR:
> +		switch (attr->attr) {
> +		case KVM_VGIC_V2_ADDR_TYPE_DIST:
> +		case KVM_VGIC_V2_ADDR_TYPE_CPU:
> +			return 0;
> +		}
> +		break;
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>  		return 0;
>  	case KVM_DEV_ARM_VGIC_GRP_CTRL:
> @@ -293,6 +324,13 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
>  			    struct kvm_device_attr *attr)
>  {
>  	switch (attr->group) {
> +	case KVM_DEV_ARM_VGIC_GRP_ADDR:
> +		switch (attr->attr) {
> +		case KVM_VGIC_V3_ADDR_TYPE_DIST:
> +		case KVM_VGIC_V3_ADDR_TYPE_REDIST:
> +			return 0;
> +		}
> +		break;
>  	case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
>  		return 0;
>  	case KVM_DEV_ARM_VGIC_GRP_CTRL:
> -- 
> 2.7.3
> 
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

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

* Re: [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
  2016-05-13  7:53         ` Christoffer Dall
@ 2016-05-13 10:44           ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-13 10:44 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 13/05/16 08:53, Christoffer Dall wrote:
> On Thu, May 12, 2016 at 07:52:38PM +0100, Andre Przywara wrote:
>> Hi,
>>
>> On 12/05/16 19:47, Christoffer Dall wrote:
>>> On Fri, May 06, 2016 at 11:46:00AM +0100, Andre Przywara wrote:
>>>> Using the VMCR accessors we provide access to GIC CPU interface state
>>>> to userland by wiring it up to the existing userland interface.
>>>> [Marc: move and make VMCR accessors static, streamline MMIO handlers]
>>>
>>> does this mean Marc did this and serves as credit or is it a lost
>>> reminder?
>>
>> It was meant as credit. I thought that is the usual annotation for this?
>>
> 
> I'm not sure if that's the usual way, I read it as a reminder, but it's
> not too important.  Mostly wanting to make sure we're not forgetting
> some todo item.
> 
>>>>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>> ---
>>>> Changelog v2 .. v3:
>>>> - total rework, moving into vgic-mmio-v2.c
>>>> - move vmcr accessor wrapper functions into this file
>>>> - use the register description table for CPU i/f registers as well
>>>> - add RAZ/WI handling for the active priority registers
>>>> - streamline MMIO handler functions
>>>>
>>>>  virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/vgic/vgic.h            |   2 +
>>>>  3 files changed, 107 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
>>>> index bb33af8..2122ff2 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
>>>> @@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
>>>>  
>>>>  	switch (attr->group) {
>>>>  	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
>>>> -		ret = -EINVAL;
>>>> +		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
>>>>  		break;
>>>>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>>>>  		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> index c453e6f..0060539 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> @@ -206,6 +206,84 @@ 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. */
>>>> +static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
>>>> +					   gpa_t addr, unsigned int len)
>>>> +{
>>>> +	struct vgic_vmcr vmcr;
>>>> +	u32 val;
>>>> +
>>>> +	vgic_get_vmcr(vcpu, &vmcr);
>>>> +
>>>> +	switch (addr & 0xff) {
>>>> +	case GIC_CPU_CTRL:
>>>> +		val = vmcr.ctlr;
>>>> +		break;
>>>> +	case GIC_CPU_PRIMASK:
>>>> +		val = vmcr.pmr;
>>>> +		break;
>>>> +	case GIC_CPU_BINPOINT:
>>>> +		val = vmcr.bpr;
>>>> +		break;
>>>> +	case GIC_CPU_ALIAS_BINPOINT:
>>>> +		val = vmcr.abpr;
>>>> +		break;
>>>> +	case GIC_CPU_IDENT:
>>>> +		val = ((PRODUCT_ID_KVM << 20) |
>>>> +		       (GICC_ARCH_VERSION_V2 << 16) |
>>>> +		       IMPLEMENTER_ARM);
>>>> +		break;
>>>> +	default:
>>>> +		return 0;
>>>> +	}
>>>> +
>>>> +	return extract_bytes(val, addr & 3, len);
>>>
>>> I don't think we allow anything than a full 32-bit aligned accesses
>>> from userspace - we shouldn't at least.
>>
>> Indeed - I think userland was always 32-bit only. And since last night
>> we even enforce this. So potentially there are more extract_bytes()
>> calls that can go.
>>
> Right.

So can I replace every call to extract_bytes() with just a "return val;"
for every register that allows 32-bit accesses only?
I think that's safe now, just checking ...

Cheers,
Andre.

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

* [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
@ 2016-05-13 10:44           ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-13 10:44 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 13/05/16 08:53, Christoffer Dall wrote:
> On Thu, May 12, 2016 at 07:52:38PM +0100, Andre Przywara wrote:
>> Hi,
>>
>> On 12/05/16 19:47, Christoffer Dall wrote:
>>> On Fri, May 06, 2016 at 11:46:00AM +0100, Andre Przywara wrote:
>>>> Using the VMCR accessors we provide access to GIC CPU interface state
>>>> to userland by wiring it up to the existing userland interface.
>>>> [Marc: move and make VMCR accessors static, streamline MMIO handlers]
>>>
>>> does this mean Marc did this and serves as credit or is it a lost
>>> reminder?
>>
>> It was meant as credit. I thought that is the usual annotation for this?
>>
> 
> I'm not sure if that's the usual way, I read it as a reminder, but it's
> not too important.  Mostly wanting to make sure we're not forgetting
> some todo item.
> 
>>>>
>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>> ---
>>>> Changelog v2 .. v3:
>>>> - total rework, moving into vgic-mmio-v2.c
>>>> - move vmcr accessor wrapper functions into this file
>>>> - use the register description table for CPU i/f registers as well
>>>> - add RAZ/WI handling for the active priority registers
>>>> - streamline MMIO handler functions
>>>>
>>>>  virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
>>>>  virt/kvm/arm/vgic/vgic.h            |   2 +
>>>>  3 files changed, 107 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
>>>> index bb33af8..2122ff2 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
>>>> @@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
>>>>  
>>>>  	switch (attr->group) {
>>>>  	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
>>>> -		ret = -EINVAL;
>>>> +		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
>>>>  		break;
>>>>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>>>>  		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> index c453e6f..0060539 100644
>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>> @@ -206,6 +206,84 @@ 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. */
>>>> +static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
>>>> +					   gpa_t addr, unsigned int len)
>>>> +{
>>>> +	struct vgic_vmcr vmcr;
>>>> +	u32 val;
>>>> +
>>>> +	vgic_get_vmcr(vcpu, &vmcr);
>>>> +
>>>> +	switch (addr & 0xff) {
>>>> +	case GIC_CPU_CTRL:
>>>> +		val = vmcr.ctlr;
>>>> +		break;
>>>> +	case GIC_CPU_PRIMASK:
>>>> +		val = vmcr.pmr;
>>>> +		break;
>>>> +	case GIC_CPU_BINPOINT:
>>>> +		val = vmcr.bpr;
>>>> +		break;
>>>> +	case GIC_CPU_ALIAS_BINPOINT:
>>>> +		val = vmcr.abpr;
>>>> +		break;
>>>> +	case GIC_CPU_IDENT:
>>>> +		val = ((PRODUCT_ID_KVM << 20) |
>>>> +		       (GICC_ARCH_VERSION_V2 << 16) |
>>>> +		       IMPLEMENTER_ARM);
>>>> +		break;
>>>> +	default:
>>>> +		return 0;
>>>> +	}
>>>> +
>>>> +	return extract_bytes(val, addr & 3, len);
>>>
>>> I don't think we allow anything than a full 32-bit aligned accesses
>>> from userspace - we shouldn't at least.
>>
>> Indeed - I think userland was always 32-bit only. And since last night
>> we even enforce this. So potentially there are more extract_bytes()
>> calls that can go.
>>
> Right.

So can I replace every call to extract_bytes() with just a "return val;"
for every register that allows 32-bit accesses only?
I think that's safe now, just checking ...

Cheers,
Andre.

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

* Re: [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
  2016-05-13 10:44           ` Andre Przywara
@ 2016-05-13 11:54             ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13 11:54 UTC (permalink / raw)
  To: Andre Przywara, g; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 13, 2016 at 11:44:38AM +0100, Andre Przywara wrote:
> Hi,
> 
> On 13/05/16 08:53, Christoffer Dall wrote:
> > On Thu, May 12, 2016 at 07:52:38PM +0100, Andre Przywara wrote:
> >> Hi,
> >>
> >> On 12/05/16 19:47, Christoffer Dall wrote:
> >>> On Fri, May 06, 2016 at 11:46:00AM +0100, Andre Przywara wrote:
> >>>> Using the VMCR accessors we provide access to GIC CPU interface state
> >>>> to userland by wiring it up to the existing userland interface.
> >>>> [Marc: move and make VMCR accessors static, streamline MMIO handlers]
> >>>
> >>> does this mean Marc did this and serves as credit or is it a lost
> >>> reminder?
> >>
> >> It was meant as credit. I thought that is the usual annotation for this?
> >>
> > 
> > I'm not sure if that's the usual way, I read it as a reminder, but it's
> > not too important.  Mostly wanting to make sure we're not forgetting
> > some todo item.
> > 
> >>>>
> >>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >>>> ---
> >>>> Changelog v2 .. v3:
> >>>> - total rework, moving into vgic-mmio-v2.c
> >>>> - move vmcr accessor wrapper functions into this file
> >>>> - use the register description table for CPU i/f registers as well
> >>>> - add RAZ/WI handling for the active priority registers
> >>>> - streamline MMIO handler functions
> >>>>
> >>>>  virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
> >>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
> >>>>  virt/kvm/arm/vgic/vgic.h            |   2 +
> >>>>  3 files changed, 107 insertions(+), 1 deletion(-)
> >>>>
> >>>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >>>> index bb33af8..2122ff2 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >>>> @@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
> >>>>  
> >>>>  	switch (attr->group) {
> >>>>  	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> >>>> -		ret = -EINVAL;
> >>>> +		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
> >>>>  		break;
> >>>>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> >>>>  		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
> >>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> index c453e6f..0060539 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> @@ -206,6 +206,84 @@ 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. */
> >>>> +static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
> >>>> +					   gpa_t addr, unsigned int len)
> >>>> +{
> >>>> +	struct vgic_vmcr vmcr;
> >>>> +	u32 val;
> >>>> +
> >>>> +	vgic_get_vmcr(vcpu, &vmcr);
> >>>> +
> >>>> +	switch (addr & 0xff) {
> >>>> +	case GIC_CPU_CTRL:
> >>>> +		val = vmcr.ctlr;
> >>>> +		break;
> >>>> +	case GIC_CPU_PRIMASK:
> >>>> +		val = vmcr.pmr;
> >>>> +		break;
> >>>> +	case GIC_CPU_BINPOINT:
> >>>> +		val = vmcr.bpr;
> >>>> +		break;
> >>>> +	case GIC_CPU_ALIAS_BINPOINT:
> >>>> +		val = vmcr.abpr;
> >>>> +		break;
> >>>> +	case GIC_CPU_IDENT:
> >>>> +		val = ((PRODUCT_ID_KVM << 20) |
> >>>> +		       (GICC_ARCH_VERSION_V2 << 16) |
> >>>> +		       IMPLEMENTER_ARM);
> >>>> +		break;
> >>>> +	default:
> >>>> +		return 0;
> >>>> +	}
> >>>> +
> >>>> +	return extract_bytes(val, addr & 3, len);
> >>>
> >>> I don't think we allow anything than a full 32-bit aligned accesses
> >>> from userspace - we shouldn't at least.
> >>
> >> Indeed - I think userland was always 32-bit only. And since last night
> >> we even enforce this. So potentially there are more extract_bytes()
> >> calls that can go.
> >>
> > Right.
> 
> So can I replace every call to extract_bytes() with just a "return val;"
> for every register that allows 32-bit accesses only?
> I think that's safe now, just checking ...

yes, I think the way we do it now, you simply return val (asuming you
build that variable at the right offset, even for byte accesses).

The only exception is for 32-bit accesses to 64-bit registers, where you
have to return either the upper or lower 32-bits.  I think you can still
use extract_bytes() there should you be so inclined.

-Christoffer


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

* [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
@ 2016-05-13 11:54             ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13 11:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 13, 2016 at 11:44:38AM +0100, Andre Przywara wrote:
> Hi,
> 
> On 13/05/16 08:53, Christoffer Dall wrote:
> > On Thu, May 12, 2016 at 07:52:38PM +0100, Andre Przywara wrote:
> >> Hi,
> >>
> >> On 12/05/16 19:47, Christoffer Dall wrote:
> >>> On Fri, May 06, 2016 at 11:46:00AM +0100, Andre Przywara wrote:
> >>>> Using the VMCR accessors we provide access to GIC CPU interface state
> >>>> to userland by wiring it up to the existing userland interface.
> >>>> [Marc: move and make VMCR accessors static, streamline MMIO handlers]
> >>>
> >>> does this mean Marc did this and serves as credit or is it a lost
> >>> reminder?
> >>
> >> It was meant as credit. I thought that is the usual annotation for this?
> >>
> > 
> > I'm not sure if that's the usual way, I read it as a reminder, but it's
> > not too important.  Mostly wanting to make sure we're not forgetting
> > some todo item.
> > 
> >>>>
> >>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >>>> ---
> >>>> Changelog v2 .. v3:
> >>>> - total rework, moving into vgic-mmio-v2.c
> >>>> - move vmcr accessor wrapper functions into this file
> >>>> - use the register description table for CPU i/f registers as well
> >>>> - add RAZ/WI handling for the active priority registers
> >>>> - streamline MMIO handler functions
> >>>>
> >>>>  virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
> >>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
> >>>>  virt/kvm/arm/vgic/vgic.h            |   2 +
> >>>>  3 files changed, 107 insertions(+), 1 deletion(-)
> >>>>
> >>>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >>>> index bb33af8..2122ff2 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >>>> @@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
> >>>>  
> >>>>  	switch (attr->group) {
> >>>>  	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> >>>> -		ret = -EINVAL;
> >>>> +		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
> >>>>  		break;
> >>>>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> >>>>  		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
> >>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> index c453e6f..0060539 100644
> >>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>> @@ -206,6 +206,84 @@ 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. */
> >>>> +static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
> >>>> +					   gpa_t addr, unsigned int len)
> >>>> +{
> >>>> +	struct vgic_vmcr vmcr;
> >>>> +	u32 val;
> >>>> +
> >>>> +	vgic_get_vmcr(vcpu, &vmcr);
> >>>> +
> >>>> +	switch (addr & 0xff) {
> >>>> +	case GIC_CPU_CTRL:
> >>>> +		val = vmcr.ctlr;
> >>>> +		break;
> >>>> +	case GIC_CPU_PRIMASK:
> >>>> +		val = vmcr.pmr;
> >>>> +		break;
> >>>> +	case GIC_CPU_BINPOINT:
> >>>> +		val = vmcr.bpr;
> >>>> +		break;
> >>>> +	case GIC_CPU_ALIAS_BINPOINT:
> >>>> +		val = vmcr.abpr;
> >>>> +		break;
> >>>> +	case GIC_CPU_IDENT:
> >>>> +		val = ((PRODUCT_ID_KVM << 20) |
> >>>> +		       (GICC_ARCH_VERSION_V2 << 16) |
> >>>> +		       IMPLEMENTER_ARM);
> >>>> +		break;
> >>>> +	default:
> >>>> +		return 0;
> >>>> +	}
> >>>> +
> >>>> +	return extract_bytes(val, addr & 3, len);
> >>>
> >>> I don't think we allow anything than a full 32-bit aligned accesses
> >>> from userspace - we shouldn't at least.
> >>
> >> Indeed - I think userland was always 32-bit only. And since last night
> >> we even enforce this. So potentially there are more extract_bytes()
> >> calls that can go.
> >>
> > Right.
> 
> So can I replace every call to extract_bytes() with just a "return val;"
> for every register that allows 32-bit accesses only?
> I think that's safe now, just checking ...

yes, I think the way we do it now, you simply return val (asuming you
build that variable at the right offset, even for byte accesses).

The only exception is for 32-bit accesses to 64-bit registers, where you
have to return either the upper or lower 32-bits.  I think you can still
use extract_bytes() there should you be so inclined.

-Christoffer

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

* Re: [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
  2016-05-13 11:54             ` Christoffer Dall
@ 2016-05-13 12:23               ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-13 12:23 UTC (permalink / raw)
  To: Christoffer Dall, Eric Auger; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 13/05/16 12:54, Christoffer Dall wrote:
> On Fri, May 13, 2016 at 11:44:38AM +0100, Andre Przywara wrote:
>> Hi,
>>
>> On 13/05/16 08:53, Christoffer Dall wrote:
>>> On Thu, May 12, 2016 at 07:52:38PM +0100, Andre Przywara wrote:
>>>> Hi,
>>>>
>>>> On 12/05/16 19:47, Christoffer Dall wrote:
>>>>> On Fri, May 06, 2016 at 11:46:00AM +0100, Andre Przywara wrote:
>>>>>> Using the VMCR accessors we provide access to GIC CPU interface state
>>>>>> to userland by wiring it up to the existing userland interface.
>>>>>> [Marc: move and make VMCR accessors static, streamline MMIO handlers]
>>>>>
>>>>> does this mean Marc did this and serves as credit or is it a lost
>>>>> reminder?
>>>>
>>>> It was meant as credit. I thought that is the usual annotation for this?
>>>>
>>>
>>> I'm not sure if that's the usual way, I read it as a reminder, but it's
>>> not too important.  Mostly wanting to make sure we're not forgetting
>>> some todo item.
>>>
>>>>>>
>>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>>>> ---
>>>>>> Changelog v2 .. v3:
>>>>>> - total rework, moving into vgic-mmio-v2.c
>>>>>> - move vmcr accessor wrapper functions into this file
>>>>>> - use the register description table for CPU i/f registers as well
>>>>>> - add RAZ/WI handling for the active priority registers
>>>>>> - streamline MMIO handler functions
>>>>>>
>>>>>>  virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
>>>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
>>>>>>  virt/kvm/arm/vgic/vgic.h            |   2 +
>>>>>>  3 files changed, 107 insertions(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
>>>>>> index bb33af8..2122ff2 100644
>>>>>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
>>>>>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
>>>>>> @@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
>>>>>>  
>>>>>>  	switch (attr->group) {
>>>>>>  	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
>>>>>> -		ret = -EINVAL;
>>>>>> +		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
>>>>>>  		break;
>>>>>>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>>>>>>  		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
>>>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>>>> index c453e6f..0060539 100644
>>>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>>>> @@ -206,6 +206,84 @@ 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. */
>>>>>> +static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
>>>>>> +					   gpa_t addr, unsigned int len)
>>>>>> +{
>>>>>> +	struct vgic_vmcr vmcr;
>>>>>> +	u32 val;
>>>>>> +
>>>>>> +	vgic_get_vmcr(vcpu, &vmcr);
>>>>>> +
>>>>>> +	switch (addr & 0xff) {
>>>>>> +	case GIC_CPU_CTRL:
>>>>>> +		val = vmcr.ctlr;
>>>>>> +		break;
>>>>>> +	case GIC_CPU_PRIMASK:
>>>>>> +		val = vmcr.pmr;
>>>>>> +		break;
>>>>>> +	case GIC_CPU_BINPOINT:
>>>>>> +		val = vmcr.bpr;
>>>>>> +		break;
>>>>>> +	case GIC_CPU_ALIAS_BINPOINT:
>>>>>> +		val = vmcr.abpr;
>>>>>> +		break;
>>>>>> +	case GIC_CPU_IDENT:
>>>>>> +		val = ((PRODUCT_ID_KVM << 20) |
>>>>>> +		       (GICC_ARCH_VERSION_V2 << 16) |
>>>>>> +		       IMPLEMENTER_ARM);
>>>>>> +		break;
>>>>>> +	default:
>>>>>> +		return 0;
>>>>>> +	}
>>>>>> +
>>>>>> +	return extract_bytes(val, addr & 3, len);
>>>>>
>>>>> I don't think we allow anything than a full 32-bit aligned accesses
>>>>> from userspace - we shouldn't at least.
>>>>
>>>> Indeed - I think userland was always 32-bit only. And since last night
>>>> we even enforce this. So potentially there are more extract_bytes()
>>>> calls that can go.
>>>>
>>> Right.
>>
>> So can I replace every call to extract_bytes() with just a "return val;"
>> for every register that allows 32-bit accesses only?
>> I think that's safe now, just checking ...
> 
> yes, I think the way we do it now, you simply return val (asuming you
> build that variable at the right offset, even for byte accesses).

??? If we only have word accesses, then we don't need to care about byte
accesses? Or do I got something wrong here?

> The only exception is for 32-bit accesses to 64-bit registers, where you
> have to return either the upper or lower 32-bits.  I think you can still
> use extract_bytes() there should you be so inclined.

Yeah, in fact GICR_TYPER and GICD_IROUTER are the only users remaining
afterwards. So I moved the declaration into vgic-mmio-v3.c and renamed
it to extract_words() on the way.
Will send the patch in a minute ...

Cheers,
Andre.

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

* [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
@ 2016-05-13 12:23               ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-13 12:23 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 13/05/16 12:54, Christoffer Dall wrote:
> On Fri, May 13, 2016 at 11:44:38AM +0100, Andre Przywara wrote:
>> Hi,
>>
>> On 13/05/16 08:53, Christoffer Dall wrote:
>>> On Thu, May 12, 2016 at 07:52:38PM +0100, Andre Przywara wrote:
>>>> Hi,
>>>>
>>>> On 12/05/16 19:47, Christoffer Dall wrote:
>>>>> On Fri, May 06, 2016 at 11:46:00AM +0100, Andre Przywara wrote:
>>>>>> Using the VMCR accessors we provide access to GIC CPU interface state
>>>>>> to userland by wiring it up to the existing userland interface.
>>>>>> [Marc: move and make VMCR accessors static, streamline MMIO handlers]
>>>>>
>>>>> does this mean Marc did this and serves as credit or is it a lost
>>>>> reminder?
>>>>
>>>> It was meant as credit. I thought that is the usual annotation for this?
>>>>
>>>
>>> I'm not sure if that's the usual way, I read it as a reminder, but it's
>>> not too important.  Mostly wanting to make sure we're not forgetting
>>> some todo item.
>>>
>>>>>>
>>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>>>> ---
>>>>>> Changelog v2 .. v3:
>>>>>> - total rework, moving into vgic-mmio-v2.c
>>>>>> - move vmcr accessor wrapper functions into this file
>>>>>> - use the register description table for CPU i/f registers as well
>>>>>> - add RAZ/WI handling for the active priority registers
>>>>>> - streamline MMIO handler functions
>>>>>>
>>>>>>  virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
>>>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
>>>>>>  virt/kvm/arm/vgic/vgic.h            |   2 +
>>>>>>  3 files changed, 107 insertions(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
>>>>>> index bb33af8..2122ff2 100644
>>>>>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
>>>>>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
>>>>>> @@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
>>>>>>  
>>>>>>  	switch (attr->group) {
>>>>>>  	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
>>>>>> -		ret = -EINVAL;
>>>>>> +		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
>>>>>>  		break;
>>>>>>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>>>>>>  		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
>>>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>>>> index c453e6f..0060539 100644
>>>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>>>>> @@ -206,6 +206,84 @@ 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. */
>>>>>> +static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
>>>>>> +					   gpa_t addr, unsigned int len)
>>>>>> +{
>>>>>> +	struct vgic_vmcr vmcr;
>>>>>> +	u32 val;
>>>>>> +
>>>>>> +	vgic_get_vmcr(vcpu, &vmcr);
>>>>>> +
>>>>>> +	switch (addr & 0xff) {
>>>>>> +	case GIC_CPU_CTRL:
>>>>>> +		val = vmcr.ctlr;
>>>>>> +		break;
>>>>>> +	case GIC_CPU_PRIMASK:
>>>>>> +		val = vmcr.pmr;
>>>>>> +		break;
>>>>>> +	case GIC_CPU_BINPOINT:
>>>>>> +		val = vmcr.bpr;
>>>>>> +		break;
>>>>>> +	case GIC_CPU_ALIAS_BINPOINT:
>>>>>> +		val = vmcr.abpr;
>>>>>> +		break;
>>>>>> +	case GIC_CPU_IDENT:
>>>>>> +		val = ((PRODUCT_ID_KVM << 20) |
>>>>>> +		       (GICC_ARCH_VERSION_V2 << 16) |
>>>>>> +		       IMPLEMENTER_ARM);
>>>>>> +		break;
>>>>>> +	default:
>>>>>> +		return 0;
>>>>>> +	}
>>>>>> +
>>>>>> +	return extract_bytes(val, addr & 3, len);
>>>>>
>>>>> I don't think we allow anything than a full 32-bit aligned accesses
>>>>> from userspace - we shouldn't at least.
>>>>
>>>> Indeed - I think userland was always 32-bit only. And since last night
>>>> we even enforce this. So potentially there are more extract_bytes()
>>>> calls that can go.
>>>>
>>> Right.
>>
>> So can I replace every call to extract_bytes() with just a "return val;"
>> for every register that allows 32-bit accesses only?
>> I think that's safe now, just checking ...
> 
> yes, I think the way we do it now, you simply return val (asuming you
> build that variable at the right offset, even for byte accesses).

??? If we only have word accesses, then we don't need to care about byte
accesses? Or do I got something wrong here?

> The only exception is for 32-bit accesses to 64-bit registers, where you
> have to return either the upper or lower 32-bits.  I think you can still
> use extract_bytes() there should you be so inclined.

Yeah, in fact GICR_TYPER and GICD_IROUTER are the only users remaining
afterwards. So I moved the declaration into vgic-mmio-v3.c and renamed
it to extract_words() on the way.
Will send the patch in a minute ...

Cheers,
Andre.

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

* Re: [PATCH v3 43/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
  2016-05-12 18:30     ` Christoffer Dall
@ 2016-05-13 12:24       ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-13 12:24 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

Hi,

On 12/05/16 19:30, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:56AM +0100, Andre Przywara wrote:
>> From: Eric Auger <eric.auger@linaro.org>
>>
>> This patch implements the switches for KVM_DEV_ARM_VGIC_GRP_DIST_REGS
>> and KVM_DEV_ARM_VGIC_GRP_CPU_REGS API which allows the userspace to
>> access VGIC registers.
>>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic-kvm-device.c | 53 +++++++++++++++++++++++++++++++++++--
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 34 ++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.h            |  1 +
>>  3 files changed, 86 insertions(+), 2 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> index 0189c13..c952f6f 100644
>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> @@ -252,6 +252,21 @@ void kvm_register_vgic_device(unsigned long type)
>>  	}
>>  }
>>  
>> +/** vgic_attr_regs_access: allows user space to read/write VGIC registers
>> + *
>> + * @dev: kvm device handle
>> + * @attr: kvm device attribute
>> + * @reg: address the value is read or written
>> + * @is_write: write flag
>> + *
>> + */
>> +static int vgic_attr_regs_access(struct kvm_device *dev,
>> +				 struct kvm_device_attr *attr,
>> +				 u32 *reg, bool is_write)
>> +{
>> +	return -ENXIO;
>> +}
>> +
>>  /* V2 ops */
>>  
>>  static int vgic_v2_set_attr(struct kvm_device *dev,
>> @@ -260,8 +275,23 @@ static int vgic_v2_set_attr(struct kvm_device *dev,
>>  	int ret;
>>  
>>  	ret = vgic_set_common_attr(dev, attr);
>> -	return ret;
>> +	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;
>> +
>> +		if (get_user(reg, uaddr))
>> +			return -EFAULT;
>>  
>> +		return vgic_attr_regs_access(dev, attr, &reg, true);
>> +	}
>> +	}
>> +
>> +	return -ENXIO;
>>  }
>>  
>>  static int vgic_v2_get_attr(struct kvm_device *dev,
>> @@ -270,7 +300,23 @@ static int vgic_v2_get_attr(struct kvm_device *dev,
>>  	int ret;
>>  
>>  	ret = vgic_get_common_attr(dev, attr);
>> -	return ret;
>> +	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 = 0;
>> +
>> +		ret = vgic_attr_regs_access(dev, attr, &reg, false);
>> +		if (ret)
>> +			return ret;
>> +		return put_user(reg, uaddr);
>> +	}
>> +	}
>> +
>> +	return -ENXIO;
>>  }
>>  
>>  static int vgic_v2_has_attr(struct kvm_device *dev,
>> @@ -284,6 +330,9 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
>>  			return 0;
>>  		}
>>  		break;
>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>> +	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
>> +		return vgic_v2_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 8006ac0..cf8fee9 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -246,3 +246,37 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
>>  
>>  	return SZ_4K;
>>  }
>> +
>> +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;
>> +
>> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
>> +
>> +	switch (attr->group) {
>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>> +		regions = vgic_v2_dist_registers;
>> +		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
>> +		break;
>> +	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
>> +		return -ENXIO;		/* TODO: describe CPU i/f regs also */
>> +	default:
>> +		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;
> 
> should we check if addr is word-aligned ?

Do we care here? This is just the function that says whether we support
this register or not, so I don't see so much benefit in checking here.
A check would be more useful in get/set_attr, if this isn't even
enforced before.

Cheers,
Andre.

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

* [PATCH v3 43/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
@ 2016-05-13 12:24       ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-13 12:24 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 12/05/16 19:30, Christoffer Dall wrote:
> On Fri, May 06, 2016 at 11:45:56AM +0100, Andre Przywara wrote:
>> From: Eric Auger <eric.auger@linaro.org>
>>
>> This patch implements the switches for KVM_DEV_ARM_VGIC_GRP_DIST_REGS
>> and KVM_DEV_ARM_VGIC_GRP_CPU_REGS API which allows the userspace to
>> access VGIC registers.
>>
>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic-kvm-device.c | 53 +++++++++++++++++++++++++++++++++++--
>>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 34 ++++++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic.h            |  1 +
>>  3 files changed, 86 insertions(+), 2 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> index 0189c13..c952f6f 100644
>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
>> @@ -252,6 +252,21 @@ void kvm_register_vgic_device(unsigned long type)
>>  	}
>>  }
>>  
>> +/** vgic_attr_regs_access: allows user space to read/write VGIC registers
>> + *
>> + * @dev: kvm device handle
>> + * @attr: kvm device attribute
>> + * @reg: address the value is read or written
>> + * @is_write: write flag
>> + *
>> + */
>> +static int vgic_attr_regs_access(struct kvm_device *dev,
>> +				 struct kvm_device_attr *attr,
>> +				 u32 *reg, bool is_write)
>> +{
>> +	return -ENXIO;
>> +}
>> +
>>  /* V2 ops */
>>  
>>  static int vgic_v2_set_attr(struct kvm_device *dev,
>> @@ -260,8 +275,23 @@ static int vgic_v2_set_attr(struct kvm_device *dev,
>>  	int ret;
>>  
>>  	ret = vgic_set_common_attr(dev, attr);
>> -	return ret;
>> +	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;
>> +
>> +		if (get_user(reg, uaddr))
>> +			return -EFAULT;
>>  
>> +		return vgic_attr_regs_access(dev, attr, &reg, true);
>> +	}
>> +	}
>> +
>> +	return -ENXIO;
>>  }
>>  
>>  static int vgic_v2_get_attr(struct kvm_device *dev,
>> @@ -270,7 +300,23 @@ static int vgic_v2_get_attr(struct kvm_device *dev,
>>  	int ret;
>>  
>>  	ret = vgic_get_common_attr(dev, attr);
>> -	return ret;
>> +	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 = 0;
>> +
>> +		ret = vgic_attr_regs_access(dev, attr, &reg, false);
>> +		if (ret)
>> +			return ret;
>> +		return put_user(reg, uaddr);
>> +	}
>> +	}
>> +
>> +	return -ENXIO;
>>  }
>>  
>>  static int vgic_v2_has_attr(struct kvm_device *dev,
>> @@ -284,6 +330,9 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
>>  			return 0;
>>  		}
>>  		break;
>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>> +	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
>> +		return vgic_v2_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 8006ac0..cf8fee9 100644
>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>> @@ -246,3 +246,37 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
>>  
>>  	return SZ_4K;
>>  }
>> +
>> +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;
>> +
>> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
>> +
>> +	switch (attr->group) {
>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>> +		regions = vgic_v2_dist_registers;
>> +		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
>> +		break;
>> +	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
>> +		return -ENXIO;		/* TODO: describe CPU i/f regs also */
>> +	default:
>> +		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;
> 
> should we check if addr is word-aligned ?

Do we care here? This is just the function that says whether we support
this register or not, so I don't see so much benefit in checking here.
A check would be more useful in get/set_attr, if this isn't even
enforced before.

Cheers,
Andre.

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

* Re: [PATCH v3 43/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
  2016-05-13 12:24       ` Andre Przywara
@ 2016-05-13 12:29         ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13 12:29 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, Eric Auger, kvmarm, kvm, linux-arm-kernel

On Fri, May 13, 2016 at 01:24:07PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 12/05/16 19:30, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:56AM +0100, Andre Przywara wrote:
> >> From: Eric Auger <eric.auger@linaro.org>
> >>
> >> This patch implements the switches for KVM_DEV_ARM_VGIC_GRP_DIST_REGS
> >> and KVM_DEV_ARM_VGIC_GRP_CPU_REGS API which allows the userspace to
> >> access VGIC registers.
> >>
> >> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

[...]

> >> +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;
> >> +
> >> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
> >> +
> >> +	switch (attr->group) {
> >> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> >> +		regions = vgic_v2_dist_registers;
> >> +		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
> >> +		break;
> >> +	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> >> +		return -ENXIO;		/* TODO: describe CPU i/f regs also */
> >> +	default:
> >> +		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;
> > 
> > should we check if addr is word-aligned ?
> 
> Do we care here? This is just the function that says whether we support
> this register or not, so I don't see so much benefit in checking here.
> A check would be more useful in get/set_attr, if this isn't even
> enforced before.
> 

It's kind of weird that you can ask 'do you have an attribute with
offset 0x2' and be told, 'yes', and then if you try to get it, you get
'this attribute doesn't exist'.

Thanks,
-Christoffer

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

* [PATCH v3 43/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
@ 2016-05-13 12:29         ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13 12:29 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 13, 2016 at 01:24:07PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 12/05/16 19:30, Christoffer Dall wrote:
> > On Fri, May 06, 2016 at 11:45:56AM +0100, Andre Przywara wrote:
> >> From: Eric Auger <eric.auger@linaro.org>
> >>
> >> This patch implements the switches for KVM_DEV_ARM_VGIC_GRP_DIST_REGS
> >> and KVM_DEV_ARM_VGIC_GRP_CPU_REGS API which allows the userspace to
> >> access VGIC registers.
> >>
> >> Signed-off-by: Eric Auger <eric.auger@linaro.org>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

[...]

> >> +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;
> >> +
> >> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
> >> +
> >> +	switch (attr->group) {
> >> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> >> +		regions = vgic_v2_dist_registers;
> >> +		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
> >> +		break;
> >> +	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> >> +		return -ENXIO;		/* TODO: describe CPU i/f regs also */
> >> +	default:
> >> +		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;
> > 
> > should we check if addr is word-aligned ?
> 
> Do we care here? This is just the function that says whether we support
> this register or not, so I don't see so much benefit in checking here.
> A check would be more useful in get/set_attr, if this isn't even
> enforced before.
> 

It's kind of weird that you can ask 'do you have an attribute with
offset 0x2' and be told, 'yes', and then if you try to get it, you get
'this attribute doesn't exist'.

Thanks,
-Christoffer

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

* Re: [PATCH v3 43/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
  2016-05-13 12:24       ` Andre Przywara
@ 2016-05-13 12:30         ` Marc Zyngier
  -1 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-13 12:30 UTC (permalink / raw)
  To: Andre Przywara, Christoffer Dall
  Cc: Eric Auger, kvmarm, kvm, linux-arm-kernel

On 13/05/16 13:24, Andre Przywara wrote:
> Hi,
> 
> On 12/05/16 19:30, Christoffer Dall wrote:
>> On Fri, May 06, 2016 at 11:45:56AM +0100, Andre Przywara wrote:
>>> From: Eric Auger <eric.auger@linaro.org>
>>>
>>> This patch implements the switches for KVM_DEV_ARM_VGIC_GRP_DIST_REGS
>>> and KVM_DEV_ARM_VGIC_GRP_CPU_REGS API which allows the userspace to
>>> access VGIC registers.
>>>
>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>>  virt/kvm/arm/vgic/vgic-kvm-device.c | 53 +++++++++++++++++++++++++++++++++++--
>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 34 ++++++++++++++++++++++++
>>>  virt/kvm/arm/vgic/vgic.h            |  1 +
>>>  3 files changed, 86 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
>>> index 0189c13..c952f6f 100644
>>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
>>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
>>> @@ -252,6 +252,21 @@ void kvm_register_vgic_device(unsigned long type)
>>>  	}
>>>  }
>>>  
>>> +/** vgic_attr_regs_access: allows user space to read/write VGIC registers
>>> + *
>>> + * @dev: kvm device handle
>>> + * @attr: kvm device attribute
>>> + * @reg: address the value is read or written
>>> + * @is_write: write flag
>>> + *
>>> + */
>>> +static int vgic_attr_regs_access(struct kvm_device *dev,
>>> +				 struct kvm_device_attr *attr,
>>> +				 u32 *reg, bool is_write)
>>> +{
>>> +	return -ENXIO;
>>> +}
>>> +
>>>  /* V2 ops */
>>>  
>>>  static int vgic_v2_set_attr(struct kvm_device *dev,
>>> @@ -260,8 +275,23 @@ static int vgic_v2_set_attr(struct kvm_device *dev,
>>>  	int ret;
>>>  
>>>  	ret = vgic_set_common_attr(dev, attr);
>>> -	return ret;
>>> +	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;
>>> +
>>> +		if (get_user(reg, uaddr))
>>> +			return -EFAULT;
>>>  
>>> +		return vgic_attr_regs_access(dev, attr, &reg, true);
>>> +	}
>>> +	}
>>> +
>>> +	return -ENXIO;
>>>  }
>>>  
>>>  static int vgic_v2_get_attr(struct kvm_device *dev,
>>> @@ -270,7 +300,23 @@ static int vgic_v2_get_attr(struct kvm_device *dev,
>>>  	int ret;
>>>  
>>>  	ret = vgic_get_common_attr(dev, attr);
>>> -	return ret;
>>> +	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 = 0;
>>> +
>>> +		ret = vgic_attr_regs_access(dev, attr, &reg, false);
>>> +		if (ret)
>>> +			return ret;
>>> +		return put_user(reg, uaddr);
>>> +	}
>>> +	}
>>> +
>>> +	return -ENXIO;
>>>  }
>>>  
>>>  static int vgic_v2_has_attr(struct kvm_device *dev,
>>> @@ -284,6 +330,9 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
>>>  			return 0;
>>>  		}
>>>  		break;
>>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>>> +	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
>>> +		return vgic_v2_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 8006ac0..cf8fee9 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> @@ -246,3 +246,37 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
>>>  
>>>  	return SZ_4K;
>>>  }
>>> +
>>> +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;
>>> +
>>> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
>>> +
>>> +	switch (attr->group) {
>>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>>> +		regions = vgic_v2_dist_registers;
>>> +		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
>>> +		break;
>>> +	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
>>> +		return -ENXIO;		/* TODO: describe CPU i/f regs also */
>>> +	default:
>>> +		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;
>>
>> should we check if addr is word-aligned ?
> 
> Do we care here? This is just the function that says whether we support
> this register or not, so I don't see so much benefit in checking here.

There definitely is value in checking the alignment. When you reply OK
to a "has_attr" request, you form a contract with userspace that the
same value will can be used for a get or set operation.

Here, has_attr will succeed while get/set will fail, and that's not an
acceptable behaviour.

> A check would be more useful in get/set_attr, if this isn't even
> enforced before.

Don't we already have that check by virtue of using the same accessors
as the MMIO path?

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v3 43/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers
@ 2016-05-13 12:30         ` Marc Zyngier
  0 siblings, 0 replies; 400+ messages in thread
From: Marc Zyngier @ 2016-05-13 12:30 UTC (permalink / raw)
  To: linux-arm-kernel

On 13/05/16 13:24, Andre Przywara wrote:
> Hi,
> 
> On 12/05/16 19:30, Christoffer Dall wrote:
>> On Fri, May 06, 2016 at 11:45:56AM +0100, Andre Przywara wrote:
>>> From: Eric Auger <eric.auger@linaro.org>
>>>
>>> This patch implements the switches for KVM_DEV_ARM_VGIC_GRP_DIST_REGS
>>> and KVM_DEV_ARM_VGIC_GRP_CPU_REGS API which allows the userspace to
>>> access VGIC registers.
>>>
>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>>  virt/kvm/arm/vgic/vgic-kvm-device.c | 53 +++++++++++++++++++++++++++++++++++--
>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 34 ++++++++++++++++++++++++
>>>  virt/kvm/arm/vgic/vgic.h            |  1 +
>>>  3 files changed, 86 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
>>> index 0189c13..c952f6f 100644
>>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
>>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
>>> @@ -252,6 +252,21 @@ void kvm_register_vgic_device(unsigned long type)
>>>  	}
>>>  }
>>>  
>>> +/** vgic_attr_regs_access: allows user space to read/write VGIC registers
>>> + *
>>> + * @dev: kvm device handle
>>> + * @attr: kvm device attribute
>>> + * @reg: address the value is read or written
>>> + * @is_write: write flag
>>> + *
>>> + */
>>> +static int vgic_attr_regs_access(struct kvm_device *dev,
>>> +				 struct kvm_device_attr *attr,
>>> +				 u32 *reg, bool is_write)
>>> +{
>>> +	return -ENXIO;
>>> +}
>>> +
>>>  /* V2 ops */
>>>  
>>>  static int vgic_v2_set_attr(struct kvm_device *dev,
>>> @@ -260,8 +275,23 @@ static int vgic_v2_set_attr(struct kvm_device *dev,
>>>  	int ret;
>>>  
>>>  	ret = vgic_set_common_attr(dev, attr);
>>> -	return ret;
>>> +	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;
>>> +
>>> +		if (get_user(reg, uaddr))
>>> +			return -EFAULT;
>>>  
>>> +		return vgic_attr_regs_access(dev, attr, &reg, true);
>>> +	}
>>> +	}
>>> +
>>> +	return -ENXIO;
>>>  }
>>>  
>>>  static int vgic_v2_get_attr(struct kvm_device *dev,
>>> @@ -270,7 +300,23 @@ static int vgic_v2_get_attr(struct kvm_device *dev,
>>>  	int ret;
>>>  
>>>  	ret = vgic_get_common_attr(dev, attr);
>>> -	return ret;
>>> +	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 = 0;
>>> +
>>> +		ret = vgic_attr_regs_access(dev, attr, &reg, false);
>>> +		if (ret)
>>> +			return ret;
>>> +		return put_user(reg, uaddr);
>>> +	}
>>> +	}
>>> +
>>> +	return -ENXIO;
>>>  }
>>>  
>>>  static int vgic_v2_has_attr(struct kvm_device *dev,
>>> @@ -284,6 +330,9 @@ static int vgic_v2_has_attr(struct kvm_device *dev,
>>>  			return 0;
>>>  		}
>>>  		break;
>>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>>> +	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
>>> +		return vgic_v2_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 8006ac0..cf8fee9 100644
>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
>>> @@ -246,3 +246,37 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
>>>  
>>>  	return SZ_4K;
>>>  }
>>> +
>>> +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;
>>> +
>>> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
>>> +
>>> +	switch (attr->group) {
>>> +	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
>>> +		regions = vgic_v2_dist_registers;
>>> +		nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
>>> +		break;
>>> +	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
>>> +		return -ENXIO;		/* TODO: describe CPU i/f regs also */
>>> +	default:
>>> +		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;
>>
>> should we check if addr is word-aligned ?
> 
> Do we care here? This is just the function that says whether we support
> this register or not, so I don't see so much benefit in checking here.

There definitely is value in checking the alignment. When you reply OK
to a "has_attr" request, you form a contract with userspace that the
same value will can be used for a get or set operation.

Here, has_attr will succeed while get/set will fail, and that's not an
acceptable behaviour.

> A check would be more useful in get/set_attr, if this isn't even
> enforced before.

Don't we already have that check by virtue of using the same accessors
as the MMIO path?

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
  2016-05-13 12:23               ` Andre Przywara
@ 2016-05-13 12:32                 ` Christoffer Dall
  -1 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13 12:32 UTC (permalink / raw)
  To: Andre Przywara; +Cc: Marc Zyngier, linux-arm-kernel, kvmarm, kvm

On Fri, May 13, 2016 at 01:23:02PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 13/05/16 12:54, Christoffer Dall wrote:
> > On Fri, May 13, 2016 at 11:44:38AM +0100, Andre Przywara wrote:
> >> Hi,
> >>
> >> On 13/05/16 08:53, Christoffer Dall wrote:
> >>> On Thu, May 12, 2016 at 07:52:38PM +0100, Andre Przywara wrote:
> >>>> Hi,
> >>>>
> >>>> On 12/05/16 19:47, Christoffer Dall wrote:
> >>>>> On Fri, May 06, 2016 at 11:46:00AM +0100, Andre Przywara wrote:
> >>>>>> Using the VMCR accessors we provide access to GIC CPU interface state
> >>>>>> to userland by wiring it up to the existing userland interface.
> >>>>>> [Marc: move and make VMCR accessors static, streamline MMIO handlers]
> >>>>>
> >>>>> does this mean Marc did this and serves as credit or is it a lost
> >>>>> reminder?
> >>>>
> >>>> It was meant as credit. I thought that is the usual annotation for this?
> >>>>
> >>>
> >>> I'm not sure if that's the usual way, I read it as a reminder, but it's
> >>> not too important.  Mostly wanting to make sure we're not forgetting
> >>> some todo item.
> >>>
> >>>>>>
> >>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >>>>>> ---
> >>>>>> Changelog v2 .. v3:
> >>>>>> - total rework, moving into vgic-mmio-v2.c
> >>>>>> - move vmcr accessor wrapper functions into this file
> >>>>>> - use the register description table for CPU i/f registers as well
> >>>>>> - add RAZ/WI handling for the active priority registers
> >>>>>> - streamline MMIO handler functions
> >>>>>>
> >>>>>>  virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
> >>>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
> >>>>>>  virt/kvm/arm/vgic/vgic.h            |   2 +
> >>>>>>  3 files changed, 107 insertions(+), 1 deletion(-)
> >>>>>>
> >>>>>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >>>>>> index bb33af8..2122ff2 100644
> >>>>>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> >>>>>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >>>>>> @@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
> >>>>>>  
> >>>>>>  	switch (attr->group) {
> >>>>>>  	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> >>>>>> -		ret = -EINVAL;
> >>>>>> +		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
> >>>>>>  		break;
> >>>>>>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> >>>>>>  		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
> >>>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>>>> index c453e6f..0060539 100644
> >>>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>>>> @@ -206,6 +206,84 @@ 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. */
> >>>>>> +static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
> >>>>>> +					   gpa_t addr, unsigned int len)
> >>>>>> +{
> >>>>>> +	struct vgic_vmcr vmcr;
> >>>>>> +	u32 val;
> >>>>>> +
> >>>>>> +	vgic_get_vmcr(vcpu, &vmcr);
> >>>>>> +
> >>>>>> +	switch (addr & 0xff) {
> >>>>>> +	case GIC_CPU_CTRL:
> >>>>>> +		val = vmcr.ctlr;
> >>>>>> +		break;
> >>>>>> +	case GIC_CPU_PRIMASK:
> >>>>>> +		val = vmcr.pmr;
> >>>>>> +		break;
> >>>>>> +	case GIC_CPU_BINPOINT:
> >>>>>> +		val = vmcr.bpr;
> >>>>>> +		break;
> >>>>>> +	case GIC_CPU_ALIAS_BINPOINT:
> >>>>>> +		val = vmcr.abpr;
> >>>>>> +		break;
> >>>>>> +	case GIC_CPU_IDENT:
> >>>>>> +		val = ((PRODUCT_ID_KVM << 20) |
> >>>>>> +		       (GICC_ARCH_VERSION_V2 << 16) |
> >>>>>> +		       IMPLEMENTER_ARM);
> >>>>>> +		break;
> >>>>>> +	default:
> >>>>>> +		return 0;
> >>>>>> +	}
> >>>>>> +
> >>>>>> +	return extract_bytes(val, addr & 3, len);
> >>>>>
> >>>>> I don't think we allow anything than a full 32-bit aligned accesses
> >>>>> from userspace - we shouldn't at least.
> >>>>
> >>>> Indeed - I think userland was always 32-bit only. And since last night
> >>>> we even enforce this. So potentially there are more extract_bytes()
> >>>> calls that can go.
> >>>>
> >>> Right.
> >>
> >> So can I replace every call to extract_bytes() with just a "return val;"
> >> for every register that allows 32-bit accesses only?
> >> I think that's safe now, just checking ...
> > 
> > yes, I think the way we do it now, you simply return val (asuming you
> > build that variable at the right offset, even for byte accesses).
> 
> ??? If we only have word accesses, then we don't need to care about byte
> accesses? Or do I got something wrong here?
> 

Ah right, we're talking about the userspace API here, never mind.

> > The only exception is for 32-bit accesses to 64-bit registers, where you
> > have to return either the upper or lower 32-bits.  I think you can still
> > use extract_bytes() there should you be so inclined.
> 
> Yeah, in fact GICR_TYPER and GICD_IROUTER are the only users remaining
> afterwards. So I moved the declaration into vgic-mmio-v3.c and renamed
> it to extract_words() on the way.

did you modify it to only work on words and let len specify the length
in words then, or?

> Will send the patch in a minute ...
> 
I guess I can comment on it there.

-Christoffer

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

* [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access
@ 2016-05-13 12:32                 ` Christoffer Dall
  0 siblings, 0 replies; 400+ messages in thread
From: Christoffer Dall @ 2016-05-13 12:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 13, 2016 at 01:23:02PM +0100, Andre Przywara wrote:
> Hi,
> 
> On 13/05/16 12:54, Christoffer Dall wrote:
> > On Fri, May 13, 2016 at 11:44:38AM +0100, Andre Przywara wrote:
> >> Hi,
> >>
> >> On 13/05/16 08:53, Christoffer Dall wrote:
> >>> On Thu, May 12, 2016 at 07:52:38PM +0100, Andre Przywara wrote:
> >>>> Hi,
> >>>>
> >>>> On 12/05/16 19:47, Christoffer Dall wrote:
> >>>>> On Fri, May 06, 2016 at 11:46:00AM +0100, Andre Przywara wrote:
> >>>>>> Using the VMCR accessors we provide access to GIC CPU interface state
> >>>>>> to userland by wiring it up to the existing userland interface.
> >>>>>> [Marc: move and make VMCR accessors static, streamline MMIO handlers]
> >>>>>
> >>>>> does this mean Marc did this and serves as credit or is it a lost
> >>>>> reminder?
> >>>>
> >>>> It was meant as credit. I thought that is the usual annotation for this?
> >>>>
> >>>
> >>> I'm not sure if that's the usual way, I read it as a reminder, but it's
> >>> not too important.  Mostly wanting to make sure we're not forgetting
> >>> some todo item.
> >>>
> >>>>>>
> >>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >>>>>> ---
> >>>>>> Changelog v2 .. v3:
> >>>>>> - total rework, moving into vgic-mmio-v2.c
> >>>>>> - move vmcr accessor wrapper functions into this file
> >>>>>> - use the register description table for CPU i/f registers as well
> >>>>>> - add RAZ/WI handling for the active priority registers
> >>>>>> - streamline MMIO handler functions
> >>>>>>
> >>>>>>  virt/kvm/arm/vgic/vgic-kvm-device.c |   2 +-
> >>>>>>  virt/kvm/arm/vgic/vgic-mmio-v2.c    | 104 ++++++++++++++++++++++++++++++++++++
> >>>>>>  virt/kvm/arm/vgic/vgic.h            |   2 +
> >>>>>>  3 files changed, 107 insertions(+), 1 deletion(-)
> >>>>>>
> >>>>>> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >>>>>> index bb33af8..2122ff2 100644
> >>>>>> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c
> >>>>>> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
> >>>>>> @@ -300,7 +300,7 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
> >>>>>>  
> >>>>>>  	switch (attr->group) {
> >>>>>>  	case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
> >>>>>> -		ret = -EINVAL;
> >>>>>> +		ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
> >>>>>>  		break;
> >>>>>>  	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
> >>>>>>  		ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
> >>>>>> diff --git a/virt/kvm/arm/vgic/vgic-mmio-v2.c b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>>>> index c453e6f..0060539 100644
> >>>>>> --- a/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>>>> +++ b/virt/kvm/arm/vgic/vgic-mmio-v2.c
> >>>>>> @@ -206,6 +206,84 @@ 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. */
> >>>>>> +static unsigned long vgic_mmio_read_vcpuif(struct kvm_vcpu *vcpu,
> >>>>>> +					   gpa_t addr, unsigned int len)
> >>>>>> +{
> >>>>>> +	struct vgic_vmcr vmcr;
> >>>>>> +	u32 val;
> >>>>>> +
> >>>>>> +	vgic_get_vmcr(vcpu, &vmcr);
> >>>>>> +
> >>>>>> +	switch (addr & 0xff) {
> >>>>>> +	case GIC_CPU_CTRL:
> >>>>>> +		val = vmcr.ctlr;
> >>>>>> +		break;
> >>>>>> +	case GIC_CPU_PRIMASK:
> >>>>>> +		val = vmcr.pmr;
> >>>>>> +		break;
> >>>>>> +	case GIC_CPU_BINPOINT:
> >>>>>> +		val = vmcr.bpr;
> >>>>>> +		break;
> >>>>>> +	case GIC_CPU_ALIAS_BINPOINT:
> >>>>>> +		val = vmcr.abpr;
> >>>>>> +		break;
> >>>>>> +	case GIC_CPU_IDENT:
> >>>>>> +		val = ((PRODUCT_ID_KVM << 20) |
> >>>>>> +		       (GICC_ARCH_VERSION_V2 << 16) |
> >>>>>> +		       IMPLEMENTER_ARM);
> >>>>>> +		break;
> >>>>>> +	default:
> >>>>>> +		return 0;
> >>>>>> +	}
> >>>>>> +
> >>>>>> +	return extract_bytes(val, addr & 3, len);
> >>>>>
> >>>>> I don't think we allow anything than a full 32-bit aligned accesses
> >>>>> from userspace - we shouldn't at least.
> >>>>
> >>>> Indeed - I think userland was always 32-bit only. And since last night
> >>>> we even enforce this. So potentially there are more extract_bytes()
> >>>> calls that can go.
> >>>>
> >>> Right.
> >>
> >> So can I replace every call to extract_bytes() with just a "return val;"
> >> for every register that allows 32-bit accesses only?
> >> I think that's safe now, just checking ...
> > 
> > yes, I think the way we do it now, you simply return val (asuming you
> > build that variable at the right offset, even for byte accesses).
> 
> ??? If we only have word accesses, then we don't need to care about byte
> accesses? Or do I got something wrong here?
> 

Ah right, we're talking about the userspace API here, never mind.

> > The only exception is for 32-bit accesses to 64-bit registers, where you
> > have to return either the upper or lower 32-bits.  I think you can still
> > use extract_bytes() there should you be so inclined.
> 
> Yeah, in fact GICR_TYPER and GICD_IROUTER are the only users remaining
> afterwards. So I moved the declaration into vgic-mmio-v3.c and renamed
> it to extract_words() on the way.

did you modify it to only work on words and let len specify the length
in words then, or?

> Will send the patch in a minute ...
> 
I guess I can comment on it there.

-Christoffer

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

* Re: [PATCH v3 08/55] KVM: arm/arm64: Get rid of vgic_cpu->nr_lr
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-18 10:43     ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-18 10:43 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

On 06/05/16 11:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> The number of list registers is a property of the underlying system, not
> of emulated VGIC CPU interface.
> 
> As we are about to move this variable to global state in the new vgic
> for clarity, move it from the legacy implementation as well to make the
> merge of the new code easier.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Thanks,
Andre.

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

* [PATCH v3 08/55] KVM: arm/arm64: Get rid of vgic_cpu->nr_lr
@ 2016-05-18 10:43     ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-18 10:43 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> The number of list registers is a property of the underlying system, not
> of emulated VGIC CPU interface.
> 
> As we are about to move this variable to global state in the new vgic
> for clarity, move it from the legacy implementation as well to make the
> merge of the new code easier.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Thanks,
Andre.

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

* Re: [PATCH v3 09/55] KVM: arm/arm64: Fix MMIO emulation data handling
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-18 11:02     ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-18 11:02 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

On 06/05/16 11:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> When the kernel was handling a guest MMIO read access internally, we
> need to copy the emulation result into the run->mmio structure in order
> for the kvm_handle_mmio_return() function to pick it up and inject the
> 	result back into the guest.
> 
> Currently the only user of kvm_io_bus for ARM is the VGIC, which did
> this copying itself, so this was not causing issues so far.
> 
> But with the upcoming new vgic implementation we need this done
> properly.
> 
> Update the kvm_handle_mmio_return description and cleanup the code to
> only perform a single copying when needed.
> 
> Code and commit message inspired by Andre Przywara.
> 
> Reported-by: Andre Przywara <andre.przywara@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Thanks,
Andre.

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

* [PATCH v3 09/55] KVM: arm/arm64: Fix MMIO emulation data handling
@ 2016-05-18 11:02     ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-18 11:02 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> When the kernel was handling a guest MMIO read access internally, we
> need to copy the emulation result into the run->mmio structure in order
> for the kvm_handle_mmio_return() function to pick it up and inject the
> 	result back into the guest.
> 
> Currently the only user of kvm_io_bus for ARM is the VGIC, which did
> this copying itself, so this was not causing issues so far.
> 
> But with the upcoming new vgic implementation we need this done
> properly.
> 
> Update the kvm_handle_mmio_return description and cleanup the code to
> only perform a single copying when needed.
> 
> Code and commit message inspired by Andre Przywara.
> 
> Reported-by: Andre Przywara <andre.przywara@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Thanks,
Andre.

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

* Re: [PATCH v3 10/55] KVM: arm/arm64: Export mmio_read/write_bus
  2016-05-06 10:45   ` Andre Przywara
@ 2016-05-18 14:18     ` Andre Przywara
  -1 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-18 14:18 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall; +Cc: linux-arm-kernel, kvmarm, kvm

On 06/05/16 11:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Rename mmio_{read,write}_bus to kvm_mmio_{read,write}_bus and export
> them out of mmio.c.
> This will be needed later for the new VGIC implementation.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Thanks,
Andre.

> ---
>  arch/arm/include/asm/kvm_mmio.h   |  3 +++
>  arch/arm/kvm/mmio.c               | 10 +++++-----
>  arch/arm64/include/asm/kvm_mmio.h |  3 +++
>  3 files changed, 11 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/arm/include/asm/kvm_mmio.h b/arch/arm/include/asm/kvm_mmio.h
> index d8e90c8..f3a7de7 100644
> --- a/arch/arm/include/asm/kvm_mmio.h
> +++ b/arch/arm/include/asm/kvm_mmio.h
> @@ -28,6 +28,9 @@ struct kvm_decode {
>  	bool sign_extend;
>  };
>  
> +void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
> +unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
> +
>  int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
>  int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
>  		 phys_addr_t fault_ipa);
> diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
> index 0158e9e..10f80a6 100644
> --- a/arch/arm/kvm/mmio.c
> +++ b/arch/arm/kvm/mmio.c
> @@ -23,7 +23,7 @@
>  
>  #include "trace.h"
>  
> -static void mmio_write_buf(char *buf, unsigned int len, unsigned long data)
> +void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data)
>  {
>  	void *datap = NULL;
>  	union {
> @@ -55,7 +55,7 @@ static void mmio_write_buf(char *buf, unsigned int len, unsigned long data)
>  	memcpy(buf, datap, len);
>  }
>  
> -static unsigned long mmio_read_buf(char *buf, unsigned int len)
> +unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len)
>  {
>  	unsigned long data = 0;
>  	union {
> @@ -66,7 +66,7 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len)
>  
>  	switch (len) {
>  	case 1:
> -		data = buf[0];
> +		data = *(u8 *)buf;
>  		break;
>  	case 2:
>  		memcpy(&tmp.hword, buf, len);
> @@ -103,7 +103,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  		if (len > sizeof(unsigned long))
>  			return -EINVAL;
>  
> -		data = mmio_read_buf(run->mmio.data, len);
> +		data = kvm_mmio_read_buf(run->mmio.data, len);
>  
>  		if (vcpu->arch.mmio_decode.sign_extend &&
>  		    len < sizeof(unsigned long)) {
> @@ -189,7 +189,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
>  					       len);
>  
>  		trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data);
> -		mmio_write_buf(data_buf, len, data);
> +		kvm_mmio_write_buf(data_buf, len, data);
>  
>  		ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len,
>  				       data_buf);
> diff --git a/arch/arm64/include/asm/kvm_mmio.h b/arch/arm64/include/asm/kvm_mmio.h
> index fe612a9..75ea420 100644
> --- a/arch/arm64/include/asm/kvm_mmio.h
> +++ b/arch/arm64/include/asm/kvm_mmio.h
> @@ -30,6 +30,9 @@ struct kvm_decode {
>  	bool sign_extend;
>  };
>  
> +void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
> +unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
> +
>  int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
>  int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
>  		 phys_addr_t fault_ipa);
> 

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

* [PATCH v3 10/55] KVM: arm/arm64: Export mmio_read/write_bus
@ 2016-05-18 14:18     ` Andre Przywara
  0 siblings, 0 replies; 400+ messages in thread
From: Andre Przywara @ 2016-05-18 14:18 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/05/16 11:45, Andre Przywara wrote:
> From: Christoffer Dall <christoffer.dall@linaro.org>
> 
> Rename mmio_{read,write}_bus to kvm_mmio_{read,write}_bus and export
> them out of mmio.c.
> This will be needed later for the new VGIC implementation.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Thanks,
Andre.

> ---
>  arch/arm/include/asm/kvm_mmio.h   |  3 +++
>  arch/arm/kvm/mmio.c               | 10 +++++-----
>  arch/arm64/include/asm/kvm_mmio.h |  3 +++
>  3 files changed, 11 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/arm/include/asm/kvm_mmio.h b/arch/arm/include/asm/kvm_mmio.h
> index d8e90c8..f3a7de7 100644
> --- a/arch/arm/include/asm/kvm_mmio.h
> +++ b/arch/arm/include/asm/kvm_mmio.h
> @@ -28,6 +28,9 @@ struct kvm_decode {
>  	bool sign_extend;
>  };
>  
> +void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
> +unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
> +
>  int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
>  int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
>  		 phys_addr_t fault_ipa);
> diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
> index 0158e9e..10f80a6 100644
> --- a/arch/arm/kvm/mmio.c
> +++ b/arch/arm/kvm/mmio.c
> @@ -23,7 +23,7 @@
>  
>  #include "trace.h"
>  
> -static void mmio_write_buf(char *buf, unsigned int len, unsigned long data)
> +void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data)
>  {
>  	void *datap = NULL;
>  	union {
> @@ -55,7 +55,7 @@ static void mmio_write_buf(char *buf, unsigned int len, unsigned long data)
>  	memcpy(buf, datap, len);
>  }
>  
> -static unsigned long mmio_read_buf(char *buf, unsigned int len)
> +unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len)
>  {
>  	unsigned long data = 0;
>  	union {
> @@ -66,7 +66,7 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len)
>  
>  	switch (len) {
>  	case 1:
> -		data = buf[0];
> +		data = *(u8 *)buf;
>  		break;
>  	case 2:
>  		memcpy(&tmp.hword, buf, len);
> @@ -103,7 +103,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  		if (len > sizeof(unsigned long))
>  			return -EINVAL;
>  
> -		data = mmio_read_buf(run->mmio.data, len);
> +		data = kvm_mmio_read_buf(run->mmio.data, len);
>  
>  		if (vcpu->arch.mmio_decode.sign_extend &&
>  		    len < sizeof(unsigned long)) {
> @@ -189,7 +189,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
>  					       len);
>  
>  		trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data);
> -		mmio_write_buf(data_buf, len, data);
> +		kvm_mmio_write_buf(data_buf, len, data);
>  
>  		ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len,
>  				       data_buf);
> diff --git a/arch/arm64/include/asm/kvm_mmio.h b/arch/arm64/include/asm/kvm_mmio.h
> index fe612a9..75ea420 100644
> --- a/arch/arm64/include/asm/kvm_mmio.h
> +++ b/arch/arm64/include/asm/kvm_mmio.h
> @@ -30,6 +30,9 @@ struct kvm_decode {
>  	bool sign_extend;
>  };
>  
> +void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
> +unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
> +
>  int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
>  int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
>  		 phys_addr_t fault_ipa);
> 

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

end of thread, other threads:[~2016-05-18 14:18 UTC | newest]

Thread overview: 400+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-06 10:45 [PATCH v3 00/55] KVM: arm/arm64: Rework virtual GIC emulation Andre Przywara
2016-05-06 10:45 ` Andre Przywara
2016-05-06 10:45 ` [PATCH v3 01/55] KVM: arm/arm64: vgic: streamline vgic_update_irq_pending() interface Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-06 10:45 ` [PATCH v3 02/55] KVM: arm/arm64: vgic: avoid map in kvm_vgic_inject_mapped_irq() Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-06 10:45 ` [PATCH v3 03/55] KVM: arm/arm64: vgic: avoid map in kvm_vgic_map_is_active() Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-06 10:45 ` [PATCH v3 04/55] KVM: arm/arm64: vgic: avoid map in kvm_vgic_unmap_phys_irq() Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-06 10:45 ` [PATCH v3 05/55] KVM: arm/arm64: Remove the IRQ field from struct irq_phys_map Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-06 10:45 ` [PATCH v3 06/55] KVM: arm/arm64: arch_timer: Remove irq_phys_map Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-10  8:33   ` Eric Auger
2016-05-10  8:33     ` Eric Auger
2016-05-06 10:45 ` [PATCH v3 07/55] KVM: arm/arm64: vgic: Remove irq_phys_map from interface Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-06 10:45 ` [PATCH v3 08/55] KVM: arm/arm64: Get rid of vgic_cpu->nr_lr Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-18 10:43   ` Andre Przywara
2016-05-18 10:43     ` Andre Przywara
2016-05-06 10:45 ` [PATCH v3 09/55] KVM: arm/arm64: Fix MMIO emulation data handling Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-10  8:57   ` Marc Zyngier
2016-05-10  8:57     ` Marc Zyngier
2016-05-18 11:02   ` Andre Przywara
2016-05-18 11:02     ` Andre Przywara
2016-05-06 10:45 ` [PATCH v3 10/55] KVM: arm/arm64: Export mmio_read/write_bus Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-10  8:59   ` Marc Zyngier
2016-05-10  8:59     ` Marc Zyngier
2016-05-18 14:18   ` Andre Przywara
2016-05-18 14:18     ` Andre Przywara
2016-05-06 10:45 ` [PATCH v3 11/55] KVM: arm/arm64: pmu: abstract access to number of SPIs Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-10  9:00   ` Marc Zyngier
2016-05-10  9:00     ` Marc Zyngier
2016-05-10  9:52   ` Eric Auger
2016-05-10  9:52     ` Eric Auger
2016-05-10 10:04     ` Marc Zyngier
2016-05-10 10:04       ` Marc Zyngier
2016-05-10 14:35     ` [PATCH v3a] " Andre Przywara
2016-05-10 14:35       ` Andre Przywara
2016-05-10 14:58       ` Andrew Jones
2016-05-10 14:58         ` Andrew Jones
2016-05-11 13:52         ` Andre Przywara
2016-05-11 13:52           ` Andre Przywara
2016-05-10 15:22       ` Marc Zyngier
2016-05-10 15:22         ` Marc Zyngier
2016-05-06 10:45 ` [PATCH v3 12/55] KVM: arm/arm64: move GICv2 emulation defines into arm-gic-v3.h Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-10  9:02   ` Marc Zyngier
2016-05-10  9:02     ` Marc Zyngier
2016-05-06 10:45 ` [PATCH v3 13/55] KVM: arm/arm64: vgic-new: Add data structure definitions Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-10  9:05   ` Marc Zyngier
2016-05-10  9:05     ` Marc Zyngier
2016-05-12 12:12   ` Christoffer Dall
2016-05-12 12:12     ` Christoffer Dall
2016-05-12 12:17     ` Marc Zyngier
2016-05-12 12:17       ` Marc Zyngier
2016-05-12 12:23       ` Christoffer Dall
2016-05-12 12:23         ` Christoffer Dall
2016-05-12 13:25     ` Andre Przywara
2016-05-12 13:25       ` Andre Przywara
2016-05-12 13:48       ` Christoffer Dall
2016-05-12 13:48         ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 14/55] KVM: arm/arm64: vgic-new: Add acccessor to new struct vgic_irq instance Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-10  9:22   ` Marc Zyngier
2016-05-10  9:22     ` Marc Zyngier
2016-05-11  9:20     ` Andre Przywara
2016-05-11  9:20       ` Andre Przywara
2016-05-10  9:35   ` Eric Auger
2016-05-10  9:35     ` Eric Auger
2016-05-06 10:45 ` [PATCH v3 15/55] KVM: arm/arm64: vgic-new: Implement virtual IRQ injection Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-10  9:25   ` Eric Auger
2016-05-10  9:25     ` Eric Auger
2016-05-10  9:39   ` Marc Zyngier
2016-05-10  9:39     ` Marc Zyngier
2016-05-10 12:08   ` Christoffer Dall
2016-05-10 12:08     ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 16/55] KVM: arm/arm64: vgic-new: Add IRQ sorting Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-10  9:29   ` Eric Auger
2016-05-10  9:29     ` Eric Auger
2016-05-10  9:48   ` Marc Zyngier
2016-05-10  9:48     ` Marc Zyngier
2016-05-06 10:45 ` [PATCH v3 17/55] KVM: arm/arm64: vgic-new: Add IRQ sync/flush framework Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-10 13:11   ` Christoffer Dall
2016-05-10 13:11     ` Christoffer Dall
2016-05-10 13:53   ` Eric Auger
2016-05-10 13:53     ` Eric Auger
2016-05-10 15:20   ` Eric Auger
2016-05-10 15:20     ` Eric Auger
2016-05-10 17:32     ` Marc Zyngier
2016-05-10 17:32       ` Marc Zyngier
2016-05-12 11:46   ` Christoffer Dall
2016-05-12 11:46     ` Christoffer Dall
2016-05-12 15:08     ` Andre Przywara
2016-05-12 15:08       ` Andre Przywara
2016-05-06 10:45 ` [PATCH v3 18/55] KVM: arm/arm64: vgic-new: Add GICv2 world switch backend Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-10 13:30   ` Christoffer Dall
2016-05-10 13:30     ` Christoffer Dall
2016-05-10 13:42     ` Marc Zyngier
2016-05-10 13:42       ` Marc Zyngier
2016-05-10 13:49       ` Eric Auger
2016-05-10 13:49         ` Eric Auger
2016-05-10 14:11       ` Christoffer Dall
2016-05-10 14:11         ` Christoffer Dall
2016-05-10 14:35         ` Marc Zyngier
2016-05-10 14:35           ` Marc Zyngier
2016-05-10 14:45           ` Marc Zyngier
2016-05-10 14:45             ` Marc Zyngier
2016-05-11  9:38             ` Christoffer Dall
2016-05-11  9:38               ` Christoffer Dall
2016-05-10 14:10   ` Eric Auger
2016-05-10 14:10     ` Eric Auger
2016-05-11 11:30     ` Andre Przywara
2016-05-11 11:30       ` Andre Przywara
2016-05-11 11:38       ` Eric Auger
2016-05-11 11:38         ` Eric Auger
2016-05-11 13:09         ` Andre Przywara
2016-05-11 13:09           ` Andre Przywara
2016-05-11 12:26       ` Christoffer Dall
2016-05-11 12:26         ` Christoffer Dall
2016-05-11 13:13         ` Andre Przywara
2016-05-11 13:13           ` Andre Przywara
2016-05-06 10:45 ` [PATCH v3 19/55] KVM: arm/arm64: vgic-new: Add GICv3 " Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-06 19:07   ` Tom Hanson
2016-05-06 19:07     ` Tom Hanson
2016-05-10 14:04   ` Christoffer Dall
2016-05-10 14:04     ` Christoffer Dall
2016-05-10 14:15     ` Peter Maydell
2016-05-10 14:15       ` Peter Maydell
2016-05-10 14:22       ` Marc Zyngier
2016-05-10 14:22         ` Marc Zyngier
2016-05-11  9:39       ` Christoffer Dall
2016-05-11  9:39         ` Christoffer Dall
2016-05-10 15:28   ` Eric Auger
2016-05-10 15:28     ` Eric Auger
2016-05-10 17:35     ` Marc Zyngier
2016-05-10 17:35       ` Marc Zyngier
2016-05-06 10:45 ` [PATCH v3 20/55] KVM: arm/arm64: vgic-new: Implement kvm_vgic_vcpu_pending_irq Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-10 10:22   ` Marc Zyngier
2016-05-10 10:22     ` Marc Zyngier
2016-05-10 14:18   ` Christoffer Dall
2016-05-10 14:18     ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 21/55] KVM: arm/arm64: vgic-new: Add MMIO handling framework Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-11  9:46   ` Christoffer Dall
2016-05-11  9:46     ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 22/55] KVM: arm/arm64: vgic-new: Add GICv2 " Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-11  9:50   ` Christoffer Dall
2016-05-11  9:50     ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 23/55] KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-11 12:05   ` Christoffer Dall
2016-05-11 12:05     ` Christoffer Dall
2016-05-11 12:47     ` Andre Przywara
2016-05-11 12:47       ` Andre Przywara
2016-05-11 12:51     ` Marc Zyngier
2016-05-11 12:51       ` Marc Zyngier
2016-05-11 13:15       ` Christoffer Dall
2016-05-11 13:15         ` Christoffer Dall
2016-05-11 13:27         ` Marc Zyngier
2016-05-11 13:27           ` Marc Zyngier
2016-05-11 13:36           ` Andre Przywara
2016-05-11 13:36             ` Andre Przywara
2016-05-11 14:40             ` Marc Zyngier
2016-05-11 14:40               ` Marc Zyngier
2016-05-11 13:38           ` Christoffer Dall
2016-05-11 13:38             ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 24/55] KVM: arm/arm64: vgic-new: Add ENABLE registers handlers Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-10 10:28   ` Marc Zyngier
2016-05-10 10:28     ` Marc Zyngier
2016-05-11 12:34   ` Christoffer Dall
2016-05-11 12:34     ` Christoffer Dall
2016-05-11 13:04     ` Andre Przywara
2016-05-11 13:04       ` Andre Przywara
2016-05-11 13:14       ` Christoffer Dall
2016-05-11 13:14         ` Christoffer Dall
2016-05-11 13:24         ` Andre Przywara
2016-05-11 13:24           ` Andre Przywara
2016-05-11 13:41           ` Christoffer Dall
2016-05-11 13:41             ` Christoffer Dall
2016-05-11 13:16       ` Christoffer Dall
2016-05-11 13:16         ` Christoffer Dall
2016-05-11 13:13     ` Marc Zyngier
2016-05-11 13:13       ` Marc Zyngier
2016-05-11 13:39       ` Andre Przywara
2016-05-11 13:39         ` Andre Przywara
2016-05-11 14:26         ` Marc Zyngier
2016-05-11 14:26           ` Marc Zyngier
2016-05-11 13:47       ` Christoffer Dall
2016-05-11 13:47         ` Christoffer Dall
2016-05-11 14:18       ` Andre Przywara
2016-05-11 14:18         ` Andre Przywara
2016-05-11 14:28         ` Andre Przywara
2016-05-11 14:28           ` Andre Przywara
2016-05-06 10:45 ` [PATCH v3 25/55] KVM: arm/arm64: vgic-new: Add PENDING " Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-10 10:49   ` Marc Zyngier
2016-05-10 10:49     ` Marc Zyngier
2016-05-11 13:11   ` Christoffer Dall
2016-05-11 13:11     ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 26/55] KVM: arm/arm64: vgic-new: Add ACTIVE " Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-10 12:09   ` Christoffer Dall
2016-05-10 12:09     ` Christoffer Dall
2016-05-10 12:14   ` Marc Zyngier
2016-05-10 12:14     ` Marc Zyngier
2016-05-10 13:04     ` Andre Przywara
2016-05-10 13:04       ` Andre Przywara
2016-05-10 13:12       ` Christoffer Dall
2016-05-10 13:12         ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 27/55] KVM: arm/arm64: vgic-new: Add PRIORITY " Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-11 13:37   ` Christoffer Dall
2016-05-11 13:37     ` Christoffer Dall
2016-05-12  9:10   ` Marc Zyngier
2016-05-12  9:10     ` Marc Zyngier
2016-05-12  9:56     ` Peter Maydell
2016-05-12  9:56       ` Peter Maydell
2016-05-12 10:09       ` Marc Zyngier
2016-05-12 10:09         ` Marc Zyngier
2016-05-06 10:45 ` [PATCH v3 28/55] KVM: arm/arm64: vgic-new: Add CONFIG " Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-12  8:32   ` Christoffer Dall
2016-05-12  8:32     ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 29/55] KVM: arm/arm64: vgic-new: Add TARGET " Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-12  8:35   ` Christoffer Dall
2016-05-12  8:35     ` Christoffer Dall
2016-05-12  8:39     ` Marc Zyngier
2016-05-12  8:39       ` Marc Zyngier
2016-05-12  8:54     ` Christoffer Dall
2016-05-12  8:54       ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 30/55] KVM: arm/arm64: vgic-new: Add SGIR register handler Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-12  8:40   ` Christoffer Dall
2016-05-12  8:40     ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 31/55] KVM: arm/arm64: vgic-new: Add SGIPENDR register handlers Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-12  9:09   ` Christoffer Dall
2016-05-12  9:09     ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 32/55] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-09 17:18   ` Marc Zyngier
2016-05-09 17:18     ` Marc Zyngier
2016-05-09 17:51     ` Chalamarla, Tirumalesh
2016-05-09 17:51       ` Chalamarla, Tirumalesh
2016-05-10 10:58     ` [PATCH] KVM: arm/arm64: vgic-new: fix overlap check for device addresses Andre Przywara
2016-05-10 10:58       ` Andre Przywara
2016-05-10 13:16       ` Marc Zyngier
2016-05-10 13:16         ` Marc Zyngier
2016-05-10 17:18         ` [PATCH v2] " Andre Przywara
2016-05-10 17:18           ` Andre Przywara
2016-05-12 19:43           ` Christoffer Dall
2016-05-12 19:43             ` Christoffer Dall
2016-05-12 10:26   ` [PATCH v3 32/55] KVM: arm/arm64: vgic-new: Add GICv3 MMIO handling framework Christoffer Dall
2016-05-12 10:26     ` Christoffer Dall
2016-05-12 10:52     ` Andre Przywara
2016-05-12 10:52       ` Andre Przywara
2016-05-12 10:58       ` Marc Zyngier
2016-05-12 10:58         ` Marc Zyngier
2016-05-06 10:45 ` [PATCH v3 33/55] KVM: arm/arm64: vgic-new: Add GICv3 CTLR, IIDR, TYPER handlers Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-12 11:47   ` Christoffer Dall
2016-05-12 11:47     ` Christoffer Dall
2016-05-12 12:33     ` Andre Przywara
2016-05-12 12:33       ` Andre Przywara
2016-05-06 10:45 ` [PATCH v3 34/55] KVM: arm/arm64: vgic-new: Add GICv3 redistributor IIDR and TYPER handler Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-12 11:59   ` Christoffer Dall
2016-05-12 11:59     ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 35/55] KVM: arm/arm64: vgic-new: Add GICv3 IDREGS register handler Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-12 12:12   ` Christoffer Dall
2016-05-12 12:12     ` Christoffer Dall
2016-05-12 12:37     ` Andre Przywara
2016-05-12 12:37       ` Andre Przywara
2016-05-06 10:45 ` [PATCH v3 36/55] KVM: arm/arm64: vgic-new: Add GICv3 IROUTER register handlers Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-12 12:21   ` Christoffer Dall
2016-05-12 12:21     ` Christoffer Dall
2016-05-12 12:37     ` Marc Zyngier
2016-05-12 12:37       ` Marc Zyngier
2016-05-12 13:41       ` Christoffer Dall
2016-05-12 13:41         ` Christoffer Dall
2016-05-12 14:00       ` Andre Przywara
2016-05-12 14:00         ` Andre Przywara
2016-05-12 14:20         ` Marc Zyngier
2016-05-12 14:20           ` Marc Zyngier
2016-05-06 10:45 ` [PATCH v3 37/55] KVM: arm/arm64: vgic-new: Add GICv3 SGI system register trap handler Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-12 12:40   ` Christoffer Dall
2016-05-12 12:40     ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 38/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM device ops registration Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-13 10:11   ` Christoffer Dall
2016-05-13 10:11     ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 39/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-13 10:11   ` Christoffer Dall
2016-05-13 10:11     ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 40/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-13 10:11   ` Christoffer Dall
2016-05-13 10:11     ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 41/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: implement kvm_vgic_addr Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-13 10:12   ` Christoffer Dall
2016-05-13 10:12     ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 42/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_ADDR Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-13 10:12   ` Christoffer Dall
2016-05-13 10:12     ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 43/55] KVM: arm/arm64: vgic-new: vgic_kvm_device: access to VGIC registers Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-12 18:30   ` Christoffer Dall
2016-05-12 18:30     ` Christoffer Dall
2016-05-13 12:24     ` Andre Przywara
2016-05-13 12:24       ` Andre Przywara
2016-05-13 12:29       ` Christoffer Dall
2016-05-13 12:29         ` Christoffer Dall
2016-05-13 12:30       ` Marc Zyngier
2016-05-13 12:30         ` Marc Zyngier
2016-05-06 10:45 ` [PATCH v3 44/55] KVM: arm/arm64: vgic-new: Export register access interface Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-06 10:45 ` [PATCH v3 45/55] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-12 18:41   ` Christoffer Dall
2016-05-12 18:41     ` Christoffer Dall
2016-05-12 19:10     ` Andre Przywara
2016-05-12 19:10       ` Andre Przywara
2016-05-13  7:51       ` Christoffer Dall
2016-05-13  7:51         ` Christoffer Dall
2016-05-06 10:45 ` [PATCH v3 46/55] KVM: arm/arm64: vgic-new: Add GICH_VMCR accessors Andre Przywara
2016-05-06 10:45   ` Andre Przywara
2016-05-12 18:43   ` Christoffer Dall
2016-05-12 18:43     ` Christoffer Dall
2016-05-06 10:46 ` [PATCH v3 47/55] KVM: arm/arm64: vgic-new: Add userland GIC CPU interface access Andre Przywara
2016-05-06 10:46   ` Andre Przywara
2016-05-09 17:27   ` Marc Zyngier
2016-05-09 17:27     ` Marc Zyngier
2016-05-11  8:24     ` Andre Przywara
2016-05-11  8:24       ` Andre Przywara
2016-05-12 18:47   ` Christoffer Dall
2016-05-12 18:47     ` Christoffer Dall
2016-05-12 18:52     ` Andre Przywara
2016-05-12 18:52       ` Andre Przywara
2016-05-13  7:53       ` Christoffer Dall
2016-05-13  7:53         ` Christoffer Dall
2016-05-13 10:44         ` Andre Przywara
2016-05-13 10:44           ` Andre Przywara
2016-05-13 11:54           ` Christoffer Dall
2016-05-13 11:54             ` Christoffer Dall
2016-05-13 12:23             ` Andre Przywara
2016-05-13 12:23               ` Andre Przywara
2016-05-13 12:32               ` Christoffer Dall
2016-05-13 12:32                 ` Christoffer Dall
2016-05-06 10:46 ` [PATCH v3 48/55] KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init Andre Przywara
2016-05-06 10:46   ` Andre Przywara
2016-05-12 19:00   ` Christoffer Dall
2016-05-12 19:00     ` Christoffer Dall
2016-05-06 10:46 ` [PATCH v3 49/55] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create Andre Przywara
2016-05-06 10:46   ` Andre Przywara
2016-05-12 19:08   ` Christoffer Dall
2016-05-12 19:08     ` Christoffer Dall
2016-05-06 10:46 ` [PATCH v3 50/55] KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init Andre Przywara
2016-05-06 10:46   ` Andre Przywara
2016-05-12 19:25   ` Christoffer Dall
2016-05-12 19:25     ` Christoffer Dall
2016-05-06 10:46 ` [PATCH v3 51/55] KVM: arm/arm64: vgic-new: vgic_init: implement map_resources Andre Przywara
2016-05-06 10:46   ` Andre Przywara
2016-05-12 19:28   ` Christoffer Dall
2016-05-12 19:28     ` Christoffer Dall
2016-05-06 10:46 ` [PATCH v3 52/55] KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable Andre Przywara
2016-05-06 10:46   ` Andre Przywara
2016-05-12 19:30   ` Christoffer Dall
2016-05-12 19:30     ` Christoffer Dall
2016-05-06 10:46 ` [PATCH v3 53/55] KVM: arm/arm64: vgic-new: Wire up irqfd injection Andre Przywara
2016-05-06 10:46   ` Andre Przywara
2016-05-12 19:33   ` Christoffer Dall
2016-05-12 19:33     ` Christoffer Dall
2016-05-06 10:46 ` [PATCH v3 54/55] KVM: arm/arm64: vgic-new: implement mapped IRQ handling Andre Przywara
2016-05-06 10:46   ` Andre Przywara
2016-05-12 19:36   ` Christoffer Dall
2016-05-12 19:36     ` Christoffer Dall
2016-05-06 10:46 ` [PATCH v3 55/55] KVM: arm/arm64: vgic-new: enable build Andre Przywara
2016-05-06 10:46   ` Andre Przywara

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.