All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/40] Optimize KVM/ARM for VHE systems
@ 2018-02-15 21:02 ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

This series redesigns parts of KVM/ARM to optimize the performance on
VHE systems.  The general approach is to try to do as little work as
possible when transitioning between the VM and the hypervisor.  This has
the benefit of lower latency when waiting for interrupts and delivering
virtual interrupts, and reduces the overhead of emulating behavior and
I/O in the host kernel.

Patches 01 through 06 are not VHE specific, but rework parts of KVM/ARM
that can be generally improved.  We then add infrastructure to move more
logic into vcpu_load and vcpu_put, we improve handling of VFP and debug
registers.

We then introduce a new world-switch function for VHE systems, which we
can tweak and optimize for VHE systems.  To do that, we rework a lot of
the system register save/restore handling and emulation code that may
need access to system registers, so that we can defer as many system
register save/restore operations to vcpu_load and vcpu_put, and move
this logic out of the VHE world switch function.

We then optimize the configuration of traps.  On non-VHE systems, both
the host and VM kernels run in EL1, but because the host kernel should
have full access to the underlying hardware, but the VM kernel should
not, we essentially make the host kernel more privileged than the VM
kernel despite them both running at the same privilege level by enabling
VE traps when entering the VM and disabling those traps when exiting the
VM.  On VHE systems, the host kernel runs in EL2 and has full access to
the hardware (as much as allowed by secure side software), and is
unaffected by the trap configuration.  That means we can configure the
traps for VMs running in EL1 once, and don't have to switch them on and
off for every entry/exit to/from the VM.

Finally, we improve our VGIC handling by moving all save/restore logic
out of the VHE world-switch, and we make it possible to truly only
evaluate if the AP list is empty and not do *any* VGIC work if that is
the case, and only do the minimal amount of work required in the course
of the VGIC processing when we have virtual interrupts in flight.

The patches are based on v4.16-rc1 with a fix for userspace irqchips and a
patch from Dave Martin that moves CPU ID register traps out of the world
switch.

I've given the patches a fair amount of testing on Thunder-X, Mustang,
Seattle, and TC2 (32-bit) for non-VHE testing, and tested VHE
functionality on TX2.

The patches are also available in the vhe-optimize-v4 branch on my
kernel.org repository [1].  The vhe-optimize-v4-base branch contains
prerequisites of this series.

Changes since v3:
 - Rebased on v4.16-rc1 (fun!)
 - Removed VFP optimizations because it was discovered that the deferred
   approach taken in v3 was buggy
   (https://lists.cs.columbia.edu/pipermail/kvmarm/2018-February/029838.html)
   This causes a fair amount of changes throughout and I've removed
   affected reviewed-by and other tags as best I could to take this into
   account.
 - Used a switch-statement to handle deferred system registers instead
   of the macro approach taken in v3.
 - Addressed other review coments (tried to keep track of this with logs
   of changes in individual patches).
 - I ran Yury's IPI benchark test and other tests on TX2 and could not
   observe a performance regression, but rather an improvement of around
   65%.  I suspect the previous regression was due to the timer WFI
   problem solved for v4.16-rc1.
 - I haven't included Tomasz' reviewed-by, because I figured too much of
   the series has changed since v3.

Changes since v2:
 - Rebased on v4.15-rc3.
 - Includes two additional patches that only does vcpu_load after
   kvm_vcpu_first_run_init and only for KVM_RUN.
 - Addressed review comments from v2 (detailed changelogs are in the
   individual patches).

Thanks,
-Christoffer

[1]: git://git.kernel.org/pub/scm/linux/kernel/git/cdall/linux.git vhe-optimize-v4

Christoffer Dall (39):
  KVM: arm/arm64: Avoid vcpu_load for other vcpu ioctls than KVM_RUN
  KVM: arm/arm64: Move vcpu_load call after kvm_vcpu_first_run_init
  KVM: arm64: Avoid storing the vcpu pointer on the stack
  KVM: arm64: Rework hyp_panic for VHE and non-VHE
  KVM: arm/arm64: Get rid of vcpu->arch.irq_lines
  KVM: arm/arm64: Add kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs
  KVM: arm/arm64: Introduce vcpu_el1_is_32bit
  KVM: arm64: Move debug dirty flag calculation out of world switch
  KVM: arm64: Slightly improve debug save/restore functions
  KVM: arm64: Improve debug register save/restore flow
  KVM: arm64: Factor out fault info population and gic workarounds
  KVM: arm64: Introduce VHE-specific kvm_vcpu_run
  KVM: arm64: Remove kern_hyp_va() use in VHE switch function
  KVM: arm64: Don't deactivate VM on VHE systems
  KVM: arm64: Remove noop calls to timer save/restore from VHE switch
  KVM: arm64: Move userspace system registers into separate function
  KVM: arm64: Rewrite sysreg alternatives to static keys
  KVM: arm64: Introduce separate VHE/non-VHE sysreg save/restore
    functions
  KVM: arm/arm64: Remove leftover comment from kvm_vcpu_run_vhe
  KVM: arm64: Unify non-VHE host/guest sysreg save and restore functions
  KVM: arm64: Don't save the host ELR_EL2 and SPSR_EL2 on VHE systems
  KVM: arm64: Change 32-bit handling of VM system registers
  KVM: arm64: Rewrite system register accessors to read/write functions
  KVM: arm64: Introduce framework for accessing deferred sysregs
  KVM: arm/arm64: Prepare to handle deferred save/restore of SPSR_EL1
  KVM: arm64: Prepare to handle deferred save/restore of ELR_EL1
  KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on
    VHE
  KVM: arm64: Prepare to handle deferred save/restore of 32-bit
    registers
  KVM: arm64: Defer saving/restoring 32-bit sysregs to vcpu load/put
  KVM: arm64: Move common VHE/non-VHE trap config in separate functions
  KVM: arm64: Directly call VHE and non-VHE FPSIMD enabled functions
  KVM: arm64: Configure c15, PMU, and debug register traps on cpu
    load/put for VHE
  KVM: arm64: Cleanup __activate_traps and __deactive_traps for VHE and
    non-VHE
  KVM: arm/arm64: Get rid of vgic_elrsr
  KVM: arm/arm64: Handle VGICv2 save/restore from the main VGIC code
  KVM: arm/arm64: Move arm64-only vgic-v2-sr.c file to arm64
  KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on
    VHE
  KVM: arm/arm64: Move VGIC APR save/restore to vgic put/load
  KVM: arm/arm64: Avoid VGICv3 save/restore on VHE with no IRQs

Shih-Wei Li (1):
  KVM: arm64: Move HCR_INT_OVERRIDE to default HCR_EL2 guest flag

 arch/arm/include/asm/kvm_asm.h                    |   5 +-
 arch/arm/include/asm/kvm_emulate.h                |  21 +-
 arch/arm/include/asm/kvm_host.h                   |   6 +-
 arch/arm/include/asm/kvm_hyp.h                    |   4 +
 arch/arm/kvm/emulate.c                            |   4 +-
 arch/arm/kvm/hyp/Makefile                         |   1 -
 arch/arm/kvm/hyp/switch.c                         |  16 +-
 arch/arm64/include/asm/kvm_arm.h                  |   4 +-
 arch/arm64/include/asm/kvm_asm.h                  |  18 +-
 arch/arm64/include/asm/kvm_emulate.h              |  74 +++--
 arch/arm64/include/asm/kvm_host.h                 |  46 ++-
 arch/arm64/include/asm/kvm_hyp.h                  |  29 +-
 arch/arm64/include/asm/kvm_mmu.h                  |   2 +-
 arch/arm64/kernel/asm-offsets.c                   |   1 +
 arch/arm64/kvm/debug.c                            |  28 +-
 arch/arm64/kvm/guest.c                            |   3 -
 arch/arm64/kvm/hyp/Makefile                       |   2 +-
 arch/arm64/kvm/hyp/debug-sr.c                     |  88 ++---
 arch/arm64/kvm/hyp/entry.S                        |   6 +-
 arch/arm64/kvm/hyp/hyp-entry.S                    |  31 +-
 arch/arm64/kvm/hyp/switch.c                       | 373 +++++++++++++---------
 arch/arm64/kvm/hyp/sysreg-sr.c                    | 172 ++++++++--
 {virt/kvm/arm => arch/arm64/kvm}/hyp/vgic-v2-sr.c |  81 -----
 arch/arm64/kvm/inject_fault.c                     |  24 +-
 arch/arm64/kvm/regmap.c                           |  67 +++-
 arch/arm64/kvm/sys_regs.c                         | 166 +++++++---
 arch/arm64/kvm/sys_regs.h                         |   4 +-
 arch/arm64/kvm/sys_regs_generic_v8.c              |   4 +-
 include/kvm/arm_vgic.h                            |   2 -
 virt/kvm/arm/aarch32.c                            |   2 +-
 virt/kvm/arm/arch_timer.c                         |   4 -
 virt/kvm/arm/arm.c                                |  50 ++-
 virt/kvm/arm/hyp/timer-sr.c                       |  44 +--
 virt/kvm/arm/hyp/vgic-v3-sr.c                     | 244 ++++++++------
 virt/kvm/arm/mmu.c                                |   6 +-
 virt/kvm/arm/pmu.c                                |  37 +--
 virt/kvm/arm/vgic/vgic-init.c                     |  11 -
 virt/kvm/arm/vgic/vgic-v2.c                       |  61 +++-
 virt/kvm/arm/vgic/vgic-v3.c                       |  12 +-
 virt/kvm/arm/vgic/vgic.c                          |  21 ++
 virt/kvm/arm/vgic/vgic.h                          |   3 +
 41 files changed, 1104 insertions(+), 673 deletions(-)
 rename {virt/kvm/arm => arch/arm64/kvm}/hyp/vgic-v2-sr.c (51%)

-- 
2.14.2

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

* [PATCH v4 00/40] Optimize KVM/ARM for VHE systems
@ 2018-02-15 21:02 ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:02 UTC (permalink / raw)
  To: linux-arm-kernel

This series redesigns parts of KVM/ARM to optimize the performance on
VHE systems.  The general approach is to try to do as little work as
possible when transitioning between the VM and the hypervisor.  This has
the benefit of lower latency when waiting for interrupts and delivering
virtual interrupts, and reduces the overhead of emulating behavior and
I/O in the host kernel.

Patches 01 through 06 are not VHE specific, but rework parts of KVM/ARM
that can be generally improved.  We then add infrastructure to move more
logic into vcpu_load and vcpu_put, we improve handling of VFP and debug
registers.

We then introduce a new world-switch function for VHE systems, which we
can tweak and optimize for VHE systems.  To do that, we rework a lot of
the system register save/restore handling and emulation code that may
need access to system registers, so that we can defer as many system
register save/restore operations to vcpu_load and vcpu_put, and move
this logic out of the VHE world switch function.

We then optimize the configuration of traps.  On non-VHE systems, both
the host and VM kernels run in EL1, but because the host kernel should
have full access to the underlying hardware, but the VM kernel should
not, we essentially make the host kernel more privileged than the VM
kernel despite them both running at the same privilege level by enabling
VE traps when entering the VM and disabling those traps when exiting the
VM.  On VHE systems, the host kernel runs in EL2 and has full access to
the hardware (as much as allowed by secure side software), and is
unaffected by the trap configuration.  That means we can configure the
traps for VMs running in EL1 once, and don't have to switch them on and
off for every entry/exit to/from the VM.

Finally, we improve our VGIC handling by moving all save/restore logic
out of the VHE world-switch, and we make it possible to truly only
evaluate if the AP list is empty and not do *any* VGIC work if that is
the case, and only do the minimal amount of work required in the course
of the VGIC processing when we have virtual interrupts in flight.

The patches are based on v4.16-rc1 with a fix for userspace irqchips and a
patch from Dave Martin that moves CPU ID register traps out of the world
switch.

I've given the patches a fair amount of testing on Thunder-X, Mustang,
Seattle, and TC2 (32-bit) for non-VHE testing, and tested VHE
functionality on TX2.

The patches are also available in the vhe-optimize-v4 branch on my
kernel.org repository [1].  The vhe-optimize-v4-base branch contains
prerequisites of this series.

Changes since v3:
 - Rebased on v4.16-rc1 (fun!)
 - Removed VFP optimizations because it was discovered that the deferred
   approach taken in v3 was buggy
   (https://lists.cs.columbia.edu/pipermail/kvmarm/2018-February/029838.html)
   This causes a fair amount of changes throughout and I've removed
   affected reviewed-by and other tags as best I could to take this into
   account.
 - Used a switch-statement to handle deferred system registers instead
   of the macro approach taken in v3.
 - Addressed other review coments (tried to keep track of this with logs
   of changes in individual patches).
 - I ran Yury's IPI benchark test and other tests on TX2 and could not
   observe a performance regression, but rather an improvement of around
   65%.  I suspect the previous regression was due to the timer WFI
   problem solved for v4.16-rc1.
 - I haven't included Tomasz' reviewed-by, because I figured too much of
   the series has changed since v3.

Changes since v2:
 - Rebased on v4.15-rc3.
 - Includes two additional patches that only does vcpu_load after
   kvm_vcpu_first_run_init and only for KVM_RUN.
 - Addressed review comments from v2 (detailed changelogs are in the
   individual patches).

Thanks,
-Christoffer

[1]: git://git.kernel.org/pub/scm/linux/kernel/git/cdall/linux.git vhe-optimize-v4

Christoffer Dall (39):
  KVM: arm/arm64: Avoid vcpu_load for other vcpu ioctls than KVM_RUN
  KVM: arm/arm64: Move vcpu_load call after kvm_vcpu_first_run_init
  KVM: arm64: Avoid storing the vcpu pointer on the stack
  KVM: arm64: Rework hyp_panic for VHE and non-VHE
  KVM: arm/arm64: Get rid of vcpu->arch.irq_lines
  KVM: arm/arm64: Add kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs
  KVM: arm/arm64: Introduce vcpu_el1_is_32bit
  KVM: arm64: Move debug dirty flag calculation out of world switch
  KVM: arm64: Slightly improve debug save/restore functions
  KVM: arm64: Improve debug register save/restore flow
  KVM: arm64: Factor out fault info population and gic workarounds
  KVM: arm64: Introduce VHE-specific kvm_vcpu_run
  KVM: arm64: Remove kern_hyp_va() use in VHE switch function
  KVM: arm64: Don't deactivate VM on VHE systems
  KVM: arm64: Remove noop calls to timer save/restore from VHE switch
  KVM: arm64: Move userspace system registers into separate function
  KVM: arm64: Rewrite sysreg alternatives to static keys
  KVM: arm64: Introduce separate VHE/non-VHE sysreg save/restore
    functions
  KVM: arm/arm64: Remove leftover comment from kvm_vcpu_run_vhe
  KVM: arm64: Unify non-VHE host/guest sysreg save and restore functions
  KVM: arm64: Don't save the host ELR_EL2 and SPSR_EL2 on VHE systems
  KVM: arm64: Change 32-bit handling of VM system registers
  KVM: arm64: Rewrite system register accessors to read/write functions
  KVM: arm64: Introduce framework for accessing deferred sysregs
  KVM: arm/arm64: Prepare to handle deferred save/restore of SPSR_EL1
  KVM: arm64: Prepare to handle deferred save/restore of ELR_EL1
  KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on
    VHE
  KVM: arm64: Prepare to handle deferred save/restore of 32-bit
    registers
  KVM: arm64: Defer saving/restoring 32-bit sysregs to vcpu load/put
  KVM: arm64: Move common VHE/non-VHE trap config in separate functions
  KVM: arm64: Directly call VHE and non-VHE FPSIMD enabled functions
  KVM: arm64: Configure c15, PMU, and debug register traps on cpu
    load/put for VHE
  KVM: arm64: Cleanup __activate_traps and __deactive_traps for VHE and
    non-VHE
  KVM: arm/arm64: Get rid of vgic_elrsr
  KVM: arm/arm64: Handle VGICv2 save/restore from the main VGIC code
  KVM: arm/arm64: Move arm64-only vgic-v2-sr.c file to arm64
  KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on
    VHE
  KVM: arm/arm64: Move VGIC APR save/restore to vgic put/load
  KVM: arm/arm64: Avoid VGICv3 save/restore on VHE with no IRQs

Shih-Wei Li (1):
  KVM: arm64: Move HCR_INT_OVERRIDE to default HCR_EL2 guest flag

 arch/arm/include/asm/kvm_asm.h                    |   5 +-
 arch/arm/include/asm/kvm_emulate.h                |  21 +-
 arch/arm/include/asm/kvm_host.h                   |   6 +-
 arch/arm/include/asm/kvm_hyp.h                    |   4 +
 arch/arm/kvm/emulate.c                            |   4 +-
 arch/arm/kvm/hyp/Makefile                         |   1 -
 arch/arm/kvm/hyp/switch.c                         |  16 +-
 arch/arm64/include/asm/kvm_arm.h                  |   4 +-
 arch/arm64/include/asm/kvm_asm.h                  |  18 +-
 arch/arm64/include/asm/kvm_emulate.h              |  74 +++--
 arch/arm64/include/asm/kvm_host.h                 |  46 ++-
 arch/arm64/include/asm/kvm_hyp.h                  |  29 +-
 arch/arm64/include/asm/kvm_mmu.h                  |   2 +-
 arch/arm64/kernel/asm-offsets.c                   |   1 +
 arch/arm64/kvm/debug.c                            |  28 +-
 arch/arm64/kvm/guest.c                            |   3 -
 arch/arm64/kvm/hyp/Makefile                       |   2 +-
 arch/arm64/kvm/hyp/debug-sr.c                     |  88 ++---
 arch/arm64/kvm/hyp/entry.S                        |   6 +-
 arch/arm64/kvm/hyp/hyp-entry.S                    |  31 +-
 arch/arm64/kvm/hyp/switch.c                       | 373 +++++++++++++---------
 arch/arm64/kvm/hyp/sysreg-sr.c                    | 172 ++++++++--
 {virt/kvm/arm => arch/arm64/kvm}/hyp/vgic-v2-sr.c |  81 -----
 arch/arm64/kvm/inject_fault.c                     |  24 +-
 arch/arm64/kvm/regmap.c                           |  67 +++-
 arch/arm64/kvm/sys_regs.c                         | 166 +++++++---
 arch/arm64/kvm/sys_regs.h                         |   4 +-
 arch/arm64/kvm/sys_regs_generic_v8.c              |   4 +-
 include/kvm/arm_vgic.h                            |   2 -
 virt/kvm/arm/aarch32.c                            |   2 +-
 virt/kvm/arm/arch_timer.c                         |   4 -
 virt/kvm/arm/arm.c                                |  50 ++-
 virt/kvm/arm/hyp/timer-sr.c                       |  44 +--
 virt/kvm/arm/hyp/vgic-v3-sr.c                     | 244 ++++++++------
 virt/kvm/arm/mmu.c                                |   6 +-
 virt/kvm/arm/pmu.c                                |  37 +--
 virt/kvm/arm/vgic/vgic-init.c                     |  11 -
 virt/kvm/arm/vgic/vgic-v2.c                       |  61 +++-
 virt/kvm/arm/vgic/vgic-v3.c                       |  12 +-
 virt/kvm/arm/vgic/vgic.c                          |  21 ++
 virt/kvm/arm/vgic/vgic.h                          |   3 +
 41 files changed, 1104 insertions(+), 673 deletions(-)
 rename {virt/kvm/arm => arch/arm64/kvm}/hyp/vgic-v2-sr.c (51%)

-- 
2.14.2

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

* [PATCH v4 01/40] KVM: arm/arm64: Avoid vcpu_load for other vcpu ioctls than KVM_RUN
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:02   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

Calling vcpu_load() registers preempt notifiers for this vcpu and calls
kvm_arch_vcpu_load().  The latter will soon be doing a lot of heavy
lifting on arm/arm64 and will try to do things such as enabling the
virtual timer and setting us up to handle interrupts from the timer
hardware.

Loading state onto hardware registers and enabling hardware to signal
interrupts can be problematic when we're not actually about to run the
VCPU, because it makes it difficult to establish the right context when
handling interrupts from the timer, and it makes the register access
code difficult to reason about.

Luckily, now when we call vcpu_load in each ioctl implementation, we can
simply remove the call from the non-KVM_RUN vcpu ioctls, and our
kvm_arch_vcpu_load() is only used for loading vcpu content to the
physical CPU when we're actually going to run the vcpu.

Reviewed-by: Julien Grall <julien.grall@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/guest.c | 3 ---
 virt/kvm/arm/arm.c     | 9 ---------
 2 files changed, 12 deletions(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index d7e3299a7734..959e50d2588c 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -363,8 +363,6 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
 {
 	int ret = 0;
 
-	vcpu_load(vcpu);
-
 	trace_kvm_set_guest_debug(vcpu, dbg->control);
 
 	if (dbg->control & ~KVM_GUESTDBG_VALID_MASK) {
@@ -386,7 +384,6 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
 	}
 
 out:
-	vcpu_put(vcpu);
 	return ret;
 }
 
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 86941f6181bb..53572304843b 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -384,14 +384,11 @@ static void vcpu_power_off(struct kvm_vcpu *vcpu)
 int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
 				    struct kvm_mp_state *mp_state)
 {
-	vcpu_load(vcpu);
-
 	if (vcpu->arch.power_off)
 		mp_state->mp_state = KVM_MP_STATE_STOPPED;
 	else
 		mp_state->mp_state = KVM_MP_STATE_RUNNABLE;
 
-	vcpu_put(vcpu);
 	return 0;
 }
 
@@ -400,8 +397,6 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
 {
 	int ret = 0;
 
-	vcpu_load(vcpu);
-
 	switch (mp_state->mp_state) {
 	case KVM_MP_STATE_RUNNABLE:
 		vcpu->arch.power_off = false;
@@ -413,7 +408,6 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
 		ret = -EINVAL;
 	}
 
-	vcpu_put(vcpu);
 	return ret;
 }
 
@@ -1036,8 +1030,6 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 	struct kvm_device_attr attr;
 	long r;
 
-	vcpu_load(vcpu);
-
 	switch (ioctl) {
 	case KVM_ARM_VCPU_INIT: {
 		struct kvm_vcpu_init init;
@@ -1114,7 +1106,6 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 		r = -EINVAL;
 	}
 
-	vcpu_put(vcpu);
 	return r;
 }
 
-- 
2.14.2

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

* [PATCH v4 01/40] KVM: arm/arm64: Avoid vcpu_load for other vcpu ioctls than KVM_RUN
@ 2018-02-15 21:02   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:02 UTC (permalink / raw)
  To: linux-arm-kernel

Calling vcpu_load() registers preempt notifiers for this vcpu and calls
kvm_arch_vcpu_load().  The latter will soon be doing a lot of heavy
lifting on arm/arm64 and will try to do things such as enabling the
virtual timer and setting us up to handle interrupts from the timer
hardware.

Loading state onto hardware registers and enabling hardware to signal
interrupts can be problematic when we're not actually about to run the
VCPU, because it makes it difficult to establish the right context when
handling interrupts from the timer, and it makes the register access
code difficult to reason about.

Luckily, now when we call vcpu_load in each ioctl implementation, we can
simply remove the call from the non-KVM_RUN vcpu ioctls, and our
kvm_arch_vcpu_load() is only used for loading vcpu content to the
physical CPU when we're actually going to run the vcpu.

Reviewed-by: Julien Grall <julien.grall@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/guest.c | 3 ---
 virt/kvm/arm/arm.c     | 9 ---------
 2 files changed, 12 deletions(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index d7e3299a7734..959e50d2588c 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -363,8 +363,6 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
 {
 	int ret = 0;
 
-	vcpu_load(vcpu);
-
 	trace_kvm_set_guest_debug(vcpu, dbg->control);
 
 	if (dbg->control & ~KVM_GUESTDBG_VALID_MASK) {
@@ -386,7 +384,6 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
 	}
 
 out:
-	vcpu_put(vcpu);
 	return ret;
 }
 
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 86941f6181bb..53572304843b 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -384,14 +384,11 @@ static void vcpu_power_off(struct kvm_vcpu *vcpu)
 int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
 				    struct kvm_mp_state *mp_state)
 {
-	vcpu_load(vcpu);
-
 	if (vcpu->arch.power_off)
 		mp_state->mp_state = KVM_MP_STATE_STOPPED;
 	else
 		mp_state->mp_state = KVM_MP_STATE_RUNNABLE;
 
-	vcpu_put(vcpu);
 	return 0;
 }
 
@@ -400,8 +397,6 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
 {
 	int ret = 0;
 
-	vcpu_load(vcpu);
-
 	switch (mp_state->mp_state) {
 	case KVM_MP_STATE_RUNNABLE:
 		vcpu->arch.power_off = false;
@@ -413,7 +408,6 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
 		ret = -EINVAL;
 	}
 
-	vcpu_put(vcpu);
 	return ret;
 }
 
@@ -1036,8 +1030,6 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 	struct kvm_device_attr attr;
 	long r;
 
-	vcpu_load(vcpu);
-
 	switch (ioctl) {
 	case KVM_ARM_VCPU_INIT: {
 		struct kvm_vcpu_init init;
@@ -1114,7 +1106,6 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 		r = -EINVAL;
 	}
 
-	vcpu_put(vcpu);
 	return r;
 }
 
-- 
2.14.2

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

* [PATCH v4 02/40] KVM: arm/arm64: Move vcpu_load call after kvm_vcpu_first_run_init
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:02   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Andrew Jones, kvm, Marc Zyngier, Tomasz Nowicki, Julien Grall,
	Yury Norov, Christoffer Dall, Dave Martin, Shih-Wei Li

Moving the call to vcpu_load() in kvm_arch_vcpu_ioctl_run() to after
we've called kvm_vcpu_first_run_init() simplifies some of the vgic and
there is also no need to do vcpu_load() for things such as handling the
immediate_exit flag.

Reviewed-by: Julien Grall <julien.grall@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 virt/kvm/arm/arch_timer.c     |  4 ----
 virt/kvm/arm/arm.c            | 22 ++++++++--------------
 virt/kvm/arm/vgic/vgic-init.c | 11 -----------
 3 files changed, 8 insertions(+), 29 deletions(-)

diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 70f4c30918eb..b744e6935a3f 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -852,11 +852,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 		return ret;
 
 no_vgic:
-	preempt_disable();
 	timer->enabled = 1;
-	kvm_timer_vcpu_load(vcpu);
-	preempt_enable();
-
 	return 0;
 }
 
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 53572304843b..932e61858c55 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -632,27 +632,22 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 	if (unlikely(!kvm_vcpu_initialized(vcpu)))
 		return -ENOEXEC;
 
-	vcpu_load(vcpu);
-
 	ret = kvm_vcpu_first_run_init(vcpu);
 	if (ret)
-		goto out;
+		return ret;
 
 	if (run->exit_reason == KVM_EXIT_MMIO) {
 		ret = kvm_handle_mmio_return(vcpu, vcpu->run);
 		if (ret)
-			goto out;
-		if (kvm_arm_handle_step_debug(vcpu, vcpu->run)) {
-			ret = 0;
-			goto out;
-		}
-
+			return ret;
+		if (kvm_arm_handle_step_debug(vcpu, vcpu->run))
+			return 0;
 	}
 
-	if (run->immediate_exit) {
-		ret = -EINTR;
-		goto out;
-	}
+	if (run->immediate_exit)
+		return -EINTR;
+
+	vcpu_load(vcpu);
 
 	kvm_sigset_activate(vcpu);
 
@@ -811,7 +806,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 	kvm_sigset_deactivate(vcpu);
 
-out:
 	vcpu_put(vcpu);
 	return ret;
 }
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
index 743ca5cb05ef..3e8209a07585 100644
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -302,17 +302,6 @@ int vgic_init(struct kvm *kvm)
 
 	dist->initialized = true;
 
-	/*
-	 * If we're initializing GICv2 on-demand when first running the VCPU
-	 * then we need to load the VGIC state onto the CPU.  We can detect
-	 * this easily by checking if we are in between vcpu_load and vcpu_put
-	 * when we just initialized the VGIC.
-	 */
-	preempt_disable();
-	vcpu = kvm_arm_get_running_vcpu();
-	if (vcpu)
-		kvm_vgic_load(vcpu);
-	preempt_enable();
 out:
 	return ret;
 }
-- 
2.14.2

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

* [PATCH v4 02/40] KVM: arm/arm64: Move vcpu_load call after kvm_vcpu_first_run_init
@ 2018-02-15 21:02   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:02 UTC (permalink / raw)
  To: linux-arm-kernel

Moving the call to vcpu_load() in kvm_arch_vcpu_ioctl_run() to after
we've called kvm_vcpu_first_run_init() simplifies some of the vgic and
there is also no need to do vcpu_load() for things such as handling the
immediate_exit flag.

Reviewed-by: Julien Grall <julien.grall@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 virt/kvm/arm/arch_timer.c     |  4 ----
 virt/kvm/arm/arm.c            | 22 ++++++++--------------
 virt/kvm/arm/vgic/vgic-init.c | 11 -----------
 3 files changed, 8 insertions(+), 29 deletions(-)

diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 70f4c30918eb..b744e6935a3f 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -852,11 +852,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 		return ret;
 
 no_vgic:
-	preempt_disable();
 	timer->enabled = 1;
-	kvm_timer_vcpu_load(vcpu);
-	preempt_enable();
-
 	return 0;
 }
 
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 53572304843b..932e61858c55 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -632,27 +632,22 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 	if (unlikely(!kvm_vcpu_initialized(vcpu)))
 		return -ENOEXEC;
 
-	vcpu_load(vcpu);
-
 	ret = kvm_vcpu_first_run_init(vcpu);
 	if (ret)
-		goto out;
+		return ret;
 
 	if (run->exit_reason == KVM_EXIT_MMIO) {
 		ret = kvm_handle_mmio_return(vcpu, vcpu->run);
 		if (ret)
-			goto out;
-		if (kvm_arm_handle_step_debug(vcpu, vcpu->run)) {
-			ret = 0;
-			goto out;
-		}
-
+			return ret;
+		if (kvm_arm_handle_step_debug(vcpu, vcpu->run))
+			return 0;
 	}
 
-	if (run->immediate_exit) {
-		ret = -EINTR;
-		goto out;
-	}
+	if (run->immediate_exit)
+		return -EINTR;
+
+	vcpu_load(vcpu);
 
 	kvm_sigset_activate(vcpu);
 
@@ -811,7 +806,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 	kvm_sigset_deactivate(vcpu);
 
-out:
 	vcpu_put(vcpu);
 	return ret;
 }
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
index 743ca5cb05ef..3e8209a07585 100644
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -302,17 +302,6 @@ int vgic_init(struct kvm *kvm)
 
 	dist->initialized = true;
 
-	/*
-	 * If we're initializing GICv2 on-demand when first running the VCPU
-	 * then we need to load the VGIC state onto the CPU.  We can detect
-	 * this easily by checking if we are in between vcpu_load and vcpu_put
-	 * when we just initialized the VGIC.
-	 */
-	preempt_disable();
-	vcpu = kvm_arm_get_running_vcpu();
-	if (vcpu)
-		kvm_vgic_load(vcpu);
-	preempt_enable();
 out:
 	return ret;
 }
-- 
2.14.2

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

* [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:02   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov,
	Ard Biesheuvel

We already have the percpu area for the host cpu state, which points to
the VCPU, so there's no need to store the VCPU pointer on the stack on
every context switch.  We can be a little more clever and just use
tpidr_el2 for the percpu offset and load the VCPU pointer from the host
context.

This does require us to calculate the percpu offset without including
the offset from the kernel mapping of the percpu array to the linear
mapping of the array (which is what we store in tpidr_el1), because a
PC-relative generated address in EL2 is already giving us the hyp alias
of the linear mapping of a kernel address.  We do this in
__cpu_init_hyp_mode() by using kvm_ksym_ref().

This change also requires us to have a scratch register, so we take the
chance to rearrange some of the el1_sync code to only look at the
vttbr_el2 to determine if this is a trap from the guest or an HVC from
the host.  We do add an extra check to call the panic code if the kernel
is configured with debugging enabled and we saw a trap from the host
which wasn't an HVC, indicating that we left some EL2 trap configured by
mistake.

The code that accesses ESR_EL2 was previously using an alternative to
use the _EL1 accessor on VHE systems, but this was actually unnecessary
as the _EL1 accessor aliases the ESR_EL2 register on VHE, and the _EL2
accessor does the same thing on both systems.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v3:
     - Reworked the assembly part of the patch after rebasing on v4.16-rc1
       which created a conflict with the variant 2 mitigations.
     - Removed Marc's reviewed-by due to the rework.
     - Removed unneeded extern keyword in declaration in header file
    
    Changes since v1:
     - Use PC-relative addressing to access per-cpu variables instead of
       using a load from the literal pool.
     - Remove stale comments as pointed out by Marc
     - Reworded the commit message as suggested by Drew

 arch/arm64/include/asm/kvm_asm.h  | 14 ++++++++++++++
 arch/arm64/include/asm/kvm_host.h | 15 +++++++++++++++
 arch/arm64/kernel/asm-offsets.c   |  1 +
 arch/arm64/kvm/hyp/entry.S        |  6 +-----
 arch/arm64/kvm/hyp/hyp-entry.S    | 31 +++++++++++++------------------
 arch/arm64/kvm/hyp/switch.c       |  5 +----
 arch/arm64/kvm/hyp/sysreg-sr.c    |  5 +++++
 7 files changed, 50 insertions(+), 27 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 24961b732e65..6b626750b0a1 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -33,6 +33,7 @@
 #define KVM_ARM64_DEBUG_DIRTY_SHIFT	0
 #define KVM_ARM64_DEBUG_DIRTY		(1 << KVM_ARM64_DEBUG_DIRTY_SHIFT)
 
+/* Translate a kernel address of @sym into its equivalent linear mapping */
 #define kvm_ksym_ref(sym)						\
 	({								\
 		void *val = &sym;					\
@@ -70,6 +71,19 @@ extern u32 __init_stage2_translation(void);
 
 extern void __qcom_hyp_sanitize_btac_predictors(void);
 
+#else /* __ASSEMBLY__ */
+
+.macro get_host_ctxt reg, tmp
+	adr_l	\reg, kvm_host_cpu_state
+	mrs	\tmp, tpidr_el2
+	add	\reg, \reg, \tmp
+.endm
+
+.macro get_vcpu vcpu, ctxt
+	ldr	\vcpu, [\ctxt, #HOST_CONTEXT_VCPU]
+	kern_hyp_va	\vcpu
+.endm
+
 #endif
 
 #endif /* __ARM_KVM_ASM_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 596f8e414a4c..618cfee7206a 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -358,10 +358,15 @@ int kvm_perf_teardown(void);
 
 struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
 
+void __kvm_set_tpidr_el2(u64 tpidr_el2);
+DECLARE_PER_CPU(kvm_cpu_context_t, kvm_host_cpu_state);
+
 static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
 				       unsigned long hyp_stack_ptr,
 				       unsigned long vector_ptr)
 {
+	u64 tpidr_el2;
+
 	/*
 	 * Call initialization code, and switch to the full blown HYP code.
 	 * If the cpucaps haven't been finalized yet, something has gone very
@@ -370,6 +375,16 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
 	 */
 	BUG_ON(!static_branch_likely(&arm64_const_caps_ready));
 	__kvm_call_hyp((void *)pgd_ptr, hyp_stack_ptr, vector_ptr);
+
+	/*
+	 * Calculate the raw per-cpu offset without a translation from the
+	 * kernel's mapping to the linear mapping, and store it in tpidr_el2
+	 * so that we can use adr_l to access per-cpu variables in EL2.
+	 */
+	tpidr_el2 = (u64)this_cpu_ptr(&kvm_host_cpu_state)
+		- (u64)kvm_ksym_ref(kvm_host_cpu_state);
+
+	kvm_call_hyp(__kvm_set_tpidr_el2, tpidr_el2);
 }
 
 static inline void kvm_arch_hardware_unsetup(void) {}
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index 1303e04110cd..78e1b0a70aaf 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -138,6 +138,7 @@ int main(void)
   DEFINE(CPU_FP_REGS,		offsetof(struct kvm_regs, fp_regs));
   DEFINE(VCPU_FPEXC32_EL2,	offsetof(struct kvm_vcpu, arch.ctxt.sys_regs[FPEXC32_EL2]));
   DEFINE(VCPU_HOST_CONTEXT,	offsetof(struct kvm_vcpu, arch.host_cpu_context));
+  DEFINE(HOST_CONTEXT_VCPU,	offsetof(struct kvm_cpu_context, __hyp_running_vcpu));
 #endif
 #ifdef CONFIG_CPU_PM
   DEFINE(CPU_SUSPEND_SZ,	sizeof(struct cpu_suspend_ctx));
diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
index fdd1068ee3a5..1f458f7c3b44 100644
--- a/arch/arm64/kvm/hyp/entry.S
+++ b/arch/arm64/kvm/hyp/entry.S
@@ -62,9 +62,6 @@ ENTRY(__guest_enter)
 	// Store the host regs
 	save_callee_saved_regs x1
 
-	// Store host_ctxt and vcpu for use at exit time
-	stp	x1, x0, [sp, #-16]!
-
 	add	x18, x0, #VCPU_CONTEXT
 
 	// Restore guest regs x0-x17
@@ -118,8 +115,7 @@ ENTRY(__guest_exit)
 	// Store the guest regs x19-x29, lr
 	save_callee_saved_regs x1
 
-	// Restore the host_ctxt from the stack
-	ldr	x2, [sp], #16
+	get_host_ctxt	x2, x3
 
 	// Now restore the host regs
 	restore_callee_saved_regs x2
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index f36464bd57c5..559b4d54bc42 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -57,13 +57,8 @@ ENDPROC(__vhe_hyp_call)
 el1_sync:				// Guest trapped into EL2
 	stp	x0, x1, [sp, #-16]!
 
-alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
-	mrs	x1, esr_el2
-alternative_else
-	mrs	x1, esr_el1
-alternative_endif
-	lsr	x0, x1, #ESR_ELx_EC_SHIFT
-
+	mrs	x0, esr_el2
+	lsr	x0, x0, #ESR_ELx_EC_SHIFT
 	cmp	x0, #ESR_ELx_EC_HVC64
 	ccmp	x0, #ESR_ELx_EC_HVC32, #4, ne
 	b.ne	el1_trap
@@ -117,10 +112,15 @@ el1_hvc_guest:
 	eret
 
 el1_trap:
+	get_host_ctxt	x0, x1
+	get_vcpu	x1, x0
+
+	mrs		x0, esr_el2
+	lsr		x0, x0, #ESR_ELx_EC_SHIFT
 	/*
 	 * x0: ESR_EC
+	 * x1: vcpu pointer
 	 */
-	ldr	x1, [sp, #16 + 8]	// vcpu stored by __guest_enter
 
 	/*
 	 * We trap the first access to the FP/SIMD to save the host context
@@ -138,13 +138,15 @@ alternative_else_nop_endif
 
 el1_irq:
 	stp     x0, x1, [sp, #-16]!
-	ldr	x1, [sp, #16 + 8]
+	get_host_ctxt	x0, x1
+	get_vcpu	x1, x0
 	mov	x0, #ARM_EXCEPTION_IRQ
 	b	__guest_exit
 
 el1_error:
 	stp     x0, x1, [sp, #-16]!
-	ldr	x1, [sp, #16 + 8]
+	get_host_ctxt	x0, x1
+	get_vcpu	x1, x0
 	mov	x0, #ARM_EXCEPTION_EL1_SERROR
 	b	__guest_exit
 
@@ -180,14 +182,7 @@ ENTRY(__hyp_do_panic)
 ENDPROC(__hyp_do_panic)
 
 ENTRY(__hyp_panic)
-	/*
-	 * '=kvm_host_cpu_state' is a host VA from the constant pool, it may
-	 * not be accessible by this address from EL2, hyp_panic() converts
-	 * it with kern_hyp_va() before use.
-	 */
-	ldr	x0, =kvm_host_cpu_state
-	mrs	x1, tpidr_el2
-	add	x0, x0, x1
+	get_host_ctxt x0, x1
 	b	hyp_panic
 ENDPROC(__hyp_panic)
 
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index b991f85c1133..d1749fa0bfc3 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -467,7 +467,7 @@ static hyp_alternate_select(__hyp_call_panic,
 			    __hyp_call_panic_nvhe, __hyp_call_panic_vhe,
 			    ARM64_HAS_VIRT_HOST_EXTN);
 
-void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt)
+void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *host_ctxt)
 {
 	struct kvm_vcpu *vcpu = NULL;
 
@@ -476,9 +476,6 @@ void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt)
 	u64 par = read_sysreg(par_el1);
 
 	if (read_sysreg(vttbr_el2)) {
-		struct kvm_cpu_context *host_ctxt;
-
-		host_ctxt = kern_hyp_va(__host_ctxt);
 		vcpu = host_ctxt->__hyp_running_vcpu;
 		__timer_disable_traps(vcpu);
 		__deactivate_traps(vcpu);
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 2c17afd2be96..43b7dd65e3e6 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -189,3 +189,8 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
 	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
 		write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
 }
+
+void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2)
+{
+	asm("msr tpidr_el2, %0": : "r" (tpidr_el2));
+}
-- 
2.14.2

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

* [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
@ 2018-02-15 21:02   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:02 UTC (permalink / raw)
  To: linux-arm-kernel

We already have the percpu area for the host cpu state, which points to
the VCPU, so there's no need to store the VCPU pointer on the stack on
every context switch.  We can be a little more clever and just use
tpidr_el2 for the percpu offset and load the VCPU pointer from the host
context.

This does require us to calculate the percpu offset without including
the offset from the kernel mapping of the percpu array to the linear
mapping of the array (which is what we store in tpidr_el1), because a
PC-relative generated address in EL2 is already giving us the hyp alias
of the linear mapping of a kernel address.  We do this in
__cpu_init_hyp_mode() by using kvm_ksym_ref().

This change also requires us to have a scratch register, so we take the
chance to rearrange some of the el1_sync code to only look at the
vttbr_el2 to determine if this is a trap from the guest or an HVC from
the host.  We do add an extra check to call the panic code if the kernel
is configured with debugging enabled and we saw a trap from the host
which wasn't an HVC, indicating that we left some EL2 trap configured by
mistake.

The code that accesses ESR_EL2 was previously using an alternative to
use the _EL1 accessor on VHE systems, but this was actually unnecessary
as the _EL1 accessor aliases the ESR_EL2 register on VHE, and the _EL2
accessor does the same thing on both systems.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v3:
     - Reworked the assembly part of the patch after rebasing on v4.16-rc1
       which created a conflict with the variant 2 mitigations.
     - Removed Marc's reviewed-by due to the rework.
     - Removed unneeded extern keyword in declaration in header file
    
    Changes since v1:
     - Use PC-relative addressing to access per-cpu variables instead of
       using a load from the literal pool.
     - Remove stale comments as pointed out by Marc
     - Reworded the commit message as suggested by Drew

 arch/arm64/include/asm/kvm_asm.h  | 14 ++++++++++++++
 arch/arm64/include/asm/kvm_host.h | 15 +++++++++++++++
 arch/arm64/kernel/asm-offsets.c   |  1 +
 arch/arm64/kvm/hyp/entry.S        |  6 +-----
 arch/arm64/kvm/hyp/hyp-entry.S    | 31 +++++++++++++------------------
 arch/arm64/kvm/hyp/switch.c       |  5 +----
 arch/arm64/kvm/hyp/sysreg-sr.c    |  5 +++++
 7 files changed, 50 insertions(+), 27 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 24961b732e65..6b626750b0a1 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -33,6 +33,7 @@
 #define KVM_ARM64_DEBUG_DIRTY_SHIFT	0
 #define KVM_ARM64_DEBUG_DIRTY		(1 << KVM_ARM64_DEBUG_DIRTY_SHIFT)
 
+/* Translate a kernel address of @sym into its equivalent linear mapping */
 #define kvm_ksym_ref(sym)						\
 	({								\
 		void *val = &sym;					\
@@ -70,6 +71,19 @@ extern u32 __init_stage2_translation(void);
 
 extern void __qcom_hyp_sanitize_btac_predictors(void);
 
+#else /* __ASSEMBLY__ */
+
+.macro get_host_ctxt reg, tmp
+	adr_l	\reg, kvm_host_cpu_state
+	mrs	\tmp, tpidr_el2
+	add	\reg, \reg, \tmp
+.endm
+
+.macro get_vcpu vcpu, ctxt
+	ldr	\vcpu, [\ctxt, #HOST_CONTEXT_VCPU]
+	kern_hyp_va	\vcpu
+.endm
+
 #endif
 
 #endif /* __ARM_KVM_ASM_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 596f8e414a4c..618cfee7206a 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -358,10 +358,15 @@ int kvm_perf_teardown(void);
 
 struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
 
+void __kvm_set_tpidr_el2(u64 tpidr_el2);
+DECLARE_PER_CPU(kvm_cpu_context_t, kvm_host_cpu_state);
+
 static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
 				       unsigned long hyp_stack_ptr,
 				       unsigned long vector_ptr)
 {
+	u64 tpidr_el2;
+
 	/*
 	 * Call initialization code, and switch to the full blown HYP code.
 	 * If the cpucaps haven't been finalized yet, something has gone very
@@ -370,6 +375,16 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
 	 */
 	BUG_ON(!static_branch_likely(&arm64_const_caps_ready));
 	__kvm_call_hyp((void *)pgd_ptr, hyp_stack_ptr, vector_ptr);
+
+	/*
+	 * Calculate the raw per-cpu offset without a translation from the
+	 * kernel's mapping to the linear mapping, and store it in tpidr_el2
+	 * so that we can use adr_l to access per-cpu variables in EL2.
+	 */
+	tpidr_el2 = (u64)this_cpu_ptr(&kvm_host_cpu_state)
+		- (u64)kvm_ksym_ref(kvm_host_cpu_state);
+
+	kvm_call_hyp(__kvm_set_tpidr_el2, tpidr_el2);
 }
 
 static inline void kvm_arch_hardware_unsetup(void) {}
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index 1303e04110cd..78e1b0a70aaf 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -138,6 +138,7 @@ int main(void)
   DEFINE(CPU_FP_REGS,		offsetof(struct kvm_regs, fp_regs));
   DEFINE(VCPU_FPEXC32_EL2,	offsetof(struct kvm_vcpu, arch.ctxt.sys_regs[FPEXC32_EL2]));
   DEFINE(VCPU_HOST_CONTEXT,	offsetof(struct kvm_vcpu, arch.host_cpu_context));
+  DEFINE(HOST_CONTEXT_VCPU,	offsetof(struct kvm_cpu_context, __hyp_running_vcpu));
 #endif
 #ifdef CONFIG_CPU_PM
   DEFINE(CPU_SUSPEND_SZ,	sizeof(struct cpu_suspend_ctx));
diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
index fdd1068ee3a5..1f458f7c3b44 100644
--- a/arch/arm64/kvm/hyp/entry.S
+++ b/arch/arm64/kvm/hyp/entry.S
@@ -62,9 +62,6 @@ ENTRY(__guest_enter)
 	// Store the host regs
 	save_callee_saved_regs x1
 
-	// Store host_ctxt and vcpu for use@exit time
-	stp	x1, x0, [sp, #-16]!
-
 	add	x18, x0, #VCPU_CONTEXT
 
 	// Restore guest regs x0-x17
@@ -118,8 +115,7 @@ ENTRY(__guest_exit)
 	// Store the guest regs x19-x29, lr
 	save_callee_saved_regs x1
 
-	// Restore the host_ctxt from the stack
-	ldr	x2, [sp], #16
+	get_host_ctxt	x2, x3
 
 	// Now restore the host regs
 	restore_callee_saved_regs x2
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index f36464bd57c5..559b4d54bc42 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -57,13 +57,8 @@ ENDPROC(__vhe_hyp_call)
 el1_sync:				// Guest trapped into EL2
 	stp	x0, x1, [sp, #-16]!
 
-alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
-	mrs	x1, esr_el2
-alternative_else
-	mrs	x1, esr_el1
-alternative_endif
-	lsr	x0, x1, #ESR_ELx_EC_SHIFT
-
+	mrs	x0, esr_el2
+	lsr	x0, x0, #ESR_ELx_EC_SHIFT
 	cmp	x0, #ESR_ELx_EC_HVC64
 	ccmp	x0, #ESR_ELx_EC_HVC32, #4, ne
 	b.ne	el1_trap
@@ -117,10 +112,15 @@ el1_hvc_guest:
 	eret
 
 el1_trap:
+	get_host_ctxt	x0, x1
+	get_vcpu	x1, x0
+
+	mrs		x0, esr_el2
+	lsr		x0, x0, #ESR_ELx_EC_SHIFT
 	/*
 	 * x0: ESR_EC
+	 * x1: vcpu pointer
 	 */
-	ldr	x1, [sp, #16 + 8]	// vcpu stored by __guest_enter
 
 	/*
 	 * We trap the first access to the FP/SIMD to save the host context
@@ -138,13 +138,15 @@ alternative_else_nop_endif
 
 el1_irq:
 	stp     x0, x1, [sp, #-16]!
-	ldr	x1, [sp, #16 + 8]
+	get_host_ctxt	x0, x1
+	get_vcpu	x1, x0
 	mov	x0, #ARM_EXCEPTION_IRQ
 	b	__guest_exit
 
 el1_error:
 	stp     x0, x1, [sp, #-16]!
-	ldr	x1, [sp, #16 + 8]
+	get_host_ctxt	x0, x1
+	get_vcpu	x1, x0
 	mov	x0, #ARM_EXCEPTION_EL1_SERROR
 	b	__guest_exit
 
@@ -180,14 +182,7 @@ ENTRY(__hyp_do_panic)
 ENDPROC(__hyp_do_panic)
 
 ENTRY(__hyp_panic)
-	/*
-	 * '=kvm_host_cpu_state' is a host VA from the constant pool, it may
-	 * not be accessible by this address from EL2, hyp_panic() converts
-	 * it with kern_hyp_va() before use.
-	 */
-	ldr	x0, =kvm_host_cpu_state
-	mrs	x1, tpidr_el2
-	add	x0, x0, x1
+	get_host_ctxt x0, x1
 	b	hyp_panic
 ENDPROC(__hyp_panic)
 
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index b991f85c1133..d1749fa0bfc3 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -467,7 +467,7 @@ static hyp_alternate_select(__hyp_call_panic,
 			    __hyp_call_panic_nvhe, __hyp_call_panic_vhe,
 			    ARM64_HAS_VIRT_HOST_EXTN);
 
-void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt)
+void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *host_ctxt)
 {
 	struct kvm_vcpu *vcpu = NULL;
 
@@ -476,9 +476,6 @@ void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt)
 	u64 par = read_sysreg(par_el1);
 
 	if (read_sysreg(vttbr_el2)) {
-		struct kvm_cpu_context *host_ctxt;
-
-		host_ctxt = kern_hyp_va(__host_ctxt);
 		vcpu = host_ctxt->__hyp_running_vcpu;
 		__timer_disable_traps(vcpu);
 		__deactivate_traps(vcpu);
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 2c17afd2be96..43b7dd65e3e6 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -189,3 +189,8 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
 	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
 		write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
 }
+
+void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2)
+{
+	asm("msr tpidr_el2, %0": : "r" (tpidr_el2));
+}
-- 
2.14.2

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

* [PATCH v4 04/40] KVM: arm64: Rework hyp_panic for VHE and non-VHE
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:02   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

VHE actually doesn't rely on clearing the VTTBR when returning to the
host kernel, and that is the current key mechanism of hyp_panic to
figure out how to attempt to return to a state good enough to print a
panic statement.

Therefore, we split the hyp_panic function into two functions, a VHE and
a non-VHE, keeping the non-VHE version intact, but changing the VHE
behavior.

The vttbr_el2 check on VHE doesn't really make that much sense, because
the only situation where we can get here on VHE is when the hypervisor
assembly code actually called into hyp_panic, which only happens when
VBAR_EL2 has been set to the KVM exception vectors.  On VHE, we can
always safely disable the traps and restore the host registers at this
point, so we simply do that unconditionally and call into the panic
function directly.

Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v1:
     - Fixed typos in the commit message
     - Still use the generic __deactivte_traps() function in the hyp panic
       code until we rework that logic later.

 arch/arm64/kvm/hyp/switch.c | 42 +++++++++++++++++++++++-------------------
 1 file changed, 23 insertions(+), 19 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index d1749fa0bfc3..079bb5243f0c 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -437,10 +437,20 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 static const char __hyp_panic_string[] = "HYP panic:\nPS:%08llx PC:%016llx ESR:%08llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%p\n";
 
 static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par,
-					     struct kvm_vcpu *vcpu)
+					     struct kvm_cpu_context *__host_ctxt)
 {
+	struct kvm_vcpu *vcpu;
 	unsigned long str_va;
 
+	vcpu = __host_ctxt->__hyp_running_vcpu;
+
+	if (read_sysreg(vttbr_el2)) {
+		__timer_disable_traps(vcpu);
+		__deactivate_traps(vcpu);
+		__deactivate_vm(vcpu);
+		__sysreg_restore_host_state(__host_ctxt);
+	}
+
 	/*
 	 * Force the panic string to be loaded from the literal pool,
 	 * making sure it is a kernel address and not a PC-relative
@@ -454,37 +464,31 @@ static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par,
 		       read_sysreg(hpfar_el2), par, vcpu);
 }
 
-static void __hyp_text __hyp_call_panic_vhe(u64 spsr, u64 elr, u64 par,
-					    struct kvm_vcpu *vcpu)
+static void __hyp_call_panic_vhe(u64 spsr, u64 elr, u64 par,
+				 struct kvm_cpu_context *host_ctxt)
 {
+	struct kvm_vcpu *vcpu;
+	vcpu = host_ctxt->__hyp_running_vcpu;
+
+	__deactivate_traps(vcpu);
+	__sysreg_restore_host_state(host_ctxt);
+
 	panic(__hyp_panic_string,
 	      spsr,  elr,
 	      read_sysreg_el2(esr),   read_sysreg_el2(far),
 	      read_sysreg(hpfar_el2), par, vcpu);
 }
 
-static hyp_alternate_select(__hyp_call_panic,
-			    __hyp_call_panic_nvhe, __hyp_call_panic_vhe,
-			    ARM64_HAS_VIRT_HOST_EXTN);
-
 void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *host_ctxt)
 {
-	struct kvm_vcpu *vcpu = NULL;
-
 	u64 spsr = read_sysreg_el2(spsr);
 	u64 elr = read_sysreg_el2(elr);
 	u64 par = read_sysreg(par_el1);
 
-	if (read_sysreg(vttbr_el2)) {
-		vcpu = host_ctxt->__hyp_running_vcpu;
-		__timer_disable_traps(vcpu);
-		__deactivate_traps(vcpu);
-		__deactivate_vm(vcpu);
-		__sysreg_restore_host_state(host_ctxt);
-	}
-
-	/* Call panic for real */
-	__hyp_call_panic()(spsr, elr, par, vcpu);
+	if (!has_vhe())
+		__hyp_call_panic_nvhe(spsr, elr, par, host_ctxt);
+	else
+		__hyp_call_panic_vhe(spsr, elr, par, host_ctxt);
 
 	unreachable();
 }
-- 
2.14.2

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

* [PATCH v4 04/40] KVM: arm64: Rework hyp_panic for VHE and non-VHE
@ 2018-02-15 21:02   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:02 UTC (permalink / raw)
  To: linux-arm-kernel

VHE actually doesn't rely on clearing the VTTBR when returning to the
host kernel, and that is the current key mechanism of hyp_panic to
figure out how to attempt to return to a state good enough to print a
panic statement.

Therefore, we split the hyp_panic function into two functions, a VHE and
a non-VHE, keeping the non-VHE version intact, but changing the VHE
behavior.

The vttbr_el2 check on VHE doesn't really make that much sense, because
the only situation where we can get here on VHE is when the hypervisor
assembly code actually called into hyp_panic, which only happens when
VBAR_EL2 has been set to the KVM exception vectors.  On VHE, we can
always safely disable the traps and restore the host registers at this
point, so we simply do that unconditionally and call into the panic
function directly.

Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v1:
     - Fixed typos in the commit message
     - Still use the generic __deactivte_traps() function in the hyp panic
       code until we rework that logic later.

 arch/arm64/kvm/hyp/switch.c | 42 +++++++++++++++++++++++-------------------
 1 file changed, 23 insertions(+), 19 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index d1749fa0bfc3..079bb5243f0c 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -437,10 +437,20 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 static const char __hyp_panic_string[] = "HYP panic:\nPS:%08llx PC:%016llx ESR:%08llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%p\n";
 
 static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par,
-					     struct kvm_vcpu *vcpu)
+					     struct kvm_cpu_context *__host_ctxt)
 {
+	struct kvm_vcpu *vcpu;
 	unsigned long str_va;
 
+	vcpu = __host_ctxt->__hyp_running_vcpu;
+
+	if (read_sysreg(vttbr_el2)) {
+		__timer_disable_traps(vcpu);
+		__deactivate_traps(vcpu);
+		__deactivate_vm(vcpu);
+		__sysreg_restore_host_state(__host_ctxt);
+	}
+
 	/*
 	 * Force the panic string to be loaded from the literal pool,
 	 * making sure it is a kernel address and not a PC-relative
@@ -454,37 +464,31 @@ static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par,
 		       read_sysreg(hpfar_el2), par, vcpu);
 }
 
-static void __hyp_text __hyp_call_panic_vhe(u64 spsr, u64 elr, u64 par,
-					    struct kvm_vcpu *vcpu)
+static void __hyp_call_panic_vhe(u64 spsr, u64 elr, u64 par,
+				 struct kvm_cpu_context *host_ctxt)
 {
+	struct kvm_vcpu *vcpu;
+	vcpu = host_ctxt->__hyp_running_vcpu;
+
+	__deactivate_traps(vcpu);
+	__sysreg_restore_host_state(host_ctxt);
+
 	panic(__hyp_panic_string,
 	      spsr,  elr,
 	      read_sysreg_el2(esr),   read_sysreg_el2(far),
 	      read_sysreg(hpfar_el2), par, vcpu);
 }
 
-static hyp_alternate_select(__hyp_call_panic,
-			    __hyp_call_panic_nvhe, __hyp_call_panic_vhe,
-			    ARM64_HAS_VIRT_HOST_EXTN);
-
 void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *host_ctxt)
 {
-	struct kvm_vcpu *vcpu = NULL;
-
 	u64 spsr = read_sysreg_el2(spsr);
 	u64 elr = read_sysreg_el2(elr);
 	u64 par = read_sysreg(par_el1);
 
-	if (read_sysreg(vttbr_el2)) {
-		vcpu = host_ctxt->__hyp_running_vcpu;
-		__timer_disable_traps(vcpu);
-		__deactivate_traps(vcpu);
-		__deactivate_vm(vcpu);
-		__sysreg_restore_host_state(host_ctxt);
-	}
-
-	/* Call panic for real */
-	__hyp_call_panic()(spsr, elr, par, vcpu);
+	if (!has_vhe())
+		__hyp_call_panic_nvhe(spsr, elr, par, host_ctxt);
+	else
+		__hyp_call_panic_vhe(spsr, elr, par, host_ctxt);
 
 	unreachable();
 }
-- 
2.14.2

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

* [PATCH v4 05/40] KVM: arm64: Move HCR_INT_OVERRIDE to default HCR_EL2 guest flag
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:02   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

From: Shih-Wei Li <shihwei@cs.columbia.edu>

We always set the IMO and FMO bits in the HCR_EL2 when running the
guest, regardless if we use the vgic or not.  By moving these flags to
HCR_GUEST_FLAGS we can avoid one of the extra save/restore operations of
HCR_EL2 in the world switch code, and we can also soon get rid of the
other one.

This is safe, because even though the IMO and FMO bits control both
taking the interrupts to EL2 and remapping ICC_*_EL1 to ICV_*_EL1 when
executed at EL1, as long as we ensure that these bits are clear when
running the EL1 host, we're OK, because we reset the HCR_EL2 to only
have the HCR_RW bit set when returning to EL1 on non-VHE systems.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Shih-Wei Li <shihwei@cs.columbia.edu>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v3:
     - Slightly reworded the commit message

 arch/arm64/include/asm/kvm_arm.h | 4 ++--
 arch/arm64/kvm/hyp/switch.c      | 3 ---
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index b0c84171e6a3..f055be241f4d 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -81,9 +81,9 @@
  */
 #define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
 			 HCR_TVM | HCR_BSU_IS | HCR_FB | HCR_TAC | \
-			 HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW)
+			 HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW | \
+			 HCR_FMO | HCR_IMO)
 #define HCR_VIRT_EXCP_MASK (HCR_VSE | HCR_VI | HCR_VF)
-#define HCR_INT_OVERRIDE   (HCR_FMO | HCR_IMO)
 #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)
 
 /* TCR_EL2 Registers bits */
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 079bb5243f0c..53f3e3486a19 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -174,8 +174,6 @@ static void __hyp_text __vgic_save_state(struct kvm_vcpu *vcpu)
 		__vgic_v3_save_state(vcpu);
 	else
 		__vgic_v2_save_state(vcpu);
-
-	write_sysreg(read_sysreg(hcr_el2) & ~HCR_INT_OVERRIDE, hcr_el2);
 }
 
 static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
@@ -183,7 +181,6 @@ static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
 	u64 val;
 
 	val = read_sysreg(hcr_el2);
-	val |= 	HCR_INT_OVERRIDE;
 	val |= vcpu->arch.irq_lines;
 	write_sysreg(val, hcr_el2);
 
-- 
2.14.2

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

* [PATCH v4 05/40] KVM: arm64: Move HCR_INT_OVERRIDE to default HCR_EL2 guest flag
@ 2018-02-15 21:02   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:02 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shih-Wei Li <shihwei@cs.columbia.edu>

We always set the IMO and FMO bits in the HCR_EL2 when running the
guest, regardless if we use the vgic or not.  By moving these flags to
HCR_GUEST_FLAGS we can avoid one of the extra save/restore operations of
HCR_EL2 in the world switch code, and we can also soon get rid of the
other one.

This is safe, because even though the IMO and FMO bits control both
taking the interrupts to EL2 and remapping ICC_*_EL1 to ICV_*_EL1 when
executed at EL1, as long as we ensure that these bits are clear when
running the EL1 host, we're OK, because we reset the HCR_EL2 to only
have the HCR_RW bit set when returning to EL1 on non-VHE systems.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Shih-Wei Li <shihwei@cs.columbia.edu>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v3:
     - Slightly reworded the commit message

 arch/arm64/include/asm/kvm_arm.h | 4 ++--
 arch/arm64/kvm/hyp/switch.c      | 3 ---
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index b0c84171e6a3..f055be241f4d 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -81,9 +81,9 @@
  */
 #define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
 			 HCR_TVM | HCR_BSU_IS | HCR_FB | HCR_TAC | \
-			 HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW)
+			 HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW | \
+			 HCR_FMO | HCR_IMO)
 #define HCR_VIRT_EXCP_MASK (HCR_VSE | HCR_VI | HCR_VF)
-#define HCR_INT_OVERRIDE   (HCR_FMO | HCR_IMO)
 #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)
 
 /* TCR_EL2 Registers bits */
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 079bb5243f0c..53f3e3486a19 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -174,8 +174,6 @@ static void __hyp_text __vgic_save_state(struct kvm_vcpu *vcpu)
 		__vgic_v3_save_state(vcpu);
 	else
 		__vgic_v2_save_state(vcpu);
-
-	write_sysreg(read_sysreg(hcr_el2) & ~HCR_INT_OVERRIDE, hcr_el2);
 }
 
 static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
@@ -183,7 +181,6 @@ static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
 	u64 val;
 
 	val = read_sysreg(hcr_el2);
-	val |= 	HCR_INT_OVERRIDE;
 	val |= vcpu->arch.irq_lines;
 	write_sysreg(val, hcr_el2);
 
-- 
2.14.2

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

* [PATCH v4 06/40] KVM: arm/arm64: Get rid of vcpu->arch.irq_lines
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:02   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

We currently have a separate read-modify-write of the HCR_EL2 on entry
to the guest for the sole purpose of setting the VF and VI bits, if set.
Since this is most rarely the case (only when using userspace IRQ chip
and interrupts are in flight), let's get rid of this operation and
instead modify the bits in the vcpu->arch.hcr[_el2] directly when
needed.

Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm/include/asm/kvm_emulate.h   |  9 ++-------
 arch/arm/include/asm/kvm_host.h      |  3 ---
 arch/arm/kvm/emulate.c               |  2 +-
 arch/arm/kvm/hyp/switch.c            |  2 +-
 arch/arm64/include/asm/kvm_emulate.h |  9 ++-------
 arch/arm64/include/asm/kvm_host.h    |  3 ---
 arch/arm64/kvm/hyp/switch.c          |  6 ------
 arch/arm64/kvm/inject_fault.c        |  2 +-
 virt/kvm/arm/arm.c                   | 11 ++++++-----
 virt/kvm/arm/mmu.c                   |  6 +++---
 10 files changed, 16 insertions(+), 37 deletions(-)

diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h
index 9003bd19cb70..e27caa4b47a1 100644
--- a/arch/arm/include/asm/kvm_emulate.h
+++ b/arch/arm/include/asm/kvm_emulate.h
@@ -92,14 +92,9 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
 	vcpu->arch.hcr = HCR_GUEST_MASK;
 }
 
-static inline unsigned long vcpu_get_hcr(const struct kvm_vcpu *vcpu)
+static inline unsigned long *vcpu_hcr(const struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.hcr;
-}
-
-static inline void vcpu_set_hcr(struct kvm_vcpu *vcpu, unsigned long hcr)
-{
-	vcpu->arch.hcr = hcr;
+	return (unsigned long *)&vcpu->arch.hcr;
 }
 
 static inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu)
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 248b930563e5..6137195ab815 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -155,9 +155,6 @@ struct kvm_vcpu_arch {
 	/* HYP trapping configuration */
 	u32 hcr;
 
-	/* Interrupt related fields */
-	u32 irq_lines;		/* IRQ and FIQ levels */
-
 	/* Exception Information */
 	struct kvm_vcpu_fault_info fault;
 
diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
index cdff963f133a..fa501bf437f3 100644
--- a/arch/arm/kvm/emulate.c
+++ b/arch/arm/kvm/emulate.c
@@ -174,5 +174,5 @@ unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu)
  */
 void kvm_inject_vabt(struct kvm_vcpu *vcpu)
 {
-	vcpu_set_hcr(vcpu, vcpu_get_hcr(vcpu) | HCR_VA);
+	*vcpu_hcr(vcpu) |= HCR_VA;
 }
diff --git a/arch/arm/kvm/hyp/switch.c b/arch/arm/kvm/hyp/switch.c
index ae45ae96aac2..e86679daddff 100644
--- a/arch/arm/kvm/hyp/switch.c
+++ b/arch/arm/kvm/hyp/switch.c
@@ -44,7 +44,7 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu, u32 *fpexc_host)
 		isb();
 	}
 
-	write_sysreg(vcpu->arch.hcr | vcpu->arch.irq_lines, HCR);
+	write_sysreg(vcpu->arch.hcr, HCR);
 	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
 	write_sysreg(HSTR_T(15), HSTR);
 	write_sysreg(HCPTR_TTA | HCPTR_TCP(10) | HCPTR_TCP(11), HCPTR);
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 4610bc818097..9ee316b962c8 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -69,14 +69,9 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
 		vcpu->arch.hcr_el2 |= HCR_TID3;
 }
 
-static inline unsigned long vcpu_get_hcr(struct kvm_vcpu *vcpu)
+static inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.hcr_el2;
-}
-
-static inline void vcpu_set_hcr(struct kvm_vcpu *vcpu, unsigned long hcr)
-{
-	vcpu->arch.hcr_el2 = hcr;
+	return (unsigned long *)&vcpu->arch.hcr_el2;
 }
 
 static inline void vcpu_set_vsesr(struct kvm_vcpu *vcpu, u64 vsesr)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 618cfee7206a..b027a7f025d4 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -272,9 +272,6 @@ struct kvm_vcpu_arch {
 	/* IO related fields */
 	struct kvm_decode mmio_decode;
 
-	/* Interrupt related fields */
-	u64 irq_lines;		/* IRQ and FIQ levels */
-
 	/* Cache some mmu pages needed inside spinlock regions */
 	struct kvm_mmu_memory_cache mmu_page_cache;
 
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 53f3e3486a19..b51638490d85 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -178,12 +178,6 @@ static void __hyp_text __vgic_save_state(struct kvm_vcpu *vcpu)
 
 static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
 {
-	u64 val;
-
-	val = read_sysreg(hcr_el2);
-	val |= vcpu->arch.irq_lines;
-	write_sysreg(val, hcr_el2);
-
 	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		__vgic_v3_restore_state(vcpu);
 	else
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index 60666a056944..c1e179d34e6a 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -167,7 +167,7 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu)
 static void pend_guest_serror(struct kvm_vcpu *vcpu, u64 esr)
 {
 	vcpu_set_vsesr(vcpu, esr);
-	vcpu_set_hcr(vcpu, vcpu_get_hcr(vcpu) | HCR_VSE);
+	*vcpu_hcr(vcpu) |= HCR_VSE;
 }
 
 /**
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 932e61858c55..49d13510e9c2 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -420,7 +420,8 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
  */
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
 {
-	return ((!!v->arch.irq_lines || kvm_vgic_vcpu_pending_irq(v))
+	bool irq_lines = *vcpu_hcr(v) & (HCR_VI | HCR_VF);
+	return ((irq_lines || kvm_vgic_vcpu_pending_irq(v))
 		&& !v->arch.power_off && !v->arch.pause);
 }
 
@@ -814,18 +815,18 @@ static int vcpu_interrupt_line(struct kvm_vcpu *vcpu, int number, bool level)
 {
 	int bit_index;
 	bool set;
-	unsigned long *ptr;
+	unsigned long *hcr;
 
 	if (number == KVM_ARM_IRQ_CPU_IRQ)
 		bit_index = __ffs(HCR_VI);
 	else /* KVM_ARM_IRQ_CPU_FIQ */
 		bit_index = __ffs(HCR_VF);
 
-	ptr = (unsigned long *)&vcpu->arch.irq_lines;
+	hcr = vcpu_hcr(vcpu);
 	if (level)
-		set = test_and_set_bit(bit_index, ptr);
+		set = test_and_set_bit(bit_index, hcr);
 	else
-		set = test_and_clear_bit(bit_index, ptr);
+		set = test_and_clear_bit(bit_index, hcr);
 
 	/*
 	 * If we didn't change anything, no need to wake up or kick other CPUs
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index ec62d1cccab7..9ebff8e530f9 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -2035,7 +2035,7 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
  */
 void kvm_set_way_flush(struct kvm_vcpu *vcpu)
 {
-	unsigned long hcr = vcpu_get_hcr(vcpu);
+	unsigned long hcr = *vcpu_hcr(vcpu);
 
 	/*
 	 * If this is the first time we do a S/W operation
@@ -2050,7 +2050,7 @@ void kvm_set_way_flush(struct kvm_vcpu *vcpu)
 		trace_kvm_set_way_flush(*vcpu_pc(vcpu),
 					vcpu_has_cache_enabled(vcpu));
 		stage2_flush_vm(vcpu->kvm);
-		vcpu_set_hcr(vcpu, hcr | HCR_TVM);
+		*vcpu_hcr(vcpu) = hcr | HCR_TVM;
 	}
 }
 
@@ -2068,7 +2068,7 @@ void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled)
 
 	/* Caches are now on, stop trapping VM ops (until a S/W op) */
 	if (now_enabled)
-		vcpu_set_hcr(vcpu, vcpu_get_hcr(vcpu) & ~HCR_TVM);
+		*vcpu_hcr(vcpu) &= ~HCR_TVM;
 
 	trace_kvm_toggle_cache(*vcpu_pc(vcpu), was_enabled, now_enabled);
 }
-- 
2.14.2

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

* [PATCH v4 06/40] KVM: arm/arm64: Get rid of vcpu->arch.irq_lines
@ 2018-02-15 21:02   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:02 UTC (permalink / raw)
  To: linux-arm-kernel

We currently have a separate read-modify-write of the HCR_EL2 on entry
to the guest for the sole purpose of setting the VF and VI bits, if set.
Since this is most rarely the case (only when using userspace IRQ chip
and interrupts are in flight), let's get rid of this operation and
instead modify the bits in the vcpu->arch.hcr[_el2] directly when
needed.

Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm/include/asm/kvm_emulate.h   |  9 ++-------
 arch/arm/include/asm/kvm_host.h      |  3 ---
 arch/arm/kvm/emulate.c               |  2 +-
 arch/arm/kvm/hyp/switch.c            |  2 +-
 arch/arm64/include/asm/kvm_emulate.h |  9 ++-------
 arch/arm64/include/asm/kvm_host.h    |  3 ---
 arch/arm64/kvm/hyp/switch.c          |  6 ------
 arch/arm64/kvm/inject_fault.c        |  2 +-
 virt/kvm/arm/arm.c                   | 11 ++++++-----
 virt/kvm/arm/mmu.c                   |  6 +++---
 10 files changed, 16 insertions(+), 37 deletions(-)

diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h
index 9003bd19cb70..e27caa4b47a1 100644
--- a/arch/arm/include/asm/kvm_emulate.h
+++ b/arch/arm/include/asm/kvm_emulate.h
@@ -92,14 +92,9 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
 	vcpu->arch.hcr = HCR_GUEST_MASK;
 }
 
-static inline unsigned long vcpu_get_hcr(const struct kvm_vcpu *vcpu)
+static inline unsigned long *vcpu_hcr(const struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.hcr;
-}
-
-static inline void vcpu_set_hcr(struct kvm_vcpu *vcpu, unsigned long hcr)
-{
-	vcpu->arch.hcr = hcr;
+	return (unsigned long *)&vcpu->arch.hcr;
 }
 
 static inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu)
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 248b930563e5..6137195ab815 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -155,9 +155,6 @@ struct kvm_vcpu_arch {
 	/* HYP trapping configuration */
 	u32 hcr;
 
-	/* Interrupt related fields */
-	u32 irq_lines;		/* IRQ and FIQ levels */
-
 	/* Exception Information */
 	struct kvm_vcpu_fault_info fault;
 
diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
index cdff963f133a..fa501bf437f3 100644
--- a/arch/arm/kvm/emulate.c
+++ b/arch/arm/kvm/emulate.c
@@ -174,5 +174,5 @@ unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu)
  */
 void kvm_inject_vabt(struct kvm_vcpu *vcpu)
 {
-	vcpu_set_hcr(vcpu, vcpu_get_hcr(vcpu) | HCR_VA);
+	*vcpu_hcr(vcpu) |= HCR_VA;
 }
diff --git a/arch/arm/kvm/hyp/switch.c b/arch/arm/kvm/hyp/switch.c
index ae45ae96aac2..e86679daddff 100644
--- a/arch/arm/kvm/hyp/switch.c
+++ b/arch/arm/kvm/hyp/switch.c
@@ -44,7 +44,7 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu, u32 *fpexc_host)
 		isb();
 	}
 
-	write_sysreg(vcpu->arch.hcr | vcpu->arch.irq_lines, HCR);
+	write_sysreg(vcpu->arch.hcr, HCR);
 	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
 	write_sysreg(HSTR_T(15), HSTR);
 	write_sysreg(HCPTR_TTA | HCPTR_TCP(10) | HCPTR_TCP(11), HCPTR);
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 4610bc818097..9ee316b962c8 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -69,14 +69,9 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
 		vcpu->arch.hcr_el2 |= HCR_TID3;
 }
 
-static inline unsigned long vcpu_get_hcr(struct kvm_vcpu *vcpu)
+static inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu)
 {
-	return vcpu->arch.hcr_el2;
-}
-
-static inline void vcpu_set_hcr(struct kvm_vcpu *vcpu, unsigned long hcr)
-{
-	vcpu->arch.hcr_el2 = hcr;
+	return (unsigned long *)&vcpu->arch.hcr_el2;
 }
 
 static inline void vcpu_set_vsesr(struct kvm_vcpu *vcpu, u64 vsesr)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 618cfee7206a..b027a7f025d4 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -272,9 +272,6 @@ struct kvm_vcpu_arch {
 	/* IO related fields */
 	struct kvm_decode mmio_decode;
 
-	/* Interrupt related fields */
-	u64 irq_lines;		/* IRQ and FIQ levels */
-
 	/* Cache some mmu pages needed inside spinlock regions */
 	struct kvm_mmu_memory_cache mmu_page_cache;
 
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 53f3e3486a19..b51638490d85 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -178,12 +178,6 @@ static void __hyp_text __vgic_save_state(struct kvm_vcpu *vcpu)
 
 static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
 {
-	u64 val;
-
-	val = read_sysreg(hcr_el2);
-	val |= vcpu->arch.irq_lines;
-	write_sysreg(val, hcr_el2);
-
 	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		__vgic_v3_restore_state(vcpu);
 	else
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index 60666a056944..c1e179d34e6a 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -167,7 +167,7 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu)
 static void pend_guest_serror(struct kvm_vcpu *vcpu, u64 esr)
 {
 	vcpu_set_vsesr(vcpu, esr);
-	vcpu_set_hcr(vcpu, vcpu_get_hcr(vcpu) | HCR_VSE);
+	*vcpu_hcr(vcpu) |= HCR_VSE;
 }
 
 /**
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 932e61858c55..49d13510e9c2 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -420,7 +420,8 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
  */
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
 {
-	return ((!!v->arch.irq_lines || kvm_vgic_vcpu_pending_irq(v))
+	bool irq_lines = *vcpu_hcr(v) & (HCR_VI | HCR_VF);
+	return ((irq_lines || kvm_vgic_vcpu_pending_irq(v))
 		&& !v->arch.power_off && !v->arch.pause);
 }
 
@@ -814,18 +815,18 @@ static int vcpu_interrupt_line(struct kvm_vcpu *vcpu, int number, bool level)
 {
 	int bit_index;
 	bool set;
-	unsigned long *ptr;
+	unsigned long *hcr;
 
 	if (number == KVM_ARM_IRQ_CPU_IRQ)
 		bit_index = __ffs(HCR_VI);
 	else /* KVM_ARM_IRQ_CPU_FIQ */
 		bit_index = __ffs(HCR_VF);
 
-	ptr = (unsigned long *)&vcpu->arch.irq_lines;
+	hcr = vcpu_hcr(vcpu);
 	if (level)
-		set = test_and_set_bit(bit_index, ptr);
+		set = test_and_set_bit(bit_index, hcr);
 	else
-		set = test_and_clear_bit(bit_index, ptr);
+		set = test_and_clear_bit(bit_index, hcr);
 
 	/*
 	 * If we didn't change anything, no need to wake up or kick other CPUs
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index ec62d1cccab7..9ebff8e530f9 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -2035,7 +2035,7 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
  */
 void kvm_set_way_flush(struct kvm_vcpu *vcpu)
 {
-	unsigned long hcr = vcpu_get_hcr(vcpu);
+	unsigned long hcr = *vcpu_hcr(vcpu);
 
 	/*
 	 * If this is the first time we do a S/W operation
@@ -2050,7 +2050,7 @@ void kvm_set_way_flush(struct kvm_vcpu *vcpu)
 		trace_kvm_set_way_flush(*vcpu_pc(vcpu),
 					vcpu_has_cache_enabled(vcpu));
 		stage2_flush_vm(vcpu->kvm);
-		vcpu_set_hcr(vcpu, hcr | HCR_TVM);
+		*vcpu_hcr(vcpu) = hcr | HCR_TVM;
 	}
 }
 
@@ -2068,7 +2068,7 @@ void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled)
 
 	/* Caches are now on, stop trapping VM ops (until a S/W op) */
 	if (now_enabled)
-		vcpu_set_hcr(vcpu, vcpu_get_hcr(vcpu) & ~HCR_TVM);
+		*vcpu_hcr(vcpu) &= ~HCR_TVM;
 
 	trace_kvm_toggle_cache(*vcpu_pc(vcpu), was_enabled, now_enabled);
 }
-- 
2.14.2

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

* [PATCH v4 07/40] KVM: arm/arm64: Add kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:02   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:02 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

As we are about to move a bunch of save/restore logic for VHE kernels to
the load and put functions, we need some infrastructure to do this.

Reviewed-by: Andrew Jones <drjones@redhat.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v1:
     - Reworded comments as suggested by Drew

 arch/arm/include/asm/kvm_host.h   |  3 +++
 arch/arm64/include/asm/kvm_host.h |  3 +++
 arch/arm64/kvm/hyp/sysreg-sr.c    | 30 ++++++++++++++++++++++++++++++
 virt/kvm/arm/arm.c                |  2 ++
 4 files changed, 38 insertions(+)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 6137195ab815..c6a749568dd6 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -312,4 +312,7 @@ static inline bool kvm_arm_harden_branch_predictor(void)
 	return false;
 }
 
+static inline void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu) {}
+static inline void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu) {}
+
 #endif /* __ARM_KVM_HOST_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index b027a7f025d4..c30fc96992df 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -435,4 +435,7 @@ static inline bool kvm_arm_harden_branch_predictor(void)
 	return cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR);
 }
 
+void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu);
+void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu);
+
 #endif /* __ARM64_KVM_HOST_H__ */
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 43b7dd65e3e6..434f0fc9cfb3 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -190,6 +190,36 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
 		write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
 }
 
+/**
+ * kvm_vcpu_load_sysregs - Load guest system registers to the physical CPU
+ *
+ * @vcpu: The VCPU pointer
+ *
+ * Load system registers that do not affect the host's execution, for
+ * example EL1 system registers on a VHE system where the host kernel
+ * runs at EL2.  This function is called from KVM's vcpu_load() function
+ * and loading system register state early avoids having to load them on
+ * every entry to the VM.
+ */
+void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
+{
+}
+
+/**
+ * kvm_vcpu_put_sysregs - Restore host system registers to the physical CPU
+ *
+ * @vcpu: The VCPU pointer
+ *
+ * Save guest system registers that do not affect the host's execution, for
+ * example EL1 system registers on a VHE system where the host kernel
+ * runs at EL2.  This function is called from KVM's vcpu_put() function
+ * and deferring saving system register state until we're no longer running the
+ * VCPU avoids having to save them on every exit from the VM.
+ */
+void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
+{
+}
+
 void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2)
 {
 	asm("msr tpidr_el2, %0": : "r" (tpidr_el2));
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 49d13510e9c2..2062d9357971 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -362,10 +362,12 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 	kvm_arm_set_running_vcpu(vcpu);
 	kvm_vgic_load(vcpu);
 	kvm_timer_vcpu_load(vcpu);
+	kvm_vcpu_load_sysregs(vcpu);
 }
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 {
+	kvm_vcpu_put_sysregs(vcpu);
 	kvm_timer_vcpu_put(vcpu);
 	kvm_vgic_put(vcpu);
 
-- 
2.14.2

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

* [PATCH v4 07/40] KVM: arm/arm64: Add kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs
@ 2018-02-15 21:02   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:02 UTC (permalink / raw)
  To: linux-arm-kernel

As we are about to move a bunch of save/restore logic for VHE kernels to
the load and put functions, we need some infrastructure to do this.

Reviewed-by: Andrew Jones <drjones@redhat.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v1:
     - Reworded comments as suggested by Drew

 arch/arm/include/asm/kvm_host.h   |  3 +++
 arch/arm64/include/asm/kvm_host.h |  3 +++
 arch/arm64/kvm/hyp/sysreg-sr.c    | 30 ++++++++++++++++++++++++++++++
 virt/kvm/arm/arm.c                |  2 ++
 4 files changed, 38 insertions(+)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 6137195ab815..c6a749568dd6 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -312,4 +312,7 @@ static inline bool kvm_arm_harden_branch_predictor(void)
 	return false;
 }
 
+static inline void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu) {}
+static inline void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu) {}
+
 #endif /* __ARM_KVM_HOST_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index b027a7f025d4..c30fc96992df 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -435,4 +435,7 @@ static inline bool kvm_arm_harden_branch_predictor(void)
 	return cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR);
 }
 
+void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu);
+void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu);
+
 #endif /* __ARM64_KVM_HOST_H__ */
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 43b7dd65e3e6..434f0fc9cfb3 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -190,6 +190,36 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
 		write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
 }
 
+/**
+ * kvm_vcpu_load_sysregs - Load guest system registers to the physical CPU
+ *
+ * @vcpu: The VCPU pointer
+ *
+ * Load system registers that do not affect the host's execution, for
+ * example EL1 system registers on a VHE system where the host kernel
+ * runs at EL2.  This function is called from KVM's vcpu_load() function
+ * and loading system register state early avoids having to load them on
+ * every entry to the VM.
+ */
+void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
+{
+}
+
+/**
+ * kvm_vcpu_put_sysregs - Restore host system registers to the physical CPU
+ *
+ * @vcpu: The VCPU pointer
+ *
+ * Save guest system registers that do not affect the host's execution, for
+ * example EL1 system registers on a VHE system where the host kernel
+ * runs at EL2.  This function is called from KVM's vcpu_put() function
+ * and deferring saving system register state until we're no longer running the
+ * VCPU avoids having to save them on every exit from the VM.
+ */
+void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
+{
+}
+
 void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2)
 {
 	asm("msr tpidr_el2, %0": : "r" (tpidr_el2));
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 49d13510e9c2..2062d9357971 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -362,10 +362,12 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 	kvm_arm_set_running_vcpu(vcpu);
 	kvm_vgic_load(vcpu);
 	kvm_timer_vcpu_load(vcpu);
+	kvm_vcpu_load_sysregs(vcpu);
 }
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 {
+	kvm_vcpu_put_sysregs(vcpu);
 	kvm_timer_vcpu_put(vcpu);
 	kvm_vgic_put(vcpu);
 
-- 
2.14.2

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

* [PATCH v4 08/40] KVM: arm/arm64: Introduce vcpu_el1_is_32bit
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

We have numerous checks around that checks if the HCR_EL2 has the RW bit
set to figure out if we're running an AArch64 or AArch32 VM.  In some
cases, directly checking the RW bit (given its unintuitive name), is a
bit confusing, and that's not going to improve as we move logic around
for the following patches that optimize KVM on AArch64 hosts with VHE.

Therefore, introduce a helper, vcpu_el1_is_32bit, and replace existing
direct checks of HCR_EL2.RW with the helper.

Reviewed-by: Julien Grall <julien.grall@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v2:
     - New patch
    
    Changes since v1:
     - Reworded comments as suggested by Drew

 arch/arm64/include/asm/kvm_emulate.h |  7 ++++++-
 arch/arm64/kvm/hyp/switch.c          | 11 +++++------
 arch/arm64/kvm/hyp/sysreg-sr.c       |  5 +++--
 arch/arm64/kvm/inject_fault.c        |  6 +++---
 4 files changed, 17 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 9ee316b962c8..3cc535591bdf 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -45,6 +45,11 @@ void kvm_inject_undef32(struct kvm_vcpu *vcpu);
 void kvm_inject_dabt32(struct kvm_vcpu *vcpu, unsigned long addr);
 void kvm_inject_pabt32(struct kvm_vcpu *vcpu, unsigned long addr);
 
+static inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
+{
+	return !(vcpu->arch.hcr_el2 & HCR_RW);
+}
+
 static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
 {
 	vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
@@ -65,7 +70,7 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
 	 * For now this is conditional, since no AArch32 feature regs
 	 * are currently virtualised.
 	 */
-	if (vcpu->arch.hcr_el2 & HCR_RW)
+	if (!vcpu_el1_is_32bit(vcpu))
 		vcpu->arch.hcr_el2 |= HCR_TID3;
 }
 
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index b51638490d85..fbab9752a9f4 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -74,7 +74,7 @@ static hyp_alternate_select(__activate_traps_arch,
 
 static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
 {
-	u64 val;
+	u64 hcr = vcpu->arch.hcr_el2;
 
 	/*
 	 * We are about to set CPTR_EL2.TFP to trap all floating point
@@ -85,17 +85,16 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
 	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
 	 * it will cause an exception.
 	 */
-	val = vcpu->arch.hcr_el2;
-
-	if (!(val & HCR_RW) && system_supports_fpsimd()) {
+	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
 		write_sysreg(1 << 30, fpexc32_el2);
 		isb();
 	}
-	write_sysreg(val, hcr_el2);
 
-	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (val & HCR_VSE))
+	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
 		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
 
+	write_sysreg(hcr, hcr_el2);
+
 	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
 	write_sysreg(1 << 15, hstr_el2);
 	/*
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 434f0fc9cfb3..99fc60516103 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -19,6 +19,7 @@
 #include <linux/kvm_host.h>
 
 #include <asm/kvm_asm.h>
+#include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
 
 /* Yes, this does nothing, on purpose */
@@ -147,7 +148,7 @@ void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
 {
 	u64 *spsr, *sysreg;
 
-	if (read_sysreg(hcr_el2) & HCR_RW)
+	if (!vcpu_el1_is_32bit(vcpu))
 		return;
 
 	spsr = vcpu->arch.ctxt.gp_regs.spsr;
@@ -172,7 +173,7 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
 {
 	u64 *spsr, *sysreg;
 
-	if (read_sysreg(hcr_el2) & HCR_RW)
+	if (!vcpu_el1_is_32bit(vcpu))
 		return;
 
 	spsr = vcpu->arch.ctxt.gp_regs.spsr;
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index c1e179d34e6a..30a3f58cdb7b 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -128,7 +128,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
  */
 void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
 {
-	if (!(vcpu->arch.hcr_el2 & HCR_RW))
+	if (vcpu_el1_is_32bit(vcpu))
 		kvm_inject_dabt32(vcpu, addr);
 	else
 		inject_abt64(vcpu, false, addr);
@@ -144,7 +144,7 @@ void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
  */
 void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
 {
-	if (!(vcpu->arch.hcr_el2 & HCR_RW))
+	if (vcpu_el1_is_32bit(vcpu))
 		kvm_inject_pabt32(vcpu, addr);
 	else
 		inject_abt64(vcpu, true, addr);
@@ -158,7 +158,7 @@ void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
  */
 void kvm_inject_undefined(struct kvm_vcpu *vcpu)
 {
-	if (!(vcpu->arch.hcr_el2 & HCR_RW))
+	if (vcpu_el1_is_32bit(vcpu))
 		kvm_inject_undef32(vcpu);
 	else
 		inject_undef64(vcpu);
-- 
2.14.2

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

* [PATCH v4 08/40] KVM: arm/arm64: Introduce vcpu_el1_is_32bit
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

We have numerous checks around that checks if the HCR_EL2 has the RW bit
set to figure out if we're running an AArch64 or AArch32 VM.  In some
cases, directly checking the RW bit (given its unintuitive name), is a
bit confusing, and that's not going to improve as we move logic around
for the following patches that optimize KVM on AArch64 hosts with VHE.

Therefore, introduce a helper, vcpu_el1_is_32bit, and replace existing
direct checks of HCR_EL2.RW with the helper.

Reviewed-by: Julien Grall <julien.grall@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v2:
     - New patch
    
    Changes since v1:
     - Reworded comments as suggested by Drew

 arch/arm64/include/asm/kvm_emulate.h |  7 ++++++-
 arch/arm64/kvm/hyp/switch.c          | 11 +++++------
 arch/arm64/kvm/hyp/sysreg-sr.c       |  5 +++--
 arch/arm64/kvm/inject_fault.c        |  6 +++---
 4 files changed, 17 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 9ee316b962c8..3cc535591bdf 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -45,6 +45,11 @@ void kvm_inject_undef32(struct kvm_vcpu *vcpu);
 void kvm_inject_dabt32(struct kvm_vcpu *vcpu, unsigned long addr);
 void kvm_inject_pabt32(struct kvm_vcpu *vcpu, unsigned long addr);
 
+static inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
+{
+	return !(vcpu->arch.hcr_el2 & HCR_RW);
+}
+
 static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
 {
 	vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
@@ -65,7 +70,7 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
 	 * For now this is conditional, since no AArch32 feature regs
 	 * are currently virtualised.
 	 */
-	if (vcpu->arch.hcr_el2 & HCR_RW)
+	if (!vcpu_el1_is_32bit(vcpu))
 		vcpu->arch.hcr_el2 |= HCR_TID3;
 }
 
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index b51638490d85..fbab9752a9f4 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -74,7 +74,7 @@ static hyp_alternate_select(__activate_traps_arch,
 
 static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
 {
-	u64 val;
+	u64 hcr = vcpu->arch.hcr_el2;
 
 	/*
 	 * We are about to set CPTR_EL2.TFP to trap all floating point
@@ -85,17 +85,16 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
 	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
 	 * it will cause an exception.
 	 */
-	val = vcpu->arch.hcr_el2;
-
-	if (!(val & HCR_RW) && system_supports_fpsimd()) {
+	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
 		write_sysreg(1 << 30, fpexc32_el2);
 		isb();
 	}
-	write_sysreg(val, hcr_el2);
 
-	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (val & HCR_VSE))
+	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
 		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
 
+	write_sysreg(hcr, hcr_el2);
+
 	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
 	write_sysreg(1 << 15, hstr_el2);
 	/*
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 434f0fc9cfb3..99fc60516103 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -19,6 +19,7 @@
 #include <linux/kvm_host.h>
 
 #include <asm/kvm_asm.h>
+#include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
 
 /* Yes, this does nothing, on purpose */
@@ -147,7 +148,7 @@ void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
 {
 	u64 *spsr, *sysreg;
 
-	if (read_sysreg(hcr_el2) & HCR_RW)
+	if (!vcpu_el1_is_32bit(vcpu))
 		return;
 
 	spsr = vcpu->arch.ctxt.gp_regs.spsr;
@@ -172,7 +173,7 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
 {
 	u64 *spsr, *sysreg;
 
-	if (read_sysreg(hcr_el2) & HCR_RW)
+	if (!vcpu_el1_is_32bit(vcpu))
 		return;
 
 	spsr = vcpu->arch.ctxt.gp_regs.spsr;
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index c1e179d34e6a..30a3f58cdb7b 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -128,7 +128,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
  */
 void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
 {
-	if (!(vcpu->arch.hcr_el2 & HCR_RW))
+	if (vcpu_el1_is_32bit(vcpu))
 		kvm_inject_dabt32(vcpu, addr);
 	else
 		inject_abt64(vcpu, false, addr);
@@ -144,7 +144,7 @@ void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
  */
 void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
 {
-	if (!(vcpu->arch.hcr_el2 & HCR_RW))
+	if (vcpu_el1_is_32bit(vcpu))
 		kvm_inject_pabt32(vcpu, addr);
 	else
 		inject_abt64(vcpu, true, addr);
@@ -158,7 +158,7 @@ void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
  */
 void kvm_inject_undefined(struct kvm_vcpu *vcpu)
 {
-	if (!(vcpu->arch.hcr_el2 & HCR_RW))
+	if (vcpu_el1_is_32bit(vcpu))
 		kvm_inject_undef32(vcpu);
 	else
 		inject_undef64(vcpu);
-- 
2.14.2

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

* [PATCH v4 09/40] KVM: arm64: Move debug dirty flag calculation out of world switch
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

There is no need to figure out inside the world-switch if we should
save/restore the debug registers or not, we might as well do that in the
higher level debug setup code, making it easier to optimize down the
line.

Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/debug.c        | 5 +++++
 arch/arm64/kvm/hyp/debug-sr.c | 6 ------
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index fa63b28c65e0..feedb877cff8 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -193,6 +193,11 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
 	if (trap_debug)
 		vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
 
+	/* If KDE or MDE are set, perform a full save/restore cycle. */
+	if ((vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_KDE) ||
+	    (vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_MDE))
+		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
+
 	trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2);
 	trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_sys_reg(vcpu, MDSCR_EL1));
 }
diff --git a/arch/arm64/kvm/hyp/debug-sr.c b/arch/arm64/kvm/hyp/debug-sr.c
index dabb5cc7b087..d958cd63a547 100644
--- a/arch/arm64/kvm/hyp/debug-sr.c
+++ b/arch/arm64/kvm/hyp/debug-sr.c
@@ -166,12 +166,6 @@ void __hyp_text __debug_restore_state(struct kvm_vcpu *vcpu,
 
 void __hyp_text __debug_cond_save_host_state(struct kvm_vcpu *vcpu)
 {
-	/* If any of KDE, MDE or KVM_ARM64_DEBUG_DIRTY is set, perform
-	 * a full save/restore cycle. */
-	if ((vcpu->arch.ctxt.sys_regs[MDSCR_EL1] & DBG_MDSCR_KDE) ||
-	    (vcpu->arch.ctxt.sys_regs[MDSCR_EL1] & DBG_MDSCR_MDE))
-		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
-
 	__debug_save_state(vcpu, &vcpu->arch.host_debug_state.regs,
 			   kern_hyp_va(vcpu->arch.host_cpu_context));
 	__debug_save_spe()(&vcpu->arch.host_debug_state.pmscr_el1);
-- 
2.14.2

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

* [PATCH v4 09/40] KVM: arm64: Move debug dirty flag calculation out of world switch
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

There is no need to figure out inside the world-switch if we should
save/restore the debug registers or not, we might as well do that in the
higher level debug setup code, making it easier to optimize down the
line.

Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/debug.c        | 5 +++++
 arch/arm64/kvm/hyp/debug-sr.c | 6 ------
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index fa63b28c65e0..feedb877cff8 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -193,6 +193,11 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
 	if (trap_debug)
 		vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
 
+	/* If KDE or MDE are set, perform a full save/restore cycle. */
+	if ((vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_KDE) ||
+	    (vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_MDE))
+		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
+
 	trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2);
 	trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_sys_reg(vcpu, MDSCR_EL1));
 }
diff --git a/arch/arm64/kvm/hyp/debug-sr.c b/arch/arm64/kvm/hyp/debug-sr.c
index dabb5cc7b087..d958cd63a547 100644
--- a/arch/arm64/kvm/hyp/debug-sr.c
+++ b/arch/arm64/kvm/hyp/debug-sr.c
@@ -166,12 +166,6 @@ void __hyp_text __debug_restore_state(struct kvm_vcpu *vcpu,
 
 void __hyp_text __debug_cond_save_host_state(struct kvm_vcpu *vcpu)
 {
-	/* If any of KDE, MDE or KVM_ARM64_DEBUG_DIRTY is set, perform
-	 * a full save/restore cycle. */
-	if ((vcpu->arch.ctxt.sys_regs[MDSCR_EL1] & DBG_MDSCR_KDE) ||
-	    (vcpu->arch.ctxt.sys_regs[MDSCR_EL1] & DBG_MDSCR_MDE))
-		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
-
 	__debug_save_state(vcpu, &vcpu->arch.host_debug_state.regs,
 			   kern_hyp_va(vcpu->arch.host_cpu_context));
 	__debug_save_spe()(&vcpu->arch.host_debug_state.pmscr_el1);
-- 
2.14.2

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

* [PATCH v4 10/40] KVM: arm64: Slightly improve debug save/restore functions
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

The debug save/restore functions can be improved by using the has_vhe()
static key instead of the instruction alternative.  Using the static key
uses the same paradigm as we're going to use elsewhere, it makes the
code more readable, and it generates slightly better code (no
stack setups and function calls unless necessary).

We also use a static key on the restore path, because it will be
marginally faster than loading a value from memory.

Finally, we don't have to conditionally clear the debug dirty flag if
it's set, we can just clear it.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v1:
     - Change dot to comma in comment
     - Rename __debug_restore_spe to __debug_restore_spe_nvhe

 arch/arm64/kvm/hyp/debug-sr.c | 26 ++++++++++++--------------
 1 file changed, 12 insertions(+), 14 deletions(-)

diff --git a/arch/arm64/kvm/hyp/debug-sr.c b/arch/arm64/kvm/hyp/debug-sr.c
index d958cd63a547..74f71fb5e36d 100644
--- a/arch/arm64/kvm/hyp/debug-sr.c
+++ b/arch/arm64/kvm/hyp/debug-sr.c
@@ -66,11 +66,6 @@
 	default:	write_debug(ptr[0], reg, 0);			\
 	}
 
-static void __hyp_text __debug_save_spe_vhe(u64 *pmscr_el1)
-{
-	/* The vcpu can run. but it can't hide. */
-}
-
 static void __hyp_text __debug_save_spe_nvhe(u64 *pmscr_el1)
 {
 	u64 reg;
@@ -103,11 +98,7 @@ static void __hyp_text __debug_save_spe_nvhe(u64 *pmscr_el1)
 	dsb(nsh);
 }
 
-static hyp_alternate_select(__debug_save_spe,
-			    __debug_save_spe_nvhe, __debug_save_spe_vhe,
-			    ARM64_HAS_VIRT_HOST_EXTN);
-
-static void __hyp_text __debug_restore_spe(u64 pmscr_el1)
+static void __hyp_text __debug_restore_spe_nvhe(u64 pmscr_el1)
 {
 	if (!pmscr_el1)
 		return;
@@ -168,17 +159,24 @@ void __hyp_text __debug_cond_save_host_state(struct kvm_vcpu *vcpu)
 {
 	__debug_save_state(vcpu, &vcpu->arch.host_debug_state.regs,
 			   kern_hyp_va(vcpu->arch.host_cpu_context));
-	__debug_save_spe()(&vcpu->arch.host_debug_state.pmscr_el1);
+
+	/*
+	 * Non-VHE: Disable and flush SPE data generation
+	 * VHE: The vcpu can run, but it can't hide.
+	 */
+	if (!has_vhe())
+		__debug_save_spe_nvhe(&vcpu->arch.host_debug_state.pmscr_el1);
 }
 
 void __hyp_text __debug_cond_restore_host_state(struct kvm_vcpu *vcpu)
 {
-	__debug_restore_spe(vcpu->arch.host_debug_state.pmscr_el1);
+	if (!has_vhe())
+		__debug_restore_spe_nvhe(vcpu->arch.host_debug_state.pmscr_el1);
+
 	__debug_restore_state(vcpu, &vcpu->arch.host_debug_state.regs,
 			      kern_hyp_va(vcpu->arch.host_cpu_context));
 
-	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
-		vcpu->arch.debug_flags &= ~KVM_ARM64_DEBUG_DIRTY;
+	vcpu->arch.debug_flags &= ~KVM_ARM64_DEBUG_DIRTY;
 }
 
 u32 __hyp_text __kvm_get_mdcr_el2(void)
-- 
2.14.2

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

* [PATCH v4 10/40] KVM: arm64: Slightly improve debug save/restore functions
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

The debug save/restore functions can be improved by using the has_vhe()
static key instead of the instruction alternative.  Using the static key
uses the same paradigm as we're going to use elsewhere, it makes the
code more readable, and it generates slightly better code (no
stack setups and function calls unless necessary).

We also use a static key on the restore path, because it will be
marginally faster than loading a value from memory.

Finally, we don't have to conditionally clear the debug dirty flag if
it's set, we can just clear it.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v1:
     - Change dot to comma in comment
     - Rename __debug_restore_spe to __debug_restore_spe_nvhe

 arch/arm64/kvm/hyp/debug-sr.c | 26 ++++++++++++--------------
 1 file changed, 12 insertions(+), 14 deletions(-)

diff --git a/arch/arm64/kvm/hyp/debug-sr.c b/arch/arm64/kvm/hyp/debug-sr.c
index d958cd63a547..74f71fb5e36d 100644
--- a/arch/arm64/kvm/hyp/debug-sr.c
+++ b/arch/arm64/kvm/hyp/debug-sr.c
@@ -66,11 +66,6 @@
 	default:	write_debug(ptr[0], reg, 0);			\
 	}
 
-static void __hyp_text __debug_save_spe_vhe(u64 *pmscr_el1)
-{
-	/* The vcpu can run. but it can't hide. */
-}
-
 static void __hyp_text __debug_save_spe_nvhe(u64 *pmscr_el1)
 {
 	u64 reg;
@@ -103,11 +98,7 @@ static void __hyp_text __debug_save_spe_nvhe(u64 *pmscr_el1)
 	dsb(nsh);
 }
 
-static hyp_alternate_select(__debug_save_spe,
-			    __debug_save_spe_nvhe, __debug_save_spe_vhe,
-			    ARM64_HAS_VIRT_HOST_EXTN);
-
-static void __hyp_text __debug_restore_spe(u64 pmscr_el1)
+static void __hyp_text __debug_restore_spe_nvhe(u64 pmscr_el1)
 {
 	if (!pmscr_el1)
 		return;
@@ -168,17 +159,24 @@ void __hyp_text __debug_cond_save_host_state(struct kvm_vcpu *vcpu)
 {
 	__debug_save_state(vcpu, &vcpu->arch.host_debug_state.regs,
 			   kern_hyp_va(vcpu->arch.host_cpu_context));
-	__debug_save_spe()(&vcpu->arch.host_debug_state.pmscr_el1);
+
+	/*
+	 * Non-VHE: Disable and flush SPE data generation
+	 * VHE: The vcpu can run, but it can't hide.
+	 */
+	if (!has_vhe())
+		__debug_save_spe_nvhe(&vcpu->arch.host_debug_state.pmscr_el1);
 }
 
 void __hyp_text __debug_cond_restore_host_state(struct kvm_vcpu *vcpu)
 {
-	__debug_restore_spe(vcpu->arch.host_debug_state.pmscr_el1);
+	if (!has_vhe())
+		__debug_restore_spe_nvhe(vcpu->arch.host_debug_state.pmscr_el1);
+
 	__debug_restore_state(vcpu, &vcpu->arch.host_debug_state.regs,
 			      kern_hyp_va(vcpu->arch.host_cpu_context));
 
-	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
-		vcpu->arch.debug_flags &= ~KVM_ARM64_DEBUG_DIRTY;
+	vcpu->arch.debug_flags &= ~KVM_ARM64_DEBUG_DIRTY;
 }
 
 u32 __hyp_text __kvm_get_mdcr_el2(void)
-- 
2.14.2

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

* [PATCH v4 11/40] KVM: arm64: Improve debug register save/restore flow
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

Instead of having multiple calls from the world switch path to the debug
logic, each figuring out if the dirty bit is set and if we should
save/restore the debug registers, let's just provide two hooks to the
debug save/restore functionality, one for switching to the guest
context, and one for switching to the host context, and we get the
benefit of only having to evaluate the dirty flag once on each path,
plus we give the compiler some more room to inline some of this
functionality.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v1:
     - Remove leading underscores from local variables

 arch/arm64/include/asm/kvm_hyp.h | 10 ++-----
 arch/arm64/kvm/hyp/debug-sr.c    | 56 +++++++++++++++++++++++++++-------------
 arch/arm64/kvm/hyp/switch.c      |  6 ++---
 3 files changed, 42 insertions(+), 30 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index f26f9cd70c72..aeda2a777365 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -138,14 +138,8 @@ void __sysreg_restore_guest_state(struct kvm_cpu_context *ctxt);
 void __sysreg32_save_state(struct kvm_vcpu *vcpu);
 void __sysreg32_restore_state(struct kvm_vcpu *vcpu);
 
-void __debug_save_state(struct kvm_vcpu *vcpu,
-			struct kvm_guest_debug_arch *dbg,
-			struct kvm_cpu_context *ctxt);
-void __debug_restore_state(struct kvm_vcpu *vcpu,
-			   struct kvm_guest_debug_arch *dbg,
-			   struct kvm_cpu_context *ctxt);
-void __debug_cond_save_host_state(struct kvm_vcpu *vcpu);
-void __debug_cond_restore_host_state(struct kvm_vcpu *vcpu);
+void __debug_switch_to_guest(struct kvm_vcpu *vcpu);
+void __debug_switch_to_host(struct kvm_vcpu *vcpu);
 
 void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
 void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
diff --git a/arch/arm64/kvm/hyp/debug-sr.c b/arch/arm64/kvm/hyp/debug-sr.c
index 74f71fb5e36d..3e717f66f011 100644
--- a/arch/arm64/kvm/hyp/debug-sr.c
+++ b/arch/arm64/kvm/hyp/debug-sr.c
@@ -110,16 +110,13 @@ static void __hyp_text __debug_restore_spe_nvhe(u64 pmscr_el1)
 	write_sysreg_s(pmscr_el1, SYS_PMSCR_EL1);
 }
 
-void __hyp_text __debug_save_state(struct kvm_vcpu *vcpu,
-				   struct kvm_guest_debug_arch *dbg,
-				   struct kvm_cpu_context *ctxt)
+static void __hyp_text __debug_save_state(struct kvm_vcpu *vcpu,
+					  struct kvm_guest_debug_arch *dbg,
+					  struct kvm_cpu_context *ctxt)
 {
 	u64 aa64dfr0;
 	int brps, wrps;
 
-	if (!(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY))
-		return;
-
 	aa64dfr0 = read_sysreg(id_aa64dfr0_el1);
 	brps = (aa64dfr0 >> 12) & 0xf;
 	wrps = (aa64dfr0 >> 20) & 0xf;
@@ -132,16 +129,13 @@ void __hyp_text __debug_save_state(struct kvm_vcpu *vcpu,
 	ctxt->sys_regs[MDCCINT_EL1] = read_sysreg(mdccint_el1);
 }
 
-void __hyp_text __debug_restore_state(struct kvm_vcpu *vcpu,
-				      struct kvm_guest_debug_arch *dbg,
-				      struct kvm_cpu_context *ctxt)
+static void __hyp_text __debug_restore_state(struct kvm_vcpu *vcpu,
+					     struct kvm_guest_debug_arch *dbg,
+					     struct kvm_cpu_context *ctxt)
 {
 	u64 aa64dfr0;
 	int brps, wrps;
 
-	if (!(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY))
-		return;
-
 	aa64dfr0 = read_sysreg(id_aa64dfr0_el1);
 
 	brps = (aa64dfr0 >> 12) & 0xf;
@@ -155,10 +149,12 @@ void __hyp_text __debug_restore_state(struct kvm_vcpu *vcpu,
 	write_sysreg(ctxt->sys_regs[MDCCINT_EL1], mdccint_el1);
 }
 
-void __hyp_text __debug_cond_save_host_state(struct kvm_vcpu *vcpu)
+void __hyp_text __debug_switch_to_guest(struct kvm_vcpu *vcpu)
 {
-	__debug_save_state(vcpu, &vcpu->arch.host_debug_state.regs,
-			   kern_hyp_va(vcpu->arch.host_cpu_context));
+	struct kvm_cpu_context *host_ctxt;
+	struct kvm_cpu_context *guest_ctxt;
+	struct kvm_guest_debug_arch *host_dbg;
+	struct kvm_guest_debug_arch *guest_dbg;
 
 	/*
 	 * Non-VHE: Disable and flush SPE data generation
@@ -166,15 +162,39 @@ void __hyp_text __debug_cond_save_host_state(struct kvm_vcpu *vcpu)
 	 */
 	if (!has_vhe())
 		__debug_save_spe_nvhe(&vcpu->arch.host_debug_state.pmscr_el1);
+
+	if (!(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY))
+		return;
+
+	host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+	guest_ctxt = &vcpu->arch.ctxt;
+	host_dbg = &vcpu->arch.host_debug_state.regs;
+	guest_dbg = kern_hyp_va(vcpu->arch.debug_ptr);
+
+	__debug_save_state(vcpu, host_dbg, host_ctxt);
+	__debug_restore_state(vcpu, guest_dbg, guest_ctxt);
 }
 
-void __hyp_text __debug_cond_restore_host_state(struct kvm_vcpu *vcpu)
+void __hyp_text __debug_switch_to_host(struct kvm_vcpu *vcpu)
 {
+	struct kvm_cpu_context *host_ctxt;
+	struct kvm_cpu_context *guest_ctxt;
+	struct kvm_guest_debug_arch *host_dbg;
+	struct kvm_guest_debug_arch *guest_dbg;
+
 	if (!has_vhe())
 		__debug_restore_spe_nvhe(vcpu->arch.host_debug_state.pmscr_el1);
 
-	__debug_restore_state(vcpu, &vcpu->arch.host_debug_state.regs,
-			      kern_hyp_va(vcpu->arch.host_cpu_context));
+	if (!(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY))
+		return;
+
+	host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+	guest_ctxt = &vcpu->arch.ctxt;
+	host_dbg = &vcpu->arch.host_debug_state.regs;
+	guest_dbg = kern_hyp_va(vcpu->arch.debug_ptr);
+
+	__debug_save_state(vcpu, guest_dbg, guest_ctxt);
+	__debug_restore_state(vcpu, host_dbg, host_ctxt);
 
 	vcpu->arch.debug_flags &= ~KVM_ARM64_DEBUG_DIRTY;
 }
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index fbab9752a9f4..0c80d6a577ca 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -305,7 +305,6 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 	guest_ctxt = &vcpu->arch.ctxt;
 
 	__sysreg_save_host_state(host_ctxt);
-	__debug_cond_save_host_state(vcpu);
 
 	__activate_traps(vcpu);
 	__activate_vm(vcpu);
@@ -319,7 +318,7 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 	 */
 	__sysreg32_restore_state(vcpu);
 	__sysreg_restore_guest_state(guest_ctxt);
-	__debug_restore_state(vcpu, kern_hyp_va(vcpu->arch.debug_ptr), guest_ctxt);
+	__debug_switch_to_guest(vcpu);
 
 	/* Jump in the fire! */
 again:
@@ -414,12 +413,11 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
 	}
 
-	__debug_save_state(vcpu, kern_hyp_va(vcpu->arch.debug_ptr), guest_ctxt);
 	/*
 	 * This must come after restoring the host sysregs, since a non-VHE
 	 * system may enable SPE here and make use of the TTBRs.
 	 */
-	__debug_cond_restore_host_state(vcpu);
+	__debug_switch_to_host(vcpu);
 
 	return exit_code;
 }
-- 
2.14.2

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

* [PATCH v4 11/40] KVM: arm64: Improve debug register save/restore flow
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

Instead of having multiple calls from the world switch path to the debug
logic, each figuring out if the dirty bit is set and if we should
save/restore the debug registers, let's just provide two hooks to the
debug save/restore functionality, one for switching to the guest
context, and one for switching to the host context, and we get the
benefit of only having to evaluate the dirty flag once on each path,
plus we give the compiler some more room to inline some of this
functionality.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v1:
     - Remove leading underscores from local variables

 arch/arm64/include/asm/kvm_hyp.h | 10 ++-----
 arch/arm64/kvm/hyp/debug-sr.c    | 56 +++++++++++++++++++++++++++-------------
 arch/arm64/kvm/hyp/switch.c      |  6 ++---
 3 files changed, 42 insertions(+), 30 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index f26f9cd70c72..aeda2a777365 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -138,14 +138,8 @@ void __sysreg_restore_guest_state(struct kvm_cpu_context *ctxt);
 void __sysreg32_save_state(struct kvm_vcpu *vcpu);
 void __sysreg32_restore_state(struct kvm_vcpu *vcpu);
 
-void __debug_save_state(struct kvm_vcpu *vcpu,
-			struct kvm_guest_debug_arch *dbg,
-			struct kvm_cpu_context *ctxt);
-void __debug_restore_state(struct kvm_vcpu *vcpu,
-			   struct kvm_guest_debug_arch *dbg,
-			   struct kvm_cpu_context *ctxt);
-void __debug_cond_save_host_state(struct kvm_vcpu *vcpu);
-void __debug_cond_restore_host_state(struct kvm_vcpu *vcpu);
+void __debug_switch_to_guest(struct kvm_vcpu *vcpu);
+void __debug_switch_to_host(struct kvm_vcpu *vcpu);
 
 void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
 void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
diff --git a/arch/arm64/kvm/hyp/debug-sr.c b/arch/arm64/kvm/hyp/debug-sr.c
index 74f71fb5e36d..3e717f66f011 100644
--- a/arch/arm64/kvm/hyp/debug-sr.c
+++ b/arch/arm64/kvm/hyp/debug-sr.c
@@ -110,16 +110,13 @@ static void __hyp_text __debug_restore_spe_nvhe(u64 pmscr_el1)
 	write_sysreg_s(pmscr_el1, SYS_PMSCR_EL1);
 }
 
-void __hyp_text __debug_save_state(struct kvm_vcpu *vcpu,
-				   struct kvm_guest_debug_arch *dbg,
-				   struct kvm_cpu_context *ctxt)
+static void __hyp_text __debug_save_state(struct kvm_vcpu *vcpu,
+					  struct kvm_guest_debug_arch *dbg,
+					  struct kvm_cpu_context *ctxt)
 {
 	u64 aa64dfr0;
 	int brps, wrps;
 
-	if (!(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY))
-		return;
-
 	aa64dfr0 = read_sysreg(id_aa64dfr0_el1);
 	brps = (aa64dfr0 >> 12) & 0xf;
 	wrps = (aa64dfr0 >> 20) & 0xf;
@@ -132,16 +129,13 @@ void __hyp_text __debug_save_state(struct kvm_vcpu *vcpu,
 	ctxt->sys_regs[MDCCINT_EL1] = read_sysreg(mdccint_el1);
 }
 
-void __hyp_text __debug_restore_state(struct kvm_vcpu *vcpu,
-				      struct kvm_guest_debug_arch *dbg,
-				      struct kvm_cpu_context *ctxt)
+static void __hyp_text __debug_restore_state(struct kvm_vcpu *vcpu,
+					     struct kvm_guest_debug_arch *dbg,
+					     struct kvm_cpu_context *ctxt)
 {
 	u64 aa64dfr0;
 	int brps, wrps;
 
-	if (!(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY))
-		return;
-
 	aa64dfr0 = read_sysreg(id_aa64dfr0_el1);
 
 	brps = (aa64dfr0 >> 12) & 0xf;
@@ -155,10 +149,12 @@ void __hyp_text __debug_restore_state(struct kvm_vcpu *vcpu,
 	write_sysreg(ctxt->sys_regs[MDCCINT_EL1], mdccint_el1);
 }
 
-void __hyp_text __debug_cond_save_host_state(struct kvm_vcpu *vcpu)
+void __hyp_text __debug_switch_to_guest(struct kvm_vcpu *vcpu)
 {
-	__debug_save_state(vcpu, &vcpu->arch.host_debug_state.regs,
-			   kern_hyp_va(vcpu->arch.host_cpu_context));
+	struct kvm_cpu_context *host_ctxt;
+	struct kvm_cpu_context *guest_ctxt;
+	struct kvm_guest_debug_arch *host_dbg;
+	struct kvm_guest_debug_arch *guest_dbg;
 
 	/*
 	 * Non-VHE: Disable and flush SPE data generation
@@ -166,15 +162,39 @@ void __hyp_text __debug_cond_save_host_state(struct kvm_vcpu *vcpu)
 	 */
 	if (!has_vhe())
 		__debug_save_spe_nvhe(&vcpu->arch.host_debug_state.pmscr_el1);
+
+	if (!(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY))
+		return;
+
+	host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+	guest_ctxt = &vcpu->arch.ctxt;
+	host_dbg = &vcpu->arch.host_debug_state.regs;
+	guest_dbg = kern_hyp_va(vcpu->arch.debug_ptr);
+
+	__debug_save_state(vcpu, host_dbg, host_ctxt);
+	__debug_restore_state(vcpu, guest_dbg, guest_ctxt);
 }
 
-void __hyp_text __debug_cond_restore_host_state(struct kvm_vcpu *vcpu)
+void __hyp_text __debug_switch_to_host(struct kvm_vcpu *vcpu)
 {
+	struct kvm_cpu_context *host_ctxt;
+	struct kvm_cpu_context *guest_ctxt;
+	struct kvm_guest_debug_arch *host_dbg;
+	struct kvm_guest_debug_arch *guest_dbg;
+
 	if (!has_vhe())
 		__debug_restore_spe_nvhe(vcpu->arch.host_debug_state.pmscr_el1);
 
-	__debug_restore_state(vcpu, &vcpu->arch.host_debug_state.regs,
-			      kern_hyp_va(vcpu->arch.host_cpu_context));
+	if (!(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY))
+		return;
+
+	host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+	guest_ctxt = &vcpu->arch.ctxt;
+	host_dbg = &vcpu->arch.host_debug_state.regs;
+	guest_dbg = kern_hyp_va(vcpu->arch.debug_ptr);
+
+	__debug_save_state(vcpu, guest_dbg, guest_ctxt);
+	__debug_restore_state(vcpu, host_dbg, host_ctxt);
 
 	vcpu->arch.debug_flags &= ~KVM_ARM64_DEBUG_DIRTY;
 }
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index fbab9752a9f4..0c80d6a577ca 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -305,7 +305,6 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 	guest_ctxt = &vcpu->arch.ctxt;
 
 	__sysreg_save_host_state(host_ctxt);
-	__debug_cond_save_host_state(vcpu);
 
 	__activate_traps(vcpu);
 	__activate_vm(vcpu);
@@ -319,7 +318,7 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 	 */
 	__sysreg32_restore_state(vcpu);
 	__sysreg_restore_guest_state(guest_ctxt);
-	__debug_restore_state(vcpu, kern_hyp_va(vcpu->arch.debug_ptr), guest_ctxt);
+	__debug_switch_to_guest(vcpu);
 
 	/* Jump in the fire! */
 again:
@@ -414,12 +413,11 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
 	}
 
-	__debug_save_state(vcpu, kern_hyp_va(vcpu->arch.debug_ptr), guest_ctxt);
 	/*
 	 * This must come after restoring the host sysregs, since a non-VHE
 	 * system may enable SPE here and make use of the TTBRs.
 	 */
-	__debug_cond_restore_host_state(vcpu);
+	__debug_switch_to_host(vcpu);
 
 	return exit_code;
 }
-- 
2.14.2

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

* [PATCH v4 12/40] KVM: arm64: Factor out fault info population and gic workarounds
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

The current world-switch function has functionality to detect a number
of cases where we need to fixup some part of the exit condition and
possibly run the guest again, before having restored the host state.

This includes populating missing fault info, emulating GICv2 CPU
interface accesses when mapped at unaligned addresses, and emulating
the GICv3 CPU interface on systems that need it.

As we are about to have an alternative switch function for VHE systems,
but VHE systems still need the same early fixup logic, factor out this
logic into a separate function that can be shared by both switch
functions.

No functional change.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/hyp/switch.c | 104 ++++++++++++++++++++++++--------------------
 1 file changed, 57 insertions(+), 47 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 0c80d6a577ca..d2c0b1ae3216 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -291,53 +291,27 @@ static bool __hyp_text __skip_instr(struct kvm_vcpu *vcpu)
 	}
 }
 
-int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
+/*
+ * Return true when we were able to fixup the guest exit and should return to
+ * the guest, false when we should restore the host state and return to the
+ * main run loop.
+ */
+static bool __hyp_text fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
 {
-	struct kvm_cpu_context *host_ctxt;
-	struct kvm_cpu_context *guest_ctxt;
-	bool fp_enabled;
-	u64 exit_code;
-
-	vcpu = kern_hyp_va(vcpu);
-
-	host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
-	host_ctxt->__hyp_running_vcpu = vcpu;
-	guest_ctxt = &vcpu->arch.ctxt;
-
-	__sysreg_save_host_state(host_ctxt);
-
-	__activate_traps(vcpu);
-	__activate_vm(vcpu);
-
-	__vgic_restore_state(vcpu);
-	__timer_enable_traps(vcpu);
-
-	/*
-	 * We must restore the 32-bit state before the sysregs, thanks
-	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
-	 */
-	__sysreg32_restore_state(vcpu);
-	__sysreg_restore_guest_state(guest_ctxt);
-	__debug_switch_to_guest(vcpu);
-
-	/* Jump in the fire! */
-again:
-	exit_code = __guest_enter(vcpu, host_ctxt);
-	/* And we're baaack! */
-
-	if (ARM_EXCEPTION_CODE(exit_code) != ARM_EXCEPTION_IRQ)
+	if (ARM_EXCEPTION_CODE(*exit_code) != ARM_EXCEPTION_IRQ)
 		vcpu->arch.fault.esr_el2 = read_sysreg_el2(esr);
+
 	/*
 	 * We're using the raw exception code in order to only process
 	 * the trap if no SError is pending. We will come back to the
 	 * same PC once the SError has been injected, and replay the
 	 * trapping instruction.
 	 */
-	if (exit_code == ARM_EXCEPTION_TRAP && !__populate_fault_info(vcpu))
-		goto again;
+	if (*exit_code == ARM_EXCEPTION_TRAP && !__populate_fault_info(vcpu))
+		return true;
 
 	if (static_branch_unlikely(&vgic_v2_cpuif_trap) &&
-	    exit_code == ARM_EXCEPTION_TRAP) {
+	    *exit_code == ARM_EXCEPTION_TRAP) {
 		bool valid;
 
 		valid = kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_DABT_LOW &&
@@ -351,9 +325,9 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 
 			if (ret == 1) {
 				if (__skip_instr(vcpu))
-					goto again;
+					return true;
 				else
-					exit_code = ARM_EXCEPTION_TRAP;
+					*exit_code = ARM_EXCEPTION_TRAP;
 			}
 
 			if (ret == -1) {
@@ -365,29 +339,65 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 				 */
 				if (!__skip_instr(vcpu))
 					*vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
-				exit_code = ARM_EXCEPTION_EL1_SERROR;
+				*exit_code = ARM_EXCEPTION_EL1_SERROR;
 			}
-
-			/* 0 falls through to be handler out of EL2 */
 		}
 	}
 
 	if (static_branch_unlikely(&vgic_v3_cpuif_trap) &&
-	    exit_code == ARM_EXCEPTION_TRAP &&
+	    *exit_code == ARM_EXCEPTION_TRAP &&
 	    (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_SYS64 ||
 	     kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_CP15_32)) {
 		int ret = __vgic_v3_perform_cpuif_access(vcpu);
 
 		if (ret == 1) {
 			if (__skip_instr(vcpu))
-				goto again;
+				return true;
 			else
-				exit_code = ARM_EXCEPTION_TRAP;
+				*exit_code = ARM_EXCEPTION_TRAP;
 		}
-
-		/* 0 falls through to be handled out of EL2 */
 	}
 
+	/* Return to the host kernel and handle the exit */
+	return false;
+}
+
+int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpu_context *host_ctxt;
+	struct kvm_cpu_context *guest_ctxt;
+	bool fp_enabled;
+	u64 exit_code;
+
+	vcpu = kern_hyp_va(vcpu);
+
+	host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+	host_ctxt->__hyp_running_vcpu = vcpu;
+	guest_ctxt = &vcpu->arch.ctxt;
+
+	__sysreg_save_host_state(host_ctxt);
+
+	__activate_traps(vcpu);
+	__activate_vm(vcpu);
+
+	__vgic_restore_state(vcpu);
+	__timer_enable_traps(vcpu);
+
+	/*
+	 * We must restore the 32-bit state before the sysregs, thanks
+	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
+	 */
+	__sysreg32_restore_state(vcpu);
+	__sysreg_restore_guest_state(guest_ctxt);
+	__debug_switch_to_guest(vcpu);
+
+	do {
+		/* Jump in the fire! */
+		exit_code = __guest_enter(vcpu, host_ctxt);
+
+		/* And we're baaack! */
+	} while (fixup_guest_exit(vcpu, &exit_code));
+
 	if (cpus_have_const_cap(ARM64_HARDEN_BP_POST_GUEST_EXIT)) {
 		u32 midr = read_cpuid_id();
 
-- 
2.14.2

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

* [PATCH v4 12/40] KVM: arm64: Factor out fault info population and gic workarounds
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

The current world-switch function has functionality to detect a number
of cases where we need to fixup some part of the exit condition and
possibly run the guest again, before having restored the host state.

This includes populating missing fault info, emulating GICv2 CPU
interface accesses when mapped at unaligned addresses, and emulating
the GICv3 CPU interface on systems that need it.

As we are about to have an alternative switch function for VHE systems,
but VHE systems still need the same early fixup logic, factor out this
logic into a separate function that can be shared by both switch
functions.

No functional change.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/hyp/switch.c | 104 ++++++++++++++++++++++++--------------------
 1 file changed, 57 insertions(+), 47 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 0c80d6a577ca..d2c0b1ae3216 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -291,53 +291,27 @@ static bool __hyp_text __skip_instr(struct kvm_vcpu *vcpu)
 	}
 }
 
-int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
+/*
+ * Return true when we were able to fixup the guest exit and should return to
+ * the guest, false when we should restore the host state and return to the
+ * main run loop.
+ */
+static bool __hyp_text fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
 {
-	struct kvm_cpu_context *host_ctxt;
-	struct kvm_cpu_context *guest_ctxt;
-	bool fp_enabled;
-	u64 exit_code;
-
-	vcpu = kern_hyp_va(vcpu);
-
-	host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
-	host_ctxt->__hyp_running_vcpu = vcpu;
-	guest_ctxt = &vcpu->arch.ctxt;
-
-	__sysreg_save_host_state(host_ctxt);
-
-	__activate_traps(vcpu);
-	__activate_vm(vcpu);
-
-	__vgic_restore_state(vcpu);
-	__timer_enable_traps(vcpu);
-
-	/*
-	 * We must restore the 32-bit state before the sysregs, thanks
-	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
-	 */
-	__sysreg32_restore_state(vcpu);
-	__sysreg_restore_guest_state(guest_ctxt);
-	__debug_switch_to_guest(vcpu);
-
-	/* Jump in the fire! */
-again:
-	exit_code = __guest_enter(vcpu, host_ctxt);
-	/* And we're baaack! */
-
-	if (ARM_EXCEPTION_CODE(exit_code) != ARM_EXCEPTION_IRQ)
+	if (ARM_EXCEPTION_CODE(*exit_code) != ARM_EXCEPTION_IRQ)
 		vcpu->arch.fault.esr_el2 = read_sysreg_el2(esr);
+
 	/*
 	 * We're using the raw exception code in order to only process
 	 * the trap if no SError is pending. We will come back to the
 	 * same PC once the SError has been injected, and replay the
 	 * trapping instruction.
 	 */
-	if (exit_code == ARM_EXCEPTION_TRAP && !__populate_fault_info(vcpu))
-		goto again;
+	if (*exit_code == ARM_EXCEPTION_TRAP && !__populate_fault_info(vcpu))
+		return true;
 
 	if (static_branch_unlikely(&vgic_v2_cpuif_trap) &&
-	    exit_code == ARM_EXCEPTION_TRAP) {
+	    *exit_code == ARM_EXCEPTION_TRAP) {
 		bool valid;
 
 		valid = kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_DABT_LOW &&
@@ -351,9 +325,9 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 
 			if (ret == 1) {
 				if (__skip_instr(vcpu))
-					goto again;
+					return true;
 				else
-					exit_code = ARM_EXCEPTION_TRAP;
+					*exit_code = ARM_EXCEPTION_TRAP;
 			}
 
 			if (ret == -1) {
@@ -365,29 +339,65 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 				 */
 				if (!__skip_instr(vcpu))
 					*vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
-				exit_code = ARM_EXCEPTION_EL1_SERROR;
+				*exit_code = ARM_EXCEPTION_EL1_SERROR;
 			}
-
-			/* 0 falls through to be handler out of EL2 */
 		}
 	}
 
 	if (static_branch_unlikely(&vgic_v3_cpuif_trap) &&
-	    exit_code == ARM_EXCEPTION_TRAP &&
+	    *exit_code == ARM_EXCEPTION_TRAP &&
 	    (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_SYS64 ||
 	     kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_CP15_32)) {
 		int ret = __vgic_v3_perform_cpuif_access(vcpu);
 
 		if (ret == 1) {
 			if (__skip_instr(vcpu))
-				goto again;
+				return true;
 			else
-				exit_code = ARM_EXCEPTION_TRAP;
+				*exit_code = ARM_EXCEPTION_TRAP;
 		}
-
-		/* 0 falls through to be handled out of EL2 */
 	}
 
+	/* Return to the host kernel and handle the exit */
+	return false;
+}
+
+int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpu_context *host_ctxt;
+	struct kvm_cpu_context *guest_ctxt;
+	bool fp_enabled;
+	u64 exit_code;
+
+	vcpu = kern_hyp_va(vcpu);
+
+	host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+	host_ctxt->__hyp_running_vcpu = vcpu;
+	guest_ctxt = &vcpu->arch.ctxt;
+
+	__sysreg_save_host_state(host_ctxt);
+
+	__activate_traps(vcpu);
+	__activate_vm(vcpu);
+
+	__vgic_restore_state(vcpu);
+	__timer_enable_traps(vcpu);
+
+	/*
+	 * We must restore the 32-bit state before the sysregs, thanks
+	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
+	 */
+	__sysreg32_restore_state(vcpu);
+	__sysreg_restore_guest_state(guest_ctxt);
+	__debug_switch_to_guest(vcpu);
+
+	do {
+		/* Jump in the fire! */
+		exit_code = __guest_enter(vcpu, host_ctxt);
+
+		/* And we're baaack! */
+	} while (fixup_guest_exit(vcpu, &exit_code));
+
 	if (cpus_have_const_cap(ARM64_HARDEN_BP_POST_GUEST_EXIT)) {
 		u32 midr = read_cpuid_id();
 
-- 
2.14.2

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

* [PATCH v4 13/40] KVM: arm64: Introduce VHE-specific kvm_vcpu_run
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

So far this is mostly (see below) a copy of the legacy non-VHE switch
function, but we will start reworking these functions in separate
directions to work on VHE and non-VHE in the most optimal way in later
patches.

The only difference after this patch between the VHE and non-VHE run
functions is that we omit the branch-predictor variant-2 hardening for
QC Falkor CPUs, because this workaround is specific to a series of
non-VHE ARMv8.0 CPUs.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v3:
     - Added BUG() to 32-bit ARM VHE run function
     - Omitted QC Falkor BP Hardening functionality from VHE-specific
       function
    
    Changes since v2:
     - Reworded commit message
    
    Changes since v1:
     - Rename kvm_vcpu_run to kvm_vcpu_run_vhe and rename __kvm_vcpu_run to
       __kvm_vcpu_run_nvhe
     - Removed stray whitespace line

 arch/arm/include/asm/kvm_asm.h   |  5 ++-
 arch/arm/kvm/hyp/switch.c        |  2 +-
 arch/arm64/include/asm/kvm_asm.h |  4 ++-
 arch/arm64/kvm/hyp/switch.c      | 66 +++++++++++++++++++++++++++++++++++++++-
 virt/kvm/arm/arm.c               |  5 ++-
 5 files changed, 77 insertions(+), 5 deletions(-)

diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
index 36dd2962a42d..5a953ecb0d78 100644
--- a/arch/arm/include/asm/kvm_asm.h
+++ b/arch/arm/include/asm/kvm_asm.h
@@ -70,7 +70,10 @@ extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
 
 extern void __kvm_timer_set_cntvoff(u32 cntvoff_low, u32 cntvoff_high);
 
-extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
+/* no VHE on 32-bit :( */
+static inline int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu) { BUG(); return 0; }
+
+extern int __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu);
 
 extern void __init_stage2_translation(void);
 
diff --git a/arch/arm/kvm/hyp/switch.c b/arch/arm/kvm/hyp/switch.c
index e86679daddff..aac025783ee8 100644
--- a/arch/arm/kvm/hyp/switch.c
+++ b/arch/arm/kvm/hyp/switch.c
@@ -154,7 +154,7 @@ static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
 	return true;
 }
 
-int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
+int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 {
 	struct kvm_cpu_context *host_ctxt;
 	struct kvm_cpu_context *guest_ctxt;
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 6b626750b0a1..0be2747a6c5f 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -58,7 +58,9 @@ extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
 
 extern void __kvm_timer_set_cntvoff(u32 cntvoff_low, u32 cntvoff_high);
 
-extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
+extern int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu);
+
+extern int __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu);
 
 extern u64 __vgic_v3_get_ich_vtr_el2(void);
 extern u64 __vgic_v3_read_vmcr(void);
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index d2c0b1ae3216..b6126af539b6 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -362,7 +362,71 @@ static bool __hyp_text fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
 	return false;
 }
 
-int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
+/* Switch to the guest for VHE systems running in EL2 */
+int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpu_context *host_ctxt;
+	struct kvm_cpu_context *guest_ctxt;
+	bool fp_enabled;
+	u64 exit_code;
+
+	vcpu = kern_hyp_va(vcpu);
+
+	host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+	host_ctxt->__hyp_running_vcpu = vcpu;
+	guest_ctxt = &vcpu->arch.ctxt;
+
+	__sysreg_save_host_state(host_ctxt);
+
+	__activate_traps(vcpu);
+	__activate_vm(vcpu);
+
+	__vgic_restore_state(vcpu);
+	__timer_enable_traps(vcpu);
+
+	/*
+	 * We must restore the 32-bit state before the sysregs, thanks
+	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
+	 */
+	__sysreg32_restore_state(vcpu);
+	__sysreg_restore_guest_state(guest_ctxt);
+	__debug_switch_to_guest(vcpu);
+
+	do {
+		/* Jump in the fire! */
+		exit_code = __guest_enter(vcpu, host_ctxt);
+
+		/* And we're baaack! */
+	} while (fixup_guest_exit(vcpu, &exit_code));
+
+	fp_enabled = __fpsimd_enabled();
+
+	__sysreg_save_guest_state(guest_ctxt);
+	__sysreg32_save_state(vcpu);
+	__timer_disable_traps(vcpu);
+	__vgic_save_state(vcpu);
+
+	__deactivate_traps(vcpu);
+	__deactivate_vm(vcpu);
+
+	__sysreg_restore_host_state(host_ctxt);
+
+	if (fp_enabled) {
+		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
+		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
+	}
+
+	/*
+	 * This must come after restoring the host sysregs, since a non-VHE
+	 * system may enable SPE here and make use of the TTBRs.
+	 */
+	__debug_switch_to_host(vcpu);
+
+	return exit_code;
+}
+
+/* Switch to the guest for legacy non-VHE systems */
+int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 {
 	struct kvm_cpu_context *host_ctxt;
 	struct kvm_cpu_context *guest_ctxt;
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 2062d9357971..5bd879c78951 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -736,7 +736,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		if (has_vhe())
 			kvm_arm_vhe_guest_enter();
 
-		ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);
+		if (has_vhe())
+			ret = kvm_vcpu_run_vhe(vcpu);
+		else
+			ret = kvm_call_hyp(__kvm_vcpu_run_nvhe, vcpu);
 
 		if (has_vhe())
 			kvm_arm_vhe_guest_exit();
-- 
2.14.2

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

* [PATCH v4 13/40] KVM: arm64: Introduce VHE-specific kvm_vcpu_run
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

So far this is mostly (see below) a copy of the legacy non-VHE switch
function, but we will start reworking these functions in separate
directions to work on VHE and non-VHE in the most optimal way in later
patches.

The only difference after this patch between the VHE and non-VHE run
functions is that we omit the branch-predictor variant-2 hardening for
QC Falkor CPUs, because this workaround is specific to a series of
non-VHE ARMv8.0 CPUs.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v3:
     - Added BUG() to 32-bit ARM VHE run function
     - Omitted QC Falkor BP Hardening functionality from VHE-specific
       function
    
    Changes since v2:
     - Reworded commit message
    
    Changes since v1:
     - Rename kvm_vcpu_run to kvm_vcpu_run_vhe and rename __kvm_vcpu_run to
       __kvm_vcpu_run_nvhe
     - Removed stray whitespace line

 arch/arm/include/asm/kvm_asm.h   |  5 ++-
 arch/arm/kvm/hyp/switch.c        |  2 +-
 arch/arm64/include/asm/kvm_asm.h |  4 ++-
 arch/arm64/kvm/hyp/switch.c      | 66 +++++++++++++++++++++++++++++++++++++++-
 virt/kvm/arm/arm.c               |  5 ++-
 5 files changed, 77 insertions(+), 5 deletions(-)

diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
index 36dd2962a42d..5a953ecb0d78 100644
--- a/arch/arm/include/asm/kvm_asm.h
+++ b/arch/arm/include/asm/kvm_asm.h
@@ -70,7 +70,10 @@ extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
 
 extern void __kvm_timer_set_cntvoff(u32 cntvoff_low, u32 cntvoff_high);
 
-extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
+/* no VHE on 32-bit :( */
+static inline int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu) { BUG(); return 0; }
+
+extern int __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu);
 
 extern void __init_stage2_translation(void);
 
diff --git a/arch/arm/kvm/hyp/switch.c b/arch/arm/kvm/hyp/switch.c
index e86679daddff..aac025783ee8 100644
--- a/arch/arm/kvm/hyp/switch.c
+++ b/arch/arm/kvm/hyp/switch.c
@@ -154,7 +154,7 @@ static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
 	return true;
 }
 
-int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
+int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 {
 	struct kvm_cpu_context *host_ctxt;
 	struct kvm_cpu_context *guest_ctxt;
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 6b626750b0a1..0be2747a6c5f 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -58,7 +58,9 @@ extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
 
 extern void __kvm_timer_set_cntvoff(u32 cntvoff_low, u32 cntvoff_high);
 
-extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
+extern int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu);
+
+extern int __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu);
 
 extern u64 __vgic_v3_get_ich_vtr_el2(void);
 extern u64 __vgic_v3_read_vmcr(void);
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index d2c0b1ae3216..b6126af539b6 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -362,7 +362,71 @@ static bool __hyp_text fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
 	return false;
 }
 
-int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
+/* Switch to the guest for VHE systems running in EL2 */
+int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpu_context *host_ctxt;
+	struct kvm_cpu_context *guest_ctxt;
+	bool fp_enabled;
+	u64 exit_code;
+
+	vcpu = kern_hyp_va(vcpu);
+
+	host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+	host_ctxt->__hyp_running_vcpu = vcpu;
+	guest_ctxt = &vcpu->arch.ctxt;
+
+	__sysreg_save_host_state(host_ctxt);
+
+	__activate_traps(vcpu);
+	__activate_vm(vcpu);
+
+	__vgic_restore_state(vcpu);
+	__timer_enable_traps(vcpu);
+
+	/*
+	 * We must restore the 32-bit state before the sysregs, thanks
+	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
+	 */
+	__sysreg32_restore_state(vcpu);
+	__sysreg_restore_guest_state(guest_ctxt);
+	__debug_switch_to_guest(vcpu);
+
+	do {
+		/* Jump in the fire! */
+		exit_code = __guest_enter(vcpu, host_ctxt);
+
+		/* And we're baaack! */
+	} while (fixup_guest_exit(vcpu, &exit_code));
+
+	fp_enabled = __fpsimd_enabled();
+
+	__sysreg_save_guest_state(guest_ctxt);
+	__sysreg32_save_state(vcpu);
+	__timer_disable_traps(vcpu);
+	__vgic_save_state(vcpu);
+
+	__deactivate_traps(vcpu);
+	__deactivate_vm(vcpu);
+
+	__sysreg_restore_host_state(host_ctxt);
+
+	if (fp_enabled) {
+		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
+		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
+	}
+
+	/*
+	 * This must come after restoring the host sysregs, since a non-VHE
+	 * system may enable SPE here and make use of the TTBRs.
+	 */
+	__debug_switch_to_host(vcpu);
+
+	return exit_code;
+}
+
+/* Switch to the guest for legacy non-VHE systems */
+int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 {
 	struct kvm_cpu_context *host_ctxt;
 	struct kvm_cpu_context *guest_ctxt;
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 2062d9357971..5bd879c78951 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -736,7 +736,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		if (has_vhe())
 			kvm_arm_vhe_guest_enter();
 
-		ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);
+		if (has_vhe())
+			ret = kvm_vcpu_run_vhe(vcpu);
+		else
+			ret = kvm_call_hyp(__kvm_vcpu_run_nvhe, vcpu);
 
 		if (has_vhe())
 			kvm_arm_vhe_guest_exit();
-- 
2.14.2

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

* [PATCH v4 14/40] KVM: arm64: Remove kern_hyp_va() use in VHE switch function
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

VHE kernels run completely in EL2 and therefore don't have a notion of
kernel and hyp addresses, they are all just kernel addresses.  Therefore
don't call kern_hyp_va() in the VHE switch function.

Reviewed-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/hyp/switch.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index b6126af539b6..85dae7b94a0f 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -370,9 +370,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	bool fp_enabled;
 	u64 exit_code;
 
-	vcpu = kern_hyp_va(vcpu);
-
-	host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+	host_ctxt = vcpu->arch.host_cpu_context;
 	host_ctxt->__hyp_running_vcpu = vcpu;
 	guest_ctxt = &vcpu->arch.ctxt;
 
-- 
2.14.2

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

* [PATCH v4 14/40] KVM: arm64: Remove kern_hyp_va() use in VHE switch function
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

VHE kernels run completely in EL2 and therefore don't have a notion of
kernel and hyp addresses, they are all just kernel addresses.  Therefore
don't call kern_hyp_va() in the VHE switch function.

Reviewed-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/hyp/switch.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index b6126af539b6..85dae7b94a0f 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -370,9 +370,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	bool fp_enabled;
 	u64 exit_code;
 
-	vcpu = kern_hyp_va(vcpu);
-
-	host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+	host_ctxt = vcpu->arch.host_cpu_context;
 	host_ctxt->__hyp_running_vcpu = vcpu;
 	guest_ctxt = &vcpu->arch.ctxt;
 
-- 
2.14.2

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

* [PATCH v4 15/40] KVM: arm64: Don't deactivate VM on VHE systems
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

There is no need to reset the VTTBR to zero when exiting the guest on
VHE systems.  VHE systems don't use stage 2 translations for the EL2&0
translation regime used by the host.

Reviewed-by: Andrew Jones <drjones@redhat.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v1:
     - Changed __activate_vm to take a kvm pointer
     - No longer adding inline attributes to functions

 arch/arm64/kvm/hyp/switch.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 85dae7b94a0f..734dac7f808f 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -156,9 +156,8 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
 	write_sysreg(0, pmuserenr_el0);
 }
 
-static void __hyp_text __activate_vm(struct kvm_vcpu *vcpu)
+static void __hyp_text __activate_vm(struct kvm *kvm)
 {
-	struct kvm *kvm = kern_hyp_va(vcpu->kvm);
 	write_sysreg(kvm->arch.vttbr, vttbr_el2);
 }
 
@@ -377,7 +376,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	__sysreg_save_host_state(host_ctxt);
 
 	__activate_traps(vcpu);
-	__activate_vm(vcpu);
+	__activate_vm(vcpu->kvm);
 
 	__vgic_restore_state(vcpu);
 	__timer_enable_traps(vcpu);
@@ -405,7 +404,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	__vgic_save_state(vcpu);
 
 	__deactivate_traps(vcpu);
-	__deactivate_vm(vcpu);
 
 	__sysreg_restore_host_state(host_ctxt);
 
@@ -440,7 +438,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 	__sysreg_save_host_state(host_ctxt);
 
 	__activate_traps(vcpu);
-	__activate_vm(vcpu);
+	__activate_vm(kern_hyp_va(vcpu->kvm));
 
 	__vgic_restore_state(vcpu);
 	__timer_enable_traps(vcpu);
-- 
2.14.2

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

* [PATCH v4 15/40] KVM: arm64: Don't deactivate VM on VHE systems
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

There is no need to reset the VTTBR to zero when exiting the guest on
VHE systems.  VHE systems don't use stage 2 translations for the EL2&0
translation regime used by the host.

Reviewed-by: Andrew Jones <drjones@redhat.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v1:
     - Changed __activate_vm to take a kvm pointer
     - No longer adding inline attributes to functions

 arch/arm64/kvm/hyp/switch.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 85dae7b94a0f..734dac7f808f 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -156,9 +156,8 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
 	write_sysreg(0, pmuserenr_el0);
 }
 
-static void __hyp_text __activate_vm(struct kvm_vcpu *vcpu)
+static void __hyp_text __activate_vm(struct kvm *kvm)
 {
-	struct kvm *kvm = kern_hyp_va(vcpu->kvm);
 	write_sysreg(kvm->arch.vttbr, vttbr_el2);
 }
 
@@ -377,7 +376,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	__sysreg_save_host_state(host_ctxt);
 
 	__activate_traps(vcpu);
-	__activate_vm(vcpu);
+	__activate_vm(vcpu->kvm);
 
 	__vgic_restore_state(vcpu);
 	__timer_enable_traps(vcpu);
@@ -405,7 +404,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	__vgic_save_state(vcpu);
 
 	__deactivate_traps(vcpu);
-	__deactivate_vm(vcpu);
 
 	__sysreg_restore_host_state(host_ctxt);
 
@@ -440,7 +438,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 	__sysreg_save_host_state(host_ctxt);
 
 	__activate_traps(vcpu);
-	__activate_vm(vcpu);
+	__activate_vm(kern_hyp_va(vcpu->kvm));
 
 	__vgic_restore_state(vcpu);
 	__timer_enable_traps(vcpu);
-- 
2.14.2

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

* [PATCH v4 16/40] KVM: arm64: Remove noop calls to timer save/restore from VHE switch
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

The VHE switch function calls __timer_enable_traps and
__timer_disable_traps which don't do anything on VHE systems.
Therefore, simply remove these calls from the VHE switch function and
make the functions non-conditional as they are now only called from the
non-VHE switch path.

Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v2:
     - Added comment explaining the timer enable/disable functions
       are for !VHE only.

 arch/arm64/kvm/hyp/switch.c |  2 --
 virt/kvm/arm/hyp/timer-sr.c | 44 ++++++++++++++++++++++----------------------
 2 files changed, 22 insertions(+), 24 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 734dac7f808f..f0fae320edc0 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -379,7 +379,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	__activate_vm(vcpu->kvm);
 
 	__vgic_restore_state(vcpu);
-	__timer_enable_traps(vcpu);
 
 	/*
 	 * We must restore the 32-bit state before the sysregs, thanks
@@ -400,7 +399,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 
 	__sysreg_save_guest_state(guest_ctxt);
 	__sysreg32_save_state(vcpu);
-	__timer_disable_traps(vcpu);
 	__vgic_save_state(vcpu);
 
 	__deactivate_traps(vcpu);
diff --git a/virt/kvm/arm/hyp/timer-sr.c b/virt/kvm/arm/hyp/timer-sr.c
index f24404b3c8df..77754a62eb0c 100644
--- a/virt/kvm/arm/hyp/timer-sr.c
+++ b/virt/kvm/arm/hyp/timer-sr.c
@@ -27,34 +27,34 @@ void __hyp_text __kvm_timer_set_cntvoff(u32 cntvoff_low, u32 cntvoff_high)
 	write_sysreg(cntvoff, cntvoff_el2);
 }
 
+/*
+ * Should only be called on non-VHE systems.
+ * VHE systems use EL2 timers and configure EL1 timers in kvm_timer_init_vhe().
+ */
 void __hyp_text __timer_disable_traps(struct kvm_vcpu *vcpu)
 {
-	/*
-	 * We don't need to do this for VHE since the host kernel runs in EL2
-	 * with HCR_EL2.TGE ==1, which makes those bits have no impact.
-	 */
-	if (!has_vhe()) {
-		u64 val;
+	u64 val;
 
-		/* Allow physical timer/counter access for the host */
-		val = read_sysreg(cnthctl_el2);
-		val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
-		write_sysreg(val, cnthctl_el2);
-	}
+	/* Allow physical timer/counter access for the host */
+	val = read_sysreg(cnthctl_el2);
+	val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
+	write_sysreg(val, cnthctl_el2);
 }
 
+/*
+ * Should only be called on non-VHE systems.
+ * VHE systems use EL2 timers and configure EL1 timers in kvm_timer_init_vhe().
+ */
 void __hyp_text __timer_enable_traps(struct kvm_vcpu *vcpu)
 {
-	if (!has_vhe()) {
-		u64 val;
+	u64 val;
 
-		/*
-		 * Disallow physical timer access for the guest
-		 * Physical counter access is allowed
-		 */
-		val = read_sysreg(cnthctl_el2);
-		val &= ~CNTHCTL_EL1PCEN;
-		val |= CNTHCTL_EL1PCTEN;
-		write_sysreg(val, cnthctl_el2);
-	}
+	/*
+	 * Disallow physical timer access for the guest
+	 * Physical counter access is allowed
+	 */
+	val = read_sysreg(cnthctl_el2);
+	val &= ~CNTHCTL_EL1PCEN;
+	val |= CNTHCTL_EL1PCTEN;
+	write_sysreg(val, cnthctl_el2);
 }
-- 
2.14.2

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

* [PATCH v4 16/40] KVM: arm64: Remove noop calls to timer save/restore from VHE switch
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

The VHE switch function calls __timer_enable_traps and
__timer_disable_traps which don't do anything on VHE systems.
Therefore, simply remove these calls from the VHE switch function and
make the functions non-conditional as they are now only called from the
non-VHE switch path.

Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v2:
     - Added comment explaining the timer enable/disable functions
       are for !VHE only.

 arch/arm64/kvm/hyp/switch.c |  2 --
 virt/kvm/arm/hyp/timer-sr.c | 44 ++++++++++++++++++++++----------------------
 2 files changed, 22 insertions(+), 24 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 734dac7f808f..f0fae320edc0 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -379,7 +379,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	__activate_vm(vcpu->kvm);
 
 	__vgic_restore_state(vcpu);
-	__timer_enable_traps(vcpu);
 
 	/*
 	 * We must restore the 32-bit state before the sysregs, thanks
@@ -400,7 +399,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 
 	__sysreg_save_guest_state(guest_ctxt);
 	__sysreg32_save_state(vcpu);
-	__timer_disable_traps(vcpu);
 	__vgic_save_state(vcpu);
 
 	__deactivate_traps(vcpu);
diff --git a/virt/kvm/arm/hyp/timer-sr.c b/virt/kvm/arm/hyp/timer-sr.c
index f24404b3c8df..77754a62eb0c 100644
--- a/virt/kvm/arm/hyp/timer-sr.c
+++ b/virt/kvm/arm/hyp/timer-sr.c
@@ -27,34 +27,34 @@ void __hyp_text __kvm_timer_set_cntvoff(u32 cntvoff_low, u32 cntvoff_high)
 	write_sysreg(cntvoff, cntvoff_el2);
 }
 
+/*
+ * Should only be called on non-VHE systems.
+ * VHE systems use EL2 timers and configure EL1 timers in kvm_timer_init_vhe().
+ */
 void __hyp_text __timer_disable_traps(struct kvm_vcpu *vcpu)
 {
-	/*
-	 * We don't need to do this for VHE since the host kernel runs in EL2
-	 * with HCR_EL2.TGE ==1, which makes those bits have no impact.
-	 */
-	if (!has_vhe()) {
-		u64 val;
+	u64 val;
 
-		/* Allow physical timer/counter access for the host */
-		val = read_sysreg(cnthctl_el2);
-		val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
-		write_sysreg(val, cnthctl_el2);
-	}
+	/* Allow physical timer/counter access for the host */
+	val = read_sysreg(cnthctl_el2);
+	val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
+	write_sysreg(val, cnthctl_el2);
 }
 
+/*
+ * Should only be called on non-VHE systems.
+ * VHE systems use EL2 timers and configure EL1 timers in kvm_timer_init_vhe().
+ */
 void __hyp_text __timer_enable_traps(struct kvm_vcpu *vcpu)
 {
-	if (!has_vhe()) {
-		u64 val;
+	u64 val;
 
-		/*
-		 * Disallow physical timer access for the guest
-		 * Physical counter access is allowed
-		 */
-		val = read_sysreg(cnthctl_el2);
-		val &= ~CNTHCTL_EL1PCEN;
-		val |= CNTHCTL_EL1PCTEN;
-		write_sysreg(val, cnthctl_el2);
-	}
+	/*
+	 * Disallow physical timer access for the guest
+	 * Physical counter access is allowed
+	 */
+	val = read_sysreg(cnthctl_el2);
+	val &= ~CNTHCTL_EL1PCEN;
+	val |= CNTHCTL_EL1PCTEN;
+	write_sysreg(val, cnthctl_el2);
 }
-- 
2.14.2

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

* [PATCH v4 17/40] KVM: arm64: Move userspace system registers into separate function
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

There's a semantic difference between the EL1 registers that control
operation of a kernel running in EL1 and EL1 registers that only control
userspace execution in EL0.  Since we can defer saving/restoring the
latter, move them into their own function.

ACTLR_EL1 is not used by a VHE host, so we can move this register into
the EL1 state which is not saved/restored for a VHE host.

We also take this chance to rename the function saving/restoring the
remaining system register to make it clear this function deals with
the EL1 system registers.

Reviewed-by: Andrew Jones <drjones@redhat.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v3:
     - Correct the comment about ACTLR_EL1 and adjust commit text.
    
    Changes since v2:
     - Save restore ACTLR_EL1 as part of the EL1 registers state instead of
       the user register state, as ACTLR_EL1 can't affect the host's execution
       on VHE systems.
    
    Changes since v1:
     - Added comment about sp_el0 to common save sysreg save/restore functions

 arch/arm64/kvm/hyp/sysreg-sr.c | 48 ++++++++++++++++++++++++++++++------------
 1 file changed, 35 insertions(+), 13 deletions(-)

diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 99fc60516103..d5a5145b4e7c 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -28,24 +28,33 @@ static void __hyp_text __sysreg_do_nothing(struct kvm_cpu_context *ctxt) { }
 /*
  * Non-VHE: Both host and guest must save everything.
  *
- * VHE: Host must save tpidr*_el0, actlr_el1, mdscr_el1, sp_el0,
+ * VHE: Host must save tpidr*_el0, mdscr_el1, sp_el0,
  * and guest must save everything.
  */
 
 static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
 {
-	ctxt->sys_regs[ACTLR_EL1]	= read_sysreg(actlr_el1);
-	ctxt->sys_regs[TPIDR_EL0]	= read_sysreg(tpidr_el0);
-	ctxt->sys_regs[TPIDRRO_EL0]	= read_sysreg(tpidrro_el0);
 	ctxt->sys_regs[MDSCR_EL1]	= read_sysreg(mdscr_el1);
+
+	/*
+	 * The host arm64 Linux uses sp_el0 to point to 'current' and it must
+	 * therefore be saved/restored on every entry/exit to/from the guest.
+	 */
 	ctxt->gp_regs.regs.sp		= read_sysreg(sp_el0);
 }
 
-static void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt)
+static void __hyp_text __sysreg_save_user_state(struct kvm_cpu_context *ctxt)
+{
+	ctxt->sys_regs[TPIDR_EL0]	= read_sysreg(tpidr_el0);
+	ctxt->sys_regs[TPIDRRO_EL0]	= read_sysreg(tpidrro_el0);
+}
+
+static void __hyp_text __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
 {
 	ctxt->sys_regs[MPIDR_EL1]	= read_sysreg(vmpidr_el2);
 	ctxt->sys_regs[CSSELR_EL1]	= read_sysreg(csselr_el1);
 	ctxt->sys_regs[SCTLR_EL1]	= read_sysreg_el1(sctlr);
+	ctxt->sys_regs[ACTLR_EL1]	= read_sysreg(actlr_el1);
 	ctxt->sys_regs[CPACR_EL1]	= read_sysreg_el1(cpacr);
 	ctxt->sys_regs[TTBR0_EL1]	= read_sysreg_el1(ttbr0);
 	ctxt->sys_regs[TTBR1_EL1]	= read_sysreg_el1(ttbr1);
@@ -73,35 +82,46 @@ static void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt)
 }
 
 static hyp_alternate_select(__sysreg_call_save_host_state,
-			    __sysreg_save_state, __sysreg_do_nothing,
+			    __sysreg_save_el1_state, __sysreg_do_nothing,
 			    ARM64_HAS_VIRT_HOST_EXTN);
 
 void __hyp_text __sysreg_save_host_state(struct kvm_cpu_context *ctxt)
 {
 	__sysreg_call_save_host_state()(ctxt);
 	__sysreg_save_common_state(ctxt);
+	__sysreg_save_user_state(ctxt);
 }
 
 void __hyp_text __sysreg_save_guest_state(struct kvm_cpu_context *ctxt)
 {
-	__sysreg_save_state(ctxt);
+	__sysreg_save_el1_state(ctxt);
 	__sysreg_save_common_state(ctxt);
+	__sysreg_save_user_state(ctxt);
 }
 
 static void __hyp_text __sysreg_restore_common_state(struct kvm_cpu_context *ctxt)
 {
-	write_sysreg(ctxt->sys_regs[ACTLR_EL1],	  actlr_el1);
-	write_sysreg(ctxt->sys_regs[TPIDR_EL0],	  tpidr_el0);
-	write_sysreg(ctxt->sys_regs[TPIDRRO_EL0], tpidrro_el0);
 	write_sysreg(ctxt->sys_regs[MDSCR_EL1],	  mdscr_el1);
+
+	/*
+	 * The host arm64 Linux uses sp_el0 to point to 'current' and it must
+	 * therefore be saved/restored on every entry/exit to/from the guest.
+	 */
 	write_sysreg(ctxt->gp_regs.regs.sp,	  sp_el0);
 }
 
-static void __hyp_text __sysreg_restore_state(struct kvm_cpu_context *ctxt)
+static void __hyp_text __sysreg_restore_user_state(struct kvm_cpu_context *ctxt)
+{
+	write_sysreg(ctxt->sys_regs[TPIDR_EL0],	  	tpidr_el0);
+	write_sysreg(ctxt->sys_regs[TPIDRRO_EL0], 	tpidrro_el0);
+}
+
+static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
 {
 	write_sysreg(ctxt->sys_regs[MPIDR_EL1],		vmpidr_el2);
 	write_sysreg(ctxt->sys_regs[CSSELR_EL1],	csselr_el1);
 	write_sysreg_el1(ctxt->sys_regs[SCTLR_EL1],	sctlr);
+	write_sysreg(ctxt->sys_regs[ACTLR_EL1],	  	actlr_el1);
 	write_sysreg_el1(ctxt->sys_regs[CPACR_EL1],	cpacr);
 	write_sysreg_el1(ctxt->sys_regs[TTBR0_EL1],	ttbr0);
 	write_sysreg_el1(ctxt->sys_regs[TTBR1_EL1],	ttbr1);
@@ -129,19 +149,21 @@ static void __hyp_text __sysreg_restore_state(struct kvm_cpu_context *ctxt)
 }
 
 static hyp_alternate_select(__sysreg_call_restore_host_state,
-			    __sysreg_restore_state, __sysreg_do_nothing,
+			    __sysreg_restore_el1_state, __sysreg_do_nothing,
 			    ARM64_HAS_VIRT_HOST_EXTN);
 
 void __hyp_text __sysreg_restore_host_state(struct kvm_cpu_context *ctxt)
 {
 	__sysreg_call_restore_host_state()(ctxt);
 	__sysreg_restore_common_state(ctxt);
+	__sysreg_restore_user_state(ctxt);
 }
 
 void __hyp_text __sysreg_restore_guest_state(struct kvm_cpu_context *ctxt)
 {
-	__sysreg_restore_state(ctxt);
+	__sysreg_restore_el1_state(ctxt);
 	__sysreg_restore_common_state(ctxt);
+	__sysreg_restore_user_state(ctxt);
 }
 
 void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
-- 
2.14.2

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

* [PATCH v4 17/40] KVM: arm64: Move userspace system registers into separate function
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

There's a semantic difference between the EL1 registers that control
operation of a kernel running in EL1 and EL1 registers that only control
userspace execution in EL0.  Since we can defer saving/restoring the
latter, move them into their own function.

ACTLR_EL1 is not used by a VHE host, so we can move this register into
the EL1 state which is not saved/restored for a VHE host.

We also take this chance to rename the function saving/restoring the
remaining system register to make it clear this function deals with
the EL1 system registers.

Reviewed-by: Andrew Jones <drjones@redhat.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---

Notes:
    Changes since v3:
     - Correct the comment about ACTLR_EL1 and adjust commit text.
    
    Changes since v2:
     - Save restore ACTLR_EL1 as part of the EL1 registers state instead of
       the user register state, as ACTLR_EL1 can't affect the host's execution
       on VHE systems.
    
    Changes since v1:
     - Added comment about sp_el0 to common save sysreg save/restore functions

 arch/arm64/kvm/hyp/sysreg-sr.c | 48 ++++++++++++++++++++++++++++++------------
 1 file changed, 35 insertions(+), 13 deletions(-)

diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 99fc60516103..d5a5145b4e7c 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -28,24 +28,33 @@ static void __hyp_text __sysreg_do_nothing(struct kvm_cpu_context *ctxt) { }
 /*
  * Non-VHE: Both host and guest must save everything.
  *
- * VHE: Host must save tpidr*_el0, actlr_el1, mdscr_el1, sp_el0,
+ * VHE: Host must save tpidr*_el0, mdscr_el1, sp_el0,
  * and guest must save everything.
  */
 
 static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
 {
-	ctxt->sys_regs[ACTLR_EL1]	= read_sysreg(actlr_el1);
-	ctxt->sys_regs[TPIDR_EL0]	= read_sysreg(tpidr_el0);
-	ctxt->sys_regs[TPIDRRO_EL0]	= read_sysreg(tpidrro_el0);
 	ctxt->sys_regs[MDSCR_EL1]	= read_sysreg(mdscr_el1);
+
+	/*
+	 * The host arm64 Linux uses sp_el0 to point to 'current' and it must
+	 * therefore be saved/restored on every entry/exit to/from the guest.
+	 */
 	ctxt->gp_regs.regs.sp		= read_sysreg(sp_el0);
 }
 
-static void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt)
+static void __hyp_text __sysreg_save_user_state(struct kvm_cpu_context *ctxt)
+{
+	ctxt->sys_regs[TPIDR_EL0]	= read_sysreg(tpidr_el0);
+	ctxt->sys_regs[TPIDRRO_EL0]	= read_sysreg(tpidrro_el0);
+}
+
+static void __hyp_text __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
 {
 	ctxt->sys_regs[MPIDR_EL1]	= read_sysreg(vmpidr_el2);
 	ctxt->sys_regs[CSSELR_EL1]	= read_sysreg(csselr_el1);
 	ctxt->sys_regs[SCTLR_EL1]	= read_sysreg_el1(sctlr);
+	ctxt->sys_regs[ACTLR_EL1]	= read_sysreg(actlr_el1);
 	ctxt->sys_regs[CPACR_EL1]	= read_sysreg_el1(cpacr);
 	ctxt->sys_regs[TTBR0_EL1]	= read_sysreg_el1(ttbr0);
 	ctxt->sys_regs[TTBR1_EL1]	= read_sysreg_el1(ttbr1);
@@ -73,35 +82,46 @@ static void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt)
 }
 
 static hyp_alternate_select(__sysreg_call_save_host_state,
-			    __sysreg_save_state, __sysreg_do_nothing,
+			    __sysreg_save_el1_state, __sysreg_do_nothing,
 			    ARM64_HAS_VIRT_HOST_EXTN);
 
 void __hyp_text __sysreg_save_host_state(struct kvm_cpu_context *ctxt)
 {
 	__sysreg_call_save_host_state()(ctxt);
 	__sysreg_save_common_state(ctxt);
+	__sysreg_save_user_state(ctxt);
 }
 
 void __hyp_text __sysreg_save_guest_state(struct kvm_cpu_context *ctxt)
 {
-	__sysreg_save_state(ctxt);
+	__sysreg_save_el1_state(ctxt);
 	__sysreg_save_common_state(ctxt);
+	__sysreg_save_user_state(ctxt);
 }
 
 static void __hyp_text __sysreg_restore_common_state(struct kvm_cpu_context *ctxt)
 {
-	write_sysreg(ctxt->sys_regs[ACTLR_EL1],	  actlr_el1);
-	write_sysreg(ctxt->sys_regs[TPIDR_EL0],	  tpidr_el0);
-	write_sysreg(ctxt->sys_regs[TPIDRRO_EL0], tpidrro_el0);
 	write_sysreg(ctxt->sys_regs[MDSCR_EL1],	  mdscr_el1);
+
+	/*
+	 * The host arm64 Linux uses sp_el0 to point to 'current' and it must
+	 * therefore be saved/restored on every entry/exit to/from the guest.
+	 */
 	write_sysreg(ctxt->gp_regs.regs.sp,	  sp_el0);
 }
 
-static void __hyp_text __sysreg_restore_state(struct kvm_cpu_context *ctxt)
+static void __hyp_text __sysreg_restore_user_state(struct kvm_cpu_context *ctxt)
+{
+	write_sysreg(ctxt->sys_regs[TPIDR_EL0],	  	tpidr_el0);
+	write_sysreg(ctxt->sys_regs[TPIDRRO_EL0], 	tpidrro_el0);
+}
+
+static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
 {
 	write_sysreg(ctxt->sys_regs[MPIDR_EL1],		vmpidr_el2);
 	write_sysreg(ctxt->sys_regs[CSSELR_EL1],	csselr_el1);
 	write_sysreg_el1(ctxt->sys_regs[SCTLR_EL1],	sctlr);
+	write_sysreg(ctxt->sys_regs[ACTLR_EL1],	  	actlr_el1);
 	write_sysreg_el1(ctxt->sys_regs[CPACR_EL1],	cpacr);
 	write_sysreg_el1(ctxt->sys_regs[TTBR0_EL1],	ttbr0);
 	write_sysreg_el1(ctxt->sys_regs[TTBR1_EL1],	ttbr1);
@@ -129,19 +149,21 @@ static void __hyp_text __sysreg_restore_state(struct kvm_cpu_context *ctxt)
 }
 
 static hyp_alternate_select(__sysreg_call_restore_host_state,
-			    __sysreg_restore_state, __sysreg_do_nothing,
+			    __sysreg_restore_el1_state, __sysreg_do_nothing,
 			    ARM64_HAS_VIRT_HOST_EXTN);
 
 void __hyp_text __sysreg_restore_host_state(struct kvm_cpu_context *ctxt)
 {
 	__sysreg_call_restore_host_state()(ctxt);
 	__sysreg_restore_common_state(ctxt);
+	__sysreg_restore_user_state(ctxt);
 }
 
 void __hyp_text __sysreg_restore_guest_state(struct kvm_cpu_context *ctxt)
 {
-	__sysreg_restore_state(ctxt);
+	__sysreg_restore_el1_state(ctxt);
 	__sysreg_restore_common_state(ctxt);
+	__sysreg_restore_user_state(ctxt);
 }
 
 void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
-- 
2.14.2

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

* [PATCH v4 18/40] KVM: arm64: Rewrite sysreg alternatives to static keys
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

As we are about to move calls around in the sysreg save/restore logic,
let's first rewrite the alternative function callers, because it is
going to make the next patches much easier to read.

Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/hyp/sysreg-sr.c | 17 ++++-------------
 1 file changed, 4 insertions(+), 13 deletions(-)

diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index d5a5145b4e7c..51b557226170 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -22,9 +22,6 @@
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
 
-/* Yes, this does nothing, on purpose */
-static void __hyp_text __sysreg_do_nothing(struct kvm_cpu_context *ctxt) { }
-
 /*
  * Non-VHE: Both host and guest must save everything.
  *
@@ -81,13 +78,10 @@ static void __hyp_text __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
 		ctxt->sys_regs[DISR_EL1] = read_sysreg_s(SYS_VDISR_EL2);
 }
 
-static hyp_alternate_select(__sysreg_call_save_host_state,
-			    __sysreg_save_el1_state, __sysreg_do_nothing,
-			    ARM64_HAS_VIRT_HOST_EXTN);
-
 void __hyp_text __sysreg_save_host_state(struct kvm_cpu_context *ctxt)
 {
-	__sysreg_call_save_host_state()(ctxt);
+	if (!has_vhe())
+		__sysreg_save_el1_state(ctxt);
 	__sysreg_save_common_state(ctxt);
 	__sysreg_save_user_state(ctxt);
 }
@@ -148,13 +142,10 @@ static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
 		write_sysreg_s(ctxt->sys_regs[DISR_EL1], SYS_VDISR_EL2);
 }
 
-static hyp_alternate_select(__sysreg_call_restore_host_state,
-			    __sysreg_restore_el1_state, __sysreg_do_nothing,
-			    ARM64_HAS_VIRT_HOST_EXTN);
-
 void __hyp_text __sysreg_restore_host_state(struct kvm_cpu_context *ctxt)
 {
-	__sysreg_call_restore_host_state()(ctxt);
+	if (!has_vhe())
+		__sysreg_restore_el1_state(ctxt);
 	__sysreg_restore_common_state(ctxt);
 	__sysreg_restore_user_state(ctxt);
 }
-- 
2.14.2

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

* [PATCH v4 18/40] KVM: arm64: Rewrite sysreg alternatives to static keys
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

As we are about to move calls around in the sysreg save/restore logic,
let's first rewrite the alternative function callers, because it is
going to make the next patches much easier to read.

Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/hyp/sysreg-sr.c | 17 ++++-------------
 1 file changed, 4 insertions(+), 13 deletions(-)

diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index d5a5145b4e7c..51b557226170 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -22,9 +22,6 @@
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
 
-/* Yes, this does nothing, on purpose */
-static void __hyp_text __sysreg_do_nothing(struct kvm_cpu_context *ctxt) { }
-
 /*
  * Non-VHE: Both host and guest must save everything.
  *
@@ -81,13 +78,10 @@ static void __hyp_text __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
 		ctxt->sys_regs[DISR_EL1] = read_sysreg_s(SYS_VDISR_EL2);
 }
 
-static hyp_alternate_select(__sysreg_call_save_host_state,
-			    __sysreg_save_el1_state, __sysreg_do_nothing,
-			    ARM64_HAS_VIRT_HOST_EXTN);
-
 void __hyp_text __sysreg_save_host_state(struct kvm_cpu_context *ctxt)
 {
-	__sysreg_call_save_host_state()(ctxt);
+	if (!has_vhe())
+		__sysreg_save_el1_state(ctxt);
 	__sysreg_save_common_state(ctxt);
 	__sysreg_save_user_state(ctxt);
 }
@@ -148,13 +142,10 @@ static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
 		write_sysreg_s(ctxt->sys_regs[DISR_EL1], SYS_VDISR_EL2);
 }
 
-static hyp_alternate_select(__sysreg_call_restore_host_state,
-			    __sysreg_restore_el1_state, __sysreg_do_nothing,
-			    ARM64_HAS_VIRT_HOST_EXTN);
-
 void __hyp_text __sysreg_restore_host_state(struct kvm_cpu_context *ctxt)
 {
-	__sysreg_call_restore_host_state()(ctxt);
+	if (!has_vhe())
+		__sysreg_restore_el1_state(ctxt);
 	__sysreg_restore_common_state(ctxt);
 	__sysreg_restore_user_state(ctxt);
 }
-- 
2.14.2

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

* [PATCH v4 19/40] KVM: arm64: Introduce separate VHE/non-VHE sysreg save/restore functions
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

As we are about to handle system registers quite differently between VHE
and non-VHE systems.  In preparation for that, we need to split some of
the handling functions between VHE and non-VHE functionality.

For now, we simply copy the non-VHE functions, but we do change the use
of static keys for VHE and non-VHE functionality now that we have
separate functions.

Reviewed-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/include/asm/kvm_hyp.h | 12 ++++++++----
 arch/arm64/kvm/hyp/switch.c      | 20 ++++++++++----------
 arch/arm64/kvm/hyp/sysreg-sr.c   | 40 ++++++++++++++++++++++++++++++++--------
 3 files changed, 50 insertions(+), 22 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index aeda2a777365..23c09d9af343 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -131,10 +131,14 @@ int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
 void __timer_enable_traps(struct kvm_vcpu *vcpu);
 void __timer_disable_traps(struct kvm_vcpu *vcpu);
 
-void __sysreg_save_host_state(struct kvm_cpu_context *ctxt);
-void __sysreg_restore_host_state(struct kvm_cpu_context *ctxt);
-void __sysreg_save_guest_state(struct kvm_cpu_context *ctxt);
-void __sysreg_restore_guest_state(struct kvm_cpu_context *ctxt);
+void __sysreg_save_host_state_nvhe(struct kvm_cpu_context *ctxt);
+void __sysreg_restore_host_state_nvhe(struct kvm_cpu_context *ctxt);
+void __sysreg_save_guest_state_nvhe(struct kvm_cpu_context *ctxt);
+void __sysreg_restore_guest_state_nvhe(struct kvm_cpu_context *ctxt);
+void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt);
+void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt);
+void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt);
+void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt);
 void __sysreg32_save_state(struct kvm_vcpu *vcpu);
 void __sysreg32_restore_state(struct kvm_vcpu *vcpu);
 
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index f0fae320edc0..717c8f5c6be7 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -373,7 +373,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	host_ctxt->__hyp_running_vcpu = vcpu;
 	guest_ctxt = &vcpu->arch.ctxt;
 
-	__sysreg_save_host_state(host_ctxt);
+	sysreg_save_host_state_vhe(host_ctxt);
 
 	__activate_traps(vcpu);
 	__activate_vm(vcpu->kvm);
@@ -385,7 +385,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
 	 */
 	__sysreg32_restore_state(vcpu);
-	__sysreg_restore_guest_state(guest_ctxt);
+	sysreg_restore_guest_state_vhe(guest_ctxt);
 	__debug_switch_to_guest(vcpu);
 
 	do {
@@ -397,13 +397,13 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 
 	fp_enabled = __fpsimd_enabled();
 
-	__sysreg_save_guest_state(guest_ctxt);
+	sysreg_save_guest_state_vhe(guest_ctxt);
 	__sysreg32_save_state(vcpu);
 	__vgic_save_state(vcpu);
 
 	__deactivate_traps(vcpu);
 
-	__sysreg_restore_host_state(host_ctxt);
+	sysreg_restore_host_state_vhe(host_ctxt);
 
 	if (fp_enabled) {
 		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
@@ -433,7 +433,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 	host_ctxt->__hyp_running_vcpu = vcpu;
 	guest_ctxt = &vcpu->arch.ctxt;
 
-	__sysreg_save_host_state(host_ctxt);
+	__sysreg_save_host_state_nvhe(host_ctxt);
 
 	__activate_traps(vcpu);
 	__activate_vm(kern_hyp_va(vcpu->kvm));
@@ -446,7 +446,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
 	 */
 	__sysreg32_restore_state(vcpu);
-	__sysreg_restore_guest_state(guest_ctxt);
+	__sysreg_restore_guest_state_nvhe(guest_ctxt);
 	__debug_switch_to_guest(vcpu);
 
 	do {
@@ -466,7 +466,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 
 	fp_enabled = __fpsimd_enabled();
 
-	__sysreg_save_guest_state(guest_ctxt);
+	__sysreg_save_guest_state_nvhe(guest_ctxt);
 	__sysreg32_save_state(vcpu);
 	__timer_disable_traps(vcpu);
 	__vgic_save_state(vcpu);
@@ -474,7 +474,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 	__deactivate_traps(vcpu);
 	__deactivate_vm(vcpu);
 
-	__sysreg_restore_host_state(host_ctxt);
+	__sysreg_restore_host_state_nvhe(host_ctxt);
 
 	if (fp_enabled) {
 		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
@@ -504,7 +504,7 @@ static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par,
 		__timer_disable_traps(vcpu);
 		__deactivate_traps(vcpu);
 		__deactivate_vm(vcpu);
-		__sysreg_restore_host_state(__host_ctxt);
+		__sysreg_restore_host_state_nvhe(__host_ctxt);
 	}
 
 	/*
@@ -527,7 +527,7 @@ static void __hyp_call_panic_vhe(u64 spsr, u64 elr, u64 par,
 	vcpu = host_ctxt->__hyp_running_vcpu;
 
 	__deactivate_traps(vcpu);
-	__sysreg_restore_host_state(host_ctxt);
+	sysreg_restore_host_state_vhe(host_ctxt);
 
 	panic(__hyp_panic_string,
 	      spsr,  elr,
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 51b557226170..18801ab56e8b 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -78,15 +78,27 @@ static void __hyp_text __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
 		ctxt->sys_regs[DISR_EL1] = read_sysreg_s(SYS_VDISR_EL2);
 }
 
-void __hyp_text __sysreg_save_host_state(struct kvm_cpu_context *ctxt)
+void __hyp_text __sysreg_save_host_state_nvhe(struct kvm_cpu_context *ctxt)
+{
+	__sysreg_save_el1_state(ctxt);
+	__sysreg_save_common_state(ctxt);
+	__sysreg_save_user_state(ctxt);
+}
+
+void __hyp_text __sysreg_save_guest_state_nvhe(struct kvm_cpu_context *ctxt)
+{
+	__sysreg_save_el1_state(ctxt);
+	__sysreg_save_common_state(ctxt);
+	__sysreg_save_user_state(ctxt);
+}
+
+void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt)
 {
-	if (!has_vhe())
-		__sysreg_save_el1_state(ctxt);
 	__sysreg_save_common_state(ctxt);
 	__sysreg_save_user_state(ctxt);
 }
 
-void __hyp_text __sysreg_save_guest_state(struct kvm_cpu_context *ctxt)
+void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt)
 {
 	__sysreg_save_el1_state(ctxt);
 	__sysreg_save_common_state(ctxt);
@@ -142,15 +154,27 @@ static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
 		write_sysreg_s(ctxt->sys_regs[DISR_EL1], SYS_VDISR_EL2);
 }
 
-void __hyp_text __sysreg_restore_host_state(struct kvm_cpu_context *ctxt)
+void __hyp_text __sysreg_restore_host_state_nvhe(struct kvm_cpu_context *ctxt)
+{
+	__sysreg_restore_el1_state(ctxt);
+	__sysreg_restore_common_state(ctxt);
+	__sysreg_restore_user_state(ctxt);
+}
+
+void __hyp_text __sysreg_restore_guest_state_nvhe(struct kvm_cpu_context *ctxt)
+{
+	__sysreg_restore_el1_state(ctxt);
+	__sysreg_restore_common_state(ctxt);
+	__sysreg_restore_user_state(ctxt);
+}
+
+void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt)
 {
-	if (!has_vhe())
-		__sysreg_restore_el1_state(ctxt);
 	__sysreg_restore_common_state(ctxt);
 	__sysreg_restore_user_state(ctxt);
 }
 
-void __hyp_text __sysreg_restore_guest_state(struct kvm_cpu_context *ctxt)
+void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt)
 {
 	__sysreg_restore_el1_state(ctxt);
 	__sysreg_restore_common_state(ctxt);
-- 
2.14.2

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

* [PATCH v4 19/40] KVM: arm64: Introduce separate VHE/non-VHE sysreg save/restore functions
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

As we are about to handle system registers quite differently between VHE
and non-VHE systems.  In preparation for that, we need to split some of
the handling functions between VHE and non-VHE functionality.

For now, we simply copy the non-VHE functions, but we do change the use
of static keys for VHE and non-VHE functionality now that we have
separate functions.

Reviewed-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/include/asm/kvm_hyp.h | 12 ++++++++----
 arch/arm64/kvm/hyp/switch.c      | 20 ++++++++++----------
 arch/arm64/kvm/hyp/sysreg-sr.c   | 40 ++++++++++++++++++++++++++++++++--------
 3 files changed, 50 insertions(+), 22 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index aeda2a777365..23c09d9af343 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -131,10 +131,14 @@ int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
 void __timer_enable_traps(struct kvm_vcpu *vcpu);
 void __timer_disable_traps(struct kvm_vcpu *vcpu);
 
-void __sysreg_save_host_state(struct kvm_cpu_context *ctxt);
-void __sysreg_restore_host_state(struct kvm_cpu_context *ctxt);
-void __sysreg_save_guest_state(struct kvm_cpu_context *ctxt);
-void __sysreg_restore_guest_state(struct kvm_cpu_context *ctxt);
+void __sysreg_save_host_state_nvhe(struct kvm_cpu_context *ctxt);
+void __sysreg_restore_host_state_nvhe(struct kvm_cpu_context *ctxt);
+void __sysreg_save_guest_state_nvhe(struct kvm_cpu_context *ctxt);
+void __sysreg_restore_guest_state_nvhe(struct kvm_cpu_context *ctxt);
+void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt);
+void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt);
+void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt);
+void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt);
 void __sysreg32_save_state(struct kvm_vcpu *vcpu);
 void __sysreg32_restore_state(struct kvm_vcpu *vcpu);
 
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index f0fae320edc0..717c8f5c6be7 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -373,7 +373,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	host_ctxt->__hyp_running_vcpu = vcpu;
 	guest_ctxt = &vcpu->arch.ctxt;
 
-	__sysreg_save_host_state(host_ctxt);
+	sysreg_save_host_state_vhe(host_ctxt);
 
 	__activate_traps(vcpu);
 	__activate_vm(vcpu->kvm);
@@ -385,7 +385,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
 	 */
 	__sysreg32_restore_state(vcpu);
-	__sysreg_restore_guest_state(guest_ctxt);
+	sysreg_restore_guest_state_vhe(guest_ctxt);
 	__debug_switch_to_guest(vcpu);
 
 	do {
@@ -397,13 +397,13 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 
 	fp_enabled = __fpsimd_enabled();
 
-	__sysreg_save_guest_state(guest_ctxt);
+	sysreg_save_guest_state_vhe(guest_ctxt);
 	__sysreg32_save_state(vcpu);
 	__vgic_save_state(vcpu);
 
 	__deactivate_traps(vcpu);
 
-	__sysreg_restore_host_state(host_ctxt);
+	sysreg_restore_host_state_vhe(host_ctxt);
 
 	if (fp_enabled) {
 		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
@@ -433,7 +433,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 	host_ctxt->__hyp_running_vcpu = vcpu;
 	guest_ctxt = &vcpu->arch.ctxt;
 
-	__sysreg_save_host_state(host_ctxt);
+	__sysreg_save_host_state_nvhe(host_ctxt);
 
 	__activate_traps(vcpu);
 	__activate_vm(kern_hyp_va(vcpu->kvm));
@@ -446,7 +446,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
 	 */
 	__sysreg32_restore_state(vcpu);
-	__sysreg_restore_guest_state(guest_ctxt);
+	__sysreg_restore_guest_state_nvhe(guest_ctxt);
 	__debug_switch_to_guest(vcpu);
 
 	do {
@@ -466,7 +466,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 
 	fp_enabled = __fpsimd_enabled();
 
-	__sysreg_save_guest_state(guest_ctxt);
+	__sysreg_save_guest_state_nvhe(guest_ctxt);
 	__sysreg32_save_state(vcpu);
 	__timer_disable_traps(vcpu);
 	__vgic_save_state(vcpu);
@@ -474,7 +474,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 	__deactivate_traps(vcpu);
 	__deactivate_vm(vcpu);
 
-	__sysreg_restore_host_state(host_ctxt);
+	__sysreg_restore_host_state_nvhe(host_ctxt);
 
 	if (fp_enabled) {
 		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
@@ -504,7 +504,7 @@ static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par,
 		__timer_disable_traps(vcpu);
 		__deactivate_traps(vcpu);
 		__deactivate_vm(vcpu);
-		__sysreg_restore_host_state(__host_ctxt);
+		__sysreg_restore_host_state_nvhe(__host_ctxt);
 	}
 
 	/*
@@ -527,7 +527,7 @@ static void __hyp_call_panic_vhe(u64 spsr, u64 elr, u64 par,
 	vcpu = host_ctxt->__hyp_running_vcpu;
 
 	__deactivate_traps(vcpu);
-	__sysreg_restore_host_state(host_ctxt);
+	sysreg_restore_host_state_vhe(host_ctxt);
 
 	panic(__hyp_panic_string,
 	      spsr,  elr,
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 51b557226170..18801ab56e8b 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -78,15 +78,27 @@ static void __hyp_text __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
 		ctxt->sys_regs[DISR_EL1] = read_sysreg_s(SYS_VDISR_EL2);
 }
 
-void __hyp_text __sysreg_save_host_state(struct kvm_cpu_context *ctxt)
+void __hyp_text __sysreg_save_host_state_nvhe(struct kvm_cpu_context *ctxt)
+{
+	__sysreg_save_el1_state(ctxt);
+	__sysreg_save_common_state(ctxt);
+	__sysreg_save_user_state(ctxt);
+}
+
+void __hyp_text __sysreg_save_guest_state_nvhe(struct kvm_cpu_context *ctxt)
+{
+	__sysreg_save_el1_state(ctxt);
+	__sysreg_save_common_state(ctxt);
+	__sysreg_save_user_state(ctxt);
+}
+
+void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt)
 {
-	if (!has_vhe())
-		__sysreg_save_el1_state(ctxt);
 	__sysreg_save_common_state(ctxt);
 	__sysreg_save_user_state(ctxt);
 }
 
-void __hyp_text __sysreg_save_guest_state(struct kvm_cpu_context *ctxt)
+void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt)
 {
 	__sysreg_save_el1_state(ctxt);
 	__sysreg_save_common_state(ctxt);
@@ -142,15 +154,27 @@ static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
 		write_sysreg_s(ctxt->sys_regs[DISR_EL1], SYS_VDISR_EL2);
 }
 
-void __hyp_text __sysreg_restore_host_state(struct kvm_cpu_context *ctxt)
+void __hyp_text __sysreg_restore_host_state_nvhe(struct kvm_cpu_context *ctxt)
+{
+	__sysreg_restore_el1_state(ctxt);
+	__sysreg_restore_common_state(ctxt);
+	__sysreg_restore_user_state(ctxt);
+}
+
+void __hyp_text __sysreg_restore_guest_state_nvhe(struct kvm_cpu_context *ctxt)
+{
+	__sysreg_restore_el1_state(ctxt);
+	__sysreg_restore_common_state(ctxt);
+	__sysreg_restore_user_state(ctxt);
+}
+
+void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt)
 {
-	if (!has_vhe())
-		__sysreg_restore_el1_state(ctxt);
 	__sysreg_restore_common_state(ctxt);
 	__sysreg_restore_user_state(ctxt);
 }
 
-void __hyp_text __sysreg_restore_guest_state(struct kvm_cpu_context *ctxt)
+void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt)
 {
 	__sysreg_restore_el1_state(ctxt);
 	__sysreg_restore_common_state(ctxt);
-- 
2.14.2

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

* [PATCH v4 20/40] KVM: arm/arm64: Remove leftover comment from kvm_vcpu_run_vhe
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

The comment only applied to SPE on non-VHE systems, so we simply remove
it.

Suggested-by: Andrew Jones <drjones@redhat.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/hyp/switch.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 717c8f5c6be7..a99224996e33 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -410,10 +410,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
 	}
 
-	/*
-	 * This must come after restoring the host sysregs, since a non-VHE
-	 * system may enable SPE here and make use of the TTBRs.
-	 */
 	__debug_switch_to_host(vcpu);
 
 	return exit_code;
-- 
2.14.2

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

* [PATCH v4 20/40] KVM: arm/arm64: Remove leftover comment from kvm_vcpu_run_vhe
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

The comment only applied to SPE on non-VHE systems, so we simply remove
it.

Suggested-by: Andrew Jones <drjones@redhat.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/hyp/switch.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 717c8f5c6be7..a99224996e33 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -410,10 +410,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
 	}
 
-	/*
-	 * This must come after restoring the host sysregs, since a non-VHE
-	 * system may enable SPE here and make use of the TTBRs.
-	 */
 	__debug_switch_to_host(vcpu);
 
 	return exit_code;
-- 
2.14.2

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

* [PATCH v4 21/40] KVM: arm64: Unify non-VHE host/guest sysreg save and restore functions
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

There is no need to have multiple identical functions with different
names for saving host and guest state.  When saving and restoring state
for the host and guest, the state is the same for both contexts, and
that's why we have the kvm_cpu_context structure.  Delete one
version and rename the other into simply save/restore.

Reviewed-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/include/asm/kvm_hyp.h |  6 ++----
 arch/arm64/kvm/hyp/switch.c      | 10 +++++-----
 arch/arm64/kvm/hyp/sysreg-sr.c   | 18 ++----------------
 3 files changed, 9 insertions(+), 25 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 23c09d9af343..2b1fda90dde4 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -131,10 +131,8 @@ int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
 void __timer_enable_traps(struct kvm_vcpu *vcpu);
 void __timer_disable_traps(struct kvm_vcpu *vcpu);
 
-void __sysreg_save_host_state_nvhe(struct kvm_cpu_context *ctxt);
-void __sysreg_restore_host_state_nvhe(struct kvm_cpu_context *ctxt);
-void __sysreg_save_guest_state_nvhe(struct kvm_cpu_context *ctxt);
-void __sysreg_restore_guest_state_nvhe(struct kvm_cpu_context *ctxt);
+void __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt);
+void __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt);
 void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt);
 void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt);
 void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt);
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index a99224996e33..22e77deb8e2e 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -429,7 +429,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 	host_ctxt->__hyp_running_vcpu = vcpu;
 	guest_ctxt = &vcpu->arch.ctxt;
 
-	__sysreg_save_host_state_nvhe(host_ctxt);
+	__sysreg_save_state_nvhe(host_ctxt);
 
 	__activate_traps(vcpu);
 	__activate_vm(kern_hyp_va(vcpu->kvm));
@@ -442,7 +442,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
 	 */
 	__sysreg32_restore_state(vcpu);
-	__sysreg_restore_guest_state_nvhe(guest_ctxt);
+	__sysreg_restore_state_nvhe(guest_ctxt);
 	__debug_switch_to_guest(vcpu);
 
 	do {
@@ -462,7 +462,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 
 	fp_enabled = __fpsimd_enabled();
 
-	__sysreg_save_guest_state_nvhe(guest_ctxt);
+	__sysreg_save_state_nvhe(guest_ctxt);
 	__sysreg32_save_state(vcpu);
 	__timer_disable_traps(vcpu);
 	__vgic_save_state(vcpu);
@@ -470,7 +470,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 	__deactivate_traps(vcpu);
 	__deactivate_vm(vcpu);
 
-	__sysreg_restore_host_state_nvhe(host_ctxt);
+	__sysreg_restore_state_nvhe(host_ctxt);
 
 	if (fp_enabled) {
 		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
@@ -500,7 +500,7 @@ static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par,
 		__timer_disable_traps(vcpu);
 		__deactivate_traps(vcpu);
 		__deactivate_vm(vcpu);
-		__sysreg_restore_host_state_nvhe(__host_ctxt);
+		__sysreg_restore_state_nvhe(__host_ctxt);
 	}
 
 	/*
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 18801ab56e8b..d35b3aa680ab 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -78,14 +78,7 @@ static void __hyp_text __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
 		ctxt->sys_regs[DISR_EL1] = read_sysreg_s(SYS_VDISR_EL2);
 }
 
-void __hyp_text __sysreg_save_host_state_nvhe(struct kvm_cpu_context *ctxt)
-{
-	__sysreg_save_el1_state(ctxt);
-	__sysreg_save_common_state(ctxt);
-	__sysreg_save_user_state(ctxt);
-}
-
-void __hyp_text __sysreg_save_guest_state_nvhe(struct kvm_cpu_context *ctxt)
+void __hyp_text __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt)
 {
 	__sysreg_save_el1_state(ctxt);
 	__sysreg_save_common_state(ctxt);
@@ -154,14 +147,7 @@ static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
 		write_sysreg_s(ctxt->sys_regs[DISR_EL1], SYS_VDISR_EL2);
 }
 
-void __hyp_text __sysreg_restore_host_state_nvhe(struct kvm_cpu_context *ctxt)
-{
-	__sysreg_restore_el1_state(ctxt);
-	__sysreg_restore_common_state(ctxt);
-	__sysreg_restore_user_state(ctxt);
-}
-
-void __hyp_text __sysreg_restore_guest_state_nvhe(struct kvm_cpu_context *ctxt)
+void __hyp_text __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt)
 {
 	__sysreg_restore_el1_state(ctxt);
 	__sysreg_restore_common_state(ctxt);
-- 
2.14.2

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

* [PATCH v4 21/40] KVM: arm64: Unify non-VHE host/guest sysreg save and restore functions
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

There is no need to have multiple identical functions with different
names for saving host and guest state.  When saving and restoring state
for the host and guest, the state is the same for both contexts, and
that's why we have the kvm_cpu_context structure.  Delete one
version and rename the other into simply save/restore.

Reviewed-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/include/asm/kvm_hyp.h |  6 ++----
 arch/arm64/kvm/hyp/switch.c      | 10 +++++-----
 arch/arm64/kvm/hyp/sysreg-sr.c   | 18 ++----------------
 3 files changed, 9 insertions(+), 25 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 23c09d9af343..2b1fda90dde4 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -131,10 +131,8 @@ int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
 void __timer_enable_traps(struct kvm_vcpu *vcpu);
 void __timer_disable_traps(struct kvm_vcpu *vcpu);
 
-void __sysreg_save_host_state_nvhe(struct kvm_cpu_context *ctxt);
-void __sysreg_restore_host_state_nvhe(struct kvm_cpu_context *ctxt);
-void __sysreg_save_guest_state_nvhe(struct kvm_cpu_context *ctxt);
-void __sysreg_restore_guest_state_nvhe(struct kvm_cpu_context *ctxt);
+void __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt);
+void __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt);
 void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt);
 void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt);
 void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt);
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index a99224996e33..22e77deb8e2e 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -429,7 +429,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 	host_ctxt->__hyp_running_vcpu = vcpu;
 	guest_ctxt = &vcpu->arch.ctxt;
 
-	__sysreg_save_host_state_nvhe(host_ctxt);
+	__sysreg_save_state_nvhe(host_ctxt);
 
 	__activate_traps(vcpu);
 	__activate_vm(kern_hyp_va(vcpu->kvm));
@@ -442,7 +442,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
 	 */
 	__sysreg32_restore_state(vcpu);
-	__sysreg_restore_guest_state_nvhe(guest_ctxt);
+	__sysreg_restore_state_nvhe(guest_ctxt);
 	__debug_switch_to_guest(vcpu);
 
 	do {
@@ -462,7 +462,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 
 	fp_enabled = __fpsimd_enabled();
 
-	__sysreg_save_guest_state_nvhe(guest_ctxt);
+	__sysreg_save_state_nvhe(guest_ctxt);
 	__sysreg32_save_state(vcpu);
 	__timer_disable_traps(vcpu);
 	__vgic_save_state(vcpu);
@@ -470,7 +470,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 	__deactivate_traps(vcpu);
 	__deactivate_vm(vcpu);
 
-	__sysreg_restore_host_state_nvhe(host_ctxt);
+	__sysreg_restore_state_nvhe(host_ctxt);
 
 	if (fp_enabled) {
 		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
@@ -500,7 +500,7 @@ static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par,
 		__timer_disable_traps(vcpu);
 		__deactivate_traps(vcpu);
 		__deactivate_vm(vcpu);
-		__sysreg_restore_host_state_nvhe(__host_ctxt);
+		__sysreg_restore_state_nvhe(__host_ctxt);
 	}
 
 	/*
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 18801ab56e8b..d35b3aa680ab 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -78,14 +78,7 @@ static void __hyp_text __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
 		ctxt->sys_regs[DISR_EL1] = read_sysreg_s(SYS_VDISR_EL2);
 }
 
-void __hyp_text __sysreg_save_host_state_nvhe(struct kvm_cpu_context *ctxt)
-{
-	__sysreg_save_el1_state(ctxt);
-	__sysreg_save_common_state(ctxt);
-	__sysreg_save_user_state(ctxt);
-}
-
-void __hyp_text __sysreg_save_guest_state_nvhe(struct kvm_cpu_context *ctxt)
+void __hyp_text __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt)
 {
 	__sysreg_save_el1_state(ctxt);
 	__sysreg_save_common_state(ctxt);
@@ -154,14 +147,7 @@ static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
 		write_sysreg_s(ctxt->sys_regs[DISR_EL1], SYS_VDISR_EL2);
 }
 
-void __hyp_text __sysreg_restore_host_state_nvhe(struct kvm_cpu_context *ctxt)
-{
-	__sysreg_restore_el1_state(ctxt);
-	__sysreg_restore_common_state(ctxt);
-	__sysreg_restore_user_state(ctxt);
-}
-
-void __hyp_text __sysreg_restore_guest_state_nvhe(struct kvm_cpu_context *ctxt)
+void __hyp_text __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt)
 {
 	__sysreg_restore_el1_state(ctxt);
 	__sysreg_restore_common_state(ctxt);
-- 
2.14.2

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

* [PATCH v4 22/40] KVM: arm64: Don't save the host ELR_EL2 and SPSR_EL2 on VHE systems
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

On non-VHE systems we need to save the ELR_EL2 and SPSR_EL2 so that we can
return to the host in EL1 in the same state and location where we issued a
hypercall to EL2, but on VHE ELR_EL2 and SPSR_EL2 are not useful because we
never enter a guest as a result of an exception entry that would be directly
handled by KVM. The kernel entry code already saves ELR_EL1/SPSR_EL1 on
exception entry, which is enough.  Therefore, factor out these registers into
separate save/restore functions, making it easy to exclude them from the VHE
world-switch path later on.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/hyp/sysreg-sr.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index d35b3aa680ab..906606dc4e2c 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -71,6 +71,10 @@ static void __hyp_text __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
 	ctxt->gp_regs.sp_el1		= read_sysreg(sp_el1);
 	ctxt->gp_regs.elr_el1		= read_sysreg_el1(elr);
 	ctxt->gp_regs.spsr[KVM_SPSR_EL1]= read_sysreg_el1(spsr);
+}
+
+static void __hyp_text __sysreg_save_el2_return_state(struct kvm_cpu_context *ctxt)
+{
 	ctxt->gp_regs.regs.pc		= read_sysreg_el2(elr);
 	ctxt->gp_regs.regs.pstate	= read_sysreg_el2(spsr);
 
@@ -83,6 +87,7 @@ void __hyp_text __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt)
 	__sysreg_save_el1_state(ctxt);
 	__sysreg_save_common_state(ctxt);
 	__sysreg_save_user_state(ctxt);
+	__sysreg_save_el2_return_state(ctxt);
 }
 
 void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt)
@@ -96,6 +101,7 @@ void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt)
 	__sysreg_save_el1_state(ctxt);
 	__sysreg_save_common_state(ctxt);
 	__sysreg_save_user_state(ctxt);
+	__sysreg_save_el2_return_state(ctxt);
 }
 
 static void __hyp_text __sysreg_restore_common_state(struct kvm_cpu_context *ctxt)
@@ -140,6 +146,11 @@ static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
 	write_sysreg(ctxt->gp_regs.sp_el1,		sp_el1);
 	write_sysreg_el1(ctxt->gp_regs.elr_el1,		elr);
 	write_sysreg_el1(ctxt->gp_regs.spsr[KVM_SPSR_EL1],spsr);
+}
+
+static void __hyp_text
+__sysreg_restore_el2_return_state(struct kvm_cpu_context *ctxt)
+{
 	write_sysreg_el2(ctxt->gp_regs.regs.pc,		elr);
 	write_sysreg_el2(ctxt->gp_regs.regs.pstate,	spsr);
 
@@ -152,6 +163,7 @@ void __hyp_text __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt)
 	__sysreg_restore_el1_state(ctxt);
 	__sysreg_restore_common_state(ctxt);
 	__sysreg_restore_user_state(ctxt);
+	__sysreg_restore_el2_return_state(ctxt);
 }
 
 void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt)
@@ -165,6 +177,7 @@ void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt)
 	__sysreg_restore_el1_state(ctxt);
 	__sysreg_restore_common_state(ctxt);
 	__sysreg_restore_user_state(ctxt);
+	__sysreg_restore_el2_return_state(ctxt);
 }
 
 void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
-- 
2.14.2

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

* [PATCH v4 22/40] KVM: arm64: Don't save the host ELR_EL2 and SPSR_EL2 on VHE systems
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

On non-VHE systems we need to save the ELR_EL2 and SPSR_EL2 so that we can
return to the host in EL1 in the same state and location where we issued a
hypercall to EL2, but on VHE ELR_EL2 and SPSR_EL2 are not useful because we
never enter a guest as a result of an exception entry that would be directly
handled by KVM. The kernel entry code already saves ELR_EL1/SPSR_EL1 on
exception entry, which is enough.  Therefore, factor out these registers into
separate save/restore functions, making it easy to exclude them from the VHE
world-switch path later on.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/hyp/sysreg-sr.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index d35b3aa680ab..906606dc4e2c 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -71,6 +71,10 @@ static void __hyp_text __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
 	ctxt->gp_regs.sp_el1		= read_sysreg(sp_el1);
 	ctxt->gp_regs.elr_el1		= read_sysreg_el1(elr);
 	ctxt->gp_regs.spsr[KVM_SPSR_EL1]= read_sysreg_el1(spsr);
+}
+
+static void __hyp_text __sysreg_save_el2_return_state(struct kvm_cpu_context *ctxt)
+{
 	ctxt->gp_regs.regs.pc		= read_sysreg_el2(elr);
 	ctxt->gp_regs.regs.pstate	= read_sysreg_el2(spsr);
 
@@ -83,6 +87,7 @@ void __hyp_text __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt)
 	__sysreg_save_el1_state(ctxt);
 	__sysreg_save_common_state(ctxt);
 	__sysreg_save_user_state(ctxt);
+	__sysreg_save_el2_return_state(ctxt);
 }
 
 void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt)
@@ -96,6 +101,7 @@ void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt)
 	__sysreg_save_el1_state(ctxt);
 	__sysreg_save_common_state(ctxt);
 	__sysreg_save_user_state(ctxt);
+	__sysreg_save_el2_return_state(ctxt);
 }
 
 static void __hyp_text __sysreg_restore_common_state(struct kvm_cpu_context *ctxt)
@@ -140,6 +146,11 @@ static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
 	write_sysreg(ctxt->gp_regs.sp_el1,		sp_el1);
 	write_sysreg_el1(ctxt->gp_regs.elr_el1,		elr);
 	write_sysreg_el1(ctxt->gp_regs.spsr[KVM_SPSR_EL1],spsr);
+}
+
+static void __hyp_text
+__sysreg_restore_el2_return_state(struct kvm_cpu_context *ctxt)
+{
 	write_sysreg_el2(ctxt->gp_regs.regs.pc,		elr);
 	write_sysreg_el2(ctxt->gp_regs.regs.pstate,	spsr);
 
@@ -152,6 +163,7 @@ void __hyp_text __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt)
 	__sysreg_restore_el1_state(ctxt);
 	__sysreg_restore_common_state(ctxt);
 	__sysreg_restore_user_state(ctxt);
+	__sysreg_restore_el2_return_state(ctxt);
 }
 
 void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt)
@@ -165,6 +177,7 @@ void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt)
 	__sysreg_restore_el1_state(ctxt);
 	__sysreg_restore_common_state(ctxt);
 	__sysreg_restore_user_state(ctxt);
+	__sysreg_restore_el2_return_state(ctxt);
 }
 
 void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
-- 
2.14.2

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

* [PATCH v4 23/40] KVM: arm64: Change 32-bit handling of VM system registers
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

We currently handle 32-bit accesses to trapped VM system registers using
the 32-bit index into the coproc array on the vcpu structure, which is a
union of the coproc array and the sysreg array.

Since all the 32-bit coproc indices are created to correspond to the
architectural mapping between 64-bit system registers and 32-bit
coprocessor registers, and because the AArch64 system registers are the
double in size of the AArch32 coprocessor registers, we can always find
the system register entry that we must update by dividing the 32-bit
coproc index by 2.

This is going to make our lives much easier when we have to start
accessing system registers that use deferred save/restore and might
have to be read directly from the physical CPU.

Reviewed-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/include/asm/kvm_host.h |  8 --------
 arch/arm64/kvm/sys_regs.c         | 20 +++++++++++++++-----
 2 files changed, 15 insertions(+), 13 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index c30fc96992df..f2a6f39aec87 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -295,14 +295,6 @@ struct kvm_vcpu_arch {
 #define vcpu_cp14(v,r)		((v)->arch.ctxt.copro[(r)])
 #define vcpu_cp15(v,r)		((v)->arch.ctxt.copro[(r)])
 
-#ifdef CONFIG_CPU_BIG_ENDIAN
-#define vcpu_cp15_64_high(v,r)	vcpu_cp15((v),(r))
-#define vcpu_cp15_64_low(v,r)	vcpu_cp15((v),(r) + 1)
-#else
-#define vcpu_cp15_64_high(v,r)	vcpu_cp15((v),(r) + 1)
-#define vcpu_cp15_64_low(v,r)	vcpu_cp15((v),(r))
-#endif
-
 struct kvm_vm_stat {
 	ulong remote_tlb_flush;
 };
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 50a43c7b97ca..b48af790615e 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -121,16 +121,26 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
 			  const struct sys_reg_desc *r)
 {
 	bool was_enabled = vcpu_has_cache_enabled(vcpu);
+	u64 val;
+	int reg = r->reg;
 
 	BUG_ON(!p->is_write);
 
-	if (!p->is_aarch32) {
-		vcpu_sys_reg(vcpu, r->reg) = p->regval;
+	/* See the 32bit mapping in kvm_host.h */
+	if (p->is_aarch32)
+		reg = r->reg / 2;
+
+	if (!p->is_aarch32 || !p->is_32bit) {
+		val = p->regval;
 	} else {
-		if (!p->is_32bit)
-			vcpu_cp15_64_high(vcpu, r->reg) = upper_32_bits(p->regval);
-		vcpu_cp15_64_low(vcpu, r->reg) = lower_32_bits(p->regval);
+		val = vcpu_sys_reg(vcpu, reg);
+		if (r->reg % 2)
+			val = (p->regval << 32) | (u64)lower_32_bits(val);
+		else
+			val = ((u64)upper_32_bits(val) << 32) |
+				lower_32_bits(p->regval);
 	}
+	vcpu_sys_reg(vcpu, reg) = val;
 
 	kvm_toggle_cache(vcpu, was_enabled);
 	return true;
-- 
2.14.2

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

* [PATCH v4 23/40] KVM: arm64: Change 32-bit handling of VM system registers
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

We currently handle 32-bit accesses to trapped VM system registers using
the 32-bit index into the coproc array on the vcpu structure, which is a
union of the coproc array and the sysreg array.

Since all the 32-bit coproc indices are created to correspond to the
architectural mapping between 64-bit system registers and 32-bit
coprocessor registers, and because the AArch64 system registers are the
double in size of the AArch32 coprocessor registers, we can always find
the system register entry that we must update by dividing the 32-bit
coproc index by 2.

This is going to make our lives much easier when we have to start
accessing system registers that use deferred save/restore and might
have to be read directly from the physical CPU.

Reviewed-by: Andrew Jones <drjones@redhat.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/include/asm/kvm_host.h |  8 --------
 arch/arm64/kvm/sys_regs.c         | 20 +++++++++++++++-----
 2 files changed, 15 insertions(+), 13 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index c30fc96992df..f2a6f39aec87 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -295,14 +295,6 @@ struct kvm_vcpu_arch {
 #define vcpu_cp14(v,r)		((v)->arch.ctxt.copro[(r)])
 #define vcpu_cp15(v,r)		((v)->arch.ctxt.copro[(r)])
 
-#ifdef CONFIG_CPU_BIG_ENDIAN
-#define vcpu_cp15_64_high(v,r)	vcpu_cp15((v),(r))
-#define vcpu_cp15_64_low(v,r)	vcpu_cp15((v),(r) + 1)
-#else
-#define vcpu_cp15_64_high(v,r)	vcpu_cp15((v),(r) + 1)
-#define vcpu_cp15_64_low(v,r)	vcpu_cp15((v),(r))
-#endif
-
 struct kvm_vm_stat {
 	ulong remote_tlb_flush;
 };
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 50a43c7b97ca..b48af790615e 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -121,16 +121,26 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
 			  const struct sys_reg_desc *r)
 {
 	bool was_enabled = vcpu_has_cache_enabled(vcpu);
+	u64 val;
+	int reg = r->reg;
 
 	BUG_ON(!p->is_write);
 
-	if (!p->is_aarch32) {
-		vcpu_sys_reg(vcpu, r->reg) = p->regval;
+	/* See the 32bit mapping in kvm_host.h */
+	if (p->is_aarch32)
+		reg = r->reg / 2;
+
+	if (!p->is_aarch32 || !p->is_32bit) {
+		val = p->regval;
 	} else {
-		if (!p->is_32bit)
-			vcpu_cp15_64_high(vcpu, r->reg) = upper_32_bits(p->regval);
-		vcpu_cp15_64_low(vcpu, r->reg) = lower_32_bits(p->regval);
+		val = vcpu_sys_reg(vcpu, reg);
+		if (r->reg % 2)
+			val = (p->regval << 32) | (u64)lower_32_bits(val);
+		else
+			val = ((u64)upper_32_bits(val) << 32) |
+				lower_32_bits(p->regval);
 	}
+	vcpu_sys_reg(vcpu, reg) = val;
 
 	kvm_toggle_cache(vcpu, was_enabled);
 	return true;
-- 
2.14.2

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

* [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov,
	Christoffer Dall

From: Christoffer Dall <cdall@cs.columbia.edu>

Currently we access the system registers array via the vcpu_sys_reg()
macro.  However, we are about to change the behavior to some times
modify the register file directly, so let's change this to two
primitives:

 * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
 * Direct array access macro __vcpu_sys_reg()

The first primitive should be used in places where the code needs to
access the currently loaded VCPU's state as observed by the guest.  For
example, when trapping on cache related registers, a write to a system
register should go directly to the VCPU version of the register.

The second primitive can be used in places where the VCPU is known to
never be running (for example userspace access) or for registers which
are never context switched (for example all the PMU system registers).

This rewrites all users of vcpu_sys_regs to one of the two primitives
above.

No functional change.

Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
---

Notes:
    Changes since v2:
     - New patch (deferred register handling has been reworked)

 arch/arm64/include/asm/kvm_emulate.h | 13 ++++---
 arch/arm64/include/asm/kvm_host.h    | 13 ++++++-
 arch/arm64/include/asm/kvm_mmu.h     |  2 +-
 arch/arm64/kvm/debug.c               | 27 +++++++++-----
 arch/arm64/kvm/inject_fault.c        |  8 ++--
 arch/arm64/kvm/sys_regs.c            | 71 ++++++++++++++++++------------------
 arch/arm64/kvm/sys_regs.h            |  4 +-
 arch/arm64/kvm/sys_regs_generic_v8.c |  4 +-
 virt/kvm/arm/pmu.c                   | 37 ++++++++++---------
 9 files changed, 102 insertions(+), 77 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 3cc535591bdf..d313aaae5c38 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -290,15 +290,18 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
 
 static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
 {
-	return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
+	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
 }
 
 static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
 {
-	if (vcpu_mode_is_32bit(vcpu))
+	if (vcpu_mode_is_32bit(vcpu)) {
 		*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
-	else
-		vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
+	} else {
+		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
+		sctlr |= (1 << 25);
+		vcpu_write_sys_reg(vcpu, SCTLR_EL1, sctlr);
+	}
 }
 
 static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
@@ -306,7 +309,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
 	if (vcpu_mode_is_32bit(vcpu))
 		return !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_E_BIT);
 
-	return !!(vcpu_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
+	return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
 }
 
 static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index f2a6f39aec87..68398bf7882f 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
 };
 
 #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
-#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
+
+/*
+ * Only use __vcpu_sys_reg if you know you want the memory backed version of a
+ * register, and not the one most recently accessed by a runnning VCPU.  For
+ * example, for userpace access or for system registers that are never context
+ * switched, but only emulated.
+ */
+#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
+
+#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
+#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
+
 /*
  * CP14 and CP15 live in the same array, as they are backed by the
  * same system registers.
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 9679067a1574..95f46e73c4dc 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -249,7 +249,7 @@ struct kvm;
 
 static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
 {
-	return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
+	return (vcpu_read_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
 }
 
 static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index feedb877cff8..db32d10a56a1 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -46,7 +46,8 @@ static DEFINE_PER_CPU(u32, mdcr_el2);
  */
 static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
 {
-	vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1);
+	vcpu->arch.guest_debug_preserved.mdscr_el1 =
+		vcpu_read_sys_reg(vcpu, MDSCR_EL1);
 
 	trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
 				vcpu->arch.guest_debug_preserved.mdscr_el1);
@@ -54,10 +55,11 @@ static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
 
 static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
 {
-	vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1;
+	vcpu_write_sys_reg(vcpu, MDSCR_EL1,
+			   vcpu->arch.guest_debug_preserved.mdscr_el1);
 
 	trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
-				vcpu_sys_reg(vcpu, MDSCR_EL1));
+				vcpu_read_sys_reg(vcpu, MDSCR_EL1));
 }
 
 /**
@@ -108,6 +110,7 @@ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
 void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
 {
 	bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY);
+	unsigned long mdscr;
 
 	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
 
@@ -152,9 +155,13 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
 		 */
 		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
 			*vcpu_cpsr(vcpu) |=  DBG_SPSR_SS;
-			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_SS;
+			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
+			mdscr |= DBG_MDSCR_SS;
+			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
 		} else {
-			vcpu_sys_reg(vcpu, MDSCR_EL1) &= ~DBG_MDSCR_SS;
+			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
+			mdscr &= ~DBG_MDSCR_SS;
+			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
 		}
 
 		trace_kvm_arm_set_dreg32("SPSR_EL2", *vcpu_cpsr(vcpu));
@@ -170,7 +177,9 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
 		 */
 		if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) {
 			/* Enable breakpoints/watchpoints */
-			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_MDE;
+			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
+			mdscr |= DBG_MDSCR_MDE;
+			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
 
 			vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state;
 			vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
@@ -194,12 +203,12 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
 		vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
 
 	/* If KDE or MDE are set, perform a full save/restore cycle. */
-	if ((vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_KDE) ||
-	    (vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_MDE))
+	if (vcpu_read_sys_reg(vcpu, MDSCR_EL1) & (DBG_MDSCR_KDE | DBG_MDSCR_MDE))
 		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
 
 	trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2);
-	trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_sys_reg(vcpu, MDSCR_EL1));
+	trace_kvm_arm_set_dreg32("MDSCR_EL1",
+				 vcpu_read_sys_reg(vcpu, MDSCR_EL1));
 }
 
 void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index 30a3f58cdb7b..e08db2f2dd75 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -58,7 +58,7 @@ static u64 get_except_vector(struct kvm_vcpu *vcpu, enum exception_type type)
 		exc_offset = LOWER_EL_AArch32_VECTOR;
 	}
 
-	return vcpu_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
+	return vcpu_read_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
 }
 
 static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
@@ -73,7 +73,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
 	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
 	*vcpu_spsr(vcpu) = cpsr;
 
-	vcpu_sys_reg(vcpu, FAR_EL1) = addr;
+	vcpu_write_sys_reg(vcpu, FAR_EL1, addr);
 
 	/*
 	 * Build an {i,d}abort, depending on the level and the
@@ -94,7 +94,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
 	if (!is_iabt)
 		esr |= ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT;
 
-	vcpu_sys_reg(vcpu, ESR_EL1) = esr | ESR_ELx_FSC_EXTABT;
+	vcpu_write_sys_reg(vcpu, ESR_EL1, esr | ESR_ELx_FSC_EXTABT);
 }
 
 static void inject_undef64(struct kvm_vcpu *vcpu)
@@ -115,7 +115,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
 	if (kvm_vcpu_trap_il_is32bit(vcpu))
 		esr |= ESR_ELx_IL;
 
-	vcpu_sys_reg(vcpu, ESR_EL1) = esr;
+	vcpu_write_sys_reg(vcpu, ESR_EL1, esr);
 }
 
 /**
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index b48af790615e..a05d2c01c786 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -133,14 +133,14 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
 	if (!p->is_aarch32 || !p->is_32bit) {
 		val = p->regval;
 	} else {
-		val = vcpu_sys_reg(vcpu, reg);
+		val = vcpu_read_sys_reg(vcpu, reg);
 		if (r->reg % 2)
 			val = (p->regval << 32) | (u64)lower_32_bits(val);
 		else
 			val = ((u64)upper_32_bits(val) << 32) |
 				lower_32_bits(p->regval);
 	}
-	vcpu_sys_reg(vcpu, reg) = val;
+	vcpu_write_sys_reg(vcpu, reg, val);
 
 	kvm_toggle_cache(vcpu, was_enabled);
 	return true;
@@ -241,10 +241,10 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
 			    const struct sys_reg_desc *r)
 {
 	if (p->is_write) {
-		vcpu_sys_reg(vcpu, r->reg) = p->regval;
+		vcpu_write_sys_reg(vcpu, r->reg, p->regval);
 		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
 	} else {
-		p->regval = vcpu_sys_reg(vcpu, r->reg);
+		p->regval = vcpu_read_sys_reg(vcpu, r->reg);
 	}
 
 	trace_trap_reg(__func__, r->reg, p->is_write, p->regval);
@@ -457,7 +457,8 @@ static void reset_wcr(struct kvm_vcpu *vcpu,
 
 static void reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 {
-	vcpu_sys_reg(vcpu, AMAIR_EL1) = read_sysreg(amair_el1);
+	u64 amair = read_sysreg(amair_el1);
+	vcpu_write_sys_reg(vcpu, AMAIR_EL1, amair);
 }
 
 static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
@@ -474,7 +475,7 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 	mpidr = (vcpu->vcpu_id & 0x0f) << MPIDR_LEVEL_SHIFT(0);
 	mpidr |= ((vcpu->vcpu_id >> 4) & 0xff) << MPIDR_LEVEL_SHIFT(1);
 	mpidr |= ((vcpu->vcpu_id >> 12) & 0xff) << MPIDR_LEVEL_SHIFT(2);
-	vcpu_sys_reg(vcpu, MPIDR_EL1) = (1ULL << 31) | mpidr;
+	vcpu_write_sys_reg(vcpu, MPIDR_EL1, (1ULL << 31) | mpidr);
 }
 
 static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
@@ -488,12 +489,12 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 	 */
 	val = ((pmcr & ~ARMV8_PMU_PMCR_MASK)
 	       | (ARMV8_PMU_PMCR_MASK & 0xdecafbad)) & (~ARMV8_PMU_PMCR_E);
-	vcpu_sys_reg(vcpu, PMCR_EL0) = val;
+	__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
 }
 
 static bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags)
 {
-	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+	u64 reg = __vcpu_sys_reg(vcpu, PMUSERENR_EL0);
 	bool enabled = (reg & flags) || vcpu_mode_priv(vcpu);
 
 	if (!enabled)
@@ -535,14 +536,14 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 
 	if (p->is_write) {
 		/* Only update writeable bits of PMCR */
-		val = vcpu_sys_reg(vcpu, PMCR_EL0);
+		val = __vcpu_sys_reg(vcpu, PMCR_EL0);
 		val &= ~ARMV8_PMU_PMCR_MASK;
 		val |= p->regval & ARMV8_PMU_PMCR_MASK;
-		vcpu_sys_reg(vcpu, PMCR_EL0) = val;
+		__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
 		kvm_pmu_handle_pmcr(vcpu, val);
 	} else {
 		/* PMCR.P & PMCR.C are RAZ */
-		val = vcpu_sys_reg(vcpu, PMCR_EL0)
+		val = __vcpu_sys_reg(vcpu, PMCR_EL0)
 		      & ~(ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C);
 		p->regval = val;
 	}
@@ -560,10 +561,10 @@ static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 		return false;
 
 	if (p->is_write)
-		vcpu_sys_reg(vcpu, PMSELR_EL0) = p->regval;
+		__vcpu_sys_reg(vcpu, PMSELR_EL0) = p->regval;
 	else
 		/* return PMSELR.SEL field */
-		p->regval = vcpu_sys_reg(vcpu, PMSELR_EL0)
+		p->regval = __vcpu_sys_reg(vcpu, PMSELR_EL0)
 			    & ARMV8_PMU_COUNTER_MASK;
 
 	return true;
@@ -596,7 +597,7 @@ static bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
 {
 	u64 pmcr, val;
 
-	pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
+	pmcr = __vcpu_sys_reg(vcpu, PMCR_EL0);
 	val = (pmcr >> ARMV8_PMU_PMCR_N_SHIFT) & ARMV8_PMU_PMCR_N_MASK;
 	if (idx >= val && idx != ARMV8_PMU_CYCLE_IDX) {
 		kvm_inject_undefined(vcpu);
@@ -621,7 +622,7 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
 			if (pmu_access_event_counter_el0_disabled(vcpu))
 				return false;
 
-			idx = vcpu_sys_reg(vcpu, PMSELR_EL0)
+			idx = __vcpu_sys_reg(vcpu, PMSELR_EL0)
 			      & ARMV8_PMU_COUNTER_MASK;
 		} else if (r->Op2 == 0) {
 			/* PMCCNTR_EL0 */
@@ -676,7 +677,7 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 
 	if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 1) {
 		/* PMXEVTYPER_EL0 */
-		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_PMU_COUNTER_MASK;
+		idx = __vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_PMU_COUNTER_MASK;
 		reg = PMEVTYPER0_EL0 + idx;
 	} else if (r->CRn == 14 && (r->CRm & 12) == 12) {
 		idx = ((r->CRm & 3) << 3) | (r->Op2 & 7);
@@ -694,9 +695,9 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 
 	if (p->is_write) {
 		kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
-		vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_PMU_EVTYPE_MASK;
+		__vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_PMU_EVTYPE_MASK;
 	} else {
-		p->regval = vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK;
+		p->regval = __vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK;
 	}
 
 	return true;
@@ -718,15 +719,15 @@ static bool access_pmcnten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 		val = p->regval & mask;
 		if (r->Op2 & 0x1) {
 			/* accessing PMCNTENSET_EL0 */
-			vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val;
+			__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val;
 			kvm_pmu_enable_counter(vcpu, val);
 		} else {
 			/* accessing PMCNTENCLR_EL0 */
-			vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val;
+			__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val;
 			kvm_pmu_disable_counter(vcpu, val);
 		}
 	} else {
-		p->regval = vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask;
+		p->regval = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask;
 	}
 
 	return true;
@@ -750,12 +751,12 @@ static bool access_pminten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 
 		if (r->Op2 & 0x1)
 			/* accessing PMINTENSET_EL1 */
-			vcpu_sys_reg(vcpu, PMINTENSET_EL1) |= val;
+			__vcpu_sys_reg(vcpu, PMINTENSET_EL1) |= val;
 		else
 			/* accessing PMINTENCLR_EL1 */
-			vcpu_sys_reg(vcpu, PMINTENSET_EL1) &= ~val;
+			__vcpu_sys_reg(vcpu, PMINTENSET_EL1) &= ~val;
 	} else {
-		p->regval = vcpu_sys_reg(vcpu, PMINTENSET_EL1) & mask;
+		p->regval = __vcpu_sys_reg(vcpu, PMINTENSET_EL1) & mask;
 	}
 
 	return true;
@@ -775,12 +776,12 @@ static bool access_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	if (p->is_write) {
 		if (r->CRm & 0x2)
 			/* accessing PMOVSSET_EL0 */
-			vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= (p->regval & mask);
+			__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= (p->regval & mask);
 		else
 			/* accessing PMOVSCLR_EL0 */
-			vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= ~(p->regval & mask);
+			__vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= ~(p->regval & mask);
 	} else {
-		p->regval = vcpu_sys_reg(vcpu, PMOVSSET_EL0) & mask;
+		p->regval = __vcpu_sys_reg(vcpu, PMOVSSET_EL0) & mask;
 	}
 
 	return true;
@@ -817,10 +818,10 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			return false;
 		}
 
-		vcpu_sys_reg(vcpu, PMUSERENR_EL0) = p->regval
-						    & ARMV8_PMU_USERENR_MASK;
-	} else {
-		p->regval = vcpu_sys_reg(vcpu, PMUSERENR_EL0)
+		__vcpu_sys_reg(vcpu, PMUSERENR_EL0) =
+			       p->regval & ARMV8_PMU_USERENR_MASK;
+	} else  {
+		p->regval = __vcpu_sys_reg(vcpu, PMUSERENR_EL0)
 			    & ARMV8_PMU_USERENR_MASK;
 	}
 
@@ -2204,7 +2205,7 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
 	if (r->get_user)
 		return (r->get_user)(vcpu, r, reg, uaddr);
 
-	return reg_to_user(uaddr, &vcpu_sys_reg(vcpu, r->reg), reg->id);
+	return reg_to_user(uaddr, &__vcpu_sys_reg(vcpu, r->reg), reg->id);
 }
 
 int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
@@ -2225,7 +2226,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
 	if (r->set_user)
 		return (r->set_user)(vcpu, r, reg, uaddr);
 
-	return reg_from_user(&vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
+	return reg_from_user(&__vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
 }
 
 static unsigned int num_demux_regs(void)
@@ -2431,6 +2432,6 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
 	reset_sys_reg_descs(vcpu, table, num);
 
 	for (num = 1; num < NR_SYS_REGS; num++)
-		if (vcpu_sys_reg(vcpu, num) == 0x4242424242424242)
-			panic("Didn't reset vcpu_sys_reg(%zi)", num);
+		if (__vcpu_sys_reg(vcpu, num) == 0x4242424242424242)
+			panic("Didn't reset __vcpu_sys_reg(%zi)", num);
 }
diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
index 060f5348ef25..cd710f8b63e0 100644
--- a/arch/arm64/kvm/sys_regs.h
+++ b/arch/arm64/kvm/sys_regs.h
@@ -89,14 +89,14 @@ static inline void reset_unknown(struct kvm_vcpu *vcpu,
 {
 	BUG_ON(!r->reg);
 	BUG_ON(r->reg >= NR_SYS_REGS);
-	vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
+	__vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
 }
 
 static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 {
 	BUG_ON(!r->reg);
 	BUG_ON(r->reg >= NR_SYS_REGS);
-	vcpu_sys_reg(vcpu, r->reg) = r->val;
+	__vcpu_sys_reg(vcpu, r->reg) = r->val;
 }
 
 static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
diff --git a/arch/arm64/kvm/sys_regs_generic_v8.c b/arch/arm64/kvm/sys_regs_generic_v8.c
index 969ade1d333d..ddb8497d18d6 100644
--- a/arch/arm64/kvm/sys_regs_generic_v8.c
+++ b/arch/arm64/kvm/sys_regs_generic_v8.c
@@ -38,13 +38,13 @@ static bool access_actlr(struct kvm_vcpu *vcpu,
 	if (p->is_write)
 		return ignore_write(vcpu, p);
 
-	p->regval = vcpu_sys_reg(vcpu, ACTLR_EL1);
+	p->regval = vcpu_read_sys_reg(vcpu, ACTLR_EL1);
 	return true;
 }
 
 static void reset_actlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 {
-	vcpu_sys_reg(vcpu, ACTLR_EL1) = read_sysreg(actlr_el1);
+	__vcpu_sys_reg(vcpu, ACTLR_EL1) = read_sysreg(actlr_el1);
 }
 
 /*
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 8a9c42366db7..29cb4a1ff26b 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -37,7 +37,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 
 	reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
 	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
-	counter = vcpu_sys_reg(vcpu, reg);
+	counter = __vcpu_sys_reg(vcpu, reg);
 
 	/* The real counter value is equal to the value of counter register plus
 	 * the value perf event counts.
@@ -61,7 +61,8 @@ void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val)
 
 	reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
 	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
-	vcpu_sys_reg(vcpu, reg) += (s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);
+	__vcpu_sys_reg(vcpu, reg) +=
+		(s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);
 }
 
 /**
@@ -78,7 +79,7 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
 		counter = kvm_pmu_get_counter_value(vcpu, pmc->idx);
 		reg = (pmc->idx == ARMV8_PMU_CYCLE_IDX)
 		       ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + pmc->idx;
-		vcpu_sys_reg(vcpu, reg) = counter;
+		__vcpu_sys_reg(vcpu, reg) = counter;
 		perf_event_disable(pmc->perf_event);
 		perf_event_release_kernel(pmc->perf_event);
 		pmc->perf_event = NULL;
@@ -125,7 +126,7 @@ void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu)
 
 u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
 {
-	u64 val = vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMU_PMCR_N_SHIFT;
+	u64 val = __vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMU_PMCR_N_SHIFT;
 
 	val &= ARMV8_PMU_PMCR_N_MASK;
 	if (val == 0)
@@ -147,7 +148,7 @@ void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val)
 	struct kvm_pmu *pmu = &vcpu->arch.pmu;
 	struct kvm_pmc *pmc;
 
-	if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) || !val)
+	if (!(__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) || !val)
 		return;
 
 	for (i = 0; i < ARMV8_PMU_MAX_COUNTERS; i++) {
@@ -193,10 +194,10 @@ static u64 kvm_pmu_overflow_status(struct kvm_vcpu *vcpu)
 {
 	u64 reg = 0;
 
-	if ((vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E)) {
-		reg = vcpu_sys_reg(vcpu, PMOVSSET_EL0);
-		reg &= vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
-		reg &= vcpu_sys_reg(vcpu, PMINTENSET_EL1);
+	if ((__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E)) {
+		reg = __vcpu_sys_reg(vcpu, PMOVSSET_EL0);
+		reg &= __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
+		reg &= __vcpu_sys_reg(vcpu, PMINTENSET_EL1);
 		reg &= kvm_pmu_valid_counter_mask(vcpu);
 	}
 
@@ -295,7 +296,7 @@ static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
 	struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
 	int idx = pmc->idx;
 
-	vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(idx);
+	__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(idx);
 
 	if (kvm_pmu_overflow_status(vcpu)) {
 		kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
@@ -316,19 +317,19 @@ void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
 	if (val == 0)
 		return;
 
-	enable = vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
+	enable = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
 	for (i = 0; i < ARMV8_PMU_CYCLE_IDX; i++) {
 		if (!(val & BIT(i)))
 			continue;
-		type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
+		type = __vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
 		       & ARMV8_PMU_EVTYPE_EVENT;
 		if ((type == ARMV8_PMUV3_PERFCTR_SW_INCR)
 		    && (enable & BIT(i))) {
-			reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
+			reg = __vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
 			reg = lower_32_bits(reg);
-			vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
+			__vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
 			if (!reg)
-				vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
+				__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
 		}
 	}
 }
@@ -348,7 +349,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
 	mask = kvm_pmu_valid_counter_mask(vcpu);
 	if (val & ARMV8_PMU_PMCR_E) {
 		kvm_pmu_enable_counter(vcpu,
-				vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask);
+		       __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask);
 	} else {
 		kvm_pmu_disable_counter(vcpu, mask);
 	}
@@ -369,8 +370,8 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
 
 static bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu, u64 select_idx)
 {
-	return (vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) &&
-	       (vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
+	return (__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) &&
+	       (__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
 }
 
 /**
-- 
2.14.2

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

* [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

From: Christoffer Dall <cdall@cs.columbia.edu>

Currently we access the system registers array via the vcpu_sys_reg()
macro.  However, we are about to change the behavior to some times
modify the register file directly, so let's change this to two
primitives:

 * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
 * Direct array access macro __vcpu_sys_reg()

The first primitive should be used in places where the code needs to
access the currently loaded VCPU's state as observed by the guest.  For
example, when trapping on cache related registers, a write to a system
register should go directly to the VCPU version of the register.

The second primitive can be used in places where the VCPU is known to
never be running (for example userspace access) or for registers which
are never context switched (for example all the PMU system registers).

This rewrites all users of vcpu_sys_regs to one of the two primitives
above.

No functional change.

Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
---

Notes:
    Changes since v2:
     - New patch (deferred register handling has been reworked)

 arch/arm64/include/asm/kvm_emulate.h | 13 ++++---
 arch/arm64/include/asm/kvm_host.h    | 13 ++++++-
 arch/arm64/include/asm/kvm_mmu.h     |  2 +-
 arch/arm64/kvm/debug.c               | 27 +++++++++-----
 arch/arm64/kvm/inject_fault.c        |  8 ++--
 arch/arm64/kvm/sys_regs.c            | 71 ++++++++++++++++++------------------
 arch/arm64/kvm/sys_regs.h            |  4 +-
 arch/arm64/kvm/sys_regs_generic_v8.c |  4 +-
 virt/kvm/arm/pmu.c                   | 37 ++++++++++---------
 9 files changed, 102 insertions(+), 77 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 3cc535591bdf..d313aaae5c38 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -290,15 +290,18 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
 
 static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
 {
-	return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
+	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
 }
 
 static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
 {
-	if (vcpu_mode_is_32bit(vcpu))
+	if (vcpu_mode_is_32bit(vcpu)) {
 		*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
-	else
-		vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
+	} else {
+		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
+		sctlr |= (1 << 25);
+		vcpu_write_sys_reg(vcpu, SCTLR_EL1, sctlr);
+	}
 }
 
 static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
@@ -306,7 +309,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
 	if (vcpu_mode_is_32bit(vcpu))
 		return !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_E_BIT);
 
-	return !!(vcpu_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
+	return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
 }
 
 static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index f2a6f39aec87..68398bf7882f 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
 };
 
 #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
-#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
+
+/*
+ * Only use __vcpu_sys_reg if you know you want the memory backed version of a
+ * register, and not the one most recently accessed by a runnning VCPU.  For
+ * example, for userpace access or for system registers that are never context
+ * switched, but only emulated.
+ */
+#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
+
+#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
+#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
+
 /*
  * CP14 and CP15 live in the same array, as they are backed by the
  * same system registers.
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 9679067a1574..95f46e73c4dc 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -249,7 +249,7 @@ struct kvm;
 
 static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
 {
-	return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
+	return (vcpu_read_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
 }
 
 static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index feedb877cff8..db32d10a56a1 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -46,7 +46,8 @@ static DEFINE_PER_CPU(u32, mdcr_el2);
  */
 static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
 {
-	vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1);
+	vcpu->arch.guest_debug_preserved.mdscr_el1 =
+		vcpu_read_sys_reg(vcpu, MDSCR_EL1);
 
 	trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
 				vcpu->arch.guest_debug_preserved.mdscr_el1);
@@ -54,10 +55,11 @@ static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
 
 static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
 {
-	vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1;
+	vcpu_write_sys_reg(vcpu, MDSCR_EL1,
+			   vcpu->arch.guest_debug_preserved.mdscr_el1);
 
 	trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
-				vcpu_sys_reg(vcpu, MDSCR_EL1));
+				vcpu_read_sys_reg(vcpu, MDSCR_EL1));
 }
 
 /**
@@ -108,6 +110,7 @@ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
 void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
 {
 	bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY);
+	unsigned long mdscr;
 
 	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
 
@@ -152,9 +155,13 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
 		 */
 		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
 			*vcpu_cpsr(vcpu) |=  DBG_SPSR_SS;
-			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_SS;
+			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
+			mdscr |= DBG_MDSCR_SS;
+			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
 		} else {
-			vcpu_sys_reg(vcpu, MDSCR_EL1) &= ~DBG_MDSCR_SS;
+			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
+			mdscr &= ~DBG_MDSCR_SS;
+			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
 		}
 
 		trace_kvm_arm_set_dreg32("SPSR_EL2", *vcpu_cpsr(vcpu));
@@ -170,7 +177,9 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
 		 */
 		if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) {
 			/* Enable breakpoints/watchpoints */
-			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_MDE;
+			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
+			mdscr |= DBG_MDSCR_MDE;
+			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
 
 			vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state;
 			vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
@@ -194,12 +203,12 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
 		vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
 
 	/* If KDE or MDE are set, perform a full save/restore cycle. */
-	if ((vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_KDE) ||
-	    (vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_MDE))
+	if (vcpu_read_sys_reg(vcpu, MDSCR_EL1) & (DBG_MDSCR_KDE | DBG_MDSCR_MDE))
 		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
 
 	trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2);
-	trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_sys_reg(vcpu, MDSCR_EL1));
+	trace_kvm_arm_set_dreg32("MDSCR_EL1",
+				 vcpu_read_sys_reg(vcpu, MDSCR_EL1));
 }
 
 void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index 30a3f58cdb7b..e08db2f2dd75 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -58,7 +58,7 @@ static u64 get_except_vector(struct kvm_vcpu *vcpu, enum exception_type type)
 		exc_offset = LOWER_EL_AArch32_VECTOR;
 	}
 
-	return vcpu_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
+	return vcpu_read_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
 }
 
 static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
@@ -73,7 +73,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
 	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
 	*vcpu_spsr(vcpu) = cpsr;
 
-	vcpu_sys_reg(vcpu, FAR_EL1) = addr;
+	vcpu_write_sys_reg(vcpu, FAR_EL1, addr);
 
 	/*
 	 * Build an {i,d}abort, depending on the level and the
@@ -94,7 +94,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
 	if (!is_iabt)
 		esr |= ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT;
 
-	vcpu_sys_reg(vcpu, ESR_EL1) = esr | ESR_ELx_FSC_EXTABT;
+	vcpu_write_sys_reg(vcpu, ESR_EL1, esr | ESR_ELx_FSC_EXTABT);
 }
 
 static void inject_undef64(struct kvm_vcpu *vcpu)
@@ -115,7 +115,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
 	if (kvm_vcpu_trap_il_is32bit(vcpu))
 		esr |= ESR_ELx_IL;
 
-	vcpu_sys_reg(vcpu, ESR_EL1) = esr;
+	vcpu_write_sys_reg(vcpu, ESR_EL1, esr);
 }
 
 /**
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index b48af790615e..a05d2c01c786 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -133,14 +133,14 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
 	if (!p->is_aarch32 || !p->is_32bit) {
 		val = p->regval;
 	} else {
-		val = vcpu_sys_reg(vcpu, reg);
+		val = vcpu_read_sys_reg(vcpu, reg);
 		if (r->reg % 2)
 			val = (p->regval << 32) | (u64)lower_32_bits(val);
 		else
 			val = ((u64)upper_32_bits(val) << 32) |
 				lower_32_bits(p->regval);
 	}
-	vcpu_sys_reg(vcpu, reg) = val;
+	vcpu_write_sys_reg(vcpu, reg, val);
 
 	kvm_toggle_cache(vcpu, was_enabled);
 	return true;
@@ -241,10 +241,10 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
 			    const struct sys_reg_desc *r)
 {
 	if (p->is_write) {
-		vcpu_sys_reg(vcpu, r->reg) = p->regval;
+		vcpu_write_sys_reg(vcpu, r->reg, p->regval);
 		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
 	} else {
-		p->regval = vcpu_sys_reg(vcpu, r->reg);
+		p->regval = vcpu_read_sys_reg(vcpu, r->reg);
 	}
 
 	trace_trap_reg(__func__, r->reg, p->is_write, p->regval);
@@ -457,7 +457,8 @@ static void reset_wcr(struct kvm_vcpu *vcpu,
 
 static void reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 {
-	vcpu_sys_reg(vcpu, AMAIR_EL1) = read_sysreg(amair_el1);
+	u64 amair = read_sysreg(amair_el1);
+	vcpu_write_sys_reg(vcpu, AMAIR_EL1, amair);
 }
 
 static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
@@ -474,7 +475,7 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 	mpidr = (vcpu->vcpu_id & 0x0f) << MPIDR_LEVEL_SHIFT(0);
 	mpidr |= ((vcpu->vcpu_id >> 4) & 0xff) << MPIDR_LEVEL_SHIFT(1);
 	mpidr |= ((vcpu->vcpu_id >> 12) & 0xff) << MPIDR_LEVEL_SHIFT(2);
-	vcpu_sys_reg(vcpu, MPIDR_EL1) = (1ULL << 31) | mpidr;
+	vcpu_write_sys_reg(vcpu, MPIDR_EL1, (1ULL << 31) | mpidr);
 }
 
 static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
@@ -488,12 +489,12 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 	 */
 	val = ((pmcr & ~ARMV8_PMU_PMCR_MASK)
 	       | (ARMV8_PMU_PMCR_MASK & 0xdecafbad)) & (~ARMV8_PMU_PMCR_E);
-	vcpu_sys_reg(vcpu, PMCR_EL0) = val;
+	__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
 }
 
 static bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags)
 {
-	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+	u64 reg = __vcpu_sys_reg(vcpu, PMUSERENR_EL0);
 	bool enabled = (reg & flags) || vcpu_mode_priv(vcpu);
 
 	if (!enabled)
@@ -535,14 +536,14 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 
 	if (p->is_write) {
 		/* Only update writeable bits of PMCR */
-		val = vcpu_sys_reg(vcpu, PMCR_EL0);
+		val = __vcpu_sys_reg(vcpu, PMCR_EL0);
 		val &= ~ARMV8_PMU_PMCR_MASK;
 		val |= p->regval & ARMV8_PMU_PMCR_MASK;
-		vcpu_sys_reg(vcpu, PMCR_EL0) = val;
+		__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
 		kvm_pmu_handle_pmcr(vcpu, val);
 	} else {
 		/* PMCR.P & PMCR.C are RAZ */
-		val = vcpu_sys_reg(vcpu, PMCR_EL0)
+		val = __vcpu_sys_reg(vcpu, PMCR_EL0)
 		      & ~(ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C);
 		p->regval = val;
 	}
@@ -560,10 +561,10 @@ static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 		return false;
 
 	if (p->is_write)
-		vcpu_sys_reg(vcpu, PMSELR_EL0) = p->regval;
+		__vcpu_sys_reg(vcpu, PMSELR_EL0) = p->regval;
 	else
 		/* return PMSELR.SEL field */
-		p->regval = vcpu_sys_reg(vcpu, PMSELR_EL0)
+		p->regval = __vcpu_sys_reg(vcpu, PMSELR_EL0)
 			    & ARMV8_PMU_COUNTER_MASK;
 
 	return true;
@@ -596,7 +597,7 @@ static bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
 {
 	u64 pmcr, val;
 
-	pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
+	pmcr = __vcpu_sys_reg(vcpu, PMCR_EL0);
 	val = (pmcr >> ARMV8_PMU_PMCR_N_SHIFT) & ARMV8_PMU_PMCR_N_MASK;
 	if (idx >= val && idx != ARMV8_PMU_CYCLE_IDX) {
 		kvm_inject_undefined(vcpu);
@@ -621,7 +622,7 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
 			if (pmu_access_event_counter_el0_disabled(vcpu))
 				return false;
 
-			idx = vcpu_sys_reg(vcpu, PMSELR_EL0)
+			idx = __vcpu_sys_reg(vcpu, PMSELR_EL0)
 			      & ARMV8_PMU_COUNTER_MASK;
 		} else if (r->Op2 == 0) {
 			/* PMCCNTR_EL0 */
@@ -676,7 +677,7 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 
 	if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 1) {
 		/* PMXEVTYPER_EL0 */
-		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_PMU_COUNTER_MASK;
+		idx = __vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_PMU_COUNTER_MASK;
 		reg = PMEVTYPER0_EL0 + idx;
 	} else if (r->CRn == 14 && (r->CRm & 12) == 12) {
 		idx = ((r->CRm & 3) << 3) | (r->Op2 & 7);
@@ -694,9 +695,9 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 
 	if (p->is_write) {
 		kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
-		vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_PMU_EVTYPE_MASK;
+		__vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_PMU_EVTYPE_MASK;
 	} else {
-		p->regval = vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK;
+		p->regval = __vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK;
 	}
 
 	return true;
@@ -718,15 +719,15 @@ static bool access_pmcnten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 		val = p->regval & mask;
 		if (r->Op2 & 0x1) {
 			/* accessing PMCNTENSET_EL0 */
-			vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val;
+			__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val;
 			kvm_pmu_enable_counter(vcpu, val);
 		} else {
 			/* accessing PMCNTENCLR_EL0 */
-			vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val;
+			__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val;
 			kvm_pmu_disable_counter(vcpu, val);
 		}
 	} else {
-		p->regval = vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask;
+		p->regval = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask;
 	}
 
 	return true;
@@ -750,12 +751,12 @@ static bool access_pminten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 
 		if (r->Op2 & 0x1)
 			/* accessing PMINTENSET_EL1 */
-			vcpu_sys_reg(vcpu, PMINTENSET_EL1) |= val;
+			__vcpu_sys_reg(vcpu, PMINTENSET_EL1) |= val;
 		else
 			/* accessing PMINTENCLR_EL1 */
-			vcpu_sys_reg(vcpu, PMINTENSET_EL1) &= ~val;
+			__vcpu_sys_reg(vcpu, PMINTENSET_EL1) &= ~val;
 	} else {
-		p->regval = vcpu_sys_reg(vcpu, PMINTENSET_EL1) & mask;
+		p->regval = __vcpu_sys_reg(vcpu, PMINTENSET_EL1) & mask;
 	}
 
 	return true;
@@ -775,12 +776,12 @@ static bool access_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	if (p->is_write) {
 		if (r->CRm & 0x2)
 			/* accessing PMOVSSET_EL0 */
-			vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= (p->regval & mask);
+			__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= (p->regval & mask);
 		else
 			/* accessing PMOVSCLR_EL0 */
-			vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= ~(p->regval & mask);
+			__vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= ~(p->regval & mask);
 	} else {
-		p->regval = vcpu_sys_reg(vcpu, PMOVSSET_EL0) & mask;
+		p->regval = __vcpu_sys_reg(vcpu, PMOVSSET_EL0) & mask;
 	}
 
 	return true;
@@ -817,10 +818,10 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			return false;
 		}
 
-		vcpu_sys_reg(vcpu, PMUSERENR_EL0) = p->regval
-						    & ARMV8_PMU_USERENR_MASK;
-	} else {
-		p->regval = vcpu_sys_reg(vcpu, PMUSERENR_EL0)
+		__vcpu_sys_reg(vcpu, PMUSERENR_EL0) =
+			       p->regval & ARMV8_PMU_USERENR_MASK;
+	} else  {
+		p->regval = __vcpu_sys_reg(vcpu, PMUSERENR_EL0)
 			    & ARMV8_PMU_USERENR_MASK;
 	}
 
@@ -2204,7 +2205,7 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
 	if (r->get_user)
 		return (r->get_user)(vcpu, r, reg, uaddr);
 
-	return reg_to_user(uaddr, &vcpu_sys_reg(vcpu, r->reg), reg->id);
+	return reg_to_user(uaddr, &__vcpu_sys_reg(vcpu, r->reg), reg->id);
 }
 
 int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
@@ -2225,7 +2226,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
 	if (r->set_user)
 		return (r->set_user)(vcpu, r, reg, uaddr);
 
-	return reg_from_user(&vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
+	return reg_from_user(&__vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
 }
 
 static unsigned int num_demux_regs(void)
@@ -2431,6 +2432,6 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
 	reset_sys_reg_descs(vcpu, table, num);
 
 	for (num = 1; num < NR_SYS_REGS; num++)
-		if (vcpu_sys_reg(vcpu, num) == 0x4242424242424242)
-			panic("Didn't reset vcpu_sys_reg(%zi)", num);
+		if (__vcpu_sys_reg(vcpu, num) == 0x4242424242424242)
+			panic("Didn't reset __vcpu_sys_reg(%zi)", num);
 }
diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
index 060f5348ef25..cd710f8b63e0 100644
--- a/arch/arm64/kvm/sys_regs.h
+++ b/arch/arm64/kvm/sys_regs.h
@@ -89,14 +89,14 @@ static inline void reset_unknown(struct kvm_vcpu *vcpu,
 {
 	BUG_ON(!r->reg);
 	BUG_ON(r->reg >= NR_SYS_REGS);
-	vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
+	__vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
 }
 
 static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 {
 	BUG_ON(!r->reg);
 	BUG_ON(r->reg >= NR_SYS_REGS);
-	vcpu_sys_reg(vcpu, r->reg) = r->val;
+	__vcpu_sys_reg(vcpu, r->reg) = r->val;
 }
 
 static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
diff --git a/arch/arm64/kvm/sys_regs_generic_v8.c b/arch/arm64/kvm/sys_regs_generic_v8.c
index 969ade1d333d..ddb8497d18d6 100644
--- a/arch/arm64/kvm/sys_regs_generic_v8.c
+++ b/arch/arm64/kvm/sys_regs_generic_v8.c
@@ -38,13 +38,13 @@ static bool access_actlr(struct kvm_vcpu *vcpu,
 	if (p->is_write)
 		return ignore_write(vcpu, p);
 
-	p->regval = vcpu_sys_reg(vcpu, ACTLR_EL1);
+	p->regval = vcpu_read_sys_reg(vcpu, ACTLR_EL1);
 	return true;
 }
 
 static void reset_actlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 {
-	vcpu_sys_reg(vcpu, ACTLR_EL1) = read_sysreg(actlr_el1);
+	__vcpu_sys_reg(vcpu, ACTLR_EL1) = read_sysreg(actlr_el1);
 }
 
 /*
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 8a9c42366db7..29cb4a1ff26b 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -37,7 +37,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 
 	reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
 	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
-	counter = vcpu_sys_reg(vcpu, reg);
+	counter = __vcpu_sys_reg(vcpu, reg);
 
 	/* The real counter value is equal to the value of counter register plus
 	 * the value perf event counts.
@@ -61,7 +61,8 @@ void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val)
 
 	reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
 	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
-	vcpu_sys_reg(vcpu, reg) += (s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);
+	__vcpu_sys_reg(vcpu, reg) +=
+		(s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);
 }
 
 /**
@@ -78,7 +79,7 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
 		counter = kvm_pmu_get_counter_value(vcpu, pmc->idx);
 		reg = (pmc->idx == ARMV8_PMU_CYCLE_IDX)
 		       ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + pmc->idx;
-		vcpu_sys_reg(vcpu, reg) = counter;
+		__vcpu_sys_reg(vcpu, reg) = counter;
 		perf_event_disable(pmc->perf_event);
 		perf_event_release_kernel(pmc->perf_event);
 		pmc->perf_event = NULL;
@@ -125,7 +126,7 @@ void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu)
 
 u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
 {
-	u64 val = vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMU_PMCR_N_SHIFT;
+	u64 val = __vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMU_PMCR_N_SHIFT;
 
 	val &= ARMV8_PMU_PMCR_N_MASK;
 	if (val == 0)
@@ -147,7 +148,7 @@ void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val)
 	struct kvm_pmu *pmu = &vcpu->arch.pmu;
 	struct kvm_pmc *pmc;
 
-	if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) || !val)
+	if (!(__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) || !val)
 		return;
 
 	for (i = 0; i < ARMV8_PMU_MAX_COUNTERS; i++) {
@@ -193,10 +194,10 @@ static u64 kvm_pmu_overflow_status(struct kvm_vcpu *vcpu)
 {
 	u64 reg = 0;
 
-	if ((vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E)) {
-		reg = vcpu_sys_reg(vcpu, PMOVSSET_EL0);
-		reg &= vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
-		reg &= vcpu_sys_reg(vcpu, PMINTENSET_EL1);
+	if ((__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E)) {
+		reg = __vcpu_sys_reg(vcpu, PMOVSSET_EL0);
+		reg &= __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
+		reg &= __vcpu_sys_reg(vcpu, PMINTENSET_EL1);
 		reg &= kvm_pmu_valid_counter_mask(vcpu);
 	}
 
@@ -295,7 +296,7 @@ static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
 	struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
 	int idx = pmc->idx;
 
-	vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(idx);
+	__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(idx);
 
 	if (kvm_pmu_overflow_status(vcpu)) {
 		kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
@@ -316,19 +317,19 @@ void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
 	if (val == 0)
 		return;
 
-	enable = vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
+	enable = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
 	for (i = 0; i < ARMV8_PMU_CYCLE_IDX; i++) {
 		if (!(val & BIT(i)))
 			continue;
-		type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
+		type = __vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
 		       & ARMV8_PMU_EVTYPE_EVENT;
 		if ((type == ARMV8_PMUV3_PERFCTR_SW_INCR)
 		    && (enable & BIT(i))) {
-			reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
+			reg = __vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
 			reg = lower_32_bits(reg);
-			vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
+			__vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
 			if (!reg)
-				vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
+				__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
 		}
 	}
 }
@@ -348,7 +349,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
 	mask = kvm_pmu_valid_counter_mask(vcpu);
 	if (val & ARMV8_PMU_PMCR_E) {
 		kvm_pmu_enable_counter(vcpu,
-				vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask);
+		       __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask);
 	} else {
 		kvm_pmu_disable_counter(vcpu, mask);
 	}
@@ -369,8 +370,8 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
 
 static bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu, u64 select_idx)
 {
-	return (vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) &&
-	       (vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
+	return (__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) &&
+	       (__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
 }
 
 /**
-- 
2.14.2

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

* [PATCH v4 25/40] KVM: arm64: Introduce framework for accessing deferred sysregs
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

We are about to defer saving and restoring some groups of system
registers to vcpu_put and vcpu_load on supported systems.  This means
that we need some infrastructure to access system registes which
supports either accessing the memory backing of the register or directly
accessing the system registers, depending on the state of the system
when we access the register.

We do this by defining read/write accessor functions, which can handle
both "immediate" and "deferrable" system registers.  Immediate registers
are always saved/restored in the world-switch path, but deferrable
registers are only saved/restored in vcpu_put/vcpu_load when supported
and sysregs_loaded_on_cpu will be set in that case.

Note that we don't use the deferred mechanism yet in this patch, but only
introduce infrastructure.  This is to improve convenience of review in
the subsequent patches where it is clear which registers become
deferred.

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

Notes:
    Changes since v3:
     - Changed to a switch-statement based approach to improve
       readability.
    
    Changes since v2:
     - New patch (deferred register handling has been reworked)

 arch/arm64/include/asm/kvm_host.h |  8 ++++++--
 arch/arm64/kvm/sys_regs.c         | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 68398bf7882f..b463b5e28959 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -284,6 +284,10 @@ struct kvm_vcpu_arch {
 
 	/* Virtual SError ESR to restore when HCR_EL2.VSE is set */
 	u64 vsesr_el2;
+
+	/* True when deferrable sysregs are loaded on the physical CPU,
+	 * see kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs. */
+	bool sysregs_loaded_on_cpu;
 };
 
 #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
@@ -296,8 +300,8 @@ struct kvm_vcpu_arch {
  */
 #define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
 
-#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
-#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
+u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg);
+void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val);
 
 /*
  * CP14 and CP15 live in the same array, as they are backed by the
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index a05d2c01c786..b3c3f014aa61 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -35,6 +35,7 @@
 #include <asm/kvm_coproc.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_host.h>
+#include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
 #include <asm/perf_event.h>
 #include <asm/sysreg.h>
@@ -76,6 +77,38 @@ static bool write_to_read_only(struct kvm_vcpu *vcpu,
 	return false;
 }
 
+u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
+{
+	if (!vcpu->arch.sysregs_loaded_on_cpu)
+		goto immediate_read;
+
+	/*
+	 * All system registers listed in the switch are not saved on every
+	 * exit from the guest but are only saved on vcpu_put.
+	 */
+	switch (reg) {
+	}
+
+immediate_read:
+	return __vcpu_sys_reg(vcpu, reg);
+}
+
+void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
+{
+	if (!vcpu->arch.sysregs_loaded_on_cpu)
+		goto immediate_write;
+
+	/*
+	 * All system registers listed in the switch are not restored on every
+	 * entry to the guest but are only restored on vcpu_load.
+	 */
+	switch (reg) {
+	}
+
+immediate_write:
+	 __vcpu_sys_reg(vcpu, reg) = val;
+}
+
 /* 3 bits per cache level, as per CLIDR, but non-existent caches always 0 */
 static u32 cache_levels;
 
-- 
2.14.2

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

* [PATCH v4 25/40] KVM: arm64: Introduce framework for accessing deferred sysregs
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

We are about to defer saving and restoring some groups of system
registers to vcpu_put and vcpu_load on supported systems.  This means
that we need some infrastructure to access system registes which
supports either accessing the memory backing of the register or directly
accessing the system registers, depending on the state of the system
when we access the register.

We do this by defining read/write accessor functions, which can handle
both "immediate" and "deferrable" system registers.  Immediate registers
are always saved/restored in the world-switch path, but deferrable
registers are only saved/restored in vcpu_put/vcpu_load when supported
and sysregs_loaded_on_cpu will be set in that case.

Note that we don't use the deferred mechanism yet in this patch, but only
introduce infrastructure.  This is to improve convenience of review in
the subsequent patches where it is clear which registers become
deferred.

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

Notes:
    Changes since v3:
     - Changed to a switch-statement based approach to improve
       readability.
    
    Changes since v2:
     - New patch (deferred register handling has been reworked)

 arch/arm64/include/asm/kvm_host.h |  8 ++++++--
 arch/arm64/kvm/sys_regs.c         | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 68398bf7882f..b463b5e28959 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -284,6 +284,10 @@ struct kvm_vcpu_arch {
 
 	/* Virtual SError ESR to restore when HCR_EL2.VSE is set */
 	u64 vsesr_el2;
+
+	/* True when deferrable sysregs are loaded on the physical CPU,
+	 * see kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs. */
+	bool sysregs_loaded_on_cpu;
 };
 
 #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
@@ -296,8 +300,8 @@ struct kvm_vcpu_arch {
  */
 #define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
 
-#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
-#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
+u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg);
+void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val);
 
 /*
  * CP14 and CP15 live in the same array, as they are backed by the
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index a05d2c01c786..b3c3f014aa61 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -35,6 +35,7 @@
 #include <asm/kvm_coproc.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_host.h>
+#include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
 #include <asm/perf_event.h>
 #include <asm/sysreg.h>
@@ -76,6 +77,38 @@ static bool write_to_read_only(struct kvm_vcpu *vcpu,
 	return false;
 }
 
+u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
+{
+	if (!vcpu->arch.sysregs_loaded_on_cpu)
+		goto immediate_read;
+
+	/*
+	 * All system registers listed in the switch are not saved on every
+	 * exit from the guest but are only saved on vcpu_put.
+	 */
+	switch (reg) {
+	}
+
+immediate_read:
+	return __vcpu_sys_reg(vcpu, reg);
+}
+
+void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
+{
+	if (!vcpu->arch.sysregs_loaded_on_cpu)
+		goto immediate_write;
+
+	/*
+	 * All system registers listed in the switch are not restored on every
+	 * entry to the guest but are only restored on vcpu_load.
+	 */
+	switch (reg) {
+	}
+
+immediate_write:
+	 __vcpu_sys_reg(vcpu, reg) = val;
+}
+
 /* 3 bits per cache level, as per CLIDR, but non-existent caches always 0 */
 static u32 cache_levels;
 
-- 
2.14.2

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

* [PATCH v4 26/40] KVM: arm/arm64: Prepare to handle deferred save/restore of SPSR_EL1
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

SPSR_EL1 is not used by a VHE host kernel and can be deferred, but we
need to rework the accesses to this register to access the latest value
depending on whether or not guest system registers are loaded on the CPU
or only reside in memory.

The handling of accessing the various banked SPSRs for 32-bit VMs is a
bit clunky, but this will be improved in following patches which will
first prepare and subsequently implement deferred save/restore of the
32-bit registers, including the 32-bit SPSRs.

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

Notes:
    Changes since v2:
     - New patch (deferred register handling has been reworked)

 arch/arm/include/asm/kvm_emulate.h   | 12 ++++++++++-
 arch/arm/kvm/emulate.c               |  2 +-
 arch/arm64/include/asm/kvm_emulate.h | 41 +++++++++++++++++++++++++++++++-----
 arch/arm64/kvm/inject_fault.c        |  4 ++--
 virt/kvm/arm/aarch32.c               |  2 +-
 5 files changed, 51 insertions(+), 10 deletions(-)

diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h
index e27caa4b47a1..6493bd479ddc 100644
--- a/arch/arm/include/asm/kvm_emulate.h
+++ b/arch/arm/include/asm/kvm_emulate.h
@@ -41,7 +41,17 @@ static inline unsigned long *vcpu_reg32(struct kvm_vcpu *vcpu, u8 reg_num)
 	return vcpu_reg(vcpu, reg_num);
 }
 
-unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu);
+unsigned long *__vcpu_spsr(struct kvm_vcpu *vcpu);
+
+static inline unsigned long vpcu_read_spsr(struct kvm_vcpu *vcpu)
+{
+	return *__vcpu_spsr(vcpu);
+}
+
+static inline void vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long v)
+{
+	*__vcpu_spsr(vcpu) = v;
+}
 
 static inline unsigned long vcpu_get_reg(struct kvm_vcpu *vcpu,
 					 u8 reg_num)
diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
index fa501bf437f3..9046b53d87c1 100644
--- a/arch/arm/kvm/emulate.c
+++ b/arch/arm/kvm/emulate.c
@@ -142,7 +142,7 @@ unsigned long *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num)
 /*
  * Return the SPSR for the current mode of the virtual CPU.
  */
-unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu)
+unsigned long *__vcpu_spsr(struct kvm_vcpu *vcpu)
 {
 	unsigned long mode = *vcpu_cpsr(vcpu) & MODE_MASK;
 	switch (mode) {
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index d313aaae5c38..47c2406755fa 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -26,6 +26,7 @@
 
 #include <asm/esr.h>
 #include <asm/kvm_arm.h>
+#include <asm/kvm_hyp.h>
 #include <asm/kvm_mmio.h>
 #include <asm/ptrace.h>
 #include <asm/cputype.h>
@@ -143,13 +144,43 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
 		vcpu_gp_regs(vcpu)->regs.regs[reg_num] = val;
 }
 
-/* Get vcpu SPSR for current mode */
-static inline unsigned long *vcpu_spsr(const struct kvm_vcpu *vcpu)
+static inline unsigned long vcpu_read_spsr(const struct kvm_vcpu *vcpu)
 {
-	if (vcpu_mode_is_32bit(vcpu))
-		return vcpu_spsr32(vcpu);
+	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
+
+	if (vcpu_mode_is_32bit(vcpu)) {
+		unsigned long *p_32bit = vcpu_spsr32(vcpu);
+
+		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
+		if (p_32bit != (unsigned long *)p)
+			return *p_32bit;
+	}
+
+	if (vcpu->arch.sysregs_loaded_on_cpu)
+		return read_sysreg_el1(spsr);
+	else
+		return *p;
+}
 
-	return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
+static inline void vcpu_write_spsr(const struct kvm_vcpu *vcpu, unsigned long v)
+{
+	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
+
+	/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
+	if (vcpu_mode_is_32bit(vcpu)) {
+		unsigned long *p_32bit = vcpu_spsr32(vcpu);
+
+		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
+		if (p_32bit != (unsigned long *)p) {
+			*p_32bit = v;
+			return;
+		}
+	}
+
+	if (vcpu->arch.sysregs_loaded_on_cpu)
+		write_sysreg_el1(v, spsr);
+	else
+		*p = v;
 }
 
 static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index e08db2f2dd75..8dda1edae727 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -71,7 +71,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
 	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
 
 	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
-	*vcpu_spsr(vcpu) = cpsr;
+	vcpu_write_spsr(vcpu, cpsr);
 
 	vcpu_write_sys_reg(vcpu, FAR_EL1, addr);
 
@@ -106,7 +106,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
 	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
 
 	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
-	*vcpu_spsr(vcpu) = cpsr;
+	vcpu_write_spsr(vcpu, cpsr);
 
 	/*
 	 * Build an unknown exception, depending on the instruction
diff --git a/virt/kvm/arm/aarch32.c b/virt/kvm/arm/aarch32.c
index 8bc479fa37e6..efc84cbe8277 100644
--- a/virt/kvm/arm/aarch32.c
+++ b/virt/kvm/arm/aarch32.c
@@ -178,7 +178,7 @@ static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
 	*vcpu_cpsr(vcpu) = cpsr;
 
 	/* Note: These now point to the banked copies */
-	*vcpu_spsr(vcpu) = new_spsr_value;
+	vcpu_write_spsr(vcpu, new_spsr_value);
 	*vcpu_reg32(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
 
 	/* Branch to exception vector */
-- 
2.14.2

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

* [PATCH v4 26/40] KVM: arm/arm64: Prepare to handle deferred save/restore of SPSR_EL1
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

SPSR_EL1 is not used by a VHE host kernel and can be deferred, but we
need to rework the accesses to this register to access the latest value
depending on whether or not guest system registers are loaded on the CPU
or only reside in memory.

The handling of accessing the various banked SPSRs for 32-bit VMs is a
bit clunky, but this will be improved in following patches which will
first prepare and subsequently implement deferred save/restore of the
32-bit registers, including the 32-bit SPSRs.

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

Notes:
    Changes since v2:
     - New patch (deferred register handling has been reworked)

 arch/arm/include/asm/kvm_emulate.h   | 12 ++++++++++-
 arch/arm/kvm/emulate.c               |  2 +-
 arch/arm64/include/asm/kvm_emulate.h | 41 +++++++++++++++++++++++++++++++-----
 arch/arm64/kvm/inject_fault.c        |  4 ++--
 virt/kvm/arm/aarch32.c               |  2 +-
 5 files changed, 51 insertions(+), 10 deletions(-)

diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h
index e27caa4b47a1..6493bd479ddc 100644
--- a/arch/arm/include/asm/kvm_emulate.h
+++ b/arch/arm/include/asm/kvm_emulate.h
@@ -41,7 +41,17 @@ static inline unsigned long *vcpu_reg32(struct kvm_vcpu *vcpu, u8 reg_num)
 	return vcpu_reg(vcpu, reg_num);
 }
 
-unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu);
+unsigned long *__vcpu_spsr(struct kvm_vcpu *vcpu);
+
+static inline unsigned long vpcu_read_spsr(struct kvm_vcpu *vcpu)
+{
+	return *__vcpu_spsr(vcpu);
+}
+
+static inline void vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long v)
+{
+	*__vcpu_spsr(vcpu) = v;
+}
 
 static inline unsigned long vcpu_get_reg(struct kvm_vcpu *vcpu,
 					 u8 reg_num)
diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
index fa501bf437f3..9046b53d87c1 100644
--- a/arch/arm/kvm/emulate.c
+++ b/arch/arm/kvm/emulate.c
@@ -142,7 +142,7 @@ unsigned long *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num)
 /*
  * Return the SPSR for the current mode of the virtual CPU.
  */
-unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu)
+unsigned long *__vcpu_spsr(struct kvm_vcpu *vcpu)
 {
 	unsigned long mode = *vcpu_cpsr(vcpu) & MODE_MASK;
 	switch (mode) {
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index d313aaae5c38..47c2406755fa 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -26,6 +26,7 @@
 
 #include <asm/esr.h>
 #include <asm/kvm_arm.h>
+#include <asm/kvm_hyp.h>
 #include <asm/kvm_mmio.h>
 #include <asm/ptrace.h>
 #include <asm/cputype.h>
@@ -143,13 +144,43 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
 		vcpu_gp_regs(vcpu)->regs.regs[reg_num] = val;
 }
 
-/* Get vcpu SPSR for current mode */
-static inline unsigned long *vcpu_spsr(const struct kvm_vcpu *vcpu)
+static inline unsigned long vcpu_read_spsr(const struct kvm_vcpu *vcpu)
 {
-	if (vcpu_mode_is_32bit(vcpu))
-		return vcpu_spsr32(vcpu);
+	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
+
+	if (vcpu_mode_is_32bit(vcpu)) {
+		unsigned long *p_32bit = vcpu_spsr32(vcpu);
+
+		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
+		if (p_32bit != (unsigned long *)p)
+			return *p_32bit;
+	}
+
+	if (vcpu->arch.sysregs_loaded_on_cpu)
+		return read_sysreg_el1(spsr);
+	else
+		return *p;
+}
 
-	return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
+static inline void vcpu_write_spsr(const struct kvm_vcpu *vcpu, unsigned long v)
+{
+	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
+
+	/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
+	if (vcpu_mode_is_32bit(vcpu)) {
+		unsigned long *p_32bit = vcpu_spsr32(vcpu);
+
+		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
+		if (p_32bit != (unsigned long *)p) {
+			*p_32bit = v;
+			return;
+		}
+	}
+
+	if (vcpu->arch.sysregs_loaded_on_cpu)
+		write_sysreg_el1(v, spsr);
+	else
+		*p = v;
 }
 
 static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index e08db2f2dd75..8dda1edae727 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -71,7 +71,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
 	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
 
 	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
-	*vcpu_spsr(vcpu) = cpsr;
+	vcpu_write_spsr(vcpu, cpsr);
 
 	vcpu_write_sys_reg(vcpu, FAR_EL1, addr);
 
@@ -106,7 +106,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
 	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
 
 	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
-	*vcpu_spsr(vcpu) = cpsr;
+	vcpu_write_spsr(vcpu, cpsr);
 
 	/*
 	 * Build an unknown exception, depending on the instruction
diff --git a/virt/kvm/arm/aarch32.c b/virt/kvm/arm/aarch32.c
index 8bc479fa37e6..efc84cbe8277 100644
--- a/virt/kvm/arm/aarch32.c
+++ b/virt/kvm/arm/aarch32.c
@@ -178,7 +178,7 @@ static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
 	*vcpu_cpsr(vcpu) = cpsr;
 
 	/* Note: These now point to the banked copies */
-	*vcpu_spsr(vcpu) = new_spsr_value;
+	vcpu_write_spsr(vcpu, new_spsr_value);
 	*vcpu_reg32(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
 
 	/* Branch to exception vector */
-- 
2.14.2

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

* [PATCH v4 27/40] KVM: arm64: Prepare to handle deferred save/restore of ELR_EL1
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

ELR_EL1 is not used by a VHE host kernel and can be deferred, but we
need to rework the accesses to this register to access the latest value
depending on whether or not guest system registers are loaded on the CPU
or only reside in memory.

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

Notes:
    Changes since v2:
     - New patch (deferred register handling has been reworked)

 arch/arm64/include/asm/kvm_emulate.h | 18 +++++++++++++++++-
 arch/arm64/kvm/inject_fault.c        |  4 ++--
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 47c2406755fa..9cb13b23c7a1 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -90,11 +90,27 @@ static inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
 	return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pc;
 }
 
-static inline unsigned long *vcpu_elr_el1(const struct kvm_vcpu *vcpu)
+static inline unsigned long *__vcpu_elr_el1(const struct kvm_vcpu *vcpu)
 {
 	return (unsigned long *)&vcpu_gp_regs(vcpu)->elr_el1;
 }
 
+static inline unsigned long vcpu_read_elr_el1(const struct kvm_vcpu *vcpu)
+{
+	if (vcpu->arch.sysregs_loaded_on_cpu)
+		return read_sysreg_el1(elr);
+	else
+		return *__vcpu_elr_el1(vcpu);
+}
+
+static inline void vcpu_write_elr_el1(const struct kvm_vcpu *vcpu, unsigned long v)
+{
+	if (vcpu->arch.sysregs_loaded_on_cpu)
+		write_sysreg_el1(v, elr);
+	else
+		*__vcpu_elr_el1(vcpu) = v;
+}
+
 static inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
 {
 	return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pstate;
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index 8dda1edae727..cc13b6f5ad11 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -67,7 +67,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
 	bool is_aarch32 = vcpu_mode_is_32bit(vcpu);
 	u32 esr = 0;
 
-	*vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
+	vcpu_write_elr_el1(vcpu, *vcpu_pc(vcpu));
 	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
 
 	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
@@ -102,7 +102,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
 	unsigned long cpsr = *vcpu_cpsr(vcpu);
 	u32 esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT);
 
-	*vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
+	vcpu_write_elr_el1(vcpu, *vcpu_pc(vcpu));
 	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
 
 	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
-- 
2.14.2

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

* [PATCH v4 27/40] KVM: arm64: Prepare to handle deferred save/restore of ELR_EL1
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

ELR_EL1 is not used by a VHE host kernel and can be deferred, but we
need to rework the accesses to this register to access the latest value
depending on whether or not guest system registers are loaded on the CPU
or only reside in memory.

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

Notes:
    Changes since v2:
     - New patch (deferred register handling has been reworked)

 arch/arm64/include/asm/kvm_emulate.h | 18 +++++++++++++++++-
 arch/arm64/kvm/inject_fault.c        |  4 ++--
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 47c2406755fa..9cb13b23c7a1 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -90,11 +90,27 @@ static inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
 	return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pc;
 }
 
-static inline unsigned long *vcpu_elr_el1(const struct kvm_vcpu *vcpu)
+static inline unsigned long *__vcpu_elr_el1(const struct kvm_vcpu *vcpu)
 {
 	return (unsigned long *)&vcpu_gp_regs(vcpu)->elr_el1;
 }
 
+static inline unsigned long vcpu_read_elr_el1(const struct kvm_vcpu *vcpu)
+{
+	if (vcpu->arch.sysregs_loaded_on_cpu)
+		return read_sysreg_el1(elr);
+	else
+		return *__vcpu_elr_el1(vcpu);
+}
+
+static inline void vcpu_write_elr_el1(const struct kvm_vcpu *vcpu, unsigned long v)
+{
+	if (vcpu->arch.sysregs_loaded_on_cpu)
+		write_sysreg_el1(v, elr);
+	else
+		*__vcpu_elr_el1(vcpu) = v;
+}
+
 static inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
 {
 	return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pstate;
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index 8dda1edae727..cc13b6f5ad11 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -67,7 +67,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
 	bool is_aarch32 = vcpu_mode_is_32bit(vcpu);
 	u32 esr = 0;
 
-	*vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
+	vcpu_write_elr_el1(vcpu, *vcpu_pc(vcpu));
 	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
 
 	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
@@ -102,7 +102,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
 	unsigned long cpsr = *vcpu_cpsr(vcpu);
 	u32 esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT);
 
-	*vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
+	vcpu_write_elr_el1(vcpu, *vcpu_pc(vcpu));
 	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
 
 	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
-- 
2.14.2

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

* [PATCH v4 28/40] KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on VHE
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

Some system registers do not affect the host kernel's execution and can
therefore be loaded when we are about to run a VCPU and we don't have to
restore the host state to the hardware before the time when we are
actually about to return to userspace or schedule out the VCPU thread.

The EL1 system registers and the userspace state registers only
affecting EL0 execution do not need to be saved and restored on every
switch between the VM and the host, because they don't affect the host
kernel's execution.

We mark all registers which are now deffered as such in the
vcpu_{read,write}_sys_reg accessors in sys-regs.c to ensure the most
up-to-date copy is always accessed.

Note MPIDR_EL1 (controlled via VMPIDR_EL2) is accessed from other vcpu
threads, for example via the GIC emulation, and therefore must be
declared as immediate, which is fine as the guest cannot modify this
value.

The 32-bit sysregs can also be deferred but we do this in a separate
patch as it requires a bit more infrastructure.

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

Notes:
    Changes since v3:
     - Changed to switch-based sysreg approach

 arch/arm64/kvm/hyp/sysreg-sr.c | 39 +++++++++++++++++++++++++++++++--------
 arch/arm64/kvm/sys_regs.c      | 40 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 906606dc4e2c..9c60b8062724 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -25,8 +25,12 @@
 /*
  * Non-VHE: Both host and guest must save everything.
  *
- * VHE: Host must save tpidr*_el0, mdscr_el1, sp_el0,
- * and guest must save everything.
+ * VHE: Host and guest must save mdscr_el1 and sp_el0 (and the PC and pstate,
+ * which are handled as part of the el2 return state) on every switch.
+ * tpidr_el0 and tpidrro_el0 only need to be switched when going
+ * to host userspace or a different VCPU.  EL1 registers only need to be
+ * switched when potentially going to run a different VCPU.  The latter two
+ * classes are handled as part of kvm_arch_vcpu_load and kvm_arch_vcpu_put.
  */
 
 static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
@@ -93,14 +97,11 @@ void __hyp_text __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt)
 void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt)
 {
 	__sysreg_save_common_state(ctxt);
-	__sysreg_save_user_state(ctxt);
 }
 
 void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt)
 {
-	__sysreg_save_el1_state(ctxt);
 	__sysreg_save_common_state(ctxt);
-	__sysreg_save_user_state(ctxt);
 	__sysreg_save_el2_return_state(ctxt);
 }
 
@@ -169,14 +170,11 @@ void __hyp_text __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt)
 void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt)
 {
 	__sysreg_restore_common_state(ctxt);
-	__sysreg_restore_user_state(ctxt);
 }
 
 void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt)
 {
-	__sysreg_restore_el1_state(ctxt);
 	__sysreg_restore_common_state(ctxt);
-	__sysreg_restore_user_state(ctxt);
 	__sysreg_restore_el2_return_state(ctxt);
 }
 
@@ -240,6 +238,18 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
  */
 void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
 {
+	struct kvm_cpu_context *host_ctxt = vcpu->arch.host_cpu_context;
+	struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt;
+
+	if (!has_vhe())
+		return;
+
+	__sysreg_save_user_state(host_ctxt);
+
+	__sysreg_restore_user_state(guest_ctxt);
+	__sysreg_restore_el1_state(guest_ctxt);
+
+	vcpu->arch.sysregs_loaded_on_cpu = true;
 }
 
 /**
@@ -255,6 +265,19 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
  */
 void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
 {
+	struct kvm_cpu_context *host_ctxt = vcpu->arch.host_cpu_context;
+	struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt;
+
+	if (!has_vhe())
+		return;
+
+	__sysreg_save_el1_state(guest_ctxt);
+	__sysreg_save_user_state(guest_ctxt);
+
+	/* Restore host user state */
+	__sysreg_restore_user_state(host_ctxt);
+
+	vcpu->arch.sysregs_loaded_on_cpu = false;
 }
 
 void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index b3c3f014aa61..f060309337aa 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -87,6 +87,26 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
 	 * exit from the guest but are only saved on vcpu_put.
 	 */
 	switch (reg) {
+	case CSSELR_EL1:	return read_sysreg_s(SYS_CSSELR_EL1);
+	case SCTLR_EL1:		return read_sysreg_s(sctlr_EL12);
+	case ACTLR_EL1:		return read_sysreg_s(SYS_ACTLR_EL1);
+	case CPACR_EL1:		return read_sysreg_s(cpacr_EL12);
+	case TTBR0_EL1:		return read_sysreg_s(ttbr0_EL12);
+	case TTBR1_EL1:		return read_sysreg_s(ttbr1_EL12);
+	case TCR_EL1:		return read_sysreg_s(tcr_EL12);
+	case ESR_EL1:		return read_sysreg_s(esr_EL12);
+	case AFSR0_EL1:		return read_sysreg_s(afsr0_EL12);
+	case AFSR1_EL1:		return read_sysreg_s(afsr1_EL12);
+	case FAR_EL1:		return read_sysreg_s(far_EL12);
+	case MAIR_EL1:		return read_sysreg_s(mair_EL12);
+	case VBAR_EL1:		return read_sysreg_s(vbar_EL12);
+	case CONTEXTIDR_EL1:	return read_sysreg_s(contextidr_EL12);
+	case TPIDR_EL0:		return read_sysreg_s(SYS_TPIDR_EL0);
+	case TPIDRRO_EL0:	return read_sysreg_s(SYS_TPIDRRO_EL0);
+	case TPIDR_EL1:		return read_sysreg_s(SYS_TPIDR_EL1);
+	case AMAIR_EL1:		return read_sysreg_s(amair_EL12);
+	case CNTKCTL_EL1:	return read_sysreg_s(cntkctl_EL12);
+	case PAR_EL1:		return read_sysreg_s(SYS_PAR_EL1);
 	}
 
 immediate_read:
@@ -103,6 +123,26 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
 	 * entry to the guest but are only restored on vcpu_load.
 	 */
 	switch (reg) {
+	case CSSELR_EL1:	write_sysreg_s(val, SYS_CSSELR_EL1);	return;
+	case SCTLR_EL1:		write_sysreg_s(val, sctlr_EL12);	return;
+	case ACTLR_EL1:		write_sysreg_s(val, SYS_ACTLR_EL1);	return;
+	case CPACR_EL1:		write_sysreg_s(val, cpacr_EL12);	return;
+	case TTBR0_EL1:		write_sysreg_s(val, ttbr0_EL12);	return;
+	case TTBR1_EL1:		write_sysreg_s(val, ttbr1_EL12);	return;
+	case TCR_EL1:		write_sysreg_s(val, tcr_EL12);		return;
+	case ESR_EL1:		write_sysreg_s(val, esr_EL12);		return;
+	case AFSR0_EL1:		write_sysreg_s(val, afsr0_EL12);	return;
+	case AFSR1_EL1:		write_sysreg_s(val, afsr1_EL12);	return;
+	case FAR_EL1:		write_sysreg_s(val, far_EL12);		return;
+	case MAIR_EL1:		write_sysreg_s(val, mair_EL12);		return;
+	case VBAR_EL1:		write_sysreg_s(val, vbar_EL12);		return;
+	case CONTEXTIDR_EL1:	write_sysreg_s(val, contextidr_EL12);	return;
+	case TPIDR_EL0:		write_sysreg_s(val, SYS_TPIDR_EL0);	return;
+	case TPIDRRO_EL0:	write_sysreg_s(val, SYS_TPIDRRO_EL0);	return;
+	case TPIDR_EL1:		write_sysreg_s(val, SYS_TPIDR_EL1);	return;
+	case AMAIR_EL1:		write_sysreg_s(val, amair_EL12);	return;
+	case CNTKCTL_EL1:	write_sysreg_s(val, cntkctl_EL12);	return;
+	case PAR_EL1:		write_sysreg_s(val, SYS_PAR_EL1);	return;
 	}
 
 immediate_write:
-- 
2.14.2

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

* [PATCH v4 28/40] KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on VHE
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

Some system registers do not affect the host kernel's execution and can
therefore be loaded when we are about to run a VCPU and we don't have to
restore the host state to the hardware before the time when we are
actually about to return to userspace or schedule out the VCPU thread.

The EL1 system registers and the userspace state registers only
affecting EL0 execution do not need to be saved and restored on every
switch between the VM and the host, because they don't affect the host
kernel's execution.

We mark all registers which are now deffered as such in the
vcpu_{read,write}_sys_reg accessors in sys-regs.c to ensure the most
up-to-date copy is always accessed.

Note MPIDR_EL1 (controlled via VMPIDR_EL2) is accessed from other vcpu
threads, for example via the GIC emulation, and therefore must be
declared as immediate, which is fine as the guest cannot modify this
value.

The 32-bit sysregs can also be deferred but we do this in a separate
patch as it requires a bit more infrastructure.

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

Notes:
    Changes since v3:
     - Changed to switch-based sysreg approach

 arch/arm64/kvm/hyp/sysreg-sr.c | 39 +++++++++++++++++++++++++++++++--------
 arch/arm64/kvm/sys_regs.c      | 40 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 906606dc4e2c..9c60b8062724 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -25,8 +25,12 @@
 /*
  * Non-VHE: Both host and guest must save everything.
  *
- * VHE: Host must save tpidr*_el0, mdscr_el1, sp_el0,
- * and guest must save everything.
+ * VHE: Host and guest must save mdscr_el1 and sp_el0 (and the PC and pstate,
+ * which are handled as part of the el2 return state) on every switch.
+ * tpidr_el0 and tpidrro_el0 only need to be switched when going
+ * to host userspace or a different VCPU.  EL1 registers only need to be
+ * switched when potentially going to run a different VCPU.  The latter two
+ * classes are handled as part of kvm_arch_vcpu_load and kvm_arch_vcpu_put.
  */
 
 static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
@@ -93,14 +97,11 @@ void __hyp_text __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt)
 void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt)
 {
 	__sysreg_save_common_state(ctxt);
-	__sysreg_save_user_state(ctxt);
 }
 
 void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt)
 {
-	__sysreg_save_el1_state(ctxt);
 	__sysreg_save_common_state(ctxt);
-	__sysreg_save_user_state(ctxt);
 	__sysreg_save_el2_return_state(ctxt);
 }
 
@@ -169,14 +170,11 @@ void __hyp_text __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt)
 void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt)
 {
 	__sysreg_restore_common_state(ctxt);
-	__sysreg_restore_user_state(ctxt);
 }
 
 void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt)
 {
-	__sysreg_restore_el1_state(ctxt);
 	__sysreg_restore_common_state(ctxt);
-	__sysreg_restore_user_state(ctxt);
 	__sysreg_restore_el2_return_state(ctxt);
 }
 
@@ -240,6 +238,18 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
  */
 void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
 {
+	struct kvm_cpu_context *host_ctxt = vcpu->arch.host_cpu_context;
+	struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt;
+
+	if (!has_vhe())
+		return;
+
+	__sysreg_save_user_state(host_ctxt);
+
+	__sysreg_restore_user_state(guest_ctxt);
+	__sysreg_restore_el1_state(guest_ctxt);
+
+	vcpu->arch.sysregs_loaded_on_cpu = true;
 }
 
 /**
@@ -255,6 +265,19 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
  */
 void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
 {
+	struct kvm_cpu_context *host_ctxt = vcpu->arch.host_cpu_context;
+	struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt;
+
+	if (!has_vhe())
+		return;
+
+	__sysreg_save_el1_state(guest_ctxt);
+	__sysreg_save_user_state(guest_ctxt);
+
+	/* Restore host user state */
+	__sysreg_restore_user_state(host_ctxt);
+
+	vcpu->arch.sysregs_loaded_on_cpu = false;
 }
 
 void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index b3c3f014aa61..f060309337aa 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -87,6 +87,26 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
 	 * exit from the guest but are only saved on vcpu_put.
 	 */
 	switch (reg) {
+	case CSSELR_EL1:	return read_sysreg_s(SYS_CSSELR_EL1);
+	case SCTLR_EL1:		return read_sysreg_s(sctlr_EL12);
+	case ACTLR_EL1:		return read_sysreg_s(SYS_ACTLR_EL1);
+	case CPACR_EL1:		return read_sysreg_s(cpacr_EL12);
+	case TTBR0_EL1:		return read_sysreg_s(ttbr0_EL12);
+	case TTBR1_EL1:		return read_sysreg_s(ttbr1_EL12);
+	case TCR_EL1:		return read_sysreg_s(tcr_EL12);
+	case ESR_EL1:		return read_sysreg_s(esr_EL12);
+	case AFSR0_EL1:		return read_sysreg_s(afsr0_EL12);
+	case AFSR1_EL1:		return read_sysreg_s(afsr1_EL12);
+	case FAR_EL1:		return read_sysreg_s(far_EL12);
+	case MAIR_EL1:		return read_sysreg_s(mair_EL12);
+	case VBAR_EL1:		return read_sysreg_s(vbar_EL12);
+	case CONTEXTIDR_EL1:	return read_sysreg_s(contextidr_EL12);
+	case TPIDR_EL0:		return read_sysreg_s(SYS_TPIDR_EL0);
+	case TPIDRRO_EL0:	return read_sysreg_s(SYS_TPIDRRO_EL0);
+	case TPIDR_EL1:		return read_sysreg_s(SYS_TPIDR_EL1);
+	case AMAIR_EL1:		return read_sysreg_s(amair_EL12);
+	case CNTKCTL_EL1:	return read_sysreg_s(cntkctl_EL12);
+	case PAR_EL1:		return read_sysreg_s(SYS_PAR_EL1);
 	}
 
 immediate_read:
@@ -103,6 +123,26 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
 	 * entry to the guest but are only restored on vcpu_load.
 	 */
 	switch (reg) {
+	case CSSELR_EL1:	write_sysreg_s(val, SYS_CSSELR_EL1);	return;
+	case SCTLR_EL1:		write_sysreg_s(val, sctlr_EL12);	return;
+	case ACTLR_EL1:		write_sysreg_s(val, SYS_ACTLR_EL1);	return;
+	case CPACR_EL1:		write_sysreg_s(val, cpacr_EL12);	return;
+	case TTBR0_EL1:		write_sysreg_s(val, ttbr0_EL12);	return;
+	case TTBR1_EL1:		write_sysreg_s(val, ttbr1_EL12);	return;
+	case TCR_EL1:		write_sysreg_s(val, tcr_EL12);		return;
+	case ESR_EL1:		write_sysreg_s(val, esr_EL12);		return;
+	case AFSR0_EL1:		write_sysreg_s(val, afsr0_EL12);	return;
+	case AFSR1_EL1:		write_sysreg_s(val, afsr1_EL12);	return;
+	case FAR_EL1:		write_sysreg_s(val, far_EL12);		return;
+	case MAIR_EL1:		write_sysreg_s(val, mair_EL12);		return;
+	case VBAR_EL1:		write_sysreg_s(val, vbar_EL12);		return;
+	case CONTEXTIDR_EL1:	write_sysreg_s(val, contextidr_EL12);	return;
+	case TPIDR_EL0:		write_sysreg_s(val, SYS_TPIDR_EL0);	return;
+	case TPIDRRO_EL0:	write_sysreg_s(val, SYS_TPIDRRO_EL0);	return;
+	case TPIDR_EL1:		write_sysreg_s(val, SYS_TPIDR_EL1);	return;
+	case AMAIR_EL1:		write_sysreg_s(val, amair_EL12);	return;
+	case CNTKCTL_EL1:	write_sysreg_s(val, cntkctl_EL12);	return;
+	case PAR_EL1:		write_sysreg_s(val, SYS_PAR_EL1);	return;
 	}
 
 immediate_write:
-- 
2.14.2

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

* [PATCH v4 29/40] KVM: arm64: Prepare to handle deferred save/restore of 32-bit registers
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

32-bit registers are not used by a 64-bit host kernel and can be
deferred, but we need to rework the accesses to this register to access
the latest value depending on whether or not guest system registers are
loaded on the CPU or only reside in memory.

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

Notes:
    Changes since v3:
     - Don't also try to write hardware spsr when sysregs are not loaded
     - Adapted patch to use switch-based sysreg save/restore approach
     - (Kept additional BUG_ON() in vcpu_read_spsr32() to keep the compiler happy)
    
    Changes since v2:
     - New patch (deferred register handling has been reworked)

 arch/arm64/include/asm/kvm_emulate.h | 32 +++++------------
 arch/arm64/kvm/regmap.c              | 67 +++++++++++++++++++++++++++---------
 arch/arm64/kvm/sys_regs.c            |  6 ++++
 3 files changed, 65 insertions(+), 40 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 9cb13b23c7a1..23b33e8ea03a 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -33,7 +33,8 @@
 #include <asm/virt.h>
 
 unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num);
-unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu);
+unsigned long vcpu_read_spsr32(const struct kvm_vcpu *vcpu);
+void vcpu_write_spsr32(struct kvm_vcpu *vcpu, unsigned long v);
 
 bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
 void kvm_skip_instr32(struct kvm_vcpu *vcpu, bool is_wide_instr);
@@ -162,41 +163,26 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
 
 static inline unsigned long vcpu_read_spsr(const struct kvm_vcpu *vcpu)
 {
-	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
-
-	if (vcpu_mode_is_32bit(vcpu)) {
-		unsigned long *p_32bit = vcpu_spsr32(vcpu);
-
-		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
-		if (p_32bit != (unsigned long *)p)
-			return *p_32bit;
-	}
+	if (vcpu_mode_is_32bit(vcpu))
+		return vcpu_read_spsr32(vcpu);
 
 	if (vcpu->arch.sysregs_loaded_on_cpu)
 		return read_sysreg_el1(spsr);
 	else
-		return *p;
+		return vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
 }
 
-static inline void vcpu_write_spsr(const struct kvm_vcpu *vcpu, unsigned long v)
+static inline void vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long v)
 {
-	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
-
-	/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
 	if (vcpu_mode_is_32bit(vcpu)) {
-		unsigned long *p_32bit = vcpu_spsr32(vcpu);
-
-		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
-		if (p_32bit != (unsigned long *)p) {
-			*p_32bit = v;
-			return;
-		}
+		vcpu_write_spsr32(vcpu, v);
+		return;
 	}
 
 	if (vcpu->arch.sysregs_loaded_on_cpu)
 		write_sysreg_el1(v, spsr);
 	else
-		*p = v;
+		vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1] = v;
 }
 
 static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/regmap.c b/arch/arm64/kvm/regmap.c
index bbc6ae32e4af..eefe403a2e63 100644
--- a/arch/arm64/kvm/regmap.c
+++ b/arch/arm64/kvm/regmap.c
@@ -141,28 +141,61 @@ unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num)
 /*
  * Return the SPSR for the current mode of the virtual CPU.
  */
-unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu)
+static int vcpu_spsr32_mode(const struct kvm_vcpu *vcpu)
 {
 	unsigned long mode = *vcpu_cpsr(vcpu) & COMPAT_PSR_MODE_MASK;
 	switch (mode) {
-	case COMPAT_PSR_MODE_SVC:
-		mode = KVM_SPSR_SVC;
-		break;
-	case COMPAT_PSR_MODE_ABT:
-		mode = KVM_SPSR_ABT;
-		break;
-	case COMPAT_PSR_MODE_UND:
-		mode = KVM_SPSR_UND;
-		break;
-	case COMPAT_PSR_MODE_IRQ:
-		mode = KVM_SPSR_IRQ;
-		break;
-	case COMPAT_PSR_MODE_FIQ:
-		mode = KVM_SPSR_FIQ;
-		break;
+	case COMPAT_PSR_MODE_SVC: return KVM_SPSR_SVC;
+	case COMPAT_PSR_MODE_ABT: return KVM_SPSR_ABT;
+	case COMPAT_PSR_MODE_UND: return KVM_SPSR_UND;
+	case COMPAT_PSR_MODE_IRQ: return KVM_SPSR_IRQ;
+	case COMPAT_PSR_MODE_FIQ: return KVM_SPSR_FIQ;
+	default: BUG();
+	}
+}
+
+unsigned long vcpu_read_spsr32(const struct kvm_vcpu *vcpu)
+{
+	int spsr_idx = vcpu_spsr32_mode(vcpu);
+
+	if (!vcpu->arch.sysregs_loaded_on_cpu)
+		return vcpu_gp_regs(vcpu)->spsr[spsr_idx];
+
+	switch (spsr_idx) {
+	case KVM_SPSR_SVC:
+		return read_sysreg_el1(spsr);
+	case KVM_SPSR_ABT:
+		return read_sysreg(spsr_abt);
+	case KVM_SPSR_UND:
+		return read_sysreg(spsr_und);
+	case KVM_SPSR_IRQ:
+		return read_sysreg(spsr_irq);
+	case KVM_SPSR_FIQ:
+		return read_sysreg(spsr_fiq);
 	default:
 		BUG();
 	}
+}
+
+void vcpu_write_spsr32(struct kvm_vcpu *vcpu, unsigned long v)
+{
+	int spsr_idx = vcpu_spsr32_mode(vcpu);
+
+	if (!vcpu->arch.sysregs_loaded_on_cpu) {
+		vcpu_gp_regs(vcpu)->spsr[spsr_idx] = v;
+		return;
+	}
 
-	return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[mode];
+	switch (spsr_idx) {
+	case KVM_SPSR_SVC:
+		write_sysreg_el1(v, spsr);
+	case KVM_SPSR_ABT:
+		write_sysreg(v, spsr_abt);
+	case KVM_SPSR_UND:
+		write_sysreg(v, spsr_und);
+	case KVM_SPSR_IRQ:
+		write_sysreg(v, spsr_irq);
+	case KVM_SPSR_FIQ:
+		write_sysreg(v, spsr_fiq);
+	}
 }
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f060309337aa..d2324560c9f5 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -107,6 +107,9 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
 	case AMAIR_EL1:		return read_sysreg_s(amair_EL12);
 	case CNTKCTL_EL1:	return read_sysreg_s(cntkctl_EL12);
 	case PAR_EL1:		return read_sysreg_s(SYS_PAR_EL1);
+	case DACR32_EL2:	return read_sysreg_s(SYS_DACR32_EL2);
+	case IFSR32_EL2:	return read_sysreg_s(SYS_IFSR32_EL2);
+	case DBGVCR32_EL2:	return read_sysreg_s(SYS_DBGVCR32_EL2);
 	}
 
 immediate_read:
@@ -143,6 +146,9 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
 	case AMAIR_EL1:		write_sysreg_s(val, amair_EL12);	return;
 	case CNTKCTL_EL1:	write_sysreg_s(val, cntkctl_EL12);	return;
 	case PAR_EL1:		write_sysreg_s(val, SYS_PAR_EL1);	return;
+	case DACR32_EL2:	write_sysreg_s(val, SYS_DACR32_EL2);	return;
+	case IFSR32_EL2:	write_sysreg_s(val, SYS_IFSR32_EL2);	return;
+	case DBGVCR32_EL2:	write_sysreg_s(val, SYS_DBGVCR32_EL2);	return;
 	}
 
 immediate_write:
-- 
2.14.2

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

* [PATCH v4 29/40] KVM: arm64: Prepare to handle deferred save/restore of 32-bit registers
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

32-bit registers are not used by a 64-bit host kernel and can be
deferred, but we need to rework the accesses to this register to access
the latest value depending on whether or not guest system registers are
loaded on the CPU or only reside in memory.

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

Notes:
    Changes since v3:
     - Don't also try to write hardware spsr when sysregs are not loaded
     - Adapted patch to use switch-based sysreg save/restore approach
     - (Kept additional BUG_ON() in vcpu_read_spsr32() to keep the compiler happy)
    
    Changes since v2:
     - New patch (deferred register handling has been reworked)

 arch/arm64/include/asm/kvm_emulate.h | 32 +++++------------
 arch/arm64/kvm/regmap.c              | 67 +++++++++++++++++++++++++++---------
 arch/arm64/kvm/sys_regs.c            |  6 ++++
 3 files changed, 65 insertions(+), 40 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 9cb13b23c7a1..23b33e8ea03a 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -33,7 +33,8 @@
 #include <asm/virt.h>
 
 unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num);
-unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu);
+unsigned long vcpu_read_spsr32(const struct kvm_vcpu *vcpu);
+void vcpu_write_spsr32(struct kvm_vcpu *vcpu, unsigned long v);
 
 bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
 void kvm_skip_instr32(struct kvm_vcpu *vcpu, bool is_wide_instr);
@@ -162,41 +163,26 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
 
 static inline unsigned long vcpu_read_spsr(const struct kvm_vcpu *vcpu)
 {
-	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
-
-	if (vcpu_mode_is_32bit(vcpu)) {
-		unsigned long *p_32bit = vcpu_spsr32(vcpu);
-
-		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
-		if (p_32bit != (unsigned long *)p)
-			return *p_32bit;
-	}
+	if (vcpu_mode_is_32bit(vcpu))
+		return vcpu_read_spsr32(vcpu);
 
 	if (vcpu->arch.sysregs_loaded_on_cpu)
 		return read_sysreg_el1(spsr);
 	else
-		return *p;
+		return vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
 }
 
-static inline void vcpu_write_spsr(const struct kvm_vcpu *vcpu, unsigned long v)
+static inline void vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long v)
 {
-	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
-
-	/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
 	if (vcpu_mode_is_32bit(vcpu)) {
-		unsigned long *p_32bit = vcpu_spsr32(vcpu);
-
-		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
-		if (p_32bit != (unsigned long *)p) {
-			*p_32bit = v;
-			return;
-		}
+		vcpu_write_spsr32(vcpu, v);
+		return;
 	}
 
 	if (vcpu->arch.sysregs_loaded_on_cpu)
 		write_sysreg_el1(v, spsr);
 	else
-		*p = v;
+		vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1] = v;
 }
 
 static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/regmap.c b/arch/arm64/kvm/regmap.c
index bbc6ae32e4af..eefe403a2e63 100644
--- a/arch/arm64/kvm/regmap.c
+++ b/arch/arm64/kvm/regmap.c
@@ -141,28 +141,61 @@ unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num)
 /*
  * Return the SPSR for the current mode of the virtual CPU.
  */
-unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu)
+static int vcpu_spsr32_mode(const struct kvm_vcpu *vcpu)
 {
 	unsigned long mode = *vcpu_cpsr(vcpu) & COMPAT_PSR_MODE_MASK;
 	switch (mode) {
-	case COMPAT_PSR_MODE_SVC:
-		mode = KVM_SPSR_SVC;
-		break;
-	case COMPAT_PSR_MODE_ABT:
-		mode = KVM_SPSR_ABT;
-		break;
-	case COMPAT_PSR_MODE_UND:
-		mode = KVM_SPSR_UND;
-		break;
-	case COMPAT_PSR_MODE_IRQ:
-		mode = KVM_SPSR_IRQ;
-		break;
-	case COMPAT_PSR_MODE_FIQ:
-		mode = KVM_SPSR_FIQ;
-		break;
+	case COMPAT_PSR_MODE_SVC: return KVM_SPSR_SVC;
+	case COMPAT_PSR_MODE_ABT: return KVM_SPSR_ABT;
+	case COMPAT_PSR_MODE_UND: return KVM_SPSR_UND;
+	case COMPAT_PSR_MODE_IRQ: return KVM_SPSR_IRQ;
+	case COMPAT_PSR_MODE_FIQ: return KVM_SPSR_FIQ;
+	default: BUG();
+	}
+}
+
+unsigned long vcpu_read_spsr32(const struct kvm_vcpu *vcpu)
+{
+	int spsr_idx = vcpu_spsr32_mode(vcpu);
+
+	if (!vcpu->arch.sysregs_loaded_on_cpu)
+		return vcpu_gp_regs(vcpu)->spsr[spsr_idx];
+
+	switch (spsr_idx) {
+	case KVM_SPSR_SVC:
+		return read_sysreg_el1(spsr);
+	case KVM_SPSR_ABT:
+		return read_sysreg(spsr_abt);
+	case KVM_SPSR_UND:
+		return read_sysreg(spsr_und);
+	case KVM_SPSR_IRQ:
+		return read_sysreg(spsr_irq);
+	case KVM_SPSR_FIQ:
+		return read_sysreg(spsr_fiq);
 	default:
 		BUG();
 	}
+}
+
+void vcpu_write_spsr32(struct kvm_vcpu *vcpu, unsigned long v)
+{
+	int spsr_idx = vcpu_spsr32_mode(vcpu);
+
+	if (!vcpu->arch.sysregs_loaded_on_cpu) {
+		vcpu_gp_regs(vcpu)->spsr[spsr_idx] = v;
+		return;
+	}
 
-	return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[mode];
+	switch (spsr_idx) {
+	case KVM_SPSR_SVC:
+		write_sysreg_el1(v, spsr);
+	case KVM_SPSR_ABT:
+		write_sysreg(v, spsr_abt);
+	case KVM_SPSR_UND:
+		write_sysreg(v, spsr_und);
+	case KVM_SPSR_IRQ:
+		write_sysreg(v, spsr_irq);
+	case KVM_SPSR_FIQ:
+		write_sysreg(v, spsr_fiq);
+	}
 }
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f060309337aa..d2324560c9f5 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -107,6 +107,9 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
 	case AMAIR_EL1:		return read_sysreg_s(amair_EL12);
 	case CNTKCTL_EL1:	return read_sysreg_s(cntkctl_EL12);
 	case PAR_EL1:		return read_sysreg_s(SYS_PAR_EL1);
+	case DACR32_EL2:	return read_sysreg_s(SYS_DACR32_EL2);
+	case IFSR32_EL2:	return read_sysreg_s(SYS_IFSR32_EL2);
+	case DBGVCR32_EL2:	return read_sysreg_s(SYS_DBGVCR32_EL2);
 	}
 
 immediate_read:
@@ -143,6 +146,9 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
 	case AMAIR_EL1:		write_sysreg_s(val, amair_EL12);	return;
 	case CNTKCTL_EL1:	write_sysreg_s(val, cntkctl_EL12);	return;
 	case PAR_EL1:		write_sysreg_s(val, SYS_PAR_EL1);	return;
+	case DACR32_EL2:	write_sysreg_s(val, SYS_DACR32_EL2);	return;
+	case IFSR32_EL2:	write_sysreg_s(val, SYS_IFSR32_EL2);	return;
+	case DBGVCR32_EL2:	write_sysreg_s(val, SYS_DBGVCR32_EL2);	return;
 	}
 
 immediate_write:
-- 
2.14.2

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

* [PATCH v4 30/40] KVM: arm64: Defer saving/restoring 32-bit sysregs to vcpu load/put
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

When running a 32-bit VM (EL1 in AArch32), the AArch32 system registers
can be deferred to vcpu load/put on VHE systems because neither
the host kernel nor host userspace uses these registers.

Note that we can not defer saving DBGVCR32_EL2 conditionally based
on the state of the debug dirty flag on VHE, but since we do the
load/put pretty rarely, this comes out as a win anyway.

We can also not defer saving FPEXC32_32 because this register only holds
a guest-valid value for 32-bit guests during the exit path when the
guest has used FPSIMD registers and restored the register in the early
assembly handler from taking the EL2 fault, and therefore we have to
check if fpsimd is enabled for the guest in the exit path and save the
register then, for both VHE and non-VHE guests.

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

Notes:
    Changes since v3:
     - Rework the FPEXC32 save/restore logic to no longer attempt to
       save/restore this register lazily.
    
    Changes since v2:
     - New patch (deferred register handling has been reworked)

 arch/arm64/kvm/hyp/switch.c    | 17 +++++++++++------
 arch/arm64/kvm/hyp/sysreg-sr.c | 15 ++++++++++-----
 2 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 22e77deb8e2e..909aa3fe9196 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -47,6 +47,15 @@ bool __hyp_text __fpsimd_enabled(void)
 	return __fpsimd_is_enabled()();
 }
 
+/* Save the 32-bit only FPSIMD system register state */
+static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
+{
+	if (!vcpu_el1_is_32bit(vcpu))
+		return;
+
+	vcpu->arch.ctxt.sys_regs[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
+}
+
 static void __hyp_text __activate_traps_vhe(void)
 {
 	u64 val;
@@ -380,11 +389,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 
 	__vgic_restore_state(vcpu);
 
-	/*
-	 * We must restore the 32-bit state before the sysregs, thanks
-	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
-	 */
-	__sysreg32_restore_state(vcpu);
 	sysreg_restore_guest_state_vhe(guest_ctxt);
 	__debug_switch_to_guest(vcpu);
 
@@ -398,7 +402,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	fp_enabled = __fpsimd_enabled();
 
 	sysreg_save_guest_state_vhe(guest_ctxt);
-	__sysreg32_save_state(vcpu);
 	__vgic_save_state(vcpu);
 
 	__deactivate_traps(vcpu);
@@ -408,6 +411,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	if (fp_enabled) {
 		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
 		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
+		__fpsimd_save_fpexc32(vcpu);
 	}
 
 	__debug_switch_to_host(vcpu);
@@ -475,6 +479,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 	if (fp_enabled) {
 		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
 		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
+		__fpsimd_save_fpexc32(vcpu);
 	}
 
 	/*
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 9c60b8062724..aacba4636871 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -196,10 +196,7 @@ void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
 	sysreg[DACR32_EL2] = read_sysreg(dacr32_el2);
 	sysreg[IFSR32_EL2] = read_sysreg(ifsr32_el2);
 
-	if (__fpsimd_enabled())
-		sysreg[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
-
-	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
+	if (has_vhe() || vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
 		sysreg[DBGVCR32_EL2] = read_sysreg(dbgvcr32_el2);
 }
 
@@ -221,7 +218,7 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
 	write_sysreg(sysreg[DACR32_EL2], dacr32_el2);
 	write_sysreg(sysreg[IFSR32_EL2], ifsr32_el2);
 
-	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
+	if (has_vhe() || vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
 		write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
 }
 
@@ -246,6 +243,13 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
 
 	__sysreg_save_user_state(host_ctxt);
 
+	/*
+	 * Load guest EL1 and user state
+	 *
+	 * We must restore the 32-bit state before the sysregs, thanks
+	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
+	 */
+	__sysreg32_restore_state(vcpu);
 	__sysreg_restore_user_state(guest_ctxt);
 	__sysreg_restore_el1_state(guest_ctxt);
 
@@ -273,6 +277,7 @@ void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
 
 	__sysreg_save_el1_state(guest_ctxt);
 	__sysreg_save_user_state(guest_ctxt);
+	__sysreg32_save_state(vcpu);
 
 	/* Restore host user state */
 	__sysreg_restore_user_state(host_ctxt);
-- 
2.14.2

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

* [PATCH v4 30/40] KVM: arm64: Defer saving/restoring 32-bit sysregs to vcpu load/put
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

When running a 32-bit VM (EL1 in AArch32), the AArch32 system registers
can be deferred to vcpu load/put on VHE systems because neither
the host kernel nor host userspace uses these registers.

Note that we can not defer saving DBGVCR32_EL2 conditionally based
on the state of the debug dirty flag on VHE, but since we do the
load/put pretty rarely, this comes out as a win anyway.

We can also not defer saving FPEXC32_32 because this register only holds
a guest-valid value for 32-bit guests during the exit path when the
guest has used FPSIMD registers and restored the register in the early
assembly handler from taking the EL2 fault, and therefore we have to
check if fpsimd is enabled for the guest in the exit path and save the
register then, for both VHE and non-VHE guests.

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

Notes:
    Changes since v3:
     - Rework the FPEXC32 save/restore logic to no longer attempt to
       save/restore this register lazily.
    
    Changes since v2:
     - New patch (deferred register handling has been reworked)

 arch/arm64/kvm/hyp/switch.c    | 17 +++++++++++------
 arch/arm64/kvm/hyp/sysreg-sr.c | 15 ++++++++++-----
 2 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 22e77deb8e2e..909aa3fe9196 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -47,6 +47,15 @@ bool __hyp_text __fpsimd_enabled(void)
 	return __fpsimd_is_enabled()();
 }
 
+/* Save the 32-bit only FPSIMD system register state */
+static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
+{
+	if (!vcpu_el1_is_32bit(vcpu))
+		return;
+
+	vcpu->arch.ctxt.sys_regs[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
+}
+
 static void __hyp_text __activate_traps_vhe(void)
 {
 	u64 val;
@@ -380,11 +389,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 
 	__vgic_restore_state(vcpu);
 
-	/*
-	 * We must restore the 32-bit state before the sysregs, thanks
-	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
-	 */
-	__sysreg32_restore_state(vcpu);
 	sysreg_restore_guest_state_vhe(guest_ctxt);
 	__debug_switch_to_guest(vcpu);
 
@@ -398,7 +402,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	fp_enabled = __fpsimd_enabled();
 
 	sysreg_save_guest_state_vhe(guest_ctxt);
-	__sysreg32_save_state(vcpu);
 	__vgic_save_state(vcpu);
 
 	__deactivate_traps(vcpu);
@@ -408,6 +411,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	if (fp_enabled) {
 		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
 		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
+		__fpsimd_save_fpexc32(vcpu);
 	}
 
 	__debug_switch_to_host(vcpu);
@@ -475,6 +479,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 	if (fp_enabled) {
 		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
 		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
+		__fpsimd_save_fpexc32(vcpu);
 	}
 
 	/*
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 9c60b8062724..aacba4636871 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -196,10 +196,7 @@ void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
 	sysreg[DACR32_EL2] = read_sysreg(dacr32_el2);
 	sysreg[IFSR32_EL2] = read_sysreg(ifsr32_el2);
 
-	if (__fpsimd_enabled())
-		sysreg[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
-
-	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
+	if (has_vhe() || vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
 		sysreg[DBGVCR32_EL2] = read_sysreg(dbgvcr32_el2);
 }
 
@@ -221,7 +218,7 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
 	write_sysreg(sysreg[DACR32_EL2], dacr32_el2);
 	write_sysreg(sysreg[IFSR32_EL2], ifsr32_el2);
 
-	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
+	if (has_vhe() || vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
 		write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
 }
 
@@ -246,6 +243,13 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
 
 	__sysreg_save_user_state(host_ctxt);
 
+	/*
+	 * Load guest EL1 and user state
+	 *
+	 * We must restore the 32-bit state before the sysregs, thanks
+	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
+	 */
+	__sysreg32_restore_state(vcpu);
 	__sysreg_restore_user_state(guest_ctxt);
 	__sysreg_restore_el1_state(guest_ctxt);
 
@@ -273,6 +277,7 @@ void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
 
 	__sysreg_save_el1_state(guest_ctxt);
 	__sysreg_save_user_state(guest_ctxt);
+	__sysreg32_save_state(vcpu);
 
 	/* Restore host user state */
 	__sysreg_restore_user_state(host_ctxt);
-- 
2.14.2

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

* [PATCH v4 31/40] KVM: arm64: Move common VHE/non-VHE trap config in separate functions
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

As we are about to be more lazy with some of the trap configuration
register read/writes for VHE systems, move the logic that is currently
shared between VHE and non-VHE into a separate function which can be
called from either the world-switch path or from vcpu_load/vcpu_put.

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

Notes:
    Changes since v3:
     - Separate fpsimd32 trap configuration into a separate function
       which is still called from __activate_traps, because we no longer
       defer saving/restoring of VFP registers to load/put.

 arch/arm64/kvm/hyp/switch.c | 76 +++++++++++++++++++++++++++------------------
 1 file changed, 45 insertions(+), 31 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 909aa3fe9196..17e3c6f26a34 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -56,7 +56,45 @@ static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
 	vcpu->arch.ctxt.sys_regs[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
 }
 
-static void __hyp_text __activate_traps_vhe(void)
+static void __hyp_text __activate_traps_fpsimd32(struct kvm_vcpu *vcpu)
+{
+	/*
+	 * We are about to set CPTR_EL2.TFP to trap all floating point
+	 * register accesses to EL2, however, the ARM ARM clearly states that
+	 * traps are only taken to EL2 if the operation would not otherwise
+	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
+	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
+	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
+	 * it will cause an exception.
+	 */
+	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
+		write_sysreg(1 << 30, fpexc32_el2);
+		isb();
+	}
+}
+
+static void __hyp_text __activate_traps_common(struct kvm_vcpu *vcpu)
+{
+	/* Trap on AArch32 cp15 c15 (impdef sysregs) accesses (EL1 or EL0) */
+	write_sysreg(1 << 15, hstr_el2);
+	/*
+	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
+	 * PMSELR_EL0 to make sure it never contains the cycle
+	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
+	 * EL1 instead of being trapped to EL2.
+	 */
+	write_sysreg(0, pmselr_el0);
+	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
+	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
+}
+
+static void __hyp_text __deactivate_traps_common(void)
+{
+	write_sysreg(0, hstr_el2);
+	write_sysreg(0, pmuserenr_el0);
+}
+
+static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
 {
 	u64 val;
 
@@ -68,7 +106,7 @@ static void __hyp_text __activate_traps_vhe(void)
 	write_sysreg(kvm_get_hyp_vector(), vbar_el1);
 }
 
-static void __hyp_text __activate_traps_nvhe(void)
+static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
 {
 	u64 val;
 
@@ -85,37 +123,14 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
 {
 	u64 hcr = vcpu->arch.hcr_el2;
 
-	/*
-	 * We are about to set CPTR_EL2.TFP to trap all floating point
-	 * register accesses to EL2, however, the ARM ARM clearly states that
-	 * traps are only taken to EL2 if the operation would not otherwise
-	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
-	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
-	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
-	 * it will cause an exception.
-	 */
-	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
-		write_sysreg(1 << 30, fpexc32_el2);
-		isb();
-	}
+	write_sysreg(hcr, hcr_el2);
 
 	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
 		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
 
-	write_sysreg(hcr, hcr_el2);
-
-	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
-	write_sysreg(1 << 15, hstr_el2);
-	/*
-	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
-	 * PMSELR_EL0 to make sure it never contains the cycle
-	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
-	 * EL1 instead of being trapped to EL2.
-	 */
-	write_sysreg(0, pmselr_el0);
-	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
-	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
-	__activate_traps_arch()();
+	__activate_traps_fpsimd32(vcpu);
+	__activate_traps_common(vcpu);
+	__activate_traps_arch()(vcpu);
 }
 
 static void __hyp_text __deactivate_traps_vhe(void)
@@ -160,9 +175,8 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
 	if (vcpu->arch.hcr_el2 & HCR_VSE)
 		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
 
+	__deactivate_traps_common();
 	__deactivate_traps_arch()();
-	write_sysreg(0, hstr_el2);
-	write_sysreg(0, pmuserenr_el0);
 }
 
 static void __hyp_text __activate_vm(struct kvm *kvm)
-- 
2.14.2

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

* [PATCH v4 31/40] KVM: arm64: Move common VHE/non-VHE trap config in separate functions
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

As we are about to be more lazy with some of the trap configuration
register read/writes for VHE systems, move the logic that is currently
shared between VHE and non-VHE into a separate function which can be
called from either the world-switch path or from vcpu_load/vcpu_put.

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

Notes:
    Changes since v3:
     - Separate fpsimd32 trap configuration into a separate function
       which is still called from __activate_traps, because we no longer
       defer saving/restoring of VFP registers to load/put.

 arch/arm64/kvm/hyp/switch.c | 76 +++++++++++++++++++++++++++------------------
 1 file changed, 45 insertions(+), 31 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 909aa3fe9196..17e3c6f26a34 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -56,7 +56,45 @@ static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
 	vcpu->arch.ctxt.sys_regs[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
 }
 
-static void __hyp_text __activate_traps_vhe(void)
+static void __hyp_text __activate_traps_fpsimd32(struct kvm_vcpu *vcpu)
+{
+	/*
+	 * We are about to set CPTR_EL2.TFP to trap all floating point
+	 * register accesses to EL2, however, the ARM ARM clearly states that
+	 * traps are only taken to EL2 if the operation would not otherwise
+	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
+	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
+	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
+	 * it will cause an exception.
+	 */
+	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
+		write_sysreg(1 << 30, fpexc32_el2);
+		isb();
+	}
+}
+
+static void __hyp_text __activate_traps_common(struct kvm_vcpu *vcpu)
+{
+	/* Trap on AArch32 cp15 c15 (impdef sysregs) accesses (EL1 or EL0) */
+	write_sysreg(1 << 15, hstr_el2);
+	/*
+	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
+	 * PMSELR_EL0 to make sure it never contains the cycle
+	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
+	 * EL1 instead of being trapped to EL2.
+	 */
+	write_sysreg(0, pmselr_el0);
+	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
+	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
+}
+
+static void __hyp_text __deactivate_traps_common(void)
+{
+	write_sysreg(0, hstr_el2);
+	write_sysreg(0, pmuserenr_el0);
+}
+
+static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
 {
 	u64 val;
 
@@ -68,7 +106,7 @@ static void __hyp_text __activate_traps_vhe(void)
 	write_sysreg(kvm_get_hyp_vector(), vbar_el1);
 }
 
-static void __hyp_text __activate_traps_nvhe(void)
+static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
 {
 	u64 val;
 
@@ -85,37 +123,14 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
 {
 	u64 hcr = vcpu->arch.hcr_el2;
 
-	/*
-	 * We are about to set CPTR_EL2.TFP to trap all floating point
-	 * register accesses to EL2, however, the ARM ARM clearly states that
-	 * traps are only taken to EL2 if the operation would not otherwise
-	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
-	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
-	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
-	 * it will cause an exception.
-	 */
-	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
-		write_sysreg(1 << 30, fpexc32_el2);
-		isb();
-	}
+	write_sysreg(hcr, hcr_el2);
 
 	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
 		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
 
-	write_sysreg(hcr, hcr_el2);
-
-	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
-	write_sysreg(1 << 15, hstr_el2);
-	/*
-	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
-	 * PMSELR_EL0 to make sure it never contains the cycle
-	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
-	 * EL1 instead of being trapped to EL2.
-	 */
-	write_sysreg(0, pmselr_el0);
-	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
-	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
-	__activate_traps_arch()();
+	__activate_traps_fpsimd32(vcpu);
+	__activate_traps_common(vcpu);
+	__activate_traps_arch()(vcpu);
 }
 
 static void __hyp_text __deactivate_traps_vhe(void)
@@ -160,9 +175,8 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
 	if (vcpu->arch.hcr_el2 & HCR_VSE)
 		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
 
+	__deactivate_traps_common();
 	__deactivate_traps_arch()();
-	write_sysreg(0, hstr_el2);
-	write_sysreg(0, pmuserenr_el0);
 }
 
 static void __hyp_text __activate_vm(struct kvm *kvm)
-- 
2.14.2

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

* [PATCH v4 32/40] KVM: arm64: Directly call VHE and non-VHE FPSIMD enabled functions
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

There is no longer a need for an alternative to choose the right
function to tell us whether or not FPSIMD was enabled for the VM,
because we can simply cann the appropriate functions directly fromwithin
the _vhe and _nvhe run functions.

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

Notes:
    Changes since v3:
     - New patch since we no longer defer FPSIMD handling to load/put

 arch/arm64/kvm/hyp/switch.c | 15 +++------------
 1 file changed, 3 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 17e3c6f26a34..9c40e203bd09 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -33,20 +33,11 @@ static bool __hyp_text __fpsimd_enabled_nvhe(void)
 	return !(read_sysreg(cptr_el2) & CPTR_EL2_TFP);
 }
 
-static bool __hyp_text __fpsimd_enabled_vhe(void)
+static bool fpsimd_enabled_vhe(void)
 {
 	return !!(read_sysreg(cpacr_el1) & CPACR_EL1_FPEN);
 }
 
-static hyp_alternate_select(__fpsimd_is_enabled,
-			    __fpsimd_enabled_nvhe, __fpsimd_enabled_vhe,
-			    ARM64_HAS_VIRT_HOST_EXTN);
-
-bool __hyp_text __fpsimd_enabled(void)
-{
-	return __fpsimd_is_enabled()();
-}
-
 /* Save the 32-bit only FPSIMD system register state */
 static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
 {
@@ -413,7 +404,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 		/* And we're baaack! */
 	} while (fixup_guest_exit(vcpu, &exit_code));
 
-	fp_enabled = __fpsimd_enabled();
+	fp_enabled = fpsimd_enabled_vhe();
 
 	sysreg_save_guest_state_vhe(guest_ctxt);
 	__vgic_save_state(vcpu);
@@ -478,7 +469,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 			__qcom_hyp_sanitize_btac_predictors();
 	}
 
-	fp_enabled = __fpsimd_enabled();
+	fp_enabled = __fpsimd_enabled_nvhe();
 
 	__sysreg_save_state_nvhe(guest_ctxt);
 	__sysreg32_save_state(vcpu);
-- 
2.14.2

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

* [PATCH v4 32/40] KVM: arm64: Directly call VHE and non-VHE FPSIMD enabled functions
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

There is no longer a need for an alternative to choose the right
function to tell us whether or not FPSIMD was enabled for the VM,
because we can simply cann the appropriate functions directly fromwithin
the _vhe and _nvhe run functions.

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

Notes:
    Changes since v3:
     - New patch since we no longer defer FPSIMD handling to load/put

 arch/arm64/kvm/hyp/switch.c | 15 +++------------
 1 file changed, 3 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 17e3c6f26a34..9c40e203bd09 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -33,20 +33,11 @@ static bool __hyp_text __fpsimd_enabled_nvhe(void)
 	return !(read_sysreg(cptr_el2) & CPTR_EL2_TFP);
 }
 
-static bool __hyp_text __fpsimd_enabled_vhe(void)
+static bool fpsimd_enabled_vhe(void)
 {
 	return !!(read_sysreg(cpacr_el1) & CPACR_EL1_FPEN);
 }
 
-static hyp_alternate_select(__fpsimd_is_enabled,
-			    __fpsimd_enabled_nvhe, __fpsimd_enabled_vhe,
-			    ARM64_HAS_VIRT_HOST_EXTN);
-
-bool __hyp_text __fpsimd_enabled(void)
-{
-	return __fpsimd_is_enabled()();
-}
-
 /* Save the 32-bit only FPSIMD system register state */
 static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
 {
@@ -413,7 +404,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 		/* And we're baaack! */
 	} while (fixup_guest_exit(vcpu, &exit_code));
 
-	fp_enabled = __fpsimd_enabled();
+	fp_enabled = fpsimd_enabled_vhe();
 
 	sysreg_save_guest_state_vhe(guest_ctxt);
 	__vgic_save_state(vcpu);
@@ -478,7 +469,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
 			__qcom_hyp_sanitize_btac_predictors();
 	}
 
-	fp_enabled = __fpsimd_enabled();
+	fp_enabled = __fpsimd_enabled_nvhe();
 
 	__sysreg_save_state_nvhe(guest_ctxt);
 	__sysreg32_save_state(vcpu);
-- 
2.14.2

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

* [PATCH v4 33/40] KVM: arm64: Configure c15, PMU, and debug register traps on cpu load/put for VHE
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

We do not have to change the c15 trap setting on each switch to/from the
guest on VHE systems, because this setting only affects EL0.

The PMU and debug trap configuration can also be done on vcpu load/put
instead, because they don't affect how the host kernel can access the
debug registers while executing KVM kernel code.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/include/asm/kvm_hyp.h |  3 +++
 arch/arm64/kvm/hyp/switch.c      | 31 ++++++++++++++++++++++---------
 arch/arm64/kvm/hyp/sysreg-sr.c   |  4 ++++
 3 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 2b1fda90dde4..949f2e77ae58 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -147,6 +147,9 @@ void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
 void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
 bool __fpsimd_enabled(void);
 
+void activate_traps_vhe_load(struct kvm_vcpu *vcpu);
+void deactivate_traps_vhe_put(void);
+
 u64 __guest_enter(struct kvm_vcpu *vcpu, struct kvm_cpu_context *host_ctxt);
 void __noreturn __hyp_do_panic(unsigned long, ...);
 
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 9c40e203bd09..5e94955b89ea 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -101,6 +101,8 @@ static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
 {
 	u64 val;
 
+	__activate_traps_common(vcpu);
+
 	val = CPTR_EL2_DEFAULT;
 	val |= CPTR_EL2_TTA | CPTR_EL2_TFP | CPTR_EL2_TZ;
 	write_sysreg(val, cptr_el2);
@@ -120,20 +122,12 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
 		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
 
 	__activate_traps_fpsimd32(vcpu);
-	__activate_traps_common(vcpu);
 	__activate_traps_arch()(vcpu);
 }
 
 static void __hyp_text __deactivate_traps_vhe(void)
 {
 	extern char vectors[];	/* kernel exception vectors */
-	u64 mdcr_el2 = read_sysreg(mdcr_el2);
-
-	mdcr_el2 &= MDCR_EL2_HPMN_MASK |
-		    MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT |
-		    MDCR_EL2_TPMS;
-
-	write_sysreg(mdcr_el2, mdcr_el2);
 	write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
 	write_sysreg(CPACR_EL1_DEFAULT, cpacr_el1);
 	write_sysreg(vectors, vbar_el1);
@@ -143,6 +137,8 @@ static void __hyp_text __deactivate_traps_nvhe(void)
 {
 	u64 mdcr_el2 = read_sysreg(mdcr_el2);
 
+	__deactivate_traps_common();
+
 	mdcr_el2 &= MDCR_EL2_HPMN_MASK;
 	mdcr_el2 |= MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT;
 
@@ -166,10 +162,27 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
 	if (vcpu->arch.hcr_el2 & HCR_VSE)
 		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
 
-	__deactivate_traps_common();
 	__deactivate_traps_arch()();
 }
 
+void activate_traps_vhe_load(struct kvm_vcpu *vcpu)
+{
+	__activate_traps_common(vcpu);
+}
+
+void deactivate_traps_vhe_put(void)
+{
+	u64 mdcr_el2 = read_sysreg(mdcr_el2);
+
+	mdcr_el2 &= MDCR_EL2_HPMN_MASK |
+		    MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT |
+		    MDCR_EL2_TPMS;
+
+	write_sysreg(mdcr_el2, mdcr_el2);
+
+	__deactivate_traps_common();
+}
+
 static void __hyp_text __activate_vm(struct kvm *kvm)
 {
 	write_sysreg(kvm->arch.vttbr, vttbr_el2);
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index aacba4636871..b3894df6bf1a 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -254,6 +254,8 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
 	__sysreg_restore_el1_state(guest_ctxt);
 
 	vcpu->arch.sysregs_loaded_on_cpu = true;
+
+	activate_traps_vhe_load(vcpu);
 }
 
 /**
@@ -275,6 +277,8 @@ void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
 	if (!has_vhe())
 		return;
 
+	deactivate_traps_vhe_put();
+
 	__sysreg_save_el1_state(guest_ctxt);
 	__sysreg_save_user_state(guest_ctxt);
 	__sysreg32_save_state(vcpu);
-- 
2.14.2

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

* [PATCH v4 33/40] KVM: arm64: Configure c15, PMU, and debug register traps on cpu load/put for VHE
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

We do not have to change the c15 trap setting on each switch to/from the
guest on VHE systems, because this setting only affects EL0.

The PMU and debug trap configuration can also be done on vcpu load/put
instead, because they don't affect how the host kernel can access the
debug registers while executing KVM kernel code.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/include/asm/kvm_hyp.h |  3 +++
 arch/arm64/kvm/hyp/switch.c      | 31 ++++++++++++++++++++++---------
 arch/arm64/kvm/hyp/sysreg-sr.c   |  4 ++++
 3 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 2b1fda90dde4..949f2e77ae58 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -147,6 +147,9 @@ void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
 void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
 bool __fpsimd_enabled(void);
 
+void activate_traps_vhe_load(struct kvm_vcpu *vcpu);
+void deactivate_traps_vhe_put(void);
+
 u64 __guest_enter(struct kvm_vcpu *vcpu, struct kvm_cpu_context *host_ctxt);
 void __noreturn __hyp_do_panic(unsigned long, ...);
 
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 9c40e203bd09..5e94955b89ea 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -101,6 +101,8 @@ static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
 {
 	u64 val;
 
+	__activate_traps_common(vcpu);
+
 	val = CPTR_EL2_DEFAULT;
 	val |= CPTR_EL2_TTA | CPTR_EL2_TFP | CPTR_EL2_TZ;
 	write_sysreg(val, cptr_el2);
@@ -120,20 +122,12 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
 		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
 
 	__activate_traps_fpsimd32(vcpu);
-	__activate_traps_common(vcpu);
 	__activate_traps_arch()(vcpu);
 }
 
 static void __hyp_text __deactivate_traps_vhe(void)
 {
 	extern char vectors[];	/* kernel exception vectors */
-	u64 mdcr_el2 = read_sysreg(mdcr_el2);
-
-	mdcr_el2 &= MDCR_EL2_HPMN_MASK |
-		    MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT |
-		    MDCR_EL2_TPMS;
-
-	write_sysreg(mdcr_el2, mdcr_el2);
 	write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
 	write_sysreg(CPACR_EL1_DEFAULT, cpacr_el1);
 	write_sysreg(vectors, vbar_el1);
@@ -143,6 +137,8 @@ static void __hyp_text __deactivate_traps_nvhe(void)
 {
 	u64 mdcr_el2 = read_sysreg(mdcr_el2);
 
+	__deactivate_traps_common();
+
 	mdcr_el2 &= MDCR_EL2_HPMN_MASK;
 	mdcr_el2 |= MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT;
 
@@ -166,10 +162,27 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
 	if (vcpu->arch.hcr_el2 & HCR_VSE)
 		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
 
-	__deactivate_traps_common();
 	__deactivate_traps_arch()();
 }
 
+void activate_traps_vhe_load(struct kvm_vcpu *vcpu)
+{
+	__activate_traps_common(vcpu);
+}
+
+void deactivate_traps_vhe_put(void)
+{
+	u64 mdcr_el2 = read_sysreg(mdcr_el2);
+
+	mdcr_el2 &= MDCR_EL2_HPMN_MASK |
+		    MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT |
+		    MDCR_EL2_TPMS;
+
+	write_sysreg(mdcr_el2, mdcr_el2);
+
+	__deactivate_traps_common();
+}
+
 static void __hyp_text __activate_vm(struct kvm *kvm)
 {
 	write_sysreg(kvm->arch.vttbr, vttbr_el2);
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index aacba4636871..b3894df6bf1a 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -254,6 +254,8 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
 	__sysreg_restore_el1_state(guest_ctxt);
 
 	vcpu->arch.sysregs_loaded_on_cpu = true;
+
+	activate_traps_vhe_load(vcpu);
 }
 
 /**
@@ -275,6 +277,8 @@ void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
 	if (!has_vhe())
 		return;
 
+	deactivate_traps_vhe_put();
+
 	__sysreg_save_el1_state(guest_ctxt);
 	__sysreg_save_user_state(guest_ctxt);
 	__sysreg32_save_state(vcpu);
-- 
2.14.2

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

* [PATCH v4 34/40] KVM: arm64: Cleanup __activate_traps and __deactive_traps for VHE and non-VHE
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

To make the code more readable and to avoid the overhead of a function
call, let's get rid of a pair of the alternative function selectors and
explicitly call the VHE and non-VHE functions using the has_vhe() static
key based selector instead, telling the compiler to try to inline the
static function if it can.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/hyp/switch.c | 30 ++++++++++++++----------------
 1 file changed, 14 insertions(+), 16 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 5e94955b89ea..0e54fe2aab1c 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -85,7 +85,7 @@ static void __hyp_text __deactivate_traps_common(void)
 	write_sysreg(0, pmuserenr_el0);
 }
 
-static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
+static inline void activate_traps_vhe(struct kvm_vcpu *vcpu)
 {
 	u64 val;
 
@@ -97,7 +97,7 @@ static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
 	write_sysreg(kvm_get_hyp_vector(), vbar_el1);
 }
 
-static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
+static inline void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
 {
 	u64 val;
 
@@ -108,11 +108,7 @@ static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
 	write_sysreg(val, cptr_el2);
 }
 
-static hyp_alternate_select(__activate_traps_arch,
-			    __activate_traps_nvhe, __activate_traps_vhe,
-			    ARM64_HAS_VIRT_HOST_EXTN);
-
-static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
+static inline void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
 {
 	u64 hcr = vcpu->arch.hcr_el2;
 
@@ -122,10 +118,13 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
 		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
 
 	__activate_traps_fpsimd32(vcpu);
-	__activate_traps_arch()(vcpu);
+	if (has_vhe())
+		activate_traps_vhe(vcpu);
+	else
+		__activate_traps_nvhe(vcpu);
 }
 
-static void __hyp_text __deactivate_traps_vhe(void)
+static inline void deactivate_traps_vhe(void)
 {
 	extern char vectors[];	/* kernel exception vectors */
 	write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
@@ -133,7 +132,7 @@ static void __hyp_text __deactivate_traps_vhe(void)
 	write_sysreg(vectors, vbar_el1);
 }
 
-static void __hyp_text __deactivate_traps_nvhe(void)
+static inline void __hyp_text __deactivate_traps_nvhe(void)
 {
 	u64 mdcr_el2 = read_sysreg(mdcr_el2);
 
@@ -147,11 +146,7 @@ static void __hyp_text __deactivate_traps_nvhe(void)
 	write_sysreg(CPTR_EL2_DEFAULT, cptr_el2);
 }
 
-static hyp_alternate_select(__deactivate_traps_arch,
-			    __deactivate_traps_nvhe, __deactivate_traps_vhe,
-			    ARM64_HAS_VIRT_HOST_EXTN);
-
-static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
+static inline void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
 {
 	/*
 	 * If we pended a virtual abort, preserve it until it gets
@@ -162,7 +157,10 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
 	if (vcpu->arch.hcr_el2 & HCR_VSE)
 		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
 
-	__deactivate_traps_arch()();
+	if (has_vhe())
+		deactivate_traps_vhe();
+	else
+		__deactivate_traps_nvhe();
 }
 
 void activate_traps_vhe_load(struct kvm_vcpu *vcpu)
-- 
2.14.2

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

* [PATCH v4 34/40] KVM: arm64: Cleanup __activate_traps and __deactive_traps for VHE and non-VHE
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

To make the code more readable and to avoid the overhead of a function
call, let's get rid of a pair of the alternative function selectors and
explicitly call the VHE and non-VHE functions using the has_vhe() static
key based selector instead, telling the compiler to try to inline the
static function if it can.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm64/kvm/hyp/switch.c | 30 ++++++++++++++----------------
 1 file changed, 14 insertions(+), 16 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 5e94955b89ea..0e54fe2aab1c 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -85,7 +85,7 @@ static void __hyp_text __deactivate_traps_common(void)
 	write_sysreg(0, pmuserenr_el0);
 }
 
-static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
+static inline void activate_traps_vhe(struct kvm_vcpu *vcpu)
 {
 	u64 val;
 
@@ -97,7 +97,7 @@ static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
 	write_sysreg(kvm_get_hyp_vector(), vbar_el1);
 }
 
-static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
+static inline void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
 {
 	u64 val;
 
@@ -108,11 +108,7 @@ static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
 	write_sysreg(val, cptr_el2);
 }
 
-static hyp_alternate_select(__activate_traps_arch,
-			    __activate_traps_nvhe, __activate_traps_vhe,
-			    ARM64_HAS_VIRT_HOST_EXTN);
-
-static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
+static inline void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
 {
 	u64 hcr = vcpu->arch.hcr_el2;
 
@@ -122,10 +118,13 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
 		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
 
 	__activate_traps_fpsimd32(vcpu);
-	__activate_traps_arch()(vcpu);
+	if (has_vhe())
+		activate_traps_vhe(vcpu);
+	else
+		__activate_traps_nvhe(vcpu);
 }
 
-static void __hyp_text __deactivate_traps_vhe(void)
+static inline void deactivate_traps_vhe(void)
 {
 	extern char vectors[];	/* kernel exception vectors */
 	write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
@@ -133,7 +132,7 @@ static void __hyp_text __deactivate_traps_vhe(void)
 	write_sysreg(vectors, vbar_el1);
 }
 
-static void __hyp_text __deactivate_traps_nvhe(void)
+static inline void __hyp_text __deactivate_traps_nvhe(void)
 {
 	u64 mdcr_el2 = read_sysreg(mdcr_el2);
 
@@ -147,11 +146,7 @@ static void __hyp_text __deactivate_traps_nvhe(void)
 	write_sysreg(CPTR_EL2_DEFAULT, cptr_el2);
 }
 
-static hyp_alternate_select(__deactivate_traps_arch,
-			    __deactivate_traps_nvhe, __deactivate_traps_vhe,
-			    ARM64_HAS_VIRT_HOST_EXTN);
-
-static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
+static inline void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
 {
 	/*
 	 * If we pended a virtual abort, preserve it until it gets
@@ -162,7 +157,10 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
 	if (vcpu->arch.hcr_el2 & HCR_VSE)
 		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
 
-	__deactivate_traps_arch()();
+	if (has_vhe())
+		deactivate_traps_vhe();
+	else
+		__deactivate_traps_nvhe();
 }
 
 void activate_traps_vhe_load(struct kvm_vcpu *vcpu)
-- 
2.14.2

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

* [PATCH v4 35/40] KVM: arm/arm64: Get rid of vgic_elrsr
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

There is really no need to store the vgic_elrsr on the VGIC data
structures as the only need we have for the elrsr is to figure out if an
LR is inactive when we save the VGIC state upon returning from the
guest.  We can might as well store this in a temporary local variable.

This also gets rid of the endianness conversion in the VGIC save
function, which is completely unnecessary and would actually result in
incorrect functionality on big-endian systems, because we are only using
typed values here and not converting pointers and reading different
types here.

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

Notes:
    Changes since v1:
     - Moved patch up the queue before we start moving code around to avoid moving
       potentially broken code.

 include/kvm/arm_vgic.h        |  2 --
 virt/kvm/arm/hyp/vgic-v2-sr.c | 28 +++++++---------------------
 virt/kvm/arm/hyp/vgic-v3-sr.c |  6 +++---
 virt/kvm/arm/vgic/vgic-v2.c   |  1 -
 virt/kvm/arm/vgic/vgic-v3.c   |  1 -
 5 files changed, 10 insertions(+), 28 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index cdbd142ca7f2..ac98ae46bfb7 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -263,7 +263,6 @@ struct vgic_dist {
 struct vgic_v2_cpu_if {
 	u32		vgic_hcr;
 	u32		vgic_vmcr;
-	u64		vgic_elrsr;	/* Saved only */
 	u32		vgic_apr;
 	u32		vgic_lr[VGIC_V2_MAX_LRS];
 };
@@ -272,7 +271,6 @@ struct vgic_v3_cpu_if {
 	u32		vgic_hcr;
 	u32		vgic_vmcr;
 	u32		vgic_sre;	/* Restored only, change ignored */
-	u32		vgic_elrsr;	/* Saved only */
 	u32		vgic_ap0r[4];
 	u32		vgic_ap1r[4];
 	u64		vgic_lr[VGIC_V3_MAX_LRS];
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index 4fe6e797e8b3..a91b0d2b9249 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -23,29 +23,19 @@
 #include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
 
-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 = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
-	u32 elrsr0, elrsr1;
-
-	elrsr0 = readl_relaxed(base + GICH_ELRSR0);
-	if (unlikely(nr_lr > 32))
-		elrsr1 = readl_relaxed(base + GICH_ELRSR1);
-	else
-		elrsr1 = 0;
-
-	cpu_if->vgic_elrsr = ((u64)elrsr1 << 32) | elrsr0;
-}
-
 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 i;
 	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
+	u64 elrsr;
+	int i;
+
+	elrsr = readl_relaxed(base + GICH_ELRSR0);
+	if (unlikely(used_lrs > 32))
+		elrsr |= ((u64)readl_relaxed(base + GICH_ELRSR1)) << 32;
 
 	for (i = 0; i < used_lrs; i++) {
-		if (cpu_if->vgic_elrsr & (1UL << i))
+		if (elrsr & (1UL << i))
 			cpu_if->vgic_lr[i] &= ~GICH_LR_STATE;
 		else
 			cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
@@ -68,13 +58,9 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
 
 	if (used_lrs) {
 		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
-
-		save_elrsr(vcpu, base);
 		save_lrs(vcpu, base);
-
 		writel_relaxed(0, base + GICH_HCR);
 	} else {
-		cpu_if->vgic_elrsr = ~0UL;
 		cpu_if->vgic_apr = 0;
 	}
 }
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index f5c3d6d7019e..9abf2f3c12b5 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -222,15 +222,16 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 	if (used_lrs) {
 		int i;
 		u32 nr_pre_bits;
+		u32 elrsr;
 
-		cpu_if->vgic_elrsr = read_gicreg(ICH_ELSR_EL2);
+		elrsr = read_gicreg(ICH_ELSR_EL2);
 
 		write_gicreg(0, ICH_HCR_EL2);
 		val = read_gicreg(ICH_VTR_EL2);
 		nr_pre_bits = vtr_to_nr_pre_bits(val);
 
 		for (i = 0; i < used_lrs; i++) {
-			if (cpu_if->vgic_elrsr & (1 << i))
+			if (elrsr & (1 << i))
 				cpu_if->vgic_lr[i] &= ~ICH_LR_STATE;
 			else
 				cpu_if->vgic_lr[i] = __gic_v3_get_lr(i);
@@ -262,7 +263,6 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 		    cpu_if->its_vpe.its_vm)
 			write_gicreg(0, ICH_HCR_EL2);
 
-		cpu_if->vgic_elrsr = 0xffff;
 		cpu_if->vgic_ap0r[0] = 0;
 		cpu_if->vgic_ap0r[1] = 0;
 		cpu_if->vgic_ap0r[2] = 0;
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index c32d7b93ffd1..bb305d49cfdd 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -265,7 +265,6 @@ void vgic_v2_enable(struct kvm_vcpu *vcpu)
 	 * 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;
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 6b329414e57a..b76e21f3e6bd 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -267,7 +267,6 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 	 * 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
-- 
2.14.2

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

* [PATCH v4 35/40] KVM: arm/arm64: Get rid of vgic_elrsr
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

There is really no need to store the vgic_elrsr on the VGIC data
structures as the only need we have for the elrsr is to figure out if an
LR is inactive when we save the VGIC state upon returning from the
guest.  We can might as well store this in a temporary local variable.

This also gets rid of the endianness conversion in the VGIC save
function, which is completely unnecessary and would actually result in
incorrect functionality on big-endian systems, because we are only using
typed values here and not converting pointers and reading different
types here.

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

Notes:
    Changes since v1:
     - Moved patch up the queue before we start moving code around to avoid moving
       potentially broken code.

 include/kvm/arm_vgic.h        |  2 --
 virt/kvm/arm/hyp/vgic-v2-sr.c | 28 +++++++---------------------
 virt/kvm/arm/hyp/vgic-v3-sr.c |  6 +++---
 virt/kvm/arm/vgic/vgic-v2.c   |  1 -
 virt/kvm/arm/vgic/vgic-v3.c   |  1 -
 5 files changed, 10 insertions(+), 28 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index cdbd142ca7f2..ac98ae46bfb7 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -263,7 +263,6 @@ struct vgic_dist {
 struct vgic_v2_cpu_if {
 	u32		vgic_hcr;
 	u32		vgic_vmcr;
-	u64		vgic_elrsr;	/* Saved only */
 	u32		vgic_apr;
 	u32		vgic_lr[VGIC_V2_MAX_LRS];
 };
@@ -272,7 +271,6 @@ struct vgic_v3_cpu_if {
 	u32		vgic_hcr;
 	u32		vgic_vmcr;
 	u32		vgic_sre;	/* Restored only, change ignored */
-	u32		vgic_elrsr;	/* Saved only */
 	u32		vgic_ap0r[4];
 	u32		vgic_ap1r[4];
 	u64		vgic_lr[VGIC_V3_MAX_LRS];
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index 4fe6e797e8b3..a91b0d2b9249 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -23,29 +23,19 @@
 #include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
 
-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 = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
-	u32 elrsr0, elrsr1;
-
-	elrsr0 = readl_relaxed(base + GICH_ELRSR0);
-	if (unlikely(nr_lr > 32))
-		elrsr1 = readl_relaxed(base + GICH_ELRSR1);
-	else
-		elrsr1 = 0;
-
-	cpu_if->vgic_elrsr = ((u64)elrsr1 << 32) | elrsr0;
-}
-
 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 i;
 	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
+	u64 elrsr;
+	int i;
+
+	elrsr = readl_relaxed(base + GICH_ELRSR0);
+	if (unlikely(used_lrs > 32))
+		elrsr |= ((u64)readl_relaxed(base + GICH_ELRSR1)) << 32;
 
 	for (i = 0; i < used_lrs; i++) {
-		if (cpu_if->vgic_elrsr & (1UL << i))
+		if (elrsr & (1UL << i))
 			cpu_if->vgic_lr[i] &= ~GICH_LR_STATE;
 		else
 			cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
@@ -68,13 +58,9 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
 
 	if (used_lrs) {
 		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
-
-		save_elrsr(vcpu, base);
 		save_lrs(vcpu, base);
-
 		writel_relaxed(0, base + GICH_HCR);
 	} else {
-		cpu_if->vgic_elrsr = ~0UL;
 		cpu_if->vgic_apr = 0;
 	}
 }
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index f5c3d6d7019e..9abf2f3c12b5 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -222,15 +222,16 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 	if (used_lrs) {
 		int i;
 		u32 nr_pre_bits;
+		u32 elrsr;
 
-		cpu_if->vgic_elrsr = read_gicreg(ICH_ELSR_EL2);
+		elrsr = read_gicreg(ICH_ELSR_EL2);
 
 		write_gicreg(0, ICH_HCR_EL2);
 		val = read_gicreg(ICH_VTR_EL2);
 		nr_pre_bits = vtr_to_nr_pre_bits(val);
 
 		for (i = 0; i < used_lrs; i++) {
-			if (cpu_if->vgic_elrsr & (1 << i))
+			if (elrsr & (1 << i))
 				cpu_if->vgic_lr[i] &= ~ICH_LR_STATE;
 			else
 				cpu_if->vgic_lr[i] = __gic_v3_get_lr(i);
@@ -262,7 +263,6 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 		    cpu_if->its_vpe.its_vm)
 			write_gicreg(0, ICH_HCR_EL2);
 
-		cpu_if->vgic_elrsr = 0xffff;
 		cpu_if->vgic_ap0r[0] = 0;
 		cpu_if->vgic_ap0r[1] = 0;
 		cpu_if->vgic_ap0r[2] = 0;
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index c32d7b93ffd1..bb305d49cfdd 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -265,7 +265,6 @@ void vgic_v2_enable(struct kvm_vcpu *vcpu)
 	 * 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;
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 6b329414e57a..b76e21f3e6bd 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -267,7 +267,6 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 	 * 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
-- 
2.14.2

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

* [PATCH v4 36/40] KVM: arm/arm64: Handle VGICv2 save/restore from the main VGIC code
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

We can program the GICv2 hypervisor control interface logic directly
from the core vgic code and can instead do the save/restore directly
from the flush/sync functions, which can lead to a number of future
optimizations.

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

Notes:
    Changes since v1:
     - Removed unnecessary kvm_hyp.h include
     - Adapted the patch based on having gotten rid of storing the elrsr
       prior to this patch.
     - No longer change the interrupt handling of the maintenance interrupt
       handler.  That seems to have been a leftover from an earlier version
       of the timer patches where we were syncing the vgic state after
       having enabled interrupts, leading to the maintenance interrupt firing.
    
       It may be possible to move the vgic sync function out to an
       interrupts enabled section later on, which would require
       re-introducing logic to disable the VGIC maintenance interrupt in the
       maintenance interrupt handler, but we leave this for future work as
       the immediate benefit is not clear.

 arch/arm/kvm/hyp/switch.c        |  4 ---
 arch/arm64/include/asm/kvm_hyp.h |  2 --
 arch/arm64/kvm/hyp/switch.c      |  4 ---
 virt/kvm/arm/hyp/vgic-v2-sr.c    | 65 ----------------------------------------
 virt/kvm/arm/vgic/vgic-v2.c      | 63 ++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.c         | 19 +++++++++++-
 virt/kvm/arm/vgic/vgic.h         |  3 ++
 7 files changed, 84 insertions(+), 76 deletions(-)

diff --git a/arch/arm/kvm/hyp/switch.c b/arch/arm/kvm/hyp/switch.c
index aac025783ee8..882b9b9e0077 100644
--- a/arch/arm/kvm/hyp/switch.c
+++ b/arch/arm/kvm/hyp/switch.c
@@ -92,16 +92,12 @@ static void __hyp_text __vgic_save_state(struct kvm_vcpu *vcpu)
 {
 	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		__vgic_v3_save_state(vcpu);
-	else
-		__vgic_v2_save_state(vcpu);
 }
 
 static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
 {
 	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		__vgic_v3_restore_state(vcpu);
-	else
-		__vgic_v2_restore_state(vcpu);
 }
 
 static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 949f2e77ae58..febe417b8b4e 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -120,8 +120,6 @@ typeof(orig) * __hyp_text fname(void)					\
 	return val;							\
 }
 
-void __vgic_v2_save_state(struct kvm_vcpu *vcpu);
-void __vgic_v2_restore_state(struct kvm_vcpu *vcpu);
 int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
 
 void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 0e54fe2aab1c..cbafc27a617b 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -195,16 +195,12 @@ static void __hyp_text __vgic_save_state(struct kvm_vcpu *vcpu)
 {
 	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		__vgic_v3_save_state(vcpu);
-	else
-		__vgic_v2_save_state(vcpu);
 }
 
 static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
 {
 	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		__vgic_v3_restore_state(vcpu);
-	else
-		__vgic_v2_restore_state(vcpu);
 }
 
 static bool __hyp_text __true_value(void)
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index a91b0d2b9249..0bbafdfd4adb 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -23,71 +23,6 @@
 #include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
 
-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;
-	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
-	u64 elrsr;
-	int i;
-
-	elrsr = readl_relaxed(base + GICH_ELRSR0);
-	if (unlikely(used_lrs > 32))
-		elrsr |= ((u64)readl_relaxed(base + GICH_ELRSR1)) << 32;
-
-	for (i = 0; i < used_lrs; i++) {
-		if (elrsr & (1UL << i))
-			cpu_if->vgic_lr[i] &= ~GICH_LR_STATE;
-		else
-			cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
-
-		writel_relaxed(0, base + GICH_LR0 + (i * 4));
-	}
-}
-
-/* vcpu is already in the HYP VA space */
-void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
-{
-	struct kvm *kvm = kern_hyp_va(vcpu->kvm);
-	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);
-	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
-
-	if (!base)
-		return;
-
-	if (used_lrs) {
-		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
-		save_lrs(vcpu, base);
-		writel_relaxed(0, base + GICH_HCR);
-	} else {
-		cpu_if->vgic_apr = 0;
-	}
-}
-
-/* vcpu is already in the HYP VA space */
-void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
-{
-	struct kvm *kvm = kern_hyp_va(vcpu->kvm);
-	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;
-	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
-
-	if (!base)
-		return;
-
-	if (used_lrs) {
-		writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
-		writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
-		for (i = 0; i < used_lrs; i++) {
-			writel_relaxed(cpu_if->vgic_lr[i],
-				       base + GICH_LR0 + (i * 4));
-		}
-	}
-}
-
 #ifdef CONFIG_ARM64
 /*
  * __vgic_v2_perform_cpuif_access -- perform a GICV access on behalf of the
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index bb305d49cfdd..1e5f3eb6973d 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -421,6 +421,69 @@ int vgic_v2_probe(const struct gic_kvm_info *info)
 	return ret;
 }
 
+static void save_lrs(struct kvm_vcpu *vcpu, void __iomem *base)
+{
+	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
+	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
+	u64 elrsr;
+	int i;
+
+	elrsr = readl_relaxed(base + GICH_ELRSR0);
+	if (unlikely(used_lrs > 32))
+		elrsr |= ((u64)readl_relaxed(base + GICH_ELRSR1)) << 32;
+
+	for (i = 0; i < used_lrs; i++) {
+		if (elrsr & (1UL << i))
+			cpu_if->vgic_lr[i] &= ~GICH_LR_STATE;
+		else
+			cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
+
+		writel_relaxed(0, base + GICH_LR0 + (i * 4));
+	}
+}
+
+void vgic_v2_save_state(struct kvm_vcpu *vcpu)
+{
+	struct kvm *kvm = vcpu->kvm;
+	struct vgic_dist *vgic = &kvm->arch.vgic;
+	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
+	void __iomem *base = vgic->vctrl_base;
+	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
+
+	if (!base)
+		return;
+
+	if (used_lrs) {
+		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
+		save_lrs(vcpu, base);
+		writel_relaxed(0, base + GICH_HCR);
+	} else {
+		cpu_if->vgic_apr = 0;
+	}
+}
+
+void vgic_v2_restore_state(struct kvm_vcpu *vcpu)
+{
+	struct kvm *kvm = vcpu->kvm;
+	struct vgic_dist *vgic = &kvm->arch.vgic;
+	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
+	void __iomem *base = vgic->vctrl_base;
+	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
+	int i;
+
+	if (!base)
+		return;
+
+	if (used_lrs) {
+		writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
+		writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
+		for (i = 0; i < used_lrs; i++) {
+			writel_relaxed(cpu_if->vgic_lr[i],
+				       base + GICH_LR0 + (i * 4));
+		}
+	}
+}
+
 void vgic_v2_load(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index c7c5ef190afa..12e2a28f437e 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -749,11 +749,19 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
 		vgic_clear_lr(vcpu, count);
 }
 
+static inline void vgic_save_state(struct kvm_vcpu *vcpu)
+{
+	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+		vgic_v2_save_state(vcpu);
+}
+
 /* Sync back the hardware VGIC state into our emulation after a guest's run. */
 void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 
+	vgic_save_state(vcpu);
+
 	WARN_ON(vgic_v4_sync_hwstate(vcpu));
 
 	/* An empty ap_list_head implies used_lrs == 0 */
@@ -765,6 +773,12 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 	vgic_prune_ap_list(vcpu);
 }
 
+static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
+{
+	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+		vgic_v2_restore_state(vcpu);
+}
+
 /* Flush our emulation state into the GIC hardware before entering the guest. */
 void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 {
@@ -780,13 +794,16 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 	 * this.
 	 */
 	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
-		return;
+		goto out;
 
 	DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
 
 	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
 	vgic_flush_lr_state(vcpu);
 	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+out:
+	vgic_restore_state(vcpu);
 }
 
 void kvm_vgic_load(struct kvm_vcpu *vcpu)
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 12c37b89f7a3..89b9547fba27 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -176,6 +176,9 @@ void vgic_v2_init_lrs(void);
 void vgic_v2_load(struct kvm_vcpu *vcpu);
 void vgic_v2_put(struct kvm_vcpu *vcpu);
 
+void vgic_v2_save_state(struct kvm_vcpu *vcpu);
+void vgic_v2_restore_state(struct kvm_vcpu *vcpu);
+
 static inline void vgic_get_irq_kref(struct vgic_irq *irq)
 {
 	if (irq->intid < VGIC_MIN_LPI)
-- 
2.14.2

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

* [PATCH v4 36/40] KVM: arm/arm64: Handle VGICv2 save/restore from the main VGIC code
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

We can program the GICv2 hypervisor control interface logic directly
from the core vgic code and can instead do the save/restore directly
from the flush/sync functions, which can lead to a number of future
optimizations.

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

Notes:
    Changes since v1:
     - Removed unnecessary kvm_hyp.h include
     - Adapted the patch based on having gotten rid of storing the elrsr
       prior to this patch.
     - No longer change the interrupt handling of the maintenance interrupt
       handler.  That seems to have been a leftover from an earlier version
       of the timer patches where we were syncing the vgic state after
       having enabled interrupts, leading to the maintenance interrupt firing.
    
       It may be possible to move the vgic sync function out to an
       interrupts enabled section later on, which would require
       re-introducing logic to disable the VGIC maintenance interrupt in the
       maintenance interrupt handler, but we leave this for future work as
       the immediate benefit is not clear.

 arch/arm/kvm/hyp/switch.c        |  4 ---
 arch/arm64/include/asm/kvm_hyp.h |  2 --
 arch/arm64/kvm/hyp/switch.c      |  4 ---
 virt/kvm/arm/hyp/vgic-v2-sr.c    | 65 ----------------------------------------
 virt/kvm/arm/vgic/vgic-v2.c      | 63 ++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.c         | 19 +++++++++++-
 virt/kvm/arm/vgic/vgic.h         |  3 ++
 7 files changed, 84 insertions(+), 76 deletions(-)

diff --git a/arch/arm/kvm/hyp/switch.c b/arch/arm/kvm/hyp/switch.c
index aac025783ee8..882b9b9e0077 100644
--- a/arch/arm/kvm/hyp/switch.c
+++ b/arch/arm/kvm/hyp/switch.c
@@ -92,16 +92,12 @@ static void __hyp_text __vgic_save_state(struct kvm_vcpu *vcpu)
 {
 	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		__vgic_v3_save_state(vcpu);
-	else
-		__vgic_v2_save_state(vcpu);
 }
 
 static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
 {
 	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		__vgic_v3_restore_state(vcpu);
-	else
-		__vgic_v2_restore_state(vcpu);
 }
 
 static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 949f2e77ae58..febe417b8b4e 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -120,8 +120,6 @@ typeof(orig) * __hyp_text fname(void)					\
 	return val;							\
 }
 
-void __vgic_v2_save_state(struct kvm_vcpu *vcpu);
-void __vgic_v2_restore_state(struct kvm_vcpu *vcpu);
 int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
 
 void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 0e54fe2aab1c..cbafc27a617b 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -195,16 +195,12 @@ static void __hyp_text __vgic_save_state(struct kvm_vcpu *vcpu)
 {
 	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		__vgic_v3_save_state(vcpu);
-	else
-		__vgic_v2_save_state(vcpu);
 }
 
 static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
 {
 	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		__vgic_v3_restore_state(vcpu);
-	else
-		__vgic_v2_restore_state(vcpu);
 }
 
 static bool __hyp_text __true_value(void)
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index a91b0d2b9249..0bbafdfd4adb 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -23,71 +23,6 @@
 #include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
 
-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;
-	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
-	u64 elrsr;
-	int i;
-
-	elrsr = readl_relaxed(base + GICH_ELRSR0);
-	if (unlikely(used_lrs > 32))
-		elrsr |= ((u64)readl_relaxed(base + GICH_ELRSR1)) << 32;
-
-	for (i = 0; i < used_lrs; i++) {
-		if (elrsr & (1UL << i))
-			cpu_if->vgic_lr[i] &= ~GICH_LR_STATE;
-		else
-			cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
-
-		writel_relaxed(0, base + GICH_LR0 + (i * 4));
-	}
-}
-
-/* vcpu is already in the HYP VA space */
-void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
-{
-	struct kvm *kvm = kern_hyp_va(vcpu->kvm);
-	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);
-	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
-
-	if (!base)
-		return;
-
-	if (used_lrs) {
-		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
-		save_lrs(vcpu, base);
-		writel_relaxed(0, base + GICH_HCR);
-	} else {
-		cpu_if->vgic_apr = 0;
-	}
-}
-
-/* vcpu is already in the HYP VA space */
-void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
-{
-	struct kvm *kvm = kern_hyp_va(vcpu->kvm);
-	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;
-	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
-
-	if (!base)
-		return;
-
-	if (used_lrs) {
-		writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
-		writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
-		for (i = 0; i < used_lrs; i++) {
-			writel_relaxed(cpu_if->vgic_lr[i],
-				       base + GICH_LR0 + (i * 4));
-		}
-	}
-}
-
 #ifdef CONFIG_ARM64
 /*
  * __vgic_v2_perform_cpuif_access -- perform a GICV access on behalf of the
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index bb305d49cfdd..1e5f3eb6973d 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -421,6 +421,69 @@ int vgic_v2_probe(const struct gic_kvm_info *info)
 	return ret;
 }
 
+static void save_lrs(struct kvm_vcpu *vcpu, void __iomem *base)
+{
+	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
+	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
+	u64 elrsr;
+	int i;
+
+	elrsr = readl_relaxed(base + GICH_ELRSR0);
+	if (unlikely(used_lrs > 32))
+		elrsr |= ((u64)readl_relaxed(base + GICH_ELRSR1)) << 32;
+
+	for (i = 0; i < used_lrs; i++) {
+		if (elrsr & (1UL << i))
+			cpu_if->vgic_lr[i] &= ~GICH_LR_STATE;
+		else
+			cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
+
+		writel_relaxed(0, base + GICH_LR0 + (i * 4));
+	}
+}
+
+void vgic_v2_save_state(struct kvm_vcpu *vcpu)
+{
+	struct kvm *kvm = vcpu->kvm;
+	struct vgic_dist *vgic = &kvm->arch.vgic;
+	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
+	void __iomem *base = vgic->vctrl_base;
+	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
+
+	if (!base)
+		return;
+
+	if (used_lrs) {
+		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
+		save_lrs(vcpu, base);
+		writel_relaxed(0, base + GICH_HCR);
+	} else {
+		cpu_if->vgic_apr = 0;
+	}
+}
+
+void vgic_v2_restore_state(struct kvm_vcpu *vcpu)
+{
+	struct kvm *kvm = vcpu->kvm;
+	struct vgic_dist *vgic = &kvm->arch.vgic;
+	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
+	void __iomem *base = vgic->vctrl_base;
+	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
+	int i;
+
+	if (!base)
+		return;
+
+	if (used_lrs) {
+		writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
+		writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
+		for (i = 0; i < used_lrs; i++) {
+			writel_relaxed(cpu_if->vgic_lr[i],
+				       base + GICH_LR0 + (i * 4));
+		}
+	}
+}
+
 void vgic_v2_load(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index c7c5ef190afa..12e2a28f437e 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -749,11 +749,19 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
 		vgic_clear_lr(vcpu, count);
 }
 
+static inline void vgic_save_state(struct kvm_vcpu *vcpu)
+{
+	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+		vgic_v2_save_state(vcpu);
+}
+
 /* Sync back the hardware VGIC state into our emulation after a guest's run. */
 void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 
+	vgic_save_state(vcpu);
+
 	WARN_ON(vgic_v4_sync_hwstate(vcpu));
 
 	/* An empty ap_list_head implies used_lrs == 0 */
@@ -765,6 +773,12 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 	vgic_prune_ap_list(vcpu);
 }
 
+static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
+{
+	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+		vgic_v2_restore_state(vcpu);
+}
+
 /* Flush our emulation state into the GIC hardware before entering the guest. */
 void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 {
@@ -780,13 +794,16 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 	 * this.
 	 */
 	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
-		return;
+		goto out;
 
 	DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
 
 	spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
 	vgic_flush_lr_state(vcpu);
 	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
+
+out:
+	vgic_restore_state(vcpu);
 }
 
 void kvm_vgic_load(struct kvm_vcpu *vcpu)
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 12c37b89f7a3..89b9547fba27 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -176,6 +176,9 @@ void vgic_v2_init_lrs(void);
 void vgic_v2_load(struct kvm_vcpu *vcpu);
 void vgic_v2_put(struct kvm_vcpu *vcpu);
 
+void vgic_v2_save_state(struct kvm_vcpu *vcpu);
+void vgic_v2_restore_state(struct kvm_vcpu *vcpu);
+
 static inline void vgic_get_irq_kref(struct vgic_irq *irq)
 {
 	if (irq->intid < VGIC_MIN_LPI)
-- 
2.14.2

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

* [PATCH v4 37/40] KVM: arm/arm64: Move arm64-only vgic-v2-sr.c file to arm64
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

The vgic-v2-sr.c file now only contains the logic to replay unaligned
accesses to the virtual CPU interface on 16K and 64K page systems, which
is only relevant on 64-bit platforms.  Therefore move this file to the
arm64 KVM tree, remove the compile directive from the 32-bit side
makefile, and remove the ifdef in the C file.

Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm/kvm/hyp/Makefile                         | 1 -
 arch/arm64/kvm/hyp/Makefile                       | 2 +-
 {virt/kvm/arm => arch/arm64/kvm}/hyp/vgic-v2-sr.c | 2 --
 3 files changed, 1 insertion(+), 4 deletions(-)
 rename {virt/kvm/arm => arch/arm64/kvm}/hyp/vgic-v2-sr.c (98%)

diff --git a/arch/arm/kvm/hyp/Makefile b/arch/arm/kvm/hyp/Makefile
index 5638ce0c9524..1964111c984a 100644
--- a/arch/arm/kvm/hyp/Makefile
+++ b/arch/arm/kvm/hyp/Makefile
@@ -7,7 +7,6 @@ ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
 
 KVM=../../../../virt/kvm
 
-obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v3-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/timer-sr.o
 
diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
index f04400d494b7..7e8d41210288 100644
--- a/arch/arm64/kvm/hyp/Makefile
+++ b/arch/arm64/kvm/hyp/Makefile
@@ -7,10 +7,10 @@ ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
 
 KVM=../../../../virt/kvm
 
-obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v3-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/timer-sr.o
 
+obj-$(CONFIG_KVM_ARM_HOST) += vgic-v2-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += sysreg-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += debug-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += entry.o
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/arch/arm64/kvm/hyp/vgic-v2-sr.c
similarity index 98%
rename from virt/kvm/arm/hyp/vgic-v2-sr.c
rename to arch/arm64/kvm/hyp/vgic-v2-sr.c
index 0bbafdfd4adb..97f357ea9c72 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/arch/arm64/kvm/hyp/vgic-v2-sr.c
@@ -23,7 +23,6 @@
 #include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
 
-#ifdef CONFIG_ARM64
 /*
  * __vgic_v2_perform_cpuif_access -- perform a GICV access on behalf of the
  *				     guest.
@@ -77,4 +76,3 @@ int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
 
 	return 1;
 }
-#endif
-- 
2.14.2

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

* [PATCH v4 37/40] KVM: arm/arm64: Move arm64-only vgic-v2-sr.c file to arm64
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

The vgic-v2-sr.c file now only contains the logic to replay unaligned
accesses to the virtual CPU interface on 16K and 64K page systems, which
is only relevant on 64-bit platforms.  Therefore move this file to the
arm64 KVM tree, remove the compile directive from the 32-bit side
makefile, and remove the ifdef in the C file.

Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm/kvm/hyp/Makefile                         | 1 -
 arch/arm64/kvm/hyp/Makefile                       | 2 +-
 {virt/kvm/arm => arch/arm64/kvm}/hyp/vgic-v2-sr.c | 2 --
 3 files changed, 1 insertion(+), 4 deletions(-)
 rename {virt/kvm/arm => arch/arm64/kvm}/hyp/vgic-v2-sr.c (98%)

diff --git a/arch/arm/kvm/hyp/Makefile b/arch/arm/kvm/hyp/Makefile
index 5638ce0c9524..1964111c984a 100644
--- a/arch/arm/kvm/hyp/Makefile
+++ b/arch/arm/kvm/hyp/Makefile
@@ -7,7 +7,6 @@ ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
 
 KVM=../../../../virt/kvm
 
-obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v3-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/timer-sr.o
 
diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
index f04400d494b7..7e8d41210288 100644
--- a/arch/arm64/kvm/hyp/Makefile
+++ b/arch/arm64/kvm/hyp/Makefile
@@ -7,10 +7,10 @@ ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
 
 KVM=../../../../virt/kvm
 
-obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v3-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/timer-sr.o
 
+obj-$(CONFIG_KVM_ARM_HOST) += vgic-v2-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += sysreg-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += debug-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += entry.o
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/arch/arm64/kvm/hyp/vgic-v2-sr.c
similarity index 98%
rename from virt/kvm/arm/hyp/vgic-v2-sr.c
rename to arch/arm64/kvm/hyp/vgic-v2-sr.c
index 0bbafdfd4adb..97f357ea9c72 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/arch/arm64/kvm/hyp/vgic-v2-sr.c
@@ -23,7 +23,6 @@
 #include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
 
-#ifdef CONFIG_ARM64
 /*
  * __vgic_v2_perform_cpuif_access -- perform a GICV access on behalf of the
  *				     guest.
@@ -77,4 +76,3 @@ int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
 
 	return 1;
 }
-#endif
-- 
2.14.2

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

* [PATCH v4 38/40] KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on VHE
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

Just like we can program the GICv2 hypervisor control interface directly
from the core vgic code, we can do the same for the GICv3 hypervisor
control interface on VHE systems.

We do this by simply calling the save/restore functions when we have VHE
and we can then get rid of the save/restore function calls from the VHE
world switch function.

One caveat is that we now write GICv3 system register state before the
potential early exit path in the run loop, and because we sync back
state in the early exit path, we have to ensure that we read a
consistent GIC state from the sync path, even though we have never
actually run the guest with the newly written GIC state.  We solve this
by inserting an ISB in the early exit path.

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

Notes:
    Changes since v2:
     - Added ISB in the early exit path in the run loop as explained
       in the commit message.

 arch/arm64/kvm/hyp/switch.c | 3 ---
 virt/kvm/arm/arm.c          | 1 +
 virt/kvm/arm/vgic/vgic.c    | 5 +++++
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index cbafc27a617b..466cfcdbcaf3 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -399,8 +399,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	__activate_traps(vcpu);
 	__activate_vm(vcpu->kvm);
 
-	__vgic_restore_state(vcpu);
-
 	sysreg_restore_guest_state_vhe(guest_ctxt);
 	__debug_switch_to_guest(vcpu);
 
@@ -414,7 +412,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	fp_enabled = fpsimd_enabled_vhe();
 
 	sysreg_save_guest_state_vhe(guest_ctxt);
-	__vgic_save_state(vcpu);
 
 	__deactivate_traps(vcpu);
 
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 5bd879c78951..6de7641f3ff2 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -717,6 +717,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
 		    kvm_request_pending(vcpu)) {
 			vcpu->mode = OUTSIDE_GUEST_MODE;
+			isb(); /* Ensure work in x_flush_hwstate is committed */
 			kvm_pmu_sync_hwstate(vcpu);
 			if (static_branch_unlikely(&userspace_irqchip_in_use))
 				kvm_timer_sync_hwstate(vcpu);
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 12e2a28f437e..d0a19a8c196a 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -19,6 +19,7 @@
 #include <linux/list_sort.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <asm/kvm_hyp.h>
 
 #include "vgic.h"
 
@@ -753,6 +754,8 @@ static inline void vgic_save_state(struct kvm_vcpu *vcpu)
 {
 	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_save_state(vcpu);
+	else if (has_vhe())
+		__vgic_v3_save_state(vcpu);
 }
 
 /* Sync back the hardware VGIC state into our emulation after a guest's run. */
@@ -777,6 +780,8 @@ static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
 {
 	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_restore_state(vcpu);
+	else if (has_vhe())
+		__vgic_v3_restore_state(vcpu);
 }
 
 /* Flush our emulation state into the GIC hardware before entering the guest. */
-- 
2.14.2

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

* [PATCH v4 38/40] KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on VHE
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

Just like we can program the GICv2 hypervisor control interface directly
from the core vgic code, we can do the same for the GICv3 hypervisor
control interface on VHE systems.

We do this by simply calling the save/restore functions when we have VHE
and we can then get rid of the save/restore function calls from the VHE
world switch function.

One caveat is that we now write GICv3 system register state before the
potential early exit path in the run loop, and because we sync back
state in the early exit path, we have to ensure that we read a
consistent GIC state from the sync path, even though we have never
actually run the guest with the newly written GIC state.  We solve this
by inserting an ISB in the early exit path.

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

Notes:
    Changes since v2:
     - Added ISB in the early exit path in the run loop as explained
       in the commit message.

 arch/arm64/kvm/hyp/switch.c | 3 ---
 virt/kvm/arm/arm.c          | 1 +
 virt/kvm/arm/vgic/vgic.c    | 5 +++++
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index cbafc27a617b..466cfcdbcaf3 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -399,8 +399,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	__activate_traps(vcpu);
 	__activate_vm(vcpu->kvm);
 
-	__vgic_restore_state(vcpu);
-
 	sysreg_restore_guest_state_vhe(guest_ctxt);
 	__debug_switch_to_guest(vcpu);
 
@@ -414,7 +412,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 	fp_enabled = fpsimd_enabled_vhe();
 
 	sysreg_save_guest_state_vhe(guest_ctxt);
-	__vgic_save_state(vcpu);
 
 	__deactivate_traps(vcpu);
 
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 5bd879c78951..6de7641f3ff2 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -717,6 +717,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
 		    kvm_request_pending(vcpu)) {
 			vcpu->mode = OUTSIDE_GUEST_MODE;
+			isb(); /* Ensure work in x_flush_hwstate is committed */
 			kvm_pmu_sync_hwstate(vcpu);
 			if (static_branch_unlikely(&userspace_irqchip_in_use))
 				kvm_timer_sync_hwstate(vcpu);
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 12e2a28f437e..d0a19a8c196a 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -19,6 +19,7 @@
 #include <linux/list_sort.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <asm/kvm_hyp.h>
 
 #include "vgic.h"
 
@@ -753,6 +754,8 @@ static inline void vgic_save_state(struct kvm_vcpu *vcpu)
 {
 	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_save_state(vcpu);
+	else if (has_vhe())
+		__vgic_v3_save_state(vcpu);
 }
 
 /* Sync back the hardware VGIC state into our emulation after a guest's run. */
@@ -777,6 +780,8 @@ static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
 {
 	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
 		vgic_v2_restore_state(vcpu);
+	else if (has_vhe())
+		__vgic_v3_restore_state(vcpu);
 }
 
 /* Flush our emulation state into the GIC hardware before entering the guest. */
-- 
2.14.2

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

* [PATCH v4 39/40] KVM: arm/arm64: Move VGIC APR save/restore to vgic put/load
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

The APRs can only have bits set when the guest acknowledges an interrupt
in the LR and can only have a bit cleared when the guest EOIs an
interrupt in the LR.  Therefore, if we have no LRs with any
pending/active interrupts, the APR cannot change value and there is no
need to clear it on every exit from the VM (hint: it will have already
been cleared when we exited the guest the last time with the LRs all
EOIed).

The only case we need to take care of is when we migrate the VCPU away
from a CPU or migrate a new VCPU onto a CPU, or when we return to
userspace to capture the state of the VCPU for migration.  To make sure
this works, factor out the APR save/restore functionality into separate
functions called from the VCPU (and by extension VGIC) put/load hooks.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm/include/asm/kvm_hyp.h   |   2 +
 arch/arm64/include/asm/kvm_hyp.h |   2 +
 virt/kvm/arm/hyp/vgic-v3-sr.c    | 124 +++++++++++++++++++++------------------
 virt/kvm/arm/vgic/vgic-v2.c      |   7 +--
 virt/kvm/arm/vgic/vgic-v3.c      |   5 ++
 5 files changed, 78 insertions(+), 62 deletions(-)

diff --git a/arch/arm/include/asm/kvm_hyp.h b/arch/arm/include/asm/kvm_hyp.h
index 1ab8329e9ff7..530a3c1cfe6f 100644
--- a/arch/arm/include/asm/kvm_hyp.h
+++ b/arch/arm/include/asm/kvm_hyp.h
@@ -110,6 +110,8 @@ void __sysreg_restore_state(struct kvm_cpu_context *ctxt);
 
 void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
 void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
+void __vgic_v3_save_aprs(struct kvm_vcpu *vcpu);
+void __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu);
 
 asmlinkage void __vfp_save_state(struct vfp_hard_struct *vfp);
 asmlinkage void __vfp_restore_state(struct vfp_hard_struct *vfp);
diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index febe417b8b4e..6f3929b2fcf7 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -124,6 +124,8 @@ int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
 
 void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
 void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
+void __vgic_v3_save_aprs(struct kvm_vcpu *vcpu);
+void __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu);
 int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
 
 void __timer_enable_traps(struct kvm_vcpu *vcpu);
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 9abf2f3c12b5..437d7af08683 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -21,6 +21,7 @@
 
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
+#include <asm/kvm_mmu.h>
 
 #define vtr_to_max_lr_idx(v)		((v) & 0xf)
 #define vtr_to_nr_pre_bits(v)		((((u32)(v) >> 26) & 7) + 1)
@@ -221,14 +222,11 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 
 	if (used_lrs) {
 		int i;
-		u32 nr_pre_bits;
 		u32 elrsr;
 
 		elrsr = read_gicreg(ICH_ELSR_EL2);
 
 		write_gicreg(0, ICH_HCR_EL2);
-		val = read_gicreg(ICH_VTR_EL2);
-		nr_pre_bits = vtr_to_nr_pre_bits(val);
 
 		for (i = 0; i < used_lrs; i++) {
 			if (elrsr & (1 << i))
@@ -238,39 +236,10 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 
 			__gic_v3_set_lr(0, i);
 		}
-
-		switch (nr_pre_bits) {
-		case 7:
-			cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3);
-			cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2);
-		case 6:
-			cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1);
-		default:
-			cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0);
-		}
-
-		switch (nr_pre_bits) {
-		case 7:
-			cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3);
-			cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2);
-		case 6:
-			cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1);
-		default:
-			cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
-		}
 	} else {
 		if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
 		    cpu_if->its_vpe.its_vm)
 			write_gicreg(0, ICH_HCR_EL2);
-
-		cpu_if->vgic_ap0r[0] = 0;
-		cpu_if->vgic_ap0r[1] = 0;
-		cpu_if->vgic_ap0r[2] = 0;
-		cpu_if->vgic_ap0r[3] = 0;
-		cpu_if->vgic_ap1r[0] = 0;
-		cpu_if->vgic_ap1r[1] = 0;
-		cpu_if->vgic_ap1r[2] = 0;
-		cpu_if->vgic_ap1r[3] = 0;
 	}
 
 	val = read_gicreg(ICC_SRE_EL2);
@@ -287,8 +256,6 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
 	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
-	u64 val;
-	u32 nr_pre_bits;
 	int i;
 
 	/*
@@ -306,32 +273,9 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 		write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
 	}
 
-	val = read_gicreg(ICH_VTR_EL2);
-	nr_pre_bits = vtr_to_nr_pre_bits(val);
-
 	if (used_lrs) {
 		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
 
-		switch (nr_pre_bits) {
-		case 7:
-			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3);
-			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2);
-		case 6:
-			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1);
-		default:
-			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0);
-		}
-
-		switch (nr_pre_bits) {
-		case 7:
-			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3);
-			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2);
-		case 6:
-			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1);
-		default:
-			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0);
-		}
-
 		for (i = 0; i < used_lrs; i++)
 			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
 	} else {
@@ -364,6 +308,72 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 		     ICC_SRE_EL2);
 }
 
+void __hyp_text __vgic_v3_save_aprs(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpu_if;
+	u64 val;
+	u32 nr_pre_bits;
+
+	vcpu = kern_hyp_va(vcpu);
+	cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	val = read_gicreg(ICH_VTR_EL2);
+	nr_pre_bits = vtr_to_nr_pre_bits(val);
+
+	switch (nr_pre_bits) {
+	case 7:
+		cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3);
+		cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2);
+	case 6:
+		cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1);
+	default:
+		cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0);
+	}
+
+	switch (nr_pre_bits) {
+	case 7:
+		cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3);
+		cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2);
+	case 6:
+		cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1);
+	default:
+		cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
+	}
+}
+
+void __hyp_text __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpu_if;
+	u64 val;
+	u32 nr_pre_bits;
+
+	vcpu = kern_hyp_va(vcpu);
+	cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	val = read_gicreg(ICH_VTR_EL2);
+	nr_pre_bits = vtr_to_nr_pre_bits(val);
+
+	switch (nr_pre_bits) {
+	case 7:
+		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3);
+		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2);
+	case 6:
+		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1);
+	default:
+		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0);
+	}
+
+	switch (nr_pre_bits) {
+	case 7:
+		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3);
+		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2);
+	case 6:
+		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1);
+	default:
+		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0);
+	}
+}
+
 void __hyp_text __vgic_v3_init_lrs(void)
 {
 	int max_lr_idx = vtr_to_max_lr_idx(read_gicreg(ICH_VTR_EL2));
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 1e5f3eb6973d..ca7cfee9f353 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -446,7 +446,6 @@ void vgic_v2_save_state(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
 	struct vgic_dist *vgic = &kvm->arch.vgic;
-	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
 	void __iomem *base = vgic->vctrl_base;
 	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 
@@ -454,11 +453,8 @@ void vgic_v2_save_state(struct kvm_vcpu *vcpu)
 		return;
 
 	if (used_lrs) {
-		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
 		save_lrs(vcpu, base);
 		writel_relaxed(0, base + GICH_HCR);
-	} else {
-		cpu_if->vgic_apr = 0;
 	}
 }
 
@@ -476,7 +472,6 @@ void vgic_v2_restore_state(struct kvm_vcpu *vcpu)
 
 	if (used_lrs) {
 		writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
-		writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
 		for (i = 0; i < used_lrs; i++) {
 			writel_relaxed(cpu_if->vgic_lr[i],
 				       base + GICH_LR0 + (i * 4));
@@ -490,6 +485,7 @@ void vgic_v2_load(struct kvm_vcpu *vcpu)
 	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
 
 	writel_relaxed(cpu_if->vgic_vmcr, vgic->vctrl_base + GICH_VMCR);
+	writel_relaxed(cpu_if->vgic_apr, vgic->vctrl_base + GICH_APR);
 }
 
 void vgic_v2_put(struct kvm_vcpu *vcpu)
@@ -498,4 +494,5 @@ void vgic_v2_put(struct kvm_vcpu *vcpu)
 	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
 
 	cpu_if->vgic_vmcr = readl_relaxed(vgic->vctrl_base + GICH_VMCR);
+	cpu_if->vgic_apr = readl_relaxed(vgic->vctrl_base + GICH_APR);
 }
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index b76e21f3e6bd..4bafcd1e6bb8 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -16,6 +16,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <kvm/arm_vgic.h>
+#include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
 #include <asm/kvm_asm.h>
 
@@ -587,6 +588,8 @@ void vgic_v3_load(struct kvm_vcpu *vcpu)
 	 */
 	if (likely(cpu_if->vgic_sre))
 		kvm_call_hyp(__vgic_v3_write_vmcr, cpu_if->vgic_vmcr);
+
+	kvm_call_hyp(__vgic_v3_restore_aprs, vcpu);
 }
 
 void vgic_v3_put(struct kvm_vcpu *vcpu)
@@ -595,4 +598,6 @@ void vgic_v3_put(struct kvm_vcpu *vcpu)
 
 	if (likely(cpu_if->vgic_sre))
 		cpu_if->vgic_vmcr = kvm_call_hyp(__vgic_v3_read_vmcr);
+
+	kvm_call_hyp(__vgic_v3_save_aprs, vcpu);
 }
-- 
2.14.2

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

* [PATCH v4 39/40] KVM: arm/arm64: Move VGIC APR save/restore to vgic put/load
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

The APRs can only have bits set when the guest acknowledges an interrupt
in the LR and can only have a bit cleared when the guest EOIs an
interrupt in the LR.  Therefore, if we have no LRs with any
pending/active interrupts, the APR cannot change value and there is no
need to clear it on every exit from the VM (hint: it will have already
been cleared when we exited the guest the last time with the LRs all
EOIed).

The only case we need to take care of is when we migrate the VCPU away
from a CPU or migrate a new VCPU onto a CPU, or when we return to
userspace to capture the state of the VCPU for migration.  To make sure
this works, factor out the APR save/restore functionality into separate
functions called from the VCPU (and by extension VGIC) put/load hooks.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
 arch/arm/include/asm/kvm_hyp.h   |   2 +
 arch/arm64/include/asm/kvm_hyp.h |   2 +
 virt/kvm/arm/hyp/vgic-v3-sr.c    | 124 +++++++++++++++++++++------------------
 virt/kvm/arm/vgic/vgic-v2.c      |   7 +--
 virt/kvm/arm/vgic/vgic-v3.c      |   5 ++
 5 files changed, 78 insertions(+), 62 deletions(-)

diff --git a/arch/arm/include/asm/kvm_hyp.h b/arch/arm/include/asm/kvm_hyp.h
index 1ab8329e9ff7..530a3c1cfe6f 100644
--- a/arch/arm/include/asm/kvm_hyp.h
+++ b/arch/arm/include/asm/kvm_hyp.h
@@ -110,6 +110,8 @@ void __sysreg_restore_state(struct kvm_cpu_context *ctxt);
 
 void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
 void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
+void __vgic_v3_save_aprs(struct kvm_vcpu *vcpu);
+void __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu);
 
 asmlinkage void __vfp_save_state(struct vfp_hard_struct *vfp);
 asmlinkage void __vfp_restore_state(struct vfp_hard_struct *vfp);
diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index febe417b8b4e..6f3929b2fcf7 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -124,6 +124,8 @@ int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
 
 void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
 void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
+void __vgic_v3_save_aprs(struct kvm_vcpu *vcpu);
+void __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu);
 int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
 
 void __timer_enable_traps(struct kvm_vcpu *vcpu);
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 9abf2f3c12b5..437d7af08683 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -21,6 +21,7 @@
 
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
+#include <asm/kvm_mmu.h>
 
 #define vtr_to_max_lr_idx(v)		((v) & 0xf)
 #define vtr_to_nr_pre_bits(v)		((((u32)(v) >> 26) & 7) + 1)
@@ -221,14 +222,11 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 
 	if (used_lrs) {
 		int i;
-		u32 nr_pre_bits;
 		u32 elrsr;
 
 		elrsr = read_gicreg(ICH_ELSR_EL2);
 
 		write_gicreg(0, ICH_HCR_EL2);
-		val = read_gicreg(ICH_VTR_EL2);
-		nr_pre_bits = vtr_to_nr_pre_bits(val);
 
 		for (i = 0; i < used_lrs; i++) {
 			if (elrsr & (1 << i))
@@ -238,39 +236,10 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 
 			__gic_v3_set_lr(0, i);
 		}
-
-		switch (nr_pre_bits) {
-		case 7:
-			cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3);
-			cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2);
-		case 6:
-			cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1);
-		default:
-			cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0);
-		}
-
-		switch (nr_pre_bits) {
-		case 7:
-			cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3);
-			cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2);
-		case 6:
-			cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1);
-		default:
-			cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
-		}
 	} else {
 		if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
 		    cpu_if->its_vpe.its_vm)
 			write_gicreg(0, ICH_HCR_EL2);
-
-		cpu_if->vgic_ap0r[0] = 0;
-		cpu_if->vgic_ap0r[1] = 0;
-		cpu_if->vgic_ap0r[2] = 0;
-		cpu_if->vgic_ap0r[3] = 0;
-		cpu_if->vgic_ap1r[0] = 0;
-		cpu_if->vgic_ap1r[1] = 0;
-		cpu_if->vgic_ap1r[2] = 0;
-		cpu_if->vgic_ap1r[3] = 0;
 	}
 
 	val = read_gicreg(ICC_SRE_EL2);
@@ -287,8 +256,6 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
 	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
-	u64 val;
-	u32 nr_pre_bits;
 	int i;
 
 	/*
@@ -306,32 +273,9 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 		write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
 	}
 
-	val = read_gicreg(ICH_VTR_EL2);
-	nr_pre_bits = vtr_to_nr_pre_bits(val);
-
 	if (used_lrs) {
 		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
 
-		switch (nr_pre_bits) {
-		case 7:
-			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3);
-			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2);
-		case 6:
-			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1);
-		default:
-			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0);
-		}
-
-		switch (nr_pre_bits) {
-		case 7:
-			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3);
-			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2);
-		case 6:
-			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1);
-		default:
-			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0);
-		}
-
 		for (i = 0; i < used_lrs; i++)
 			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
 	} else {
@@ -364,6 +308,72 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 		     ICC_SRE_EL2);
 }
 
+void __hyp_text __vgic_v3_save_aprs(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpu_if;
+	u64 val;
+	u32 nr_pre_bits;
+
+	vcpu = kern_hyp_va(vcpu);
+	cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	val = read_gicreg(ICH_VTR_EL2);
+	nr_pre_bits = vtr_to_nr_pre_bits(val);
+
+	switch (nr_pre_bits) {
+	case 7:
+		cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3);
+		cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2);
+	case 6:
+		cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1);
+	default:
+		cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0);
+	}
+
+	switch (nr_pre_bits) {
+	case 7:
+		cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3);
+		cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2);
+	case 6:
+		cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1);
+	default:
+		cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
+	}
+}
+
+void __hyp_text __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpu_if;
+	u64 val;
+	u32 nr_pre_bits;
+
+	vcpu = kern_hyp_va(vcpu);
+	cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+
+	val = read_gicreg(ICH_VTR_EL2);
+	nr_pre_bits = vtr_to_nr_pre_bits(val);
+
+	switch (nr_pre_bits) {
+	case 7:
+		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3);
+		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2);
+	case 6:
+		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1);
+	default:
+		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0);
+	}
+
+	switch (nr_pre_bits) {
+	case 7:
+		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3);
+		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2);
+	case 6:
+		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1);
+	default:
+		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0);
+	}
+}
+
 void __hyp_text __vgic_v3_init_lrs(void)
 {
 	int max_lr_idx = vtr_to_max_lr_idx(read_gicreg(ICH_VTR_EL2));
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 1e5f3eb6973d..ca7cfee9f353 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -446,7 +446,6 @@ void vgic_v2_save_state(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = vcpu->kvm;
 	struct vgic_dist *vgic = &kvm->arch.vgic;
-	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
 	void __iomem *base = vgic->vctrl_base;
 	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 
@@ -454,11 +453,8 @@ void vgic_v2_save_state(struct kvm_vcpu *vcpu)
 		return;
 
 	if (used_lrs) {
-		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
 		save_lrs(vcpu, base);
 		writel_relaxed(0, base + GICH_HCR);
-	} else {
-		cpu_if->vgic_apr = 0;
 	}
 }
 
@@ -476,7 +472,6 @@ void vgic_v2_restore_state(struct kvm_vcpu *vcpu)
 
 	if (used_lrs) {
 		writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
-		writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
 		for (i = 0; i < used_lrs; i++) {
 			writel_relaxed(cpu_if->vgic_lr[i],
 				       base + GICH_LR0 + (i * 4));
@@ -490,6 +485,7 @@ void vgic_v2_load(struct kvm_vcpu *vcpu)
 	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
 
 	writel_relaxed(cpu_if->vgic_vmcr, vgic->vctrl_base + GICH_VMCR);
+	writel_relaxed(cpu_if->vgic_apr, vgic->vctrl_base + GICH_APR);
 }
 
 void vgic_v2_put(struct kvm_vcpu *vcpu)
@@ -498,4 +494,5 @@ void vgic_v2_put(struct kvm_vcpu *vcpu)
 	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
 
 	cpu_if->vgic_vmcr = readl_relaxed(vgic->vctrl_base + GICH_VMCR);
+	cpu_if->vgic_apr = readl_relaxed(vgic->vctrl_base + GICH_APR);
 }
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index b76e21f3e6bd..4bafcd1e6bb8 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -16,6 +16,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <kvm/arm_vgic.h>
+#include <asm/kvm_hyp.h>
 #include <asm/kvm_mmu.h>
 #include <asm/kvm_asm.h>
 
@@ -587,6 +588,8 @@ void vgic_v3_load(struct kvm_vcpu *vcpu)
 	 */
 	if (likely(cpu_if->vgic_sre))
 		kvm_call_hyp(__vgic_v3_write_vmcr, cpu_if->vgic_vmcr);
+
+	kvm_call_hyp(__vgic_v3_restore_aprs, vcpu);
 }
 
 void vgic_v3_put(struct kvm_vcpu *vcpu)
@@ -595,4 +598,6 @@ void vgic_v3_put(struct kvm_vcpu *vcpu)
 
 	if (likely(cpu_if->vgic_sre))
 		cpu_if->vgic_vmcr = kvm_call_hyp(__vgic_v3_read_vmcr);
+
+	kvm_call_hyp(__vgic_v3_save_aprs, vcpu);
 }
-- 
2.14.2

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

* [PATCH v4 40/40] KVM: arm/arm64: Avoid VGICv3 save/restore on VHE with no IRQs
  2018-02-15 21:02 ` Christoffer Dall
@ 2018-02-15 21:03   ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: kvm, Christoffer Dall, Marc Zyngier, Andrew Jones, Shih-Wei Li,
	Dave Martin, Julien Grall, Tomasz Nowicki, Yury Norov

We can finally get completely rid of any calls to the VGICv3
save/restore functions when the AP lists are empty on VHE systems.  This
requires carefully factoring out trap configuration from saving and
restoring state, and carefully choosing what to do on the VHE and
non-VHE path.

One of the challenges is that we cannot save/restore the VMCR lazily
because we can only write the VMCR when ICC_SRE_EL1.SRE is cleared when
emulating a GICv2-on-GICv3, since otherwise all Group-0 interrupts end
up being delivered as FIQ.

To solve this problem, and still provide fast performance in the fast
path of exiting a VM when no interrupts are pending (which also
optimized the latency for actually delivering virtual interrupts coming
from physical interrupts), we orchestrate a dance of only doing the
activate/deactivate traps in vgic load/put for VHE systems (which can
have ICC_SRE_EL1.SRE cleared when running in the host), and doing the
configuration on every round-trip on non-VHE systems.

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

Notes:
    Changes since v3:
     - Removed extra blank line

 arch/arm/include/asm/kvm_hyp.h   |   2 +
 arch/arm/kvm/hyp/switch.c        |   8 ++-
 arch/arm64/include/asm/kvm_hyp.h |   2 +
 arch/arm64/kvm/hyp/switch.c      |   8 ++-
 virt/kvm/arm/hyp/vgic-v3-sr.c    | 120 +++++++++++++++++++++++++--------------
 virt/kvm/arm/vgic/vgic-v3.c      |   6 ++
 virt/kvm/arm/vgic/vgic.c         |   7 +--
 7 files changed, 102 insertions(+), 51 deletions(-)

diff --git a/arch/arm/include/asm/kvm_hyp.h b/arch/arm/include/asm/kvm_hyp.h
index 530a3c1cfe6f..e93a0cac9add 100644
--- a/arch/arm/include/asm/kvm_hyp.h
+++ b/arch/arm/include/asm/kvm_hyp.h
@@ -110,6 +110,8 @@ void __sysreg_restore_state(struct kvm_cpu_context *ctxt);
 
 void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
 void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
+void __vgic_v3_activate_traps(struct kvm_vcpu *vcpu);
+void __vgic_v3_deactivate_traps(struct kvm_vcpu *vcpu);
 void __vgic_v3_save_aprs(struct kvm_vcpu *vcpu);
 void __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu);
 
diff --git a/arch/arm/kvm/hyp/switch.c b/arch/arm/kvm/hyp/switch.c
index 882b9b9e0077..acf1c37fa49c 100644
--- a/arch/arm/kvm/hyp/switch.c
+++ b/arch/arm/kvm/hyp/switch.c
@@ -90,14 +90,18 @@ static void __hyp_text __deactivate_vm(struct kvm_vcpu *vcpu)
 
 static void __hyp_text __vgic_save_state(struct kvm_vcpu *vcpu)
 {
-	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
 		__vgic_v3_save_state(vcpu);
+		__vgic_v3_deactivate_traps(vcpu);
+	}
 }
 
 static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
 {
-	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
+		__vgic_v3_activate_traps(vcpu);
 		__vgic_v3_restore_state(vcpu);
+	}
 }
 
 static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 6f3929b2fcf7..384c34397619 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -124,6 +124,8 @@ int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
 
 void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
 void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
+void __vgic_v3_activate_traps(struct kvm_vcpu *vcpu);
+void __vgic_v3_deactivate_traps(struct kvm_vcpu *vcpu);
 void __vgic_v3_save_aprs(struct kvm_vcpu *vcpu);
 void __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu);
 int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 466cfcdbcaf3..7d8a41e3c9ac 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -193,14 +193,18 @@ static void __hyp_text __deactivate_vm(struct kvm_vcpu *vcpu)
 
 static void __hyp_text __vgic_save_state(struct kvm_vcpu *vcpu)
 {
-	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
 		__vgic_v3_save_state(vcpu);
+		__vgic_v3_deactivate_traps(vcpu);
+	}
 }
 
 static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
 {
-	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
+		__vgic_v3_activate_traps(vcpu);
 		__vgic_v3_restore_state(vcpu);
+	}
 }
 
 static bool __hyp_text __true_value(void)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 437d7af08683..b13cbd41dbc3 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -209,15 +209,15 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
 	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
-	u64 val;
 
 	/*
 	 * Make sure stores to the GIC via the memory mapped interface
-	 * are now visible to the system register interface.
+	 * are now visible to the system register interface when reading the
+	 * LRs, and when reading back the VMCR on non-VHE systems.
 	 */
-	if (!cpu_if->vgic_sre) {
-		dsb(st);
-		cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2);
+	if (used_lrs || !has_vhe()) {
+		if (!cpu_if->vgic_sre)
+			dsb(st);
 	}
 
 	if (used_lrs) {
@@ -226,7 +226,7 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 
 		elrsr = read_gicreg(ICH_ELSR_EL2);
 
-		write_gicreg(0, ICH_HCR_EL2);
+		write_gicreg(cpu_if->vgic_hcr & ~ICH_HCR_EN, ICH_HCR_EL2);
 
 		for (i = 0; i < used_lrs; i++) {
 			if (elrsr & (1 << i))
@@ -236,19 +236,6 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 
 			__gic_v3_set_lr(0, i);
 		}
-	} else {
-		if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
-		    cpu_if->its_vpe.its_vm)
-			write_gicreg(0, ICH_HCR_EL2);
-	}
-
-	val = read_gicreg(ICC_SRE_EL2);
-	write_gicreg(val | ICC_SRE_EL2_ENABLE, ICC_SRE_EL2);
-
-	if (!cpu_if->vgic_sre) {
-		/* Make sure ENABLE is set at EL2 before setting SRE at EL1 */
-		isb();
-		write_gicreg(1, ICC_SRE_EL1);
 	}
 }
 
@@ -258,6 +245,31 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 	int i;
 
+	if (used_lrs) {
+		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
+
+		for (i = 0; i < used_lrs; i++)
+			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
+	}
+
+	/*
+	 * Ensure that writes to the LRs, and on non-VHE systems ensure that
+	 * the write to the VMCR in __vgic_v3_activate_traps(), will have
+	 * reached the (re)distributors. This ensure the guest will read the
+	 * correct values from the memory-mapped interface.
+	 */
+	if (used_lrs || !has_vhe()) {
+		if (!cpu_if->vgic_sre) {
+			isb();
+			dsb(sy);
+		}
+	}
+}
+
+void __hyp_text __vgic_v3_activate_traps(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+
 	/*
 	 * VFIQEn is RES1 if ICC_SRE_EL1.SRE is 1. This causes a
 	 * Group0 interrupt (as generated in GICv2 mode) to be
@@ -265,47 +277,69 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 	 * consequences. So we must make sure that ICC_SRE_EL1 has
 	 * been actually programmed with the value we want before
 	 * starting to mess with the rest of the GIC, and VMCR_EL2 in
-	 * particular.
+	 * particular.  This logic must be called before
+	 * __vgic_v3_restore_state().
 	 */
 	if (!cpu_if->vgic_sre) {
 		write_gicreg(0, ICC_SRE_EL1);
 		isb();
 		write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
-	}
 
-	if (used_lrs) {
-		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
 
-		for (i = 0; i < used_lrs; i++)
-			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
-	} else {
-		/*
-		 * If we need to trap system registers, we must write
-		 * ICH_HCR_EL2 anyway, even if no interrupts are being
-		 * injected. Same thing if GICv4 is used, as VLPI
-		 * delivery is gated by ICH_HCR_EL2.En.
-		 */
-		if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
-		    cpu_if->its_vpe.its_vm)
-			write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
+		if (has_vhe()) {
+			/*
+			 * Ensure that the write to the VMCR will have reached
+			 * the (re)distributors. This ensure the guest will
+			 * read the correct values from the memory-mapped
+			 * interface.
+			 */
+			isb();
+			dsb(sy);
+		}
 	}
 
 	/*
-	 * Ensures that the above will have reached the
-	 * (re)distributors. This ensure the guest will read the
-	 * correct values from the memory-mapped interface.
+	 * Prevent the guest from touching the GIC system registers if
+	 * SRE isn't enabled for GICv3 emulation.
 	 */
+	write_gicreg(read_gicreg(ICC_SRE_EL2) & ~ICC_SRE_EL2_ENABLE,
+		     ICC_SRE_EL2);
+
+	/*
+	 * If we need to trap system registers, we must write
+	 * ICH_HCR_EL2 anyway, even if no interrupts are being
+	 * injected,
+	 */
+	if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
+	    cpu_if->its_vpe.its_vm)
+		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
+}
+
+void __hyp_text __vgic_v3_deactivate_traps(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+	u64 val;
+
 	if (!cpu_if->vgic_sre) {
+		cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2);
+	}
+
+	val = read_gicreg(ICC_SRE_EL2);
+	write_gicreg(val | ICC_SRE_EL2_ENABLE, ICC_SRE_EL2);
+
+	if (!cpu_if->vgic_sre) {
+		/* Make sure ENABLE is set at EL2 before setting SRE at EL1 */
 		isb();
-		dsb(sy);
+		write_gicreg(1, ICC_SRE_EL1);
 	}
 
 	/*
-	 * Prevent the guest from touching the GIC system registers if
-	 * SRE isn't enabled for GICv3 emulation.
+	 * If we were trapping system registers, we enabled the VGIC even if
+	 * no interrupts were being injected, and we disable it again here.
 	 */
-	write_gicreg(read_gicreg(ICC_SRE_EL2) & ~ICC_SRE_EL2_ENABLE,
-		     ICC_SRE_EL2);
+	if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
+	    cpu_if->its_vpe.its_vm)
+		write_gicreg(0, ICH_HCR_EL2);
 }
 
 void __hyp_text __vgic_v3_save_aprs(struct kvm_vcpu *vcpu)
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 4bafcd1e6bb8..4200657694f0 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -590,6 +590,9 @@ void vgic_v3_load(struct kvm_vcpu *vcpu)
 		kvm_call_hyp(__vgic_v3_write_vmcr, cpu_if->vgic_vmcr);
 
 	kvm_call_hyp(__vgic_v3_restore_aprs, vcpu);
+
+	if (has_vhe())
+		__vgic_v3_activate_traps(vcpu);
 }
 
 void vgic_v3_put(struct kvm_vcpu *vcpu)
@@ -600,4 +603,7 @@ void vgic_v3_put(struct kvm_vcpu *vcpu)
 		cpu_if->vgic_vmcr = kvm_call_hyp(__vgic_v3_read_vmcr);
 
 	kvm_call_hyp(__vgic_v3_save_aprs, vcpu);
+
+	if (has_vhe())
+		__vgic_v3_deactivate_traps(vcpu);
 }
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index d0a19a8c196a..0d95d7b55567 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -763,14 +763,14 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 
-	vgic_save_state(vcpu);
-
 	WARN_ON(vgic_v4_sync_hwstate(vcpu));
 
 	/* An empty ap_list_head implies used_lrs == 0 */
 	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
 		return;
 
+	vgic_save_state(vcpu);
+
 	if (vgic_cpu->used_lrs)
 		vgic_fold_lr_state(vcpu);
 	vgic_prune_ap_list(vcpu);
@@ -799,7 +799,7 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 	 * this.
 	 */
 	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
-		goto out;
+		return;
 
 	DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
 
@@ -807,7 +807,6 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 	vgic_flush_lr_state(vcpu);
 	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
 
-out:
 	vgic_restore_state(vcpu);
 }
 
-- 
2.14.2

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

* [PATCH v4 40/40] KVM: arm/arm64: Avoid VGICv3 save/restore on VHE with no IRQs
@ 2018-02-15 21:03   ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-15 21:03 UTC (permalink / raw)
  To: linux-arm-kernel

We can finally get completely rid of any calls to the VGICv3
save/restore functions when the AP lists are empty on VHE systems.  This
requires carefully factoring out trap configuration from saving and
restoring state, and carefully choosing what to do on the VHE and
non-VHE path.

One of the challenges is that we cannot save/restore the VMCR lazily
because we can only write the VMCR when ICC_SRE_EL1.SRE is cleared when
emulating a GICv2-on-GICv3, since otherwise all Group-0 interrupts end
up being delivered as FIQ.

To solve this problem, and still provide fast performance in the fast
path of exiting a VM when no interrupts are pending (which also
optimized the latency for actually delivering virtual interrupts coming
from physical interrupts), we orchestrate a dance of only doing the
activate/deactivate traps in vgic load/put for VHE systems (which can
have ICC_SRE_EL1.SRE cleared when running in the host), and doing the
configuration on every round-trip on non-VHE systems.

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

Notes:
    Changes since v3:
     - Removed extra blank line

 arch/arm/include/asm/kvm_hyp.h   |   2 +
 arch/arm/kvm/hyp/switch.c        |   8 ++-
 arch/arm64/include/asm/kvm_hyp.h |   2 +
 arch/arm64/kvm/hyp/switch.c      |   8 ++-
 virt/kvm/arm/hyp/vgic-v3-sr.c    | 120 +++++++++++++++++++++++++--------------
 virt/kvm/arm/vgic/vgic-v3.c      |   6 ++
 virt/kvm/arm/vgic/vgic.c         |   7 +--
 7 files changed, 102 insertions(+), 51 deletions(-)

diff --git a/arch/arm/include/asm/kvm_hyp.h b/arch/arm/include/asm/kvm_hyp.h
index 530a3c1cfe6f..e93a0cac9add 100644
--- a/arch/arm/include/asm/kvm_hyp.h
+++ b/arch/arm/include/asm/kvm_hyp.h
@@ -110,6 +110,8 @@ void __sysreg_restore_state(struct kvm_cpu_context *ctxt);
 
 void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
 void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
+void __vgic_v3_activate_traps(struct kvm_vcpu *vcpu);
+void __vgic_v3_deactivate_traps(struct kvm_vcpu *vcpu);
 void __vgic_v3_save_aprs(struct kvm_vcpu *vcpu);
 void __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu);
 
diff --git a/arch/arm/kvm/hyp/switch.c b/arch/arm/kvm/hyp/switch.c
index 882b9b9e0077..acf1c37fa49c 100644
--- a/arch/arm/kvm/hyp/switch.c
+++ b/arch/arm/kvm/hyp/switch.c
@@ -90,14 +90,18 @@ static void __hyp_text __deactivate_vm(struct kvm_vcpu *vcpu)
 
 static void __hyp_text __vgic_save_state(struct kvm_vcpu *vcpu)
 {
-	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
 		__vgic_v3_save_state(vcpu);
+		__vgic_v3_deactivate_traps(vcpu);
+	}
 }
 
 static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
 {
-	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
+		__vgic_v3_activate_traps(vcpu);
 		__vgic_v3_restore_state(vcpu);
+	}
 }
 
 static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 6f3929b2fcf7..384c34397619 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -124,6 +124,8 @@ int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
 
 void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
 void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
+void __vgic_v3_activate_traps(struct kvm_vcpu *vcpu);
+void __vgic_v3_deactivate_traps(struct kvm_vcpu *vcpu);
 void __vgic_v3_save_aprs(struct kvm_vcpu *vcpu);
 void __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu);
 int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 466cfcdbcaf3..7d8a41e3c9ac 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -193,14 +193,18 @@ static void __hyp_text __deactivate_vm(struct kvm_vcpu *vcpu)
 
 static void __hyp_text __vgic_save_state(struct kvm_vcpu *vcpu)
 {
-	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
 		__vgic_v3_save_state(vcpu);
+		__vgic_v3_deactivate_traps(vcpu);
+	}
 }
 
 static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
 {
-	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
+		__vgic_v3_activate_traps(vcpu);
 		__vgic_v3_restore_state(vcpu);
+	}
 }
 
 static bool __hyp_text __true_value(void)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 437d7af08683..b13cbd41dbc3 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -209,15 +209,15 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
 	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
-	u64 val;
 
 	/*
 	 * Make sure stores to the GIC via the memory mapped interface
-	 * are now visible to the system register interface.
+	 * are now visible to the system register interface when reading the
+	 * LRs, and when reading back the VMCR on non-VHE systems.
 	 */
-	if (!cpu_if->vgic_sre) {
-		dsb(st);
-		cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2);
+	if (used_lrs || !has_vhe()) {
+		if (!cpu_if->vgic_sre)
+			dsb(st);
 	}
 
 	if (used_lrs) {
@@ -226,7 +226,7 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 
 		elrsr = read_gicreg(ICH_ELSR_EL2);
 
-		write_gicreg(0, ICH_HCR_EL2);
+		write_gicreg(cpu_if->vgic_hcr & ~ICH_HCR_EN, ICH_HCR_EL2);
 
 		for (i = 0; i < used_lrs; i++) {
 			if (elrsr & (1 << i))
@@ -236,19 +236,6 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 
 			__gic_v3_set_lr(0, i);
 		}
-	} else {
-		if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
-		    cpu_if->its_vpe.its_vm)
-			write_gicreg(0, ICH_HCR_EL2);
-	}
-
-	val = read_gicreg(ICC_SRE_EL2);
-	write_gicreg(val | ICC_SRE_EL2_ENABLE, ICC_SRE_EL2);
-
-	if (!cpu_if->vgic_sre) {
-		/* Make sure ENABLE is set at EL2 before setting SRE at EL1 */
-		isb();
-		write_gicreg(1, ICC_SRE_EL1);
 	}
 }
 
@@ -258,6 +245,31 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
 	int i;
 
+	if (used_lrs) {
+		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
+
+		for (i = 0; i < used_lrs; i++)
+			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
+	}
+
+	/*
+	 * Ensure that writes to the LRs, and on non-VHE systems ensure that
+	 * the write to the VMCR in __vgic_v3_activate_traps(), will have
+	 * reached the (re)distributors. This ensure the guest will read the
+	 * correct values from the memory-mapped interface.
+	 */
+	if (used_lrs || !has_vhe()) {
+		if (!cpu_if->vgic_sre) {
+			isb();
+			dsb(sy);
+		}
+	}
+}
+
+void __hyp_text __vgic_v3_activate_traps(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+
 	/*
 	 * VFIQEn is RES1 if ICC_SRE_EL1.SRE is 1. This causes a
 	 * Group0 interrupt (as generated in GICv2 mode) to be
@@ -265,47 +277,69 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 	 * consequences. So we must make sure that ICC_SRE_EL1 has
 	 * been actually programmed with the value we want before
 	 * starting to mess with the rest of the GIC, and VMCR_EL2 in
-	 * particular.
+	 * particular.  This logic must be called before
+	 * __vgic_v3_restore_state().
 	 */
 	if (!cpu_if->vgic_sre) {
 		write_gicreg(0, ICC_SRE_EL1);
 		isb();
 		write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
-	}
 
-	if (used_lrs) {
-		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
 
-		for (i = 0; i < used_lrs; i++)
-			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
-	} else {
-		/*
-		 * If we need to trap system registers, we must write
-		 * ICH_HCR_EL2 anyway, even if no interrupts are being
-		 * injected. Same thing if GICv4 is used, as VLPI
-		 * delivery is gated by ICH_HCR_EL2.En.
-		 */
-		if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
-		    cpu_if->its_vpe.its_vm)
-			write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
+		if (has_vhe()) {
+			/*
+			 * Ensure that the write to the VMCR will have reached
+			 * the (re)distributors. This ensure the guest will
+			 * read the correct values from the memory-mapped
+			 * interface.
+			 */
+			isb();
+			dsb(sy);
+		}
 	}
 
 	/*
-	 * Ensures that the above will have reached the
-	 * (re)distributors. This ensure the guest will read the
-	 * correct values from the memory-mapped interface.
+	 * Prevent the guest from touching the GIC system registers if
+	 * SRE isn't enabled for GICv3 emulation.
 	 */
+	write_gicreg(read_gicreg(ICC_SRE_EL2) & ~ICC_SRE_EL2_ENABLE,
+		     ICC_SRE_EL2);
+
+	/*
+	 * If we need to trap system registers, we must write
+	 * ICH_HCR_EL2 anyway, even if no interrupts are being
+	 * injected,
+	 */
+	if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
+	    cpu_if->its_vpe.its_vm)
+		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
+}
+
+void __hyp_text __vgic_v3_deactivate_traps(struct kvm_vcpu *vcpu)
+{
+	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+	u64 val;
+
 	if (!cpu_if->vgic_sre) {
+		cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2);
+	}
+
+	val = read_gicreg(ICC_SRE_EL2);
+	write_gicreg(val | ICC_SRE_EL2_ENABLE, ICC_SRE_EL2);
+
+	if (!cpu_if->vgic_sre) {
+		/* Make sure ENABLE is set at EL2 before setting SRE at EL1 */
 		isb();
-		dsb(sy);
+		write_gicreg(1, ICC_SRE_EL1);
 	}
 
 	/*
-	 * Prevent the guest from touching the GIC system registers if
-	 * SRE isn't enabled for GICv3 emulation.
+	 * If we were trapping system registers, we enabled the VGIC even if
+	 * no interrupts were being injected, and we disable it again here.
 	 */
-	write_gicreg(read_gicreg(ICC_SRE_EL2) & ~ICC_SRE_EL2_ENABLE,
-		     ICC_SRE_EL2);
+	if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
+	    cpu_if->its_vpe.its_vm)
+		write_gicreg(0, ICH_HCR_EL2);
 }
 
 void __hyp_text __vgic_v3_save_aprs(struct kvm_vcpu *vcpu)
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 4bafcd1e6bb8..4200657694f0 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -590,6 +590,9 @@ void vgic_v3_load(struct kvm_vcpu *vcpu)
 		kvm_call_hyp(__vgic_v3_write_vmcr, cpu_if->vgic_vmcr);
 
 	kvm_call_hyp(__vgic_v3_restore_aprs, vcpu);
+
+	if (has_vhe())
+		__vgic_v3_activate_traps(vcpu);
 }
 
 void vgic_v3_put(struct kvm_vcpu *vcpu)
@@ -600,4 +603,7 @@ void vgic_v3_put(struct kvm_vcpu *vcpu)
 		cpu_if->vgic_vmcr = kvm_call_hyp(__vgic_v3_read_vmcr);
 
 	kvm_call_hyp(__vgic_v3_save_aprs, vcpu);
+
+	if (has_vhe())
+		__vgic_v3_deactivate_traps(vcpu);
 }
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index d0a19a8c196a..0d95d7b55567 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -763,14 +763,14 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 
-	vgic_save_state(vcpu);
-
 	WARN_ON(vgic_v4_sync_hwstate(vcpu));
 
 	/* An empty ap_list_head implies used_lrs == 0 */
 	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
 		return;
 
+	vgic_save_state(vcpu);
+
 	if (vgic_cpu->used_lrs)
 		vgic_fold_lr_state(vcpu);
 	vgic_prune_ap_list(vcpu);
@@ -799,7 +799,7 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 	 * this.
 	 */
 	if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
-		goto out;
+		return;
 
 	DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
 
@@ -807,7 +807,6 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 	vgic_flush_lr_state(vcpu);
 	spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
 
-out:
 	vgic_restore_state(vcpu);
 }
 
-- 
2.14.2

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

* Re: [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
  2018-02-15 21:02   ` Christoffer Dall
@ 2018-02-19 15:50     ` Julien Grall
  -1 siblings, 0 replies; 276+ messages in thread
From: Julien Grall @ 2018-02-19 15:50 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: kvm, Ard Biesheuvel, Marc Zyngier, Yury Norov, Dave Martin, Shih-Wei Li

Hi Christoffer,

On 15/02/18 21:02, Christoffer Dall wrote:
> We already have the percpu area for the host cpu state, which points to
> the VCPU, so there's no need to store the VCPU pointer on the stack on
> every context switch.  We can be a little more clever and just use
> tpidr_el2 for the percpu offset and load the VCPU pointer from the host
> context.
> 
> This does require us to calculate the percpu offset without including
> the offset from the kernel mapping of the percpu array to the linear
> mapping of the array (which is what we store in tpidr_el1), because a
> PC-relative generated address in EL2 is already giving us the hyp alias
> of the linear mapping of a kernel address.  We do this in
> __cpu_init_hyp_mode() by using kvm_ksym_ref().
> 
> This change also requires us to have a scratch register, so we take the
> chance to rearrange some of the el1_sync code to only look at the
> vttbr_el2 to determine if this is a trap from the guest or an HVC from
> the host.  We do add an extra check to call the panic code if the kernel
> is configured with debugging enabled and we saw a trap from the host
> which wasn't an HVC, indicating that we left some EL2 trap configured by
> mistake.

You might want to remove this paragraph as you don't seem to have rework 
that part of the code in this version.

Cheers,

-- 
Julien Grall

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

* [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
@ 2018-02-19 15:50     ` Julien Grall
  0 siblings, 0 replies; 276+ messages in thread
From: Julien Grall @ 2018-02-19 15:50 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoffer,

On 15/02/18 21:02, Christoffer Dall wrote:
> We already have the percpu area for the host cpu state, which points to
> the VCPU, so there's no need to store the VCPU pointer on the stack on
> every context switch.  We can be a little more clever and just use
> tpidr_el2 for the percpu offset and load the VCPU pointer from the host
> context.
> 
> This does require us to calculate the percpu offset without including
> the offset from the kernel mapping of the percpu array to the linear
> mapping of the array (which is what we store in tpidr_el1), because a
> PC-relative generated address in EL2 is already giving us the hyp alias
> of the linear mapping of a kernel address.  We do this in
> __cpu_init_hyp_mode() by using kvm_ksym_ref().
> 
> This change also requires us to have a scratch register, so we take the
> chance to rearrange some of the el1_sync code to only look at the
> vttbr_el2 to determine if this is a trap from the guest or an HVC from
> the host.  We do add an extra check to call the panic code if the kernel
> is configured with debugging enabled and we saw a trap from the host
> which wasn't an HVC, indicating that we left some EL2 trap configured by
> mistake.

You might want to remove this paragraph as you don't seem to have rework 
that part of the code in this version.

Cheers,

-- 
Julien Grall

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

* Re: [PATCH v4 17/40] KVM: arm64: Move userspace system registers into separate function
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-19 17:21     ` Julien Grall
  -1 siblings, 0 replies; 276+ messages in thread
From: Julien Grall @ 2018-02-19 17:21 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: Andrew Jones, kvm, Marc Zyngier, Tomasz Nowicki, Yury Norov,
	Dave Martin, Shih-Wei Li

Hi Christoffer,

On 15/02/18 21:03, Christoffer Dall wrote:
> There's a semantic difference between the EL1 registers that control
> operation of a kernel running in EL1 and EL1 registers that only control
> userspace execution in EL0.  Since we can defer saving/restoring the
> latter, move them into their own function.
> 
> ACTLR_EL1 is not used by a VHE host, so we can move this register into
> the EL1 state which is not saved/restored for a VHE host.

Looking at D10.2.1 (ARM DDI 0487C.a), the statement regarding the use of 
ACTLR_EL1 seems to be less strong than what you state here. It looks 
like it would be possible to have hardware where ACTLR_EL1 would still 
have an effect on host EL0. I also read the comments on the version 2 of 
this patch but I wasn't able to find what I missing.

Cheers,

-- 
Julien Grall

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

* [PATCH v4 17/40] KVM: arm64: Move userspace system registers into separate function
@ 2018-02-19 17:21     ` Julien Grall
  0 siblings, 0 replies; 276+ messages in thread
From: Julien Grall @ 2018-02-19 17:21 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoffer,

On 15/02/18 21:03, Christoffer Dall wrote:
> There's a semantic difference between the EL1 registers that control
> operation of a kernel running in EL1 and EL1 registers that only control
> userspace execution in EL0.  Since we can defer saving/restoring the
> latter, move them into their own function.
> 
> ACTLR_EL1 is not used by a VHE host, so we can move this register into
> the EL1 state which is not saved/restored for a VHE host.

Looking at D10.2.1 (ARM DDI 0487C.a), the statement regarding the use of 
ACTLR_EL1 seems to be less strong than what you state here. It looks 
like it would be possible to have hardware where ACTLR_EL1 would still 
have an effect on host EL0. I also read the comments on the version 2 of 
this patch but I wasn't able to find what I missing.

Cheers,

-- 
Julien Grall

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

* Re: [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-19 18:12     ` Julien Grall
  -1 siblings, 0 replies; 276+ messages in thread
From: Julien Grall @ 2018-02-19 18:12 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: Christoffer Dall, Andrew Jones, kvm, Marc Zyngier,
	Tomasz Nowicki, Yury Norov, Dave Martin, Shih-Wei Li

Hi Christoffer,

On 15/02/18 21:03, Christoffer Dall wrote:
> From: Christoffer Dall <cdall@cs.columbia.edu>
> 
> Currently we access the system registers array via the vcpu_sys_reg()
> macro.  However, we are about to change the behavior to some times
> modify the register file directly, so let's change this to two
> primitives:
> 
>   * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
>   * Direct array access macro __vcpu_sys_reg()
> 
> The first primitive should be used in places where the code needs to
> access the currently loaded VCPU's state as observed by the guest.  For
> example, when trapping on cache related registers, a write to a system
> register should go directly to the VCPU version of the register.
> 
> The second primitive can be used in places where the VCPU is known to

"second primitive" is a bit confusing here. I count 3 primitives above: 
(vcpu_write_sys_reg(), vcpu_read_sys_reg() and __vcpu_sys_reg(). From 
the description, I would say to refer to the latter (i.e third one).

> never be running (for example userspace access) or for registers which
> are never context switched (for example all the PMU system registers).
> 
> This rewrites all users of vcpu_sys_regs to one of the two primitives
> above.
> 
> No functional change.
> 
> Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>

[...]

> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index f2a6f39aec87..68398bf7882f 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
>   };
>   
>   #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> -#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> +
> +/*
> + * Only use __vcpu_sys_reg if you know you want the memory backed version of a
> + * register, and not the one most recently accessed by a runnning VCPU.  For

NIT: s/runnning/running/

> + * example, for userpace access or for system registers that are never context

NIT: s/userpace/userspace/

> + * switched, but only emulated.
> + */
> +#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> +
> +#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> +#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> +
>   /*
>    * CP14 and CP15 live in the same array, as they are backed by the
>    * same system registers.

[...]

> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index b48af790615e..a05d2c01c786 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c

[...]

> @@ -817,10 +818,10 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>   			return false;
>   		}
>   
> -		vcpu_sys_reg(vcpu, PMUSERENR_EL0) = p->regval
> -						    & ARMV8_PMU_USERENR_MASK;
> -	} else {
> -		p->regval = vcpu_sys_reg(vcpu, PMUSERENR_EL0)
> +		__vcpu_sys_reg(vcpu, PMUSERENR_EL0) =
> +			       p->regval & ARMV8_PMU_USERENR_MASK;
> +	} else  {

NIT: There is a double space between else and {.

> +		p->regval = __vcpu_sys_reg(vcpu, PMUSERENR_EL0)
>   			    & ARMV8_PMU_USERENR_MASK;
>   	}
>   

Cheers,

-- 
Julien Grall

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

* [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
@ 2018-02-19 18:12     ` Julien Grall
  0 siblings, 0 replies; 276+ messages in thread
From: Julien Grall @ 2018-02-19 18:12 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoffer,

On 15/02/18 21:03, Christoffer Dall wrote:
> From: Christoffer Dall <cdall@cs.columbia.edu>
> 
> Currently we access the system registers array via the vcpu_sys_reg()
> macro.  However, we are about to change the behavior to some times
> modify the register file directly, so let's change this to two
> primitives:
> 
>   * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
>   * Direct array access macro __vcpu_sys_reg()
> 
> The first primitive should be used in places where the code needs to
> access the currently loaded VCPU's state as observed by the guest.  For
> example, when trapping on cache related registers, a write to a system
> register should go directly to the VCPU version of the register.
> 
> The second primitive can be used in places where the VCPU is known to

"second primitive" is a bit confusing here. I count 3 primitives above: 
(vcpu_write_sys_reg(), vcpu_read_sys_reg() and __vcpu_sys_reg(). From 
the description, I would say to refer to the latter (i.e third one).

> never be running (for example userspace access) or for registers which
> are never context switched (for example all the PMU system registers).
> 
> This rewrites all users of vcpu_sys_regs to one of the two primitives
> above.
> 
> No functional change.
> 
> Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>

[...]

> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index f2a6f39aec87..68398bf7882f 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
>   };
>   
>   #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> -#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> +
> +/*
> + * Only use __vcpu_sys_reg if you know you want the memory backed version of a
> + * register, and not the one most recently accessed by a runnning VCPU.  For

NIT: s/runnning/running/

> + * example, for userpace access or for system registers that are never context

NIT: s/userpace/userspace/

> + * switched, but only emulated.
> + */
> +#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> +
> +#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> +#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> +
>   /*
>    * CP14 and CP15 live in the same array, as they are backed by the
>    * same system registers.

[...]

> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index b48af790615e..a05d2c01c786 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c

[...]

> @@ -817,10 +818,10 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>   			return false;
>   		}
>   
> -		vcpu_sys_reg(vcpu, PMUSERENR_EL0) = p->regval
> -						    & ARMV8_PMU_USERENR_MASK;
> -	} else {
> -		p->regval = vcpu_sys_reg(vcpu, PMUSERENR_EL0)
> +		__vcpu_sys_reg(vcpu, PMUSERENR_EL0) =
> +			       p->regval & ARMV8_PMU_USERENR_MASK;
> +	} else  {

NIT: There is a double space between else and {.

> +		p->regval = __vcpu_sys_reg(vcpu, PMUSERENR_EL0)
>   			    & ARMV8_PMU_USERENR_MASK;
>   	}
>   

Cheers,

-- 
Julien Grall

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

* Re: [PATCH v4 01/40] KVM: arm/arm64: Avoid vcpu_load for other vcpu ioctls than KVM_RUN
  2018-02-15 21:02   ` Christoffer Dall
@ 2018-02-21  9:32     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21  9:32 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, kvmarm, Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, 15 Feb 2018 21:02:53 +0000,
Christoffer Dall wrote:
> 
> Calling vcpu_load() registers preempt notifiers for this vcpu and calls
> kvm_arch_vcpu_load().  The latter will soon be doing a lot of heavy
> lifting on arm/arm64 and will try to do things such as enabling the
> virtual timer and setting us up to handle interrupts from the timer
> hardware.
> 
> Loading state onto hardware registers and enabling hardware to signal
> interrupts can be problematic when we're not actually about to run the
> VCPU, because it makes it difficult to establish the right context when
> handling interrupts from the timer, and it makes the register access
> code difficult to reason about.
> 
> Luckily, now when we call vcpu_load in each ioctl implementation, we can
> simply remove the call from the non-KVM_RUN vcpu ioctls, and our
> kvm_arch_vcpu_load() is only used for loading vcpu content to the
> physical CPU when we're actually going to run the vcpu.
> 
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 01/40] KVM: arm/arm64: Avoid vcpu_load for other vcpu ioctls than KVM_RUN
@ 2018-02-21  9:32     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21  9:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 15 Feb 2018 21:02:53 +0000,
Christoffer Dall wrote:
> 
> Calling vcpu_load() registers preempt notifiers for this vcpu and calls
> kvm_arch_vcpu_load().  The latter will soon be doing a lot of heavy
> lifting on arm/arm64 and will try to do things such as enabling the
> virtual timer and setting us up to handle interrupts from the timer
> hardware.
> 
> Loading state onto hardware registers and enabling hardware to signal
> interrupts can be problematic when we're not actually about to run the
> VCPU, because it makes it difficult to establish the right context when
> handling interrupts from the timer, and it makes the register access
> code difficult to reason about.
> 
> Luckily, now when we call vcpu_load in each ioctl implementation, we can
> simply remove the call from the non-KVM_RUN vcpu ioctls, and our
> kvm_arch_vcpu_load() is only used for loading vcpu content to the
> physical CPU when we're actually going to run the vcpu.
> 
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 02/40] KVM: arm/arm64: Move vcpu_load call after kvm_vcpu_first_run_init
  2018-02-15 21:02   ` Christoffer Dall
@ 2018-02-21 11:05     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 11:05 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, 15 Feb 2018 21:02:54 +0000,
Christoffer Dall wrote:
> 
> Moving the call to vcpu_load() in kvm_arch_vcpu_ioctl_run() to after
> we've called kvm_vcpu_first_run_init() simplifies some of the vgic and
> there is also no need to do vcpu_load() for things such as handling the
> immediate_exit flag.
> 
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 02/40] KVM: arm/arm64: Move vcpu_load call after kvm_vcpu_first_run_init
@ 2018-02-21 11:05     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 11:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 15 Feb 2018 21:02:54 +0000,
Christoffer Dall wrote:
> 
> Moving the call to vcpu_load() in kvm_arch_vcpu_ioctl_run() to after
> we've called kvm_vcpu_first_run_init() simplifies some of the vgic and
> there is also no need to do vcpu_load() for things such as handling the
> immediate_exit flag.
> 
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
  2018-02-15 21:02   ` Christoffer Dall
@ 2018-02-21 11:34     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 11:34 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andrew Jones, kvm, Ard Biesheuvel, Tomasz Nowicki, kvmarm,
	Julien Grall, Yury Norov, linux-arm-kernel, Dave Martin,
	Shih-Wei Li

On Thu, 15 Feb 2018 21:02:55 +0000,
Christoffer Dall wrote:
> 
> We already have the percpu area for the host cpu state, which points to
> the VCPU, so there's no need to store the VCPU pointer on the stack on
> every context switch.  We can be a little more clever and just use
> tpidr_el2 for the percpu offset and load the VCPU pointer from the host
> context.
> 
> This does require us to calculate the percpu offset without including
> the offset from the kernel mapping of the percpu array to the linear
> mapping of the array (which is what we store in tpidr_el1), because a
> PC-relative generated address in EL2 is already giving us the hyp alias
> of the linear mapping of a kernel address.  We do this in
> __cpu_init_hyp_mode() by using kvm_ksym_ref().
> 
> This change also requires us to have a scratch register, so we take the
> chance to rearrange some of the el1_sync code to only look at the
> vttbr_el2 to determine if this is a trap from the guest or an HVC from
> the host.  We do add an extra check to call the panic code if the kernel
> is configured with debugging enabled and we saw a trap from the host
> which wasn't an HVC, indicating that we left some EL2 trap configured by
> mistake.
> 
> The code that accesses ESR_EL2 was previously using an alternative to
> use the _EL1 accessor on VHE systems, but this was actually unnecessary
> as the _EL1 accessor aliases the ESR_EL2 register on VHE, and the _EL2
> accessor does the same thing on both systems.
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Reworked the assembly part of the patch after rebasing on v4.16-rc1
>        which created a conflict with the variant 2 mitigations.
>      - Removed Marc's reviewed-by due to the rework.
>      - Removed unneeded extern keyword in declaration in header file
>     
>     Changes since v1:
>      - Use PC-relative addressing to access per-cpu variables instead of
>        using a load from the literal pool.
>      - Remove stale comments as pointed out by Marc
>      - Reworded the commit message as suggested by Drew
> 
>  arch/arm64/include/asm/kvm_asm.h  | 14 ++++++++++++++
>  arch/arm64/include/asm/kvm_host.h | 15 +++++++++++++++
>  arch/arm64/kernel/asm-offsets.c   |  1 +
>  arch/arm64/kvm/hyp/entry.S        |  6 +-----
>  arch/arm64/kvm/hyp/hyp-entry.S    | 31 +++++++++++++------------------
>  arch/arm64/kvm/hyp/switch.c       |  5 +----
>  arch/arm64/kvm/hyp/sysreg-sr.c    |  5 +++++
>  7 files changed, 50 insertions(+), 27 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> index 24961b732e65..6b626750b0a1 100644
> --- a/arch/arm64/include/asm/kvm_asm.h
> +++ b/arch/arm64/include/asm/kvm_asm.h
> @@ -33,6 +33,7 @@
>  #define KVM_ARM64_DEBUG_DIRTY_SHIFT	0
>  #define KVM_ARM64_DEBUG_DIRTY		(1 << KVM_ARM64_DEBUG_DIRTY_SHIFT)
>  
> +/* Translate a kernel address of @sym into its equivalent linear mapping */
>  #define kvm_ksym_ref(sym)						\
>  	({								\
>  		void *val = &sym;					\
> @@ -70,6 +71,19 @@ extern u32 __init_stage2_translation(void);
>  
>  extern void __qcom_hyp_sanitize_btac_predictors(void);
>  
> +#else /* __ASSEMBLY__ */
> +
> +.macro get_host_ctxt reg, tmp
> +	adr_l	\reg, kvm_host_cpu_state
> +	mrs	\tmp, tpidr_el2
> +	add	\reg, \reg, \tmp
> +.endm
> +
> +.macro get_vcpu vcpu, ctxt
> +	ldr	\vcpu, [\ctxt, #HOST_CONTEXT_VCPU]
> +	kern_hyp_va	\vcpu
> +.endm
> +
>  #endif
>  
>  #endif /* __ARM_KVM_ASM_H__ */
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 596f8e414a4c..618cfee7206a 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -358,10 +358,15 @@ int kvm_perf_teardown(void);
>  
>  struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
>  
> +void __kvm_set_tpidr_el2(u64 tpidr_el2);
> +DECLARE_PER_CPU(kvm_cpu_context_t, kvm_host_cpu_state);
> +
>  static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
>  				       unsigned long hyp_stack_ptr,
>  				       unsigned long vector_ptr)
>  {
> +	u64 tpidr_el2;
> +
>  	/*
>  	 * Call initialization code, and switch to the full blown HYP code.
>  	 * If the cpucaps haven't been finalized yet, something has gone very
> @@ -370,6 +375,16 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
>  	 */
>  	BUG_ON(!static_branch_likely(&arm64_const_caps_ready));
>  	__kvm_call_hyp((void *)pgd_ptr, hyp_stack_ptr, vector_ptr);
> +
> +	/*
> +	 * Calculate the raw per-cpu offset without a translation from the
> +	 * kernel's mapping to the linear mapping, and store it in tpidr_el2
> +	 * so that we can use adr_l to access per-cpu variables in EL2.
> +	 */
> +	tpidr_el2 = (u64)this_cpu_ptr(&kvm_host_cpu_state)
> +		- (u64)kvm_ksym_ref(kvm_host_cpu_state);
> +
> +	kvm_call_hyp(__kvm_set_tpidr_el2, tpidr_el2);
>  }
>  
>  static inline void kvm_arch_hardware_unsetup(void) {}
> diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
> index 1303e04110cd..78e1b0a70aaf 100644
> --- a/arch/arm64/kernel/asm-offsets.c
> +++ b/arch/arm64/kernel/asm-offsets.c
> @@ -138,6 +138,7 @@ int main(void)
>    DEFINE(CPU_FP_REGS,		offsetof(struct kvm_regs, fp_regs));
>    DEFINE(VCPU_FPEXC32_EL2,	offsetof(struct kvm_vcpu, arch.ctxt.sys_regs[FPEXC32_EL2]));
>    DEFINE(VCPU_HOST_CONTEXT,	offsetof(struct kvm_vcpu, arch.host_cpu_context));
> +  DEFINE(HOST_CONTEXT_VCPU,	offsetof(struct kvm_cpu_context, __hyp_running_vcpu));
>  #endif
>  #ifdef CONFIG_CPU_PM
>    DEFINE(CPU_SUSPEND_SZ,	sizeof(struct cpu_suspend_ctx));
> diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
> index fdd1068ee3a5..1f458f7c3b44 100644
> --- a/arch/arm64/kvm/hyp/entry.S
> +++ b/arch/arm64/kvm/hyp/entry.S
> @@ -62,9 +62,6 @@ ENTRY(__guest_enter)
>  	// Store the host regs
>  	save_callee_saved_regs x1
>  
> -	// Store host_ctxt and vcpu for use at exit time
> -	stp	x1, x0, [sp, #-16]!
> -
>  	add	x18, x0, #VCPU_CONTEXT
>  
>  	// Restore guest regs x0-x17
> @@ -118,8 +115,7 @@ ENTRY(__guest_exit)
>  	// Store the guest regs x19-x29, lr
>  	save_callee_saved_regs x1
>  
> -	// Restore the host_ctxt from the stack
> -	ldr	x2, [sp], #16
> +	get_host_ctxt	x2, x3
>  
>  	// Now restore the host regs
>  	restore_callee_saved_regs x2
> diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
> index f36464bd57c5..559b4d54bc42 100644
> --- a/arch/arm64/kvm/hyp/hyp-entry.S
> +++ b/arch/arm64/kvm/hyp/hyp-entry.S
> @@ -57,13 +57,8 @@ ENDPROC(__vhe_hyp_call)
>  el1_sync:				// Guest trapped into EL2
>  	stp	x0, x1, [sp, #-16]!
>  
> -alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
> -	mrs	x1, esr_el2
> -alternative_else
> -	mrs	x1, esr_el1
> -alternative_endif
> -	lsr	x0, x1, #ESR_ELx_EC_SHIFT
> -
> +	mrs	x0, esr_el2
> +	lsr	x0, x0, #ESR_ELx_EC_SHIFT
>  	cmp	x0, #ESR_ELx_EC_HVC64
>  	ccmp	x0, #ESR_ELx_EC_HVC32, #4, ne
>  	b.ne	el1_trap
> @@ -117,10 +112,15 @@ el1_hvc_guest:
>  	eret
>  
>  el1_trap:
> +	get_host_ctxt	x0, x1
> +	get_vcpu	x1, x0
> +
> +	mrs		x0, esr_el2
> +	lsr		x0, x0, #ESR_ELx_EC_SHIFT
>  	/*
>  	 * x0: ESR_EC
> +	 * x1: vcpu pointer
>  	 */
> -	ldr	x1, [sp, #16 + 8]	// vcpu stored by __guest_enter
>  
>  	/*
>  	 * We trap the first access to the FP/SIMD to save the host context
> @@ -138,13 +138,15 @@ alternative_else_nop_endif
>  
>  el1_irq:
>  	stp     x0, x1, [sp, #-16]!
> -	ldr	x1, [sp, #16 + 8]
> +	get_host_ctxt	x0, x1
> +	get_vcpu	x1, x0
>  	mov	x0, #ARM_EXCEPTION_IRQ
>  	b	__guest_exit
>  
>  el1_error:
>  	stp     x0, x1, [sp, #-16]!
> -	ldr	x1, [sp, #16 + 8]
> +	get_host_ctxt	x0, x1
> +	get_vcpu	x1, x0

Given how frequent this construct is, would there be a benefit in
having something like "get_vcpu_ptr" that conflates the two macros? We
don't seem to have a single case of using get_vcpu on its own.

>  	mov	x0, #ARM_EXCEPTION_EL1_SERROR
>  	b	__guest_exit
>  
> @@ -180,14 +182,7 @@ ENTRY(__hyp_do_panic)
>  ENDPROC(__hyp_do_panic)
>  
>  ENTRY(__hyp_panic)
> -	/*
> -	 * '=kvm_host_cpu_state' is a host VA from the constant pool, it may
> -	 * not be accessible by this address from EL2, hyp_panic() converts
> -	 * it with kern_hyp_va() before use.
> -	 */
> -	ldr	x0, =kvm_host_cpu_state
> -	mrs	x1, tpidr_el2
> -	add	x0, x0, x1
> +	get_host_ctxt x0, x1
>  	b	hyp_panic
>  ENDPROC(__hyp_panic)
>  
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index b991f85c1133..d1749fa0bfc3 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -467,7 +467,7 @@ static hyp_alternate_select(__hyp_call_panic,
>  			    __hyp_call_panic_nvhe, __hyp_call_panic_vhe,
>  			    ARM64_HAS_VIRT_HOST_EXTN);
>  
> -void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt)
> +void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *host_ctxt)
>  {
>  	struct kvm_vcpu *vcpu = NULL;
>  
> @@ -476,9 +476,6 @@ void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt)
>  	u64 par = read_sysreg(par_el1);
>  
>  	if (read_sysreg(vttbr_el2)) {
> -		struct kvm_cpu_context *host_ctxt;
> -
> -		host_ctxt = kern_hyp_va(__host_ctxt);
>  		vcpu = host_ctxt->__hyp_running_vcpu;
>  		__timer_disable_traps(vcpu);
>  		__deactivate_traps(vcpu);
> diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> index 2c17afd2be96..43b7dd65e3e6 100644
> --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> @@ -189,3 +189,8 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
>  	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
>  		write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
>  }
> +
> +void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2)
> +{
> +	asm("msr tpidr_el2, %0": : "r" (tpidr_el2));

The paranoid in me says that we'd want an ISB here if we can possibly
use tpidr_el2 on this path. If we had to manic, for example...

> +}
> -- 
> 2.14.2
> 

The above notwithstanding,

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
@ 2018-02-21 11:34     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 11:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 15 Feb 2018 21:02:55 +0000,
Christoffer Dall wrote:
> 
> We already have the percpu area for the host cpu state, which points to
> the VCPU, so there's no need to store the VCPU pointer on the stack on
> every context switch.  We can be a little more clever and just use
> tpidr_el2 for the percpu offset and load the VCPU pointer from the host
> context.
> 
> This does require us to calculate the percpu offset without including
> the offset from the kernel mapping of the percpu array to the linear
> mapping of the array (which is what we store in tpidr_el1), because a
> PC-relative generated address in EL2 is already giving us the hyp alias
> of the linear mapping of a kernel address.  We do this in
> __cpu_init_hyp_mode() by using kvm_ksym_ref().
> 
> This change also requires us to have a scratch register, so we take the
> chance to rearrange some of the el1_sync code to only look at the
> vttbr_el2 to determine if this is a trap from the guest or an HVC from
> the host.  We do add an extra check to call the panic code if the kernel
> is configured with debugging enabled and we saw a trap from the host
> which wasn't an HVC, indicating that we left some EL2 trap configured by
> mistake.
> 
> The code that accesses ESR_EL2 was previously using an alternative to
> use the _EL1 accessor on VHE systems, but this was actually unnecessary
> as the _EL1 accessor aliases the ESR_EL2 register on VHE, and the _EL2
> accessor does the same thing on both systems.
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Reworked the assembly part of the patch after rebasing on v4.16-rc1
>        which created a conflict with the variant 2 mitigations.
>      - Removed Marc's reviewed-by due to the rework.
>      - Removed unneeded extern keyword in declaration in header file
>     
>     Changes since v1:
>      - Use PC-relative addressing to access per-cpu variables instead of
>        using a load from the literal pool.
>      - Remove stale comments as pointed out by Marc
>      - Reworded the commit message as suggested by Drew
> 
>  arch/arm64/include/asm/kvm_asm.h  | 14 ++++++++++++++
>  arch/arm64/include/asm/kvm_host.h | 15 +++++++++++++++
>  arch/arm64/kernel/asm-offsets.c   |  1 +
>  arch/arm64/kvm/hyp/entry.S        |  6 +-----
>  arch/arm64/kvm/hyp/hyp-entry.S    | 31 +++++++++++++------------------
>  arch/arm64/kvm/hyp/switch.c       |  5 +----
>  arch/arm64/kvm/hyp/sysreg-sr.c    |  5 +++++
>  7 files changed, 50 insertions(+), 27 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> index 24961b732e65..6b626750b0a1 100644
> --- a/arch/arm64/include/asm/kvm_asm.h
> +++ b/arch/arm64/include/asm/kvm_asm.h
> @@ -33,6 +33,7 @@
>  #define KVM_ARM64_DEBUG_DIRTY_SHIFT	0
>  #define KVM_ARM64_DEBUG_DIRTY		(1 << KVM_ARM64_DEBUG_DIRTY_SHIFT)
>  
> +/* Translate a kernel address of @sym into its equivalent linear mapping */
>  #define kvm_ksym_ref(sym)						\
>  	({								\
>  		void *val = &sym;					\
> @@ -70,6 +71,19 @@ extern u32 __init_stage2_translation(void);
>  
>  extern void __qcom_hyp_sanitize_btac_predictors(void);
>  
> +#else /* __ASSEMBLY__ */
> +
> +.macro get_host_ctxt reg, tmp
> +	adr_l	\reg, kvm_host_cpu_state
> +	mrs	\tmp, tpidr_el2
> +	add	\reg, \reg, \tmp
> +.endm
> +
> +.macro get_vcpu vcpu, ctxt
> +	ldr	\vcpu, [\ctxt, #HOST_CONTEXT_VCPU]
> +	kern_hyp_va	\vcpu
> +.endm
> +
>  #endif
>  
>  #endif /* __ARM_KVM_ASM_H__ */
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 596f8e414a4c..618cfee7206a 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -358,10 +358,15 @@ int kvm_perf_teardown(void);
>  
>  struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
>  
> +void __kvm_set_tpidr_el2(u64 tpidr_el2);
> +DECLARE_PER_CPU(kvm_cpu_context_t, kvm_host_cpu_state);
> +
>  static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
>  				       unsigned long hyp_stack_ptr,
>  				       unsigned long vector_ptr)
>  {
> +	u64 tpidr_el2;
> +
>  	/*
>  	 * Call initialization code, and switch to the full blown HYP code.
>  	 * If the cpucaps haven't been finalized yet, something has gone very
> @@ -370,6 +375,16 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
>  	 */
>  	BUG_ON(!static_branch_likely(&arm64_const_caps_ready));
>  	__kvm_call_hyp((void *)pgd_ptr, hyp_stack_ptr, vector_ptr);
> +
> +	/*
> +	 * Calculate the raw per-cpu offset without a translation from the
> +	 * kernel's mapping to the linear mapping, and store it in tpidr_el2
> +	 * so that we can use adr_l to access per-cpu variables in EL2.
> +	 */
> +	tpidr_el2 = (u64)this_cpu_ptr(&kvm_host_cpu_state)
> +		- (u64)kvm_ksym_ref(kvm_host_cpu_state);
> +
> +	kvm_call_hyp(__kvm_set_tpidr_el2, tpidr_el2);
>  }
>  
>  static inline void kvm_arch_hardware_unsetup(void) {}
> diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
> index 1303e04110cd..78e1b0a70aaf 100644
> --- a/arch/arm64/kernel/asm-offsets.c
> +++ b/arch/arm64/kernel/asm-offsets.c
> @@ -138,6 +138,7 @@ int main(void)
>    DEFINE(CPU_FP_REGS,		offsetof(struct kvm_regs, fp_regs));
>    DEFINE(VCPU_FPEXC32_EL2,	offsetof(struct kvm_vcpu, arch.ctxt.sys_regs[FPEXC32_EL2]));
>    DEFINE(VCPU_HOST_CONTEXT,	offsetof(struct kvm_vcpu, arch.host_cpu_context));
> +  DEFINE(HOST_CONTEXT_VCPU,	offsetof(struct kvm_cpu_context, __hyp_running_vcpu));
>  #endif
>  #ifdef CONFIG_CPU_PM
>    DEFINE(CPU_SUSPEND_SZ,	sizeof(struct cpu_suspend_ctx));
> diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
> index fdd1068ee3a5..1f458f7c3b44 100644
> --- a/arch/arm64/kvm/hyp/entry.S
> +++ b/arch/arm64/kvm/hyp/entry.S
> @@ -62,9 +62,6 @@ ENTRY(__guest_enter)
>  	// Store the host regs
>  	save_callee_saved_regs x1
>  
> -	// Store host_ctxt and vcpu for use at exit time
> -	stp	x1, x0, [sp, #-16]!
> -
>  	add	x18, x0, #VCPU_CONTEXT
>  
>  	// Restore guest regs x0-x17
> @@ -118,8 +115,7 @@ ENTRY(__guest_exit)
>  	// Store the guest regs x19-x29, lr
>  	save_callee_saved_regs x1
>  
> -	// Restore the host_ctxt from the stack
> -	ldr	x2, [sp], #16
> +	get_host_ctxt	x2, x3
>  
>  	// Now restore the host regs
>  	restore_callee_saved_regs x2
> diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
> index f36464bd57c5..559b4d54bc42 100644
> --- a/arch/arm64/kvm/hyp/hyp-entry.S
> +++ b/arch/arm64/kvm/hyp/hyp-entry.S
> @@ -57,13 +57,8 @@ ENDPROC(__vhe_hyp_call)
>  el1_sync:				// Guest trapped into EL2
>  	stp	x0, x1, [sp, #-16]!
>  
> -alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
> -	mrs	x1, esr_el2
> -alternative_else
> -	mrs	x1, esr_el1
> -alternative_endif
> -	lsr	x0, x1, #ESR_ELx_EC_SHIFT
> -
> +	mrs	x0, esr_el2
> +	lsr	x0, x0, #ESR_ELx_EC_SHIFT
>  	cmp	x0, #ESR_ELx_EC_HVC64
>  	ccmp	x0, #ESR_ELx_EC_HVC32, #4, ne
>  	b.ne	el1_trap
> @@ -117,10 +112,15 @@ el1_hvc_guest:
>  	eret
>  
>  el1_trap:
> +	get_host_ctxt	x0, x1
> +	get_vcpu	x1, x0
> +
> +	mrs		x0, esr_el2
> +	lsr		x0, x0, #ESR_ELx_EC_SHIFT
>  	/*
>  	 * x0: ESR_EC
> +	 * x1: vcpu pointer
>  	 */
> -	ldr	x1, [sp, #16 + 8]	// vcpu stored by __guest_enter
>  
>  	/*
>  	 * We trap the first access to the FP/SIMD to save the host context
> @@ -138,13 +138,15 @@ alternative_else_nop_endif
>  
>  el1_irq:
>  	stp     x0, x1, [sp, #-16]!
> -	ldr	x1, [sp, #16 + 8]
> +	get_host_ctxt	x0, x1
> +	get_vcpu	x1, x0
>  	mov	x0, #ARM_EXCEPTION_IRQ
>  	b	__guest_exit
>  
>  el1_error:
>  	stp     x0, x1, [sp, #-16]!
> -	ldr	x1, [sp, #16 + 8]
> +	get_host_ctxt	x0, x1
> +	get_vcpu	x1, x0

Given how frequent this construct is, would there be a benefit in
having something like "get_vcpu_ptr" that conflates the two macros? We
don't seem to have a single case of using get_vcpu on its own.

>  	mov	x0, #ARM_EXCEPTION_EL1_SERROR
>  	b	__guest_exit
>  
> @@ -180,14 +182,7 @@ ENTRY(__hyp_do_panic)
>  ENDPROC(__hyp_do_panic)
>  
>  ENTRY(__hyp_panic)
> -	/*
> -	 * '=kvm_host_cpu_state' is a host VA from the constant pool, it may
> -	 * not be accessible by this address from EL2, hyp_panic() converts
> -	 * it with kern_hyp_va() before use.
> -	 */
> -	ldr	x0, =kvm_host_cpu_state
> -	mrs	x1, tpidr_el2
> -	add	x0, x0, x1
> +	get_host_ctxt x0, x1
>  	b	hyp_panic
>  ENDPROC(__hyp_panic)
>  
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index b991f85c1133..d1749fa0bfc3 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -467,7 +467,7 @@ static hyp_alternate_select(__hyp_call_panic,
>  			    __hyp_call_panic_nvhe, __hyp_call_panic_vhe,
>  			    ARM64_HAS_VIRT_HOST_EXTN);
>  
> -void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt)
> +void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *host_ctxt)
>  {
>  	struct kvm_vcpu *vcpu = NULL;
>  
> @@ -476,9 +476,6 @@ void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt)
>  	u64 par = read_sysreg(par_el1);
>  
>  	if (read_sysreg(vttbr_el2)) {
> -		struct kvm_cpu_context *host_ctxt;
> -
> -		host_ctxt = kern_hyp_va(__host_ctxt);
>  		vcpu = host_ctxt->__hyp_running_vcpu;
>  		__timer_disable_traps(vcpu);
>  		__deactivate_traps(vcpu);
> diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> index 2c17afd2be96..43b7dd65e3e6 100644
> --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> @@ -189,3 +189,8 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
>  	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
>  		write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
>  }
> +
> +void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2)
> +{
> +	asm("msr tpidr_el2, %0": : "r" (tpidr_el2));

The paranoid in me says that we'd want an ISB here if we can possibly
use tpidr_el2 on this path. If we had to manic, for example...

> +}
> -- 
> 2.14.2
> 

The above notwithstanding,

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 08/40] KVM: arm/arm64: Introduce vcpu_el1_is_32bit
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 12:05     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 12:05 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, 15 Feb 2018 21:03:00 +0000,
Christoffer Dall wrote:
> 
> We have numerous checks around that checks if the HCR_EL2 has the RW bit
> set to figure out if we're running an AArch64 or AArch32 VM.  In some
> cases, directly checking the RW bit (given its unintuitive name), is a
> bit confusing, and that's not going to improve as we move logic around
> for the following patches that optimize KVM on AArch64 hosts with VHE.
> 
> Therefore, introduce a helper, vcpu_el1_is_32bit, and replace existing
> direct checks of HCR_EL2.RW with the helper.
> 
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v2:
>      - New patch
>     
>     Changes since v1:
>      - Reworded comments as suggested by Drew
> 
>  arch/arm64/include/asm/kvm_emulate.h |  7 ++++++-
>  arch/arm64/kvm/hyp/switch.c          | 11 +++++------
>  arch/arm64/kvm/hyp/sysreg-sr.c       |  5 +++--
>  arch/arm64/kvm/inject_fault.c        |  6 +++---
>  4 files changed, 17 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 9ee316b962c8..3cc535591bdf 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -45,6 +45,11 @@ void kvm_inject_undef32(struct kvm_vcpu *vcpu);
>  void kvm_inject_dabt32(struct kvm_vcpu *vcpu, unsigned long addr);
>  void kvm_inject_pabt32(struct kvm_vcpu *vcpu, unsigned long addr);
>  
> +static inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
> +{
> +	return !(vcpu->arch.hcr_el2 & HCR_RW);
> +}
> +
>  static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
>  {
>  	vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
> @@ -65,7 +70,7 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
>  	 * For now this is conditional, since no AArch32 feature regs
>  	 * are currently virtualised.
>  	 */
> -	if (vcpu->arch.hcr_el2 & HCR_RW)
> +	if (!vcpu_el1_is_32bit(vcpu))
>  		vcpu->arch.hcr_el2 |= HCR_TID3;
>  }
>  
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index b51638490d85..fbab9752a9f4 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -74,7 +74,7 @@ static hyp_alternate_select(__activate_traps_arch,
>  
>  static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
>  {
> -	u64 val;
> +	u64 hcr = vcpu->arch.hcr_el2;
>  
>  	/*
>  	 * We are about to set CPTR_EL2.TFP to trap all floating point
> @@ -85,17 +85,16 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
>  	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
>  	 * it will cause an exception.
>  	 */
> -	val = vcpu->arch.hcr_el2;
> -
> -	if (!(val & HCR_RW) && system_supports_fpsimd()) {
> +	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
>  		write_sysreg(1 << 30, fpexc32_el2);
>  		isb();
>  	}
> -	write_sysreg(val, hcr_el2);
>  
> -	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (val & HCR_VSE))
> +	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
>  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
>  
> +	write_sysreg(hcr, hcr_el2);
> +
>  	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
>  	write_sysreg(1 << 15, hstr_el2);
>  	/*
> diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> index 434f0fc9cfb3..99fc60516103 100644
> --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> @@ -19,6 +19,7 @@
>  #include <linux/kvm_host.h>
>  
>  #include <asm/kvm_asm.h>
> +#include <asm/kvm_emulate.h>
>  #include <asm/kvm_hyp.h>
>  
>  /* Yes, this does nothing, on purpose */
> @@ -147,7 +148,7 @@ void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
>  {
>  	u64 *spsr, *sysreg;
>  
> -	if (read_sysreg(hcr_el2) & HCR_RW)
> +	if (!vcpu_el1_is_32bit(vcpu))
>  		return;
>  
>  	spsr = vcpu->arch.ctxt.gp_regs.spsr;
> @@ -172,7 +173,7 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
>  {
>  	u64 *spsr, *sysreg;
>  
> -	if (read_sysreg(hcr_el2) & HCR_RW)
> +	if (!vcpu_el1_is_32bit(vcpu))
>  		return;
>  
>  	spsr = vcpu->arch.ctxt.gp_regs.spsr;
> diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> index c1e179d34e6a..30a3f58cdb7b 100644
> --- a/arch/arm64/kvm/inject_fault.c
> +++ b/arch/arm64/kvm/inject_fault.c
> @@ -128,7 +128,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
>   */
>  void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
>  {
> -	if (!(vcpu->arch.hcr_el2 & HCR_RW))
> +	if (vcpu_el1_is_32bit(vcpu))
>  		kvm_inject_dabt32(vcpu, addr);
>  	else
>  		inject_abt64(vcpu, false, addr);
> @@ -144,7 +144,7 @@ void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
>   */
>  void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
>  {
> -	if (!(vcpu->arch.hcr_el2 & HCR_RW))
> +	if (vcpu_el1_is_32bit(vcpu))
>  		kvm_inject_pabt32(vcpu, addr);
>  	else
>  		inject_abt64(vcpu, true, addr);
> @@ -158,7 +158,7 @@ void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
>   */
>  void kvm_inject_undefined(struct kvm_vcpu *vcpu)
>  {
> -	if (!(vcpu->arch.hcr_el2 & HCR_RW))
> +	if (vcpu_el1_is_32bit(vcpu))
>  		kvm_inject_undef32(vcpu);
>  	else
>  		inject_undef64(vcpu);
> -- 
> 2.14.2
> 

nit: not strictly necessary, but would it be worth adding a similar
(and trivial) version of this predicate to the 32bit code? Just to
keep things in sync?

Otherwise,

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 08/40] KVM: arm/arm64: Introduce vcpu_el1_is_32bit
@ 2018-02-21 12:05     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 12:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 15 Feb 2018 21:03:00 +0000,
Christoffer Dall wrote:
> 
> We have numerous checks around that checks if the HCR_EL2 has the RW bit
> set to figure out if we're running an AArch64 or AArch32 VM.  In some
> cases, directly checking the RW bit (given its unintuitive name), is a
> bit confusing, and that's not going to improve as we move logic around
> for the following patches that optimize KVM on AArch64 hosts with VHE.
> 
> Therefore, introduce a helper, vcpu_el1_is_32bit, and replace existing
> direct checks of HCR_EL2.RW with the helper.
> 
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v2:
>      - New patch
>     
>     Changes since v1:
>      - Reworded comments as suggested by Drew
> 
>  arch/arm64/include/asm/kvm_emulate.h |  7 ++++++-
>  arch/arm64/kvm/hyp/switch.c          | 11 +++++------
>  arch/arm64/kvm/hyp/sysreg-sr.c       |  5 +++--
>  arch/arm64/kvm/inject_fault.c        |  6 +++---
>  4 files changed, 17 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 9ee316b962c8..3cc535591bdf 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -45,6 +45,11 @@ void kvm_inject_undef32(struct kvm_vcpu *vcpu);
>  void kvm_inject_dabt32(struct kvm_vcpu *vcpu, unsigned long addr);
>  void kvm_inject_pabt32(struct kvm_vcpu *vcpu, unsigned long addr);
>  
> +static inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
> +{
> +	return !(vcpu->arch.hcr_el2 & HCR_RW);
> +}
> +
>  static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
>  {
>  	vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
> @@ -65,7 +70,7 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
>  	 * For now this is conditional, since no AArch32 feature regs
>  	 * are currently virtualised.
>  	 */
> -	if (vcpu->arch.hcr_el2 & HCR_RW)
> +	if (!vcpu_el1_is_32bit(vcpu))
>  		vcpu->arch.hcr_el2 |= HCR_TID3;
>  }
>  
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index b51638490d85..fbab9752a9f4 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -74,7 +74,7 @@ static hyp_alternate_select(__activate_traps_arch,
>  
>  static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
>  {
> -	u64 val;
> +	u64 hcr = vcpu->arch.hcr_el2;
>  
>  	/*
>  	 * We are about to set CPTR_EL2.TFP to trap all floating point
> @@ -85,17 +85,16 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
>  	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
>  	 * it will cause an exception.
>  	 */
> -	val = vcpu->arch.hcr_el2;
> -
> -	if (!(val & HCR_RW) && system_supports_fpsimd()) {
> +	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
>  		write_sysreg(1 << 30, fpexc32_el2);
>  		isb();
>  	}
> -	write_sysreg(val, hcr_el2);
>  
> -	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (val & HCR_VSE))
> +	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
>  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
>  
> +	write_sysreg(hcr, hcr_el2);
> +
>  	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
>  	write_sysreg(1 << 15, hstr_el2);
>  	/*
> diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> index 434f0fc9cfb3..99fc60516103 100644
> --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> @@ -19,6 +19,7 @@
>  #include <linux/kvm_host.h>
>  
>  #include <asm/kvm_asm.h>
> +#include <asm/kvm_emulate.h>
>  #include <asm/kvm_hyp.h>
>  
>  /* Yes, this does nothing, on purpose */
> @@ -147,7 +148,7 @@ void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
>  {
>  	u64 *spsr, *sysreg;
>  
> -	if (read_sysreg(hcr_el2) & HCR_RW)
> +	if (!vcpu_el1_is_32bit(vcpu))
>  		return;
>  
>  	spsr = vcpu->arch.ctxt.gp_regs.spsr;
> @@ -172,7 +173,7 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
>  {
>  	u64 *spsr, *sysreg;
>  
> -	if (read_sysreg(hcr_el2) & HCR_RW)
> +	if (!vcpu_el1_is_32bit(vcpu))
>  		return;
>  
>  	spsr = vcpu->arch.ctxt.gp_regs.spsr;
> diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> index c1e179d34e6a..30a3f58cdb7b 100644
> --- a/arch/arm64/kvm/inject_fault.c
> +++ b/arch/arm64/kvm/inject_fault.c
> @@ -128,7 +128,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
>   */
>  void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
>  {
> -	if (!(vcpu->arch.hcr_el2 & HCR_RW))
> +	if (vcpu_el1_is_32bit(vcpu))
>  		kvm_inject_dabt32(vcpu, addr);
>  	else
>  		inject_abt64(vcpu, false, addr);
> @@ -144,7 +144,7 @@ void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
>   */
>  void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
>  {
> -	if (!(vcpu->arch.hcr_el2 & HCR_RW))
> +	if (vcpu_el1_is_32bit(vcpu))
>  		kvm_inject_pabt32(vcpu, addr);
>  	else
>  		inject_abt64(vcpu, true, addr);
> @@ -158,7 +158,7 @@ void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
>   */
>  void kvm_inject_undefined(struct kvm_vcpu *vcpu)
>  {
> -	if (!(vcpu->arch.hcr_el2 & HCR_RW))
> +	if (vcpu_el1_is_32bit(vcpu))
>  		kvm_inject_undef32(vcpu);
>  	else
>  		inject_undef64(vcpu);
> -- 
> 2.14.2
> 

nit: not strictly necessary, but would it be worth adding a similar
(and trivial) version of this predicate to the 32bit code? Just to
keep things in sync?

Otherwise,

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 17/40] KVM: arm64: Move userspace system registers into separate function
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 12:21     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 12:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, 15 Feb 2018 21:03:09 +0000,
Christoffer Dall wrote:
> 
> There's a semantic difference between the EL1 registers that control
> operation of a kernel running in EL1 and EL1 registers that only control
> userspace execution in EL0.  Since we can defer saving/restoring the
> latter, move them into their own function.
> 
> ACTLR_EL1 is not used by a VHE host, so we can move this register into
> the EL1 state which is not saved/restored for a VHE host.

Nit: maybe worth adding a reference to the D10.2.1 comment in the
ARMv8 ARM that indicates the "recommended" behaviour of this register?

> 
> We also take this chance to rename the function saving/restoring the
> remaining system register to make it clear this function deals with
> the EL1 system registers.
> 
> Reviewed-by: Andrew Jones <drjones@redhat.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 17/40] KVM: arm64: Move userspace system registers into separate function
@ 2018-02-21 12:21     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 12:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 15 Feb 2018 21:03:09 +0000,
Christoffer Dall wrote:
> 
> There's a semantic difference between the EL1 registers that control
> operation of a kernel running in EL1 and EL1 registers that only control
> userspace execution in EL0.  Since we can defer saving/restoring the
> latter, move them into their own function.
> 
> ACTLR_EL1 is not used by a VHE host, so we can move this register into
> the EL1 state which is not saved/restored for a VHE host.

Nit: maybe worth adding a reference to the D10.2.1 comment in the
ARMv8 ARM that indicates the "recommended" behaviour of this register?

> 
> We also take this chance to rename the function saving/restoring the
> remaining system register to make it clear this function deals with
> the EL1 system registers.
> 
> Reviewed-by: Andrew Jones <drjones@redhat.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 13:32     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 13:32 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Christoffer Dall, Andrew Jones, kvm, Tomasz Nowicki, kvmarm,
	Julien Grall, Yury Norov, linux-arm-kernel, Dave Martin,
	Shih-Wei Li

On Thu, 15 Feb 2018 21:03:16 +0000,
Christoffer Dall wrote:
> 
> From: Christoffer Dall <cdall@cs.columbia.edu>
> 
> Currently we access the system registers array via the vcpu_sys_reg()
> macro.  However, we are about to change the behavior to some times
> modify the register file directly, so let's change this to two
> primitives:
> 
>  * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
>  * Direct array access macro __vcpu_sys_reg()
> 
> The first primitive should be used in places where the code needs to
> access the currently loaded VCPU's state as observed by the guest.  For
> example, when trapping on cache related registers, a write to a system
> register should go directly to the VCPU version of the register.
> 
> The second primitive can be used in places where the VCPU is known to
> never be running (for example userspace access) or for registers which
> are never context switched (for example all the PMU system registers).
> 
> This rewrites all users of vcpu_sys_regs to one of the two primitives
> above.
> 
> No functional change.
> 
> Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> ---
> 
> Notes:
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm64/include/asm/kvm_emulate.h | 13 ++++---
>  arch/arm64/include/asm/kvm_host.h    | 13 ++++++-
>  arch/arm64/include/asm/kvm_mmu.h     |  2 +-
>  arch/arm64/kvm/debug.c               | 27 +++++++++-----
>  arch/arm64/kvm/inject_fault.c        |  8 ++--
>  arch/arm64/kvm/sys_regs.c            | 71 ++++++++++++++++++------------------
>  arch/arm64/kvm/sys_regs.h            |  4 +-
>  arch/arm64/kvm/sys_regs_generic_v8.c |  4 +-
>  virt/kvm/arm/pmu.c                   | 37 ++++++++++---------
>  9 files changed, 102 insertions(+), 77 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 3cc535591bdf..d313aaae5c38 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -290,15 +290,18 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
>  
>  static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
>  {
> -	return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> +	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
>  }
>  
>  static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
>  {
> -	if (vcpu_mode_is_32bit(vcpu))
> +	if (vcpu_mode_is_32bit(vcpu)) {
>  		*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
> -	else
> -		vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
> +	} else {
> +		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
> +		sctlr |= (1 << 25);
> +		vcpu_write_sys_reg(vcpu, SCTLR_EL1, sctlr);

General comment: it is slightly annoying that vcpu_write_sys_reg takes
its parameters in an order different from that of write_sysreg
(register followed with value, instead of value followed with
register). Not a deal breaker, but slightly confusing.

> +	}
>  }
>  
>  static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> @@ -306,7 +309,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
>  	if (vcpu_mode_is_32bit(vcpu))
>  		return !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_E_BIT);
>  
> -	return !!(vcpu_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> +	return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
>  }
>  
>  static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index f2a6f39aec87..68398bf7882f 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
>  };
>  
>  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> -#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> +
> +/*
> + * Only use __vcpu_sys_reg if you know you want the memory backed version of a
> + * register, and not the one most recently accessed by a runnning VCPU.  For
> + * example, for userpace access or for system registers that are never context
> + * switched, but only emulated.
> + */
> +#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> +
> +#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> +#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> +
>  /*
>   * CP14 and CP15 live in the same array, as they are backed by the
>   * same system registers.
> diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> index 9679067a1574..95f46e73c4dc 100644
> --- a/arch/arm64/include/asm/kvm_mmu.h
> +++ b/arch/arm64/include/asm/kvm_mmu.h
> @@ -249,7 +249,7 @@ struct kvm;
>  
>  static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
>  {
> -	return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> +	return (vcpu_read_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
>  }
>  
>  static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
> diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> index feedb877cff8..db32d10a56a1 100644
> --- a/arch/arm64/kvm/debug.c
> +++ b/arch/arm64/kvm/debug.c
> @@ -46,7 +46,8 @@ static DEFINE_PER_CPU(u32, mdcr_el2);
>   */
>  static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
>  {
> -	vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1);
> +	vcpu->arch.guest_debug_preserved.mdscr_el1 =
> +		vcpu_read_sys_reg(vcpu, MDSCR_EL1);
>  
>  	trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
>  				vcpu->arch.guest_debug_preserved.mdscr_el1);
> @@ -54,10 +55,11 @@ static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
>  
>  static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
>  {
> -	vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1;
> +	vcpu_write_sys_reg(vcpu, MDSCR_EL1,
> +			   vcpu->arch.guest_debug_preserved.mdscr_el1);
>  
>  	trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
> -				vcpu_sys_reg(vcpu, MDSCR_EL1));
> +				vcpu_read_sys_reg(vcpu, MDSCR_EL1));
>  }
>  
>  /**
> @@ -108,6 +110,7 @@ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
>  void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  {
>  	bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY);
> +	unsigned long mdscr;
>  
>  	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
>  
> @@ -152,9 +155,13 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  		 */
>  		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
>  			*vcpu_cpsr(vcpu) |=  DBG_SPSR_SS;
> -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_SS;
> +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> +			mdscr |= DBG_MDSCR_SS;
> +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);

I have the feeling that we're going to need some clearbits/setbits
variants of vcpu_write_sysreg at some point.

It otherwise looks correct to me.

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
@ 2018-02-21 13:32     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 13:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 15 Feb 2018 21:03:16 +0000,
Christoffer Dall wrote:
> 
> From: Christoffer Dall <cdall@cs.columbia.edu>
> 
> Currently we access the system registers array via the vcpu_sys_reg()
> macro.  However, we are about to change the behavior to some times
> modify the register file directly, so let's change this to two
> primitives:
> 
>  * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
>  * Direct array access macro __vcpu_sys_reg()
> 
> The first primitive should be used in places where the code needs to
> access the currently loaded VCPU's state as observed by the guest.  For
> example, when trapping on cache related registers, a write to a system
> register should go directly to the VCPU version of the register.
> 
> The second primitive can be used in places where the VCPU is known to
> never be running (for example userspace access) or for registers which
> are never context switched (for example all the PMU system registers).
> 
> This rewrites all users of vcpu_sys_regs to one of the two primitives
> above.
> 
> No functional change.
> 
> Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> ---
> 
> Notes:
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm64/include/asm/kvm_emulate.h | 13 ++++---
>  arch/arm64/include/asm/kvm_host.h    | 13 ++++++-
>  arch/arm64/include/asm/kvm_mmu.h     |  2 +-
>  arch/arm64/kvm/debug.c               | 27 +++++++++-----
>  arch/arm64/kvm/inject_fault.c        |  8 ++--
>  arch/arm64/kvm/sys_regs.c            | 71 ++++++++++++++++++------------------
>  arch/arm64/kvm/sys_regs.h            |  4 +-
>  arch/arm64/kvm/sys_regs_generic_v8.c |  4 +-
>  virt/kvm/arm/pmu.c                   | 37 ++++++++++---------
>  9 files changed, 102 insertions(+), 77 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 3cc535591bdf..d313aaae5c38 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -290,15 +290,18 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
>  
>  static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
>  {
> -	return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> +	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
>  }
>  
>  static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
>  {
> -	if (vcpu_mode_is_32bit(vcpu))
> +	if (vcpu_mode_is_32bit(vcpu)) {
>  		*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
> -	else
> -		vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
> +	} else {
> +		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
> +		sctlr |= (1 << 25);
> +		vcpu_write_sys_reg(vcpu, SCTLR_EL1, sctlr);

General comment: it is slightly annoying that vcpu_write_sys_reg takes
its parameters in an order different from that of write_sysreg
(register followed with value, instead of value followed with
register). Not a deal breaker, but slightly confusing.

> +	}
>  }
>  
>  static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> @@ -306,7 +309,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
>  	if (vcpu_mode_is_32bit(vcpu))
>  		return !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_E_BIT);
>  
> -	return !!(vcpu_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> +	return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
>  }
>  
>  static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index f2a6f39aec87..68398bf7882f 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
>  };
>  
>  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> -#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> +
> +/*
> + * Only use __vcpu_sys_reg if you know you want the memory backed version of a
> + * register, and not the one most recently accessed by a runnning VCPU.  For
> + * example, for userpace access or for system registers that are never context
> + * switched, but only emulated.
> + */
> +#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> +
> +#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> +#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> +
>  /*
>   * CP14 and CP15 live in the same array, as they are backed by the
>   * same system registers.
> diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> index 9679067a1574..95f46e73c4dc 100644
> --- a/arch/arm64/include/asm/kvm_mmu.h
> +++ b/arch/arm64/include/asm/kvm_mmu.h
> @@ -249,7 +249,7 @@ struct kvm;
>  
>  static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
>  {
> -	return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> +	return (vcpu_read_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
>  }
>  
>  static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
> diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> index feedb877cff8..db32d10a56a1 100644
> --- a/arch/arm64/kvm/debug.c
> +++ b/arch/arm64/kvm/debug.c
> @@ -46,7 +46,8 @@ static DEFINE_PER_CPU(u32, mdcr_el2);
>   */
>  static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
>  {
> -	vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1);
> +	vcpu->arch.guest_debug_preserved.mdscr_el1 =
> +		vcpu_read_sys_reg(vcpu, MDSCR_EL1);
>  
>  	trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
>  				vcpu->arch.guest_debug_preserved.mdscr_el1);
> @@ -54,10 +55,11 @@ static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
>  
>  static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
>  {
> -	vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1;
> +	vcpu_write_sys_reg(vcpu, MDSCR_EL1,
> +			   vcpu->arch.guest_debug_preserved.mdscr_el1);
>  
>  	trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
> -				vcpu_sys_reg(vcpu, MDSCR_EL1));
> +				vcpu_read_sys_reg(vcpu, MDSCR_EL1));
>  }
>  
>  /**
> @@ -108,6 +110,7 @@ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
>  void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  {
>  	bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY);
> +	unsigned long mdscr;
>  
>  	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
>  
> @@ -152,9 +155,13 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  		 */
>  		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
>  			*vcpu_cpsr(vcpu) |=  DBG_SPSR_SS;
> -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_SS;
> +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> +			mdscr |= DBG_MDSCR_SS;
> +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);

I have the feeling that we're going to need some clearbits/setbits
variants of vcpu_write_sysreg at some point.

It otherwise looks correct to me.

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 25/40] KVM: arm64: Introduce framework for accessing deferred sysregs
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 14:16     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 14:16 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, 15 Feb 2018 21:03:17 +0000,
Christoffer Dall wrote:
> 
> We are about to defer saving and restoring some groups of system
> registers to vcpu_put and vcpu_load on supported systems.  This means
> that we need some infrastructure to access system registes which
> supports either accessing the memory backing of the register or directly
> accessing the system registers, depending on the state of the system
> when we access the register.
> 
> We do this by defining read/write accessor functions, which can handle
> both "immediate" and "deferrable" system registers.  Immediate registers
> are always saved/restored in the world-switch path, but deferrable
> registers are only saved/restored in vcpu_put/vcpu_load when supported
> and sysregs_loaded_on_cpu will be set in that case.
> 
> Note that we don't use the deferred mechanism yet in this patch, but only
> introduce infrastructure.  This is to improve convenience of review in
> the subsequent patches where it is clear which registers become
> deferred.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	     M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 25/40] KVM: arm64: Introduce framework for accessing deferred sysregs
@ 2018-02-21 14:16     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 14:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 15 Feb 2018 21:03:17 +0000,
Christoffer Dall wrote:
> 
> We are about to defer saving and restoring some groups of system
> registers to vcpu_put and vcpu_load on supported systems.  This means
> that we need some infrastructure to access system registes which
> supports either accessing the memory backing of the register or directly
> accessing the system registers, depending on the state of the system
> when we access the register.
> 
> We do this by defining read/write accessor functions, which can handle
> both "immediate" and "deferrable" system registers.  Immediate registers
> are always saved/restored in the world-switch path, but deferrable
> registers are only saved/restored in vcpu_put/vcpu_load when supported
> and sysregs_loaded_on_cpu will be set in that case.
> 
> Note that we don't use the deferred mechanism yet in this patch, but only
> introduce infrastructure.  This is to improve convenience of review in
> the subsequent patches where it is clear which registers become
> deferred.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	     M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 26/40] KVM: arm/arm64: Prepare to handle deferred save/restore of SPSR_EL1
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 14:47     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 14:47 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, 15 Feb 2018 21:03:18 +0000,
Christoffer Dall wrote:
> 
> SPSR_EL1 is not used by a VHE host kernel and can be deferred, but we
> need to rework the accesses to this register to access the latest value
> depending on whether or not guest system registers are loaded on the CPU
> or only reside in memory.
> 
> The handling of accessing the various banked SPSRs for 32-bit VMs is a
> bit clunky, but this will be improved in following patches which will
> first prepare and subsequently implement deferred save/restore of the
> 32-bit registers, including the 32-bit SPSRs.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm/include/asm/kvm_emulate.h   | 12 ++++++++++-
>  arch/arm/kvm/emulate.c               |  2 +-
>  arch/arm64/include/asm/kvm_emulate.h | 41 +++++++++++++++++++++++++++++++-----
>  arch/arm64/kvm/inject_fault.c        |  4 ++--
>  virt/kvm/arm/aarch32.c               |  2 +-
>  5 files changed, 51 insertions(+), 10 deletions(-)
> 
> diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h
> index e27caa4b47a1..6493bd479ddc 100644
> --- a/arch/arm/include/asm/kvm_emulate.h
> +++ b/arch/arm/include/asm/kvm_emulate.h
> @@ -41,7 +41,17 @@ static inline unsigned long *vcpu_reg32(struct kvm_vcpu *vcpu, u8 reg_num)
>  	return vcpu_reg(vcpu, reg_num);
>  }
>  
> -unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu);
> +unsigned long *__vcpu_spsr(struct kvm_vcpu *vcpu);
> +
> +static inline unsigned long vpcu_read_spsr(struct kvm_vcpu *vcpu)
> +{
> +	return *__vcpu_spsr(vcpu);
> +}
> +
> +static inline void vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long v)
> +{
> +	*__vcpu_spsr(vcpu) = v;
> +}
>  
>  static inline unsigned long vcpu_get_reg(struct kvm_vcpu *vcpu,
>  					 u8 reg_num)
> diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
> index fa501bf437f3..9046b53d87c1 100644
> --- a/arch/arm/kvm/emulate.c
> +++ b/arch/arm/kvm/emulate.c
> @@ -142,7 +142,7 @@ unsigned long *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num)
>  /*
>   * Return the SPSR for the current mode of the virtual CPU.
>   */
> -unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu)
> +unsigned long *__vcpu_spsr(struct kvm_vcpu *vcpu)
>  {
>  	unsigned long mode = *vcpu_cpsr(vcpu) & MODE_MASK;
>  	switch (mode) {
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index d313aaae5c38..47c2406755fa 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -26,6 +26,7 @@
>  
>  #include <asm/esr.h>
>  #include <asm/kvm_arm.h>
> +#include <asm/kvm_hyp.h>
>  #include <asm/kvm_mmio.h>
>  #include <asm/ptrace.h>
>  #include <asm/cputype.h>
> @@ -143,13 +144,43 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
>  		vcpu_gp_regs(vcpu)->regs.regs[reg_num] = val;
>  }
>  
> -/* Get vcpu SPSR for current mode */
> -static inline unsigned long *vcpu_spsr(const struct kvm_vcpu *vcpu)
> +static inline unsigned long vcpu_read_spsr(const struct kvm_vcpu *vcpu)
>  {
> -	if (vcpu_mode_is_32bit(vcpu))
> -		return vcpu_spsr32(vcpu);
> +	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> +
> +	if (vcpu_mode_is_32bit(vcpu)) {
> +		unsigned long *p_32bit = vcpu_spsr32(vcpu);
> +
> +		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> +		if (p_32bit != (unsigned long *)p)
> +			return *p_32bit;

Clunky, you said? ;-) p is already an unsigned long *, so there's no
need to cast it.

> +	}
> +
> +	if (vcpu->arch.sysregs_loaded_on_cpu)
> +		return read_sysreg_el1(spsr);
> +	else
> +		return *p;
> +}
>  
> -	return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> +static inline void vcpu_write_spsr(const struct kvm_vcpu *vcpu, unsigned long v)
> +{
> +	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> +
> +	/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> +	if (vcpu_mode_is_32bit(vcpu)) {
> +		unsigned long *p_32bit = vcpu_spsr32(vcpu);
> +
> +		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> +		if (p_32bit != (unsigned long *)p) {
> +			*p_32bit = v;
> +			return;

Same remark.

> +		}
> +	}
> +
> +	if (vcpu->arch.sysregs_loaded_on_cpu)
> +		write_sysreg_el1(v, spsr);
> +	else
> +		*p = v;
>  }
>  
>  static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
> diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> index e08db2f2dd75..8dda1edae727 100644
> --- a/arch/arm64/kvm/inject_fault.c
> +++ b/arch/arm64/kvm/inject_fault.c
> @@ -71,7 +71,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
>  	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
>  
>  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> -	*vcpu_spsr(vcpu) = cpsr;
> +	vcpu_write_spsr(vcpu, cpsr);
>  
>  	vcpu_write_sys_reg(vcpu, FAR_EL1, addr);
>  
> @@ -106,7 +106,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
>  	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
>  
>  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> -	*vcpu_spsr(vcpu) = cpsr;
> +	vcpu_write_spsr(vcpu, cpsr);
>  
>  	/*
>  	 * Build an unknown exception, depending on the instruction
> diff --git a/virt/kvm/arm/aarch32.c b/virt/kvm/arm/aarch32.c
> index 8bc479fa37e6..efc84cbe8277 100644
> --- a/virt/kvm/arm/aarch32.c
> +++ b/virt/kvm/arm/aarch32.c
> @@ -178,7 +178,7 @@ static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
>  	*vcpu_cpsr(vcpu) = cpsr;
>  
>  	/* Note: These now point to the banked copies */
> -	*vcpu_spsr(vcpu) = new_spsr_value;
> +	vcpu_write_spsr(vcpu, new_spsr_value);
>  	*vcpu_reg32(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
>  
>  	/* Branch to exception vector */
> -- 
> 2.14.2
> 

Otherwise:

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 26/40] KVM: arm/arm64: Prepare to handle deferred save/restore of SPSR_EL1
@ 2018-02-21 14:47     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 14:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 15 Feb 2018 21:03:18 +0000,
Christoffer Dall wrote:
> 
> SPSR_EL1 is not used by a VHE host kernel and can be deferred, but we
> need to rework the accesses to this register to access the latest value
> depending on whether or not guest system registers are loaded on the CPU
> or only reside in memory.
> 
> The handling of accessing the various banked SPSRs for 32-bit VMs is a
> bit clunky, but this will be improved in following patches which will
> first prepare and subsequently implement deferred save/restore of the
> 32-bit registers, including the 32-bit SPSRs.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm/include/asm/kvm_emulate.h   | 12 ++++++++++-
>  arch/arm/kvm/emulate.c               |  2 +-
>  arch/arm64/include/asm/kvm_emulate.h | 41 +++++++++++++++++++++++++++++++-----
>  arch/arm64/kvm/inject_fault.c        |  4 ++--
>  virt/kvm/arm/aarch32.c               |  2 +-
>  5 files changed, 51 insertions(+), 10 deletions(-)
> 
> diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h
> index e27caa4b47a1..6493bd479ddc 100644
> --- a/arch/arm/include/asm/kvm_emulate.h
> +++ b/arch/arm/include/asm/kvm_emulate.h
> @@ -41,7 +41,17 @@ static inline unsigned long *vcpu_reg32(struct kvm_vcpu *vcpu, u8 reg_num)
>  	return vcpu_reg(vcpu, reg_num);
>  }
>  
> -unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu);
> +unsigned long *__vcpu_spsr(struct kvm_vcpu *vcpu);
> +
> +static inline unsigned long vpcu_read_spsr(struct kvm_vcpu *vcpu)
> +{
> +	return *__vcpu_spsr(vcpu);
> +}
> +
> +static inline void vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long v)
> +{
> +	*__vcpu_spsr(vcpu) = v;
> +}
>  
>  static inline unsigned long vcpu_get_reg(struct kvm_vcpu *vcpu,
>  					 u8 reg_num)
> diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
> index fa501bf437f3..9046b53d87c1 100644
> --- a/arch/arm/kvm/emulate.c
> +++ b/arch/arm/kvm/emulate.c
> @@ -142,7 +142,7 @@ unsigned long *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num)
>  /*
>   * Return the SPSR for the current mode of the virtual CPU.
>   */
> -unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu)
> +unsigned long *__vcpu_spsr(struct kvm_vcpu *vcpu)
>  {
>  	unsigned long mode = *vcpu_cpsr(vcpu) & MODE_MASK;
>  	switch (mode) {
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index d313aaae5c38..47c2406755fa 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -26,6 +26,7 @@
>  
>  #include <asm/esr.h>
>  #include <asm/kvm_arm.h>
> +#include <asm/kvm_hyp.h>
>  #include <asm/kvm_mmio.h>
>  #include <asm/ptrace.h>
>  #include <asm/cputype.h>
> @@ -143,13 +144,43 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
>  		vcpu_gp_regs(vcpu)->regs.regs[reg_num] = val;
>  }
>  
> -/* Get vcpu SPSR for current mode */
> -static inline unsigned long *vcpu_spsr(const struct kvm_vcpu *vcpu)
> +static inline unsigned long vcpu_read_spsr(const struct kvm_vcpu *vcpu)
>  {
> -	if (vcpu_mode_is_32bit(vcpu))
> -		return vcpu_spsr32(vcpu);
> +	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> +
> +	if (vcpu_mode_is_32bit(vcpu)) {
> +		unsigned long *p_32bit = vcpu_spsr32(vcpu);
> +
> +		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> +		if (p_32bit != (unsigned long *)p)
> +			return *p_32bit;

Clunky, you said? ;-) p is already an unsigned long *, so there's no
need to cast it.

> +	}
> +
> +	if (vcpu->arch.sysregs_loaded_on_cpu)
> +		return read_sysreg_el1(spsr);
> +	else
> +		return *p;
> +}
>  
> -	return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> +static inline void vcpu_write_spsr(const struct kvm_vcpu *vcpu, unsigned long v)
> +{
> +	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> +
> +	/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> +	if (vcpu_mode_is_32bit(vcpu)) {
> +		unsigned long *p_32bit = vcpu_spsr32(vcpu);
> +
> +		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> +		if (p_32bit != (unsigned long *)p) {
> +			*p_32bit = v;
> +			return;

Same remark.

> +		}
> +	}
> +
> +	if (vcpu->arch.sysregs_loaded_on_cpu)
> +		write_sysreg_el1(v, spsr);
> +	else
> +		*p = v;
>  }
>  
>  static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
> diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> index e08db2f2dd75..8dda1edae727 100644
> --- a/arch/arm64/kvm/inject_fault.c
> +++ b/arch/arm64/kvm/inject_fault.c
> @@ -71,7 +71,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
>  	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
>  
>  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> -	*vcpu_spsr(vcpu) = cpsr;
> +	vcpu_write_spsr(vcpu, cpsr);
>  
>  	vcpu_write_sys_reg(vcpu, FAR_EL1, addr);
>  
> @@ -106,7 +106,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
>  	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
>  
>  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> -	*vcpu_spsr(vcpu) = cpsr;
> +	vcpu_write_spsr(vcpu, cpsr);
>  
>  	/*
>  	 * Build an unknown exception, depending on the instruction
> diff --git a/virt/kvm/arm/aarch32.c b/virt/kvm/arm/aarch32.c
> index 8bc479fa37e6..efc84cbe8277 100644
> --- a/virt/kvm/arm/aarch32.c
> +++ b/virt/kvm/arm/aarch32.c
> @@ -178,7 +178,7 @@ static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
>  	*vcpu_cpsr(vcpu) = cpsr;
>  
>  	/* Note: These now point to the banked copies */
> -	*vcpu_spsr(vcpu) = new_spsr_value;
> +	vcpu_write_spsr(vcpu, new_spsr_value);
>  	*vcpu_reg32(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
>  
>  	/* Branch to exception vector */
> -- 
> 2.14.2
> 

Otherwise:

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 27/40] KVM: arm64: Prepare to handle deferred save/restore of ELR_EL1
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 15:08     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 15:08 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, 15 Feb 2018 21:03:19 +0000,
Christoffer Dall wrote:
> 
> ELR_EL1 is not used by a VHE host kernel and can be deferred, but we
> need to rework the accesses to this register to access the latest value
> depending on whether or not guest system registers are loaded on the CPU
> or only reside in memory.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm64/include/asm/kvm_emulate.h | 18 +++++++++++++++++-
>  arch/arm64/kvm/inject_fault.c        |  4 ++--
>  2 files changed, 19 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 47c2406755fa..9cb13b23c7a1 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -90,11 +90,27 @@ static inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
>  	return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pc;
>  }
>  
> -static inline unsigned long *vcpu_elr_el1(const struct kvm_vcpu *vcpu)
> +static inline unsigned long *__vcpu_elr_el1(const struct kvm_vcpu *vcpu)
>  {
>  	return (unsigned long *)&vcpu_gp_regs(vcpu)->elr_el1;
>  }
>  
> +static inline unsigned long vcpu_read_elr_el1(const struct kvm_vcpu *vcpu)
> +{
> +	if (vcpu->arch.sysregs_loaded_on_cpu)
> +		return read_sysreg_el1(elr);
> +	else
> +		return *__vcpu_elr_el1(vcpu);
> +}
> +
> +static inline void vcpu_write_elr_el1(const struct kvm_vcpu *vcpu, unsigned long v)
> +{
> +	if (vcpu->arch.sysregs_loaded_on_cpu)
> +		write_sysreg_el1(v, elr);
> +	else
> +		*__vcpu_elr_el1(vcpu) = v;
> +}
> +
>  static inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
>  {
>  	return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pstate;
> diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> index 8dda1edae727..cc13b6f5ad11 100644
> --- a/arch/arm64/kvm/inject_fault.c
> +++ b/arch/arm64/kvm/inject_fault.c
> @@ -67,7 +67,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
>  	bool is_aarch32 = vcpu_mode_is_32bit(vcpu);
>  	u32 esr = 0;
>  
> -	*vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
> +	vcpu_write_elr_el1(vcpu, *vcpu_pc(vcpu));
>  	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
>  
>  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> @@ -102,7 +102,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
>  	unsigned long cpsr = *vcpu_cpsr(vcpu);
>  	u32 esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT);
>  
> -	*vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
> +	vcpu_write_elr_el1(vcpu, *vcpu_pc(vcpu));
>  	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
>  
>  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> -- 
> 2.14.2
> 

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 27/40] KVM: arm64: Prepare to handle deferred save/restore of ELR_EL1
@ 2018-02-21 15:08     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 15:08 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 15 Feb 2018 21:03:19 +0000,
Christoffer Dall wrote:
> 
> ELR_EL1 is not used by a VHE host kernel and can be deferred, but we
> need to rework the accesses to this register to access the latest value
> depending on whether or not guest system registers are loaded on the CPU
> or only reside in memory.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm64/include/asm/kvm_emulate.h | 18 +++++++++++++++++-
>  arch/arm64/kvm/inject_fault.c        |  4 ++--
>  2 files changed, 19 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 47c2406755fa..9cb13b23c7a1 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -90,11 +90,27 @@ static inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
>  	return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pc;
>  }
>  
> -static inline unsigned long *vcpu_elr_el1(const struct kvm_vcpu *vcpu)
> +static inline unsigned long *__vcpu_elr_el1(const struct kvm_vcpu *vcpu)
>  {
>  	return (unsigned long *)&vcpu_gp_regs(vcpu)->elr_el1;
>  }
>  
> +static inline unsigned long vcpu_read_elr_el1(const struct kvm_vcpu *vcpu)
> +{
> +	if (vcpu->arch.sysregs_loaded_on_cpu)
> +		return read_sysreg_el1(elr);
> +	else
> +		return *__vcpu_elr_el1(vcpu);
> +}
> +
> +static inline void vcpu_write_elr_el1(const struct kvm_vcpu *vcpu, unsigned long v)
> +{
> +	if (vcpu->arch.sysregs_loaded_on_cpu)
> +		write_sysreg_el1(v, elr);
> +	else
> +		*__vcpu_elr_el1(vcpu) = v;
> +}
> +
>  static inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
>  {
>  	return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pstate;
> diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> index 8dda1edae727..cc13b6f5ad11 100644
> --- a/arch/arm64/kvm/inject_fault.c
> +++ b/arch/arm64/kvm/inject_fault.c
> @@ -67,7 +67,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
>  	bool is_aarch32 = vcpu_mode_is_32bit(vcpu);
>  	u32 esr = 0;
>  
> -	*vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
> +	vcpu_write_elr_el1(vcpu, *vcpu_pc(vcpu));
>  	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
>  
>  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> @@ -102,7 +102,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
>  	unsigned long cpsr = *vcpu_cpsr(vcpu);
>  	u32 esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT);
>  
> -	*vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
> +	vcpu_write_elr_el1(vcpu, *vcpu_pc(vcpu));
>  	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
>  
>  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> -- 
> 2.14.2
> 

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 28/40] KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on VHE
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 15:33     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 15:33 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, 15 Feb 2018 21:03:20 +0000,
Christoffer Dall wrote:
> 
> Some system registers do not affect the host kernel's execution and can
> therefore be loaded when we are about to run a VCPU and we don't have to
> restore the host state to the hardware before the time when we are
> actually about to return to userspace or schedule out the VCPU thread.
> 
> The EL1 system registers and the userspace state registers only
> affecting EL0 execution do not need to be saved and restored on every
> switch between the VM and the host, because they don't affect the host
> kernel's execution.
> 
> We mark all registers which are now deffered as such in the
> vcpu_{read,write}_sys_reg accessors in sys-regs.c to ensure the most
> up-to-date copy is always accessed.
> 
> Note MPIDR_EL1 (controlled via VMPIDR_EL2) is accessed from other vcpu
> threads, for example via the GIC emulation, and therefore must be
> declared as immediate, which is fine as the guest cannot modify this
> value.
> 
> The 32-bit sysregs can also be deferred but we do this in a separate
> patch as it requires a bit more infrastructure.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Changed to switch-based sysreg approach
> 
>  arch/arm64/kvm/hyp/sysreg-sr.c | 39 +++++++++++++++++++++++++++++++--------
>  arch/arm64/kvm/sys_regs.c      | 40 ++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 71 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> index 906606dc4e2c..9c60b8062724 100644
> --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> @@ -25,8 +25,12 @@
>  /*
>   * Non-VHE: Both host and guest must save everything.
>   *
> - * VHE: Host must save tpidr*_el0, mdscr_el1, sp_el0,
> - * and guest must save everything.
> + * VHE: Host and guest must save mdscr_el1 and sp_el0 (and the PC and pstate,
> + * which are handled as part of the el2 return state) on every switch.
> + * tpidr_el0 and tpidrro_el0 only need to be switched when going

How about suspend/resume, which saves/restores both of these EL0
registers (see cpu_do_suspend)? We may not need to do anything (either
because vcpu_put will have happened, or because we'll come back
exactly where we were), but I'd like to make sure this hasn't been
overlooked.

> + * to host userspace or a different VCPU.  EL1 registers only need to be
> + * switched when potentially going to run a different VCPU.  The latter two
> + * classes are handled as part of kvm_arch_vcpu_load and kvm_arch_vcpu_put.
>   */
>  
>  static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
> @@ -93,14 +97,11 @@ void __hyp_text __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt)
>  void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt)
>  {
>  	__sysreg_save_common_state(ctxt);
> -	__sysreg_save_user_state(ctxt);
>  }
>  
>  void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt)
>  {
> -	__sysreg_save_el1_state(ctxt);
>  	__sysreg_save_common_state(ctxt);
> -	__sysreg_save_user_state(ctxt);
>  	__sysreg_save_el2_return_state(ctxt);
>  }
>  
> @@ -169,14 +170,11 @@ void __hyp_text __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt)
>  void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt)
>  {
>  	__sysreg_restore_common_state(ctxt);
> -	__sysreg_restore_user_state(ctxt);
>  }
>  
>  void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt)
>  {
> -	__sysreg_restore_el1_state(ctxt);
>  	__sysreg_restore_common_state(ctxt);
> -	__sysreg_restore_user_state(ctxt);
>  	__sysreg_restore_el2_return_state(ctxt);
>  }
>  
> @@ -240,6 +238,18 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
>   */
>  void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
>  {
> +	struct kvm_cpu_context *host_ctxt = vcpu->arch.host_cpu_context;
> +	struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt;
> +
> +	if (!has_vhe())
> +		return;
> +
> +	__sysreg_save_user_state(host_ctxt);
> +
> +	__sysreg_restore_user_state(guest_ctxt);
> +	__sysreg_restore_el1_state(guest_ctxt);
> +
> +	vcpu->arch.sysregs_loaded_on_cpu = true;
>  }
>  
>  /**
> @@ -255,6 +265,19 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
>   */
>  void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
>  {
> +	struct kvm_cpu_context *host_ctxt = vcpu->arch.host_cpu_context;
> +	struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt;
> +
> +	if (!has_vhe())
> +		return;
> +
> +	__sysreg_save_el1_state(guest_ctxt);
> +	__sysreg_save_user_state(guest_ctxt);
> +
> +	/* Restore host user state */
> +	__sysreg_restore_user_state(host_ctxt);
> +
> +	vcpu->arch.sysregs_loaded_on_cpu = false;
>  }
>  
>  void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2)
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index b3c3f014aa61..f060309337aa 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -87,6 +87,26 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
>  	 * exit from the guest but are only saved on vcpu_put.
>  	 */
>  	switch (reg) {
> +	case CSSELR_EL1:	return read_sysreg_s(SYS_CSSELR_EL1);
> +	case SCTLR_EL1:		return read_sysreg_s(sctlr_EL12);
> +	case ACTLR_EL1:		return read_sysreg_s(SYS_ACTLR_EL1);
> +	case CPACR_EL1:		return read_sysreg_s(cpacr_EL12);
> +	case TTBR0_EL1:		return read_sysreg_s(ttbr0_EL12);
> +	case TTBR1_EL1:		return read_sysreg_s(ttbr1_EL12);
> +	case TCR_EL1:		return read_sysreg_s(tcr_EL12);
> +	case ESR_EL1:		return read_sysreg_s(esr_EL12);
> +	case AFSR0_EL1:		return read_sysreg_s(afsr0_EL12);
> +	case AFSR1_EL1:		return read_sysreg_s(afsr1_EL12);
> +	case FAR_EL1:		return read_sysreg_s(far_EL12);
> +	case MAIR_EL1:		return read_sysreg_s(mair_EL12);
> +	case VBAR_EL1:		return read_sysreg_s(vbar_EL12);
> +	case CONTEXTIDR_EL1:	return read_sysreg_s(contextidr_EL12);
> +	case TPIDR_EL0:		return read_sysreg_s(SYS_TPIDR_EL0);
> +	case TPIDRRO_EL0:	return read_sysreg_s(SYS_TPIDRRO_EL0);
> +	case TPIDR_EL1:		return read_sysreg_s(SYS_TPIDR_EL1);
> +	case AMAIR_EL1:		return read_sysreg_s(amair_EL12);
> +	case CNTKCTL_EL1:	return read_sysreg_s(cntkctl_EL12);
> +	case PAR_EL1:		return read_sysreg_s(SYS_PAR_EL1);
>  	}
>  
>  immediate_read:
> @@ -103,6 +123,26 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
>  	 * entry to the guest but are only restored on vcpu_load.
>  	 */
>  	switch (reg) {
> +	case CSSELR_EL1:	write_sysreg_s(val, SYS_CSSELR_EL1);	return;
> +	case SCTLR_EL1:		write_sysreg_s(val, sctlr_EL12);	return;
> +	case ACTLR_EL1:		write_sysreg_s(val, SYS_ACTLR_EL1);	return;
> +	case CPACR_EL1:		write_sysreg_s(val, cpacr_EL12);	return;
> +	case TTBR0_EL1:		write_sysreg_s(val, ttbr0_EL12);	return;
> +	case TTBR1_EL1:		write_sysreg_s(val, ttbr1_EL12);	return;
> +	case TCR_EL1:		write_sysreg_s(val, tcr_EL12);		return;
> +	case ESR_EL1:		write_sysreg_s(val, esr_EL12);		return;
> +	case AFSR0_EL1:		write_sysreg_s(val, afsr0_EL12);	return;
> +	case AFSR1_EL1:		write_sysreg_s(val, afsr1_EL12);	return;
> +	case FAR_EL1:		write_sysreg_s(val, far_EL12);		return;
> +	case MAIR_EL1:		write_sysreg_s(val, mair_EL12);		return;
> +	case VBAR_EL1:		write_sysreg_s(val, vbar_EL12);		return;
> +	case CONTEXTIDR_EL1:	write_sysreg_s(val, contextidr_EL12);	return;
> +	case TPIDR_EL0:		write_sysreg_s(val, SYS_TPIDR_EL0);	return;
> +	case TPIDRRO_EL0:	write_sysreg_s(val, SYS_TPIDRRO_EL0);	return;
> +	case TPIDR_EL1:		write_sysreg_s(val, SYS_TPIDR_EL1);	return;
> +	case AMAIR_EL1:		write_sysreg_s(val, amair_EL12);	return;
> +	case CNTKCTL_EL1:	write_sysreg_s(val, cntkctl_EL12);	return;
> +	case PAR_EL1:		write_sysreg_s(val, SYS_PAR_EL1);	return;
>  	}
>  
>  immediate_write:
> -- 
> 2.14.2
> 

Looks good to me otherwise.

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 28/40] KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on VHE
@ 2018-02-21 15:33     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 15 Feb 2018 21:03:20 +0000,
Christoffer Dall wrote:
> 
> Some system registers do not affect the host kernel's execution and can
> therefore be loaded when we are about to run a VCPU and we don't have to
> restore the host state to the hardware before the time when we are
> actually about to return to userspace or schedule out the VCPU thread.
> 
> The EL1 system registers and the userspace state registers only
> affecting EL0 execution do not need to be saved and restored on every
> switch between the VM and the host, because they don't affect the host
> kernel's execution.
> 
> We mark all registers which are now deffered as such in the
> vcpu_{read,write}_sys_reg accessors in sys-regs.c to ensure the most
> up-to-date copy is always accessed.
> 
> Note MPIDR_EL1 (controlled via VMPIDR_EL2) is accessed from other vcpu
> threads, for example via the GIC emulation, and therefore must be
> declared as immediate, which is fine as the guest cannot modify this
> value.
> 
> The 32-bit sysregs can also be deferred but we do this in a separate
> patch as it requires a bit more infrastructure.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Changed to switch-based sysreg approach
> 
>  arch/arm64/kvm/hyp/sysreg-sr.c | 39 +++++++++++++++++++++++++++++++--------
>  arch/arm64/kvm/sys_regs.c      | 40 ++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 71 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> index 906606dc4e2c..9c60b8062724 100644
> --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> @@ -25,8 +25,12 @@
>  /*
>   * Non-VHE: Both host and guest must save everything.
>   *
> - * VHE: Host must save tpidr*_el0, mdscr_el1, sp_el0,
> - * and guest must save everything.
> + * VHE: Host and guest must save mdscr_el1 and sp_el0 (and the PC and pstate,
> + * which are handled as part of the el2 return state) on every switch.
> + * tpidr_el0 and tpidrro_el0 only need to be switched when going

How about suspend/resume, which saves/restores both of these EL0
registers (see cpu_do_suspend)? We may not need to do anything (either
because vcpu_put will have happened, or because we'll come back
exactly where we were), but I'd like to make sure this hasn't been
overlooked.

> + * to host userspace or a different VCPU.  EL1 registers only need to be
> + * switched when potentially going to run a different VCPU.  The latter two
> + * classes are handled as part of kvm_arch_vcpu_load and kvm_arch_vcpu_put.
>   */
>  
>  static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
> @@ -93,14 +97,11 @@ void __hyp_text __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt)
>  void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt)
>  {
>  	__sysreg_save_common_state(ctxt);
> -	__sysreg_save_user_state(ctxt);
>  }
>  
>  void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt)
>  {
> -	__sysreg_save_el1_state(ctxt);
>  	__sysreg_save_common_state(ctxt);
> -	__sysreg_save_user_state(ctxt);
>  	__sysreg_save_el2_return_state(ctxt);
>  }
>  
> @@ -169,14 +170,11 @@ void __hyp_text __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt)
>  void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt)
>  {
>  	__sysreg_restore_common_state(ctxt);
> -	__sysreg_restore_user_state(ctxt);
>  }
>  
>  void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt)
>  {
> -	__sysreg_restore_el1_state(ctxt);
>  	__sysreg_restore_common_state(ctxt);
> -	__sysreg_restore_user_state(ctxt);
>  	__sysreg_restore_el2_return_state(ctxt);
>  }
>  
> @@ -240,6 +238,18 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
>   */
>  void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
>  {
> +	struct kvm_cpu_context *host_ctxt = vcpu->arch.host_cpu_context;
> +	struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt;
> +
> +	if (!has_vhe())
> +		return;
> +
> +	__sysreg_save_user_state(host_ctxt);
> +
> +	__sysreg_restore_user_state(guest_ctxt);
> +	__sysreg_restore_el1_state(guest_ctxt);
> +
> +	vcpu->arch.sysregs_loaded_on_cpu = true;
>  }
>  
>  /**
> @@ -255,6 +265,19 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
>   */
>  void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
>  {
> +	struct kvm_cpu_context *host_ctxt = vcpu->arch.host_cpu_context;
> +	struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt;
> +
> +	if (!has_vhe())
> +		return;
> +
> +	__sysreg_save_el1_state(guest_ctxt);
> +	__sysreg_save_user_state(guest_ctxt);
> +
> +	/* Restore host user state */
> +	__sysreg_restore_user_state(host_ctxt);
> +
> +	vcpu->arch.sysregs_loaded_on_cpu = false;
>  }
>  
>  void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2)
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index b3c3f014aa61..f060309337aa 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -87,6 +87,26 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
>  	 * exit from the guest but are only saved on vcpu_put.
>  	 */
>  	switch (reg) {
> +	case CSSELR_EL1:	return read_sysreg_s(SYS_CSSELR_EL1);
> +	case SCTLR_EL1:		return read_sysreg_s(sctlr_EL12);
> +	case ACTLR_EL1:		return read_sysreg_s(SYS_ACTLR_EL1);
> +	case CPACR_EL1:		return read_sysreg_s(cpacr_EL12);
> +	case TTBR0_EL1:		return read_sysreg_s(ttbr0_EL12);
> +	case TTBR1_EL1:		return read_sysreg_s(ttbr1_EL12);
> +	case TCR_EL1:		return read_sysreg_s(tcr_EL12);
> +	case ESR_EL1:		return read_sysreg_s(esr_EL12);
> +	case AFSR0_EL1:		return read_sysreg_s(afsr0_EL12);
> +	case AFSR1_EL1:		return read_sysreg_s(afsr1_EL12);
> +	case FAR_EL1:		return read_sysreg_s(far_EL12);
> +	case MAIR_EL1:		return read_sysreg_s(mair_EL12);
> +	case VBAR_EL1:		return read_sysreg_s(vbar_EL12);
> +	case CONTEXTIDR_EL1:	return read_sysreg_s(contextidr_EL12);
> +	case TPIDR_EL0:		return read_sysreg_s(SYS_TPIDR_EL0);
> +	case TPIDRRO_EL0:	return read_sysreg_s(SYS_TPIDRRO_EL0);
> +	case TPIDR_EL1:		return read_sysreg_s(SYS_TPIDR_EL1);
> +	case AMAIR_EL1:		return read_sysreg_s(amair_EL12);
> +	case CNTKCTL_EL1:	return read_sysreg_s(cntkctl_EL12);
> +	case PAR_EL1:		return read_sysreg_s(SYS_PAR_EL1);
>  	}
>  
>  immediate_read:
> @@ -103,6 +123,26 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
>  	 * entry to the guest but are only restored on vcpu_load.
>  	 */
>  	switch (reg) {
> +	case CSSELR_EL1:	write_sysreg_s(val, SYS_CSSELR_EL1);	return;
> +	case SCTLR_EL1:		write_sysreg_s(val, sctlr_EL12);	return;
> +	case ACTLR_EL1:		write_sysreg_s(val, SYS_ACTLR_EL1);	return;
> +	case CPACR_EL1:		write_sysreg_s(val, cpacr_EL12);	return;
> +	case TTBR0_EL1:		write_sysreg_s(val, ttbr0_EL12);	return;
> +	case TTBR1_EL1:		write_sysreg_s(val, ttbr1_EL12);	return;
> +	case TCR_EL1:		write_sysreg_s(val, tcr_EL12);		return;
> +	case ESR_EL1:		write_sysreg_s(val, esr_EL12);		return;
> +	case AFSR0_EL1:		write_sysreg_s(val, afsr0_EL12);	return;
> +	case AFSR1_EL1:		write_sysreg_s(val, afsr1_EL12);	return;
> +	case FAR_EL1:		write_sysreg_s(val, far_EL12);		return;
> +	case MAIR_EL1:		write_sysreg_s(val, mair_EL12);		return;
> +	case VBAR_EL1:		write_sysreg_s(val, vbar_EL12);		return;
> +	case CONTEXTIDR_EL1:	write_sysreg_s(val, contextidr_EL12);	return;
> +	case TPIDR_EL0:		write_sysreg_s(val, SYS_TPIDR_EL0);	return;
> +	case TPIDRRO_EL0:	write_sysreg_s(val, SYS_TPIDRRO_EL0);	return;
> +	case TPIDR_EL1:		write_sysreg_s(val, SYS_TPIDR_EL1);	return;
> +	case AMAIR_EL1:		write_sysreg_s(val, amair_EL12);	return;
> +	case CNTKCTL_EL1:	write_sysreg_s(val, cntkctl_EL12);	return;
> +	case PAR_EL1:		write_sysreg_s(val, SYS_PAR_EL1);	return;
>  	}
>  
>  immediate_write:
> -- 
> 2.14.2
> 

Looks good to me otherwise.

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 29/40] KVM: arm64: Prepare to handle deferred save/restore of 32-bit registers
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 15:44     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 15:44 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, 15 Feb 2018 21:03:21 +0000,
Christoffer Dall wrote:
> 
> 32-bit registers are not used by a 64-bit host kernel and can be
> deferred, but we need to rework the accesses to this register to access
> the latest value depending on whether or not guest system registers are
> loaded on the CPU or only reside in memory.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Ah, much nicer than the "clunky" version! :-)

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 29/40] KVM: arm64: Prepare to handle deferred save/restore of 32-bit registers
@ 2018-02-21 15:44     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 15:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 15 Feb 2018 21:03:21 +0000,
Christoffer Dall wrote:
> 
> 32-bit registers are not used by a 64-bit host kernel and can be
> deferred, but we need to rework the accesses to this register to access
> the latest value depending on whether or not guest system registers are
> loaded on the CPU or only reside in memory.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Ah, much nicer than the "clunky" version! :-)

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 30/40] KVM: arm64: Defer saving/restoring 32-bit sysregs to vcpu load/put
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 16:27     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 16:27 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, 15 Feb 2018 21:03:22 +0000,
Christoffer Dall wrote:
> 
> When running a 32-bit VM (EL1 in AArch32), the AArch32 system registers
> can be deferred to vcpu load/put on VHE systems because neither
> the host kernel nor host userspace uses these registers.
> 
> Note that we can not defer saving DBGVCR32_EL2 conditionally based
> on the state of the debug dirty flag on VHE, but since we do the
> load/put pretty rarely, this comes out as a win anyway.

I'm not sure I understand that comment. We don't have any deferring
for this register, so the load/put reference seems out of place.

> 
> We can also not defer saving FPEXC32_32 because this register only holds
> a guest-valid value for 32-bit guests during the exit path when the
> guest has used FPSIMD registers and restored the register in the early
> assembly handler from taking the EL2 fault, and therefore we have to
> check if fpsimd is enabled for the guest in the exit path and save the
> register then, for both VHE and non-VHE guests.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Rework the FPEXC32 save/restore logic to no longer attempt to
>        save/restore this register lazily.
>     
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm64/kvm/hyp/switch.c    | 17 +++++++++++------
>  arch/arm64/kvm/hyp/sysreg-sr.c | 15 ++++++++++-----
>  2 files changed, 21 insertions(+), 11 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 22e77deb8e2e..909aa3fe9196 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -47,6 +47,15 @@ bool __hyp_text __fpsimd_enabled(void)
>  	return __fpsimd_is_enabled()();
>  }
>  
> +/* Save the 32-bit only FPSIMD system register state */
> +static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
> +{
> +	if (!vcpu_el1_is_32bit(vcpu))
> +		return;
> +
> +	vcpu->arch.ctxt.sys_regs[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
> +}
> +
>  static void __hyp_text __activate_traps_vhe(void)
>  {
>  	u64 val;
> @@ -380,11 +389,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  
>  	__vgic_restore_state(vcpu);
>  
> -	/*
> -	 * We must restore the 32-bit state before the sysregs, thanks
> -	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
> -	 */
> -	__sysreg32_restore_state(vcpu);
>  	sysreg_restore_guest_state_vhe(guest_ctxt);
>  	__debug_switch_to_guest(vcpu);
>  
> @@ -398,7 +402,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  	fp_enabled = __fpsimd_enabled();
>  
>  	sysreg_save_guest_state_vhe(guest_ctxt);
> -	__sysreg32_save_state(vcpu);
>  	__vgic_save_state(vcpu);
>  
>  	__deactivate_traps(vcpu);
> @@ -408,6 +411,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  	if (fp_enabled) {
>  		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
>  		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
> +		__fpsimd_save_fpexc32(vcpu);
>  	}
>  
>  	__debug_switch_to_host(vcpu);
> @@ -475,6 +479,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
>  	if (fp_enabled) {
>  		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
>  		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
> +		__fpsimd_save_fpexc32(vcpu);
>  	}
>  
>  	/*
> diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> index 9c60b8062724..aacba4636871 100644
> --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> @@ -196,10 +196,7 @@ void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
>  	sysreg[DACR32_EL2] = read_sysreg(dacr32_el2);
>  	sysreg[IFSR32_EL2] = read_sysreg(ifsr32_el2);
>  
> -	if (__fpsimd_enabled())
> -		sysreg[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
> -
> -	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> +	if (has_vhe() || vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
>  		sysreg[DBGVCR32_EL2] = read_sysreg(dbgvcr32_el2);
>  }
>  
> @@ -221,7 +218,7 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
>  	write_sysreg(sysreg[DACR32_EL2], dacr32_el2);
>  	write_sysreg(sysreg[IFSR32_EL2], ifsr32_el2);
>  
> -	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> +	if (has_vhe() || vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
>  		write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
>  }
>  
> @@ -246,6 +243,13 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
>  
>  	__sysreg_save_user_state(host_ctxt);
>  
> +	/*
> +	 * Load guest EL1 and user state
> +	 *
> +	 * We must restore the 32-bit state before the sysregs, thanks
> +	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
> +	 */
> +	__sysreg32_restore_state(vcpu);
>  	__sysreg_restore_user_state(guest_ctxt);
>  	__sysreg_restore_el1_state(guest_ctxt);
>  
> @@ -273,6 +277,7 @@ void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
>  
>  	__sysreg_save_el1_state(guest_ctxt);
>  	__sysreg_save_user_state(guest_ctxt);
> +	__sysreg32_save_state(vcpu);
>  
>  	/* Restore host user state */
>  	__sysreg_restore_user_state(host_ctxt);
> -- 
> 2.14.2
> 

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 30/40] KVM: arm64: Defer saving/restoring 32-bit sysregs to vcpu load/put
@ 2018-02-21 16:27     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 16:27 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 15 Feb 2018 21:03:22 +0000,
Christoffer Dall wrote:
> 
> When running a 32-bit VM (EL1 in AArch32), the AArch32 system registers
> can be deferred to vcpu load/put on VHE systems because neither
> the host kernel nor host userspace uses these registers.
> 
> Note that we can not defer saving DBGVCR32_EL2 conditionally based
> on the state of the debug dirty flag on VHE, but since we do the
> load/put pretty rarely, this comes out as a win anyway.

I'm not sure I understand that comment. We don't have any deferring
for this register, so the load/put reference seems out of place.

> 
> We can also not defer saving FPEXC32_32 because this register only holds
> a guest-valid value for 32-bit guests during the exit path when the
> guest has used FPSIMD registers and restored the register in the early
> assembly handler from taking the EL2 fault, and therefore we have to
> check if fpsimd is enabled for the guest in the exit path and save the
> register then, for both VHE and non-VHE guests.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Rework the FPEXC32 save/restore logic to no longer attempt to
>        save/restore this register lazily.
>     
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm64/kvm/hyp/switch.c    | 17 +++++++++++------
>  arch/arm64/kvm/hyp/sysreg-sr.c | 15 ++++++++++-----
>  2 files changed, 21 insertions(+), 11 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 22e77deb8e2e..909aa3fe9196 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -47,6 +47,15 @@ bool __hyp_text __fpsimd_enabled(void)
>  	return __fpsimd_is_enabled()();
>  }
>  
> +/* Save the 32-bit only FPSIMD system register state */
> +static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
> +{
> +	if (!vcpu_el1_is_32bit(vcpu))
> +		return;
> +
> +	vcpu->arch.ctxt.sys_regs[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
> +}
> +
>  static void __hyp_text __activate_traps_vhe(void)
>  {
>  	u64 val;
> @@ -380,11 +389,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  
>  	__vgic_restore_state(vcpu);
>  
> -	/*
> -	 * We must restore the 32-bit state before the sysregs, thanks
> -	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
> -	 */
> -	__sysreg32_restore_state(vcpu);
>  	sysreg_restore_guest_state_vhe(guest_ctxt);
>  	__debug_switch_to_guest(vcpu);
>  
> @@ -398,7 +402,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  	fp_enabled = __fpsimd_enabled();
>  
>  	sysreg_save_guest_state_vhe(guest_ctxt);
> -	__sysreg32_save_state(vcpu);
>  	__vgic_save_state(vcpu);
>  
>  	__deactivate_traps(vcpu);
> @@ -408,6 +411,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  	if (fp_enabled) {
>  		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
>  		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
> +		__fpsimd_save_fpexc32(vcpu);
>  	}
>  
>  	__debug_switch_to_host(vcpu);
> @@ -475,6 +479,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
>  	if (fp_enabled) {
>  		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
>  		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
> +		__fpsimd_save_fpexc32(vcpu);
>  	}
>  
>  	/*
> diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> index 9c60b8062724..aacba4636871 100644
> --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> @@ -196,10 +196,7 @@ void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
>  	sysreg[DACR32_EL2] = read_sysreg(dacr32_el2);
>  	sysreg[IFSR32_EL2] = read_sysreg(ifsr32_el2);
>  
> -	if (__fpsimd_enabled())
> -		sysreg[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
> -
> -	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> +	if (has_vhe() || vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
>  		sysreg[DBGVCR32_EL2] = read_sysreg(dbgvcr32_el2);
>  }
>  
> @@ -221,7 +218,7 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
>  	write_sysreg(sysreg[DACR32_EL2], dacr32_el2);
>  	write_sysreg(sysreg[IFSR32_EL2], ifsr32_el2);
>  
> -	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> +	if (has_vhe() || vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
>  		write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
>  }
>  
> @@ -246,6 +243,13 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
>  
>  	__sysreg_save_user_state(host_ctxt);
>  
> +	/*
> +	 * Load guest EL1 and user state
> +	 *
> +	 * We must restore the 32-bit state before the sysregs, thanks
> +	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
> +	 */
> +	__sysreg32_restore_state(vcpu);
>  	__sysreg_restore_user_state(guest_ctxt);
>  	__sysreg_restore_el1_state(guest_ctxt);
>  
> @@ -273,6 +277,7 @@ void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
>  
>  	__sysreg_save_el1_state(guest_ctxt);
>  	__sysreg_save_user_state(guest_ctxt);
> +	__sysreg32_save_state(vcpu);
>  
>  	/* Restore host user state */
>  	__sysreg_restore_user_state(host_ctxt);
> -- 
> 2.14.2
> 

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 01/40] KVM: arm/arm64: Avoid vcpu_load for other vcpu ioctls than KVM_RUN
  2018-02-15 21:02   ` Christoffer Dall
@ 2018-02-21 17:05     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:05 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, kvmarm, Yury Norov, linux-arm-kernel,
	Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:02:53PM +0100, Christoffer Dall wrote:
> Calling vcpu_load() registers preempt notifiers for this vcpu and calls
> kvm_arch_vcpu_load().  The latter will soon be doing a lot of heavy
> lifting on arm/arm64 and will try to do things such as enabling the
> virtual timer and setting us up to handle interrupts from the timer
> hardware.
> 
> Loading state onto hardware registers and enabling hardware to signal
> interrupts can be problematic when we're not actually about to run the
> VCPU, because it makes it difficult to establish the right context when
> handling interrupts from the timer, and it makes the register access
> code difficult to reason about.
> 
> Luckily, now when we call vcpu_load in each ioctl implementation, we can
> simply remove the call from the non-KVM_RUN vcpu ioctls, and our
> kvm_arch_vcpu_load() is only used for loading vcpu content to the
> physical CPU when we're actually going to run the vcpu.
> 
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/kvm/guest.c | 3 ---
>  virt/kvm/arm/arm.c     | 9 ---------
>  2 files changed, 12 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 01/40] KVM: arm/arm64: Avoid vcpu_load for other vcpu ioctls than KVM_RUN
@ 2018-02-21 17:05     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:02:53PM +0100, Christoffer Dall wrote:
> Calling vcpu_load() registers preempt notifiers for this vcpu and calls
> kvm_arch_vcpu_load().  The latter will soon be doing a lot of heavy
> lifting on arm/arm64 and will try to do things such as enabling the
> virtual timer and setting us up to handle interrupts from the timer
> hardware.
> 
> Loading state onto hardware registers and enabling hardware to signal
> interrupts can be problematic when we're not actually about to run the
> VCPU, because it makes it difficult to establish the right context when
> handling interrupts from the timer, and it makes the register access
> code difficult to reason about.
> 
> Luckily, now when we call vcpu_load in each ioctl implementation, we can
> simply remove the call from the non-KVM_RUN vcpu ioctls, and our
> kvm_arch_vcpu_load() is only used for loading vcpu content to the
> physical CPU when we're actually going to run the vcpu.
> 
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/kvm/guest.c | 3 ---
>  virt/kvm/arm/arm.c     | 9 ---------
>  2 files changed, 12 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
  2018-02-15 21:02   ` Christoffer Dall
@ 2018-02-21 17:32     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:32 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Ard Biesheuvel, Marc Zyngier, Tomasz Nowicki, kvmarm,
	Julien Grall, Yury Norov, linux-arm-kernel, Dave Martin,
	Shih-Wei Li

On Thu, Feb 15, 2018 at 10:02:55PM +0100, Christoffer Dall wrote:
> We already have the percpu area for the host cpu state, which points to
> the VCPU, so there's no need to store the VCPU pointer on the stack on
> every context switch.  We can be a little more clever and just use
> tpidr_el2 for the percpu offset and load the VCPU pointer from the host
> context.
> 
> This does require us to calculate the percpu offset without including
> the offset from the kernel mapping of the percpu array to the linear
> mapping of the array (which is what we store in tpidr_el1), because a
> PC-relative generated address in EL2 is already giving us the hyp alias
> of the linear mapping of a kernel address.  We do this in
> __cpu_init_hyp_mode() by using kvm_ksym_ref().
> 
> This change also requires us to have a scratch register, so we take the
> chance to rearrange some of the el1_sync code to only look at the
> vttbr_el2 to determine if this is a trap from the guest or an HVC from
> the host.  We do add an extra check to call the panic code if the kernel
> is configured with debugging enabled and we saw a trap from the host
> which wasn't an HVC, indicating that we left some EL2 trap configured by
> mistake.
> 
> The code that accesses ESR_EL2 was previously using an alternative to
> use the _EL1 accessor on VHE systems, but this was actually unnecessary
> as the _EL1 accessor aliases the ESR_EL2 register on VHE, and the _EL2
> accessor does the same thing on both systems.
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Reworked the assembly part of the patch after rebasing on v4.16-rc1
>        which created a conflict with the variant 2 mitigations.
>      - Removed Marc's reviewed-by due to the rework.
>      - Removed unneeded extern keyword in declaration in header file
>     
>     Changes since v1:
>      - Use PC-relative addressing to access per-cpu variables instead of
>        using a load from the literal pool.
>      - Remove stale comments as pointed out by Marc
>      - Reworded the commit message as suggested by Drew
> 
>  arch/arm64/include/asm/kvm_asm.h  | 14 ++++++++++++++
>  arch/arm64/include/asm/kvm_host.h | 15 +++++++++++++++
>  arch/arm64/kernel/asm-offsets.c   |  1 +
>  arch/arm64/kvm/hyp/entry.S        |  6 +-----
>  arch/arm64/kvm/hyp/hyp-entry.S    | 31 +++++++++++++------------------
>  arch/arm64/kvm/hyp/switch.c       |  5 +----
>  arch/arm64/kvm/hyp/sysreg-sr.c    |  5 +++++
>  7 files changed, 50 insertions(+), 27 deletions(-)
> 

I'm not clear on the motivation for this patch. I assumed it enabled
simpler patches later in the series, but I did a bit of reading ahead
and didn't see anything obvious. I doubt it gives a speedup, so is it
just to avoid stack use? Making it easier to maintain these assembly
functions that span a couple files? If so, should it be posted separately
from this series? If not, could you please add some more text to the
commit message helping me better understand the full motivation?

Besides my confusion on motivation, it looks good to me

Reviewed-by: Andrew Jones <drjones@redhat.com>

Thanks,
drew

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

* [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
@ 2018-02-21 17:32     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:02:55PM +0100, Christoffer Dall wrote:
> We already have the percpu area for the host cpu state, which points to
> the VCPU, so there's no need to store the VCPU pointer on the stack on
> every context switch.  We can be a little more clever and just use
> tpidr_el2 for the percpu offset and load the VCPU pointer from the host
> context.
> 
> This does require us to calculate the percpu offset without including
> the offset from the kernel mapping of the percpu array to the linear
> mapping of the array (which is what we store in tpidr_el1), because a
> PC-relative generated address in EL2 is already giving us the hyp alias
> of the linear mapping of a kernel address.  We do this in
> __cpu_init_hyp_mode() by using kvm_ksym_ref().
> 
> This change also requires us to have a scratch register, so we take the
> chance to rearrange some of the el1_sync code to only look at the
> vttbr_el2 to determine if this is a trap from the guest or an HVC from
> the host.  We do add an extra check to call the panic code if the kernel
> is configured with debugging enabled and we saw a trap from the host
> which wasn't an HVC, indicating that we left some EL2 trap configured by
> mistake.
> 
> The code that accesses ESR_EL2 was previously using an alternative to
> use the _EL1 accessor on VHE systems, but this was actually unnecessary
> as the _EL1 accessor aliases the ESR_EL2 register on VHE, and the _EL2
> accessor does the same thing on both systems.
> 
> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Reworked the assembly part of the patch after rebasing on v4.16-rc1
>        which created a conflict with the variant 2 mitigations.
>      - Removed Marc's reviewed-by due to the rework.
>      - Removed unneeded extern keyword in declaration in header file
>     
>     Changes since v1:
>      - Use PC-relative addressing to access per-cpu variables instead of
>        using a load from the literal pool.
>      - Remove stale comments as pointed out by Marc
>      - Reworded the commit message as suggested by Drew
> 
>  arch/arm64/include/asm/kvm_asm.h  | 14 ++++++++++++++
>  arch/arm64/include/asm/kvm_host.h | 15 +++++++++++++++
>  arch/arm64/kernel/asm-offsets.c   |  1 +
>  arch/arm64/kvm/hyp/entry.S        |  6 +-----
>  arch/arm64/kvm/hyp/hyp-entry.S    | 31 +++++++++++++------------------
>  arch/arm64/kvm/hyp/switch.c       |  5 +----
>  arch/arm64/kvm/hyp/sysreg-sr.c    |  5 +++++
>  7 files changed, 50 insertions(+), 27 deletions(-)
> 

I'm not clear on the motivation for this patch. I assumed it enabled
simpler patches later in the series, but I did a bit of reading ahead
and didn't see anything obvious. I doubt it gives a speedup, so is it
just to avoid stack use? Making it easier to maintain these assembly
functions that span a couple files? If so, should it be posted separately
from this series? If not, could you please add some more text to the
commit message helping me better understand the full motivation?

Besides my confusion on motivation, it looks good to me

Reviewed-by: Andrew Jones <drjones@redhat.com>

Thanks,
drew

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

* Re: [PATCH v4 04/40] KVM: arm64: Rework hyp_panic for VHE and non-VHE
  2018-02-15 21:02   ` Christoffer Dall
@ 2018-02-21 17:32     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:32 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:02:56PM +0100, Christoffer Dall wrote:
> VHE actually doesn't rely on clearing the VTTBR when returning to the
> host kernel, and that is the current key mechanism of hyp_panic to
> figure out how to attempt to return to a state good enough to print a
> panic statement.
> 
> Therefore, we split the hyp_panic function into two functions, a VHE and
> a non-VHE, keeping the non-VHE version intact, but changing the VHE
> behavior.
> 
> The vttbr_el2 check on VHE doesn't really make that much sense, because
> the only situation where we can get here on VHE is when the hypervisor
> assembly code actually called into hyp_panic, which only happens when
> VBAR_EL2 has been set to the KVM exception vectors.  On VHE, we can
> always safely disable the traps and restore the host registers at this
> point, so we simply do that unconditionally and call into the panic
> function directly.
> 
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v1:
>      - Fixed typos in the commit message
>      - Still use the generic __deactivte_traps() function in the hyp panic
>        code until we rework that logic later.
> 
>  arch/arm64/kvm/hyp/switch.c | 42 +++++++++++++++++++++++-------------------
>  1 file changed, 23 insertions(+), 19 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 04/40] KVM: arm64: Rework hyp_panic for VHE and non-VHE
@ 2018-02-21 17:32     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:02:56PM +0100, Christoffer Dall wrote:
> VHE actually doesn't rely on clearing the VTTBR when returning to the
> host kernel, and that is the current key mechanism of hyp_panic to
> figure out how to attempt to return to a state good enough to print a
> panic statement.
> 
> Therefore, we split the hyp_panic function into two functions, a VHE and
> a non-VHE, keeping the non-VHE version intact, but changing the VHE
> behavior.
> 
> The vttbr_el2 check on VHE doesn't really make that much sense, because
> the only situation where we can get here on VHE is when the hypervisor
> assembly code actually called into hyp_panic, which only happens when
> VBAR_EL2 has been set to the KVM exception vectors.  On VHE, we can
> always safely disable the traps and restore the host registers at this
> point, so we simply do that unconditionally and call into the panic
> function directly.
> 
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v1:
>      - Fixed typos in the commit message
>      - Still use the generic __deactivte_traps() function in the hyp panic
>        code until we rework that logic later.
> 
>  arch/arm64/kvm/hyp/switch.c | 42 +++++++++++++++++++++++-------------------
>  1 file changed, 23 insertions(+), 19 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 08/40] KVM: arm/arm64: Introduce vcpu_el1_is_32bit
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 17:34     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:34 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:00PM +0100, Christoffer Dall wrote:
> We have numerous checks around that checks if the HCR_EL2 has the RW bit
> set to figure out if we're running an AArch64 or AArch32 VM.  In some
> cases, directly checking the RW bit (given its unintuitive name), is a
> bit confusing, and that's not going to improve as we move logic around
> for the following patches that optimize KVM on AArch64 hosts with VHE.
> 
> Therefore, introduce a helper, vcpu_el1_is_32bit, and replace existing
> direct checks of HCR_EL2.RW with the helper.
> 
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v2:
>      - New patch
>     
>     Changes since v1:
>      - Reworded comments as suggested by Drew
> 
>  arch/arm64/include/asm/kvm_emulate.h |  7 ++++++-
>  arch/arm64/kvm/hyp/switch.c          | 11 +++++------
>  arch/arm64/kvm/hyp/sysreg-sr.c       |  5 +++--
>  arch/arm64/kvm/inject_fault.c        |  6 +++---
>  4 files changed, 17 insertions(+), 12 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 08/40] KVM: arm/arm64: Introduce vcpu_el1_is_32bit
@ 2018-02-21 17:34     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:00PM +0100, Christoffer Dall wrote:
> We have numerous checks around that checks if the HCR_EL2 has the RW bit
> set to figure out if we're running an AArch64 or AArch32 VM.  In some
> cases, directly checking the RW bit (given its unintuitive name), is a
> bit confusing, and that's not going to improve as we move logic around
> for the following patches that optimize KVM on AArch64 hosts with VHE.
> 
> Therefore, introduce a helper, vcpu_el1_is_32bit, and replace existing
> direct checks of HCR_EL2.RW with the helper.
> 
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v2:
>      - New patch
>     
>     Changes since v1:
>      - Reworded comments as suggested by Drew
> 
>  arch/arm64/include/asm/kvm_emulate.h |  7 ++++++-
>  arch/arm64/kvm/hyp/switch.c          | 11 +++++------
>  arch/arm64/kvm/hyp/sysreg-sr.c       |  5 +++--
>  arch/arm64/kvm/inject_fault.c        |  6 +++---
>  4 files changed, 17 insertions(+), 12 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 09/40] KVM: arm64: Move debug dirty flag calculation out of world switch
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 17:35     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:35 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:01PM +0100, Christoffer Dall wrote:
> There is no need to figure out inside the world-switch if we should
> save/restore the debug registers or not, we might as well do that in the
> higher level debug setup code, making it easier to optimize down the
> line.
> 
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/kvm/debug.c        | 5 +++++
>  arch/arm64/kvm/hyp/debug-sr.c | 6 ------
>  2 files changed, 5 insertions(+), 6 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 09/40] KVM: arm64: Move debug dirty flag calculation out of world switch
@ 2018-02-21 17:35     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:01PM +0100, Christoffer Dall wrote:
> There is no need to figure out inside the world-switch if we should
> save/restore the debug registers or not, we might as well do that in the
> higher level debug setup code, making it easier to optimize down the
> line.
> 
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/kvm/debug.c        | 5 +++++
>  arch/arm64/kvm/hyp/debug-sr.c | 6 ------
>  2 files changed, 5 insertions(+), 6 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 10/40] KVM: arm64: Slightly improve debug save/restore functions
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 17:39     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:39 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:02PM +0100, Christoffer Dall wrote:
> The debug save/restore functions can be improved by using the has_vhe()
> static key instead of the instruction alternative.  Using the static key
> uses the same paradigm as we're going to use elsewhere, it makes the
> code more readable, and it generates slightly better code (no
> stack setups and function calls unless necessary).
> 
> We also use a static key on the restore path, because it will be
> marginally faster than loading a value from memory.
> 
> Finally, we don't have to conditionally clear the debug dirty flag if
> it's set, we can just clear it.
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v1:
>      - Change dot to comma in comment
>      - Rename __debug_restore_spe to __debug_restore_spe_nvhe
> 
>  arch/arm64/kvm/hyp/debug-sr.c | 26 ++++++++++++--------------
>  1 file changed, 12 insertions(+), 14 deletions(-)
>

Maybe after this series is merged, if there are any hyp_alternate_select's
left, we can replace all the remaining ones with has_vhe() and then just
completely remove hyp_alternate_select.

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 10/40] KVM: arm64: Slightly improve debug save/restore functions
@ 2018-02-21 17:39     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:02PM +0100, Christoffer Dall wrote:
> The debug save/restore functions can be improved by using the has_vhe()
> static key instead of the instruction alternative.  Using the static key
> uses the same paradigm as we're going to use elsewhere, it makes the
> code more readable, and it generates slightly better code (no
> stack setups and function calls unless necessary).
> 
> We also use a static key on the restore path, because it will be
> marginally faster than loading a value from memory.
> 
> Finally, we don't have to conditionally clear the debug dirty flag if
> it's set, we can just clear it.
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v1:
>      - Change dot to comma in comment
>      - Rename __debug_restore_spe to __debug_restore_spe_nvhe
> 
>  arch/arm64/kvm/hyp/debug-sr.c | 26 ++++++++++++--------------
>  1 file changed, 12 insertions(+), 14 deletions(-)
>

Maybe after this series is merged, if there are any hyp_alternate_select's
left, we can replace all the remaining ones with has_vhe() and then just
completely remove hyp_alternate_select.

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 11/40] KVM: arm64: Improve debug register save/restore flow
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 17:40     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:40 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:03PM +0100, Christoffer Dall wrote:
> Instead of having multiple calls from the world switch path to the debug
> logic, each figuring out if the dirty bit is set and if we should
> save/restore the debug registers, let's just provide two hooks to the
> debug save/restore functionality, one for switching to the guest
> context, and one for switching to the host context, and we get the
> benefit of only having to evaluate the dirty flag once on each path,
> plus we give the compiler some more room to inline some of this
> functionality.
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v1:
>      - Remove leading underscores from local variables
> 
>  arch/arm64/include/asm/kvm_hyp.h | 10 ++-----
>  arch/arm64/kvm/hyp/debug-sr.c    | 56 +++++++++++++++++++++++++++-------------
>  arch/arm64/kvm/hyp/switch.c      |  6 ++---
>  3 files changed, 42 insertions(+), 30 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 11/40] KVM: arm64: Improve debug register save/restore flow
@ 2018-02-21 17:40     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:03PM +0100, Christoffer Dall wrote:
> Instead of having multiple calls from the world switch path to the debug
> logic, each figuring out if the dirty bit is set and if we should
> save/restore the debug registers, let's just provide two hooks to the
> debug save/restore functionality, one for switching to the guest
> context, and one for switching to the host context, and we get the
> benefit of only having to evaluate the dirty flag once on each path,
> plus we give the compiler some more room to inline some of this
> functionality.
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v1:
>      - Remove leading underscores from local variables
> 
>  arch/arm64/include/asm/kvm_hyp.h | 10 ++-----
>  arch/arm64/kvm/hyp/debug-sr.c    | 56 +++++++++++++++++++++++++++-------------
>  arch/arm64/kvm/hyp/switch.c      |  6 ++---
>  3 files changed, 42 insertions(+), 30 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 12/40] KVM: arm64: Factor out fault info population and gic workarounds
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 17:41     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:41 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:04PM +0100, Christoffer Dall wrote:
> The current world-switch function has functionality to detect a number
> of cases where we need to fixup some part of the exit condition and
> possibly run the guest again, before having restored the host state.
> 
> This includes populating missing fault info, emulating GICv2 CPU
> interface accesses when mapped at unaligned addresses, and emulating
> the GICv3 CPU interface on systems that need it.
> 
> As we are about to have an alternative switch function for VHE systems,
> but VHE systems still need the same early fixup logic, factor out this
> logic into a separate function that can be shared by both switch
> functions.
> 
> No functional change.
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/kvm/hyp/switch.c | 104 ++++++++++++++++++++++++--------------------
>  1 file changed, 57 insertions(+), 47 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 12/40] KVM: arm64: Factor out fault info population and gic workarounds
@ 2018-02-21 17:41     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:04PM +0100, Christoffer Dall wrote:
> The current world-switch function has functionality to detect a number
> of cases where we need to fixup some part of the exit condition and
> possibly run the guest again, before having restored the host state.
> 
> This includes populating missing fault info, emulating GICv2 CPU
> interface accesses when mapped at unaligned addresses, and emulating
> the GICv3 CPU interface on systems that need it.
> 
> As we are about to have an alternative switch function for VHE systems,
> but VHE systems still need the same early fixup logic, factor out this
> logic into a separate function that can be shared by both switch
> functions.
> 
> No functional change.
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/kvm/hyp/switch.c | 104 ++++++++++++++++++++++++--------------------
>  1 file changed, 57 insertions(+), 47 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 13/40] KVM: arm64: Introduce VHE-specific kvm_vcpu_run
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 17:43     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:43 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:05PM +0100, Christoffer Dall wrote:
> So far this is mostly (see below) a copy of the legacy non-VHE switch
> function, but we will start reworking these functions in separate
> directions to work on VHE and non-VHE in the most optimal way in later
> patches.
> 
> The only difference after this patch between the VHE and non-VHE run
> functions is that we omit the branch-predictor variant-2 hardening for
> QC Falkor CPUs, because this workaround is specific to a series of
> non-VHE ARMv8.0 CPUs.
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Added BUG() to 32-bit ARM VHE run function
>      - Omitted QC Falkor BP Hardening functionality from VHE-specific
>        function
>     
>     Changes since v2:
>      - Reworded commit message
>     
>     Changes since v1:
>      - Rename kvm_vcpu_run to kvm_vcpu_run_vhe and rename __kvm_vcpu_run to
>        __kvm_vcpu_run_nvhe
>      - Removed stray whitespace line
> 
>  arch/arm/include/asm/kvm_asm.h   |  5 ++-
>  arch/arm/kvm/hyp/switch.c        |  2 +-
>  arch/arm64/include/asm/kvm_asm.h |  4 ++-
>  arch/arm64/kvm/hyp/switch.c      | 66 +++++++++++++++++++++++++++++++++++++++-
>  virt/kvm/arm/arm.c               |  5 ++-
>  5 files changed, 77 insertions(+), 5 deletions(-)
> 

...

> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> index 2062d9357971..5bd879c78951 100644
> --- a/virt/kvm/arm/arm.c
> +++ b/virt/kvm/arm/arm.c
> @@ -736,7 +736,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  		if (has_vhe())
>  			kvm_arm_vhe_guest_enter();
>  
> -		ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);
> +		if (has_vhe())
> +			ret = kvm_vcpu_run_vhe(vcpu);
> +		else
> +			ret = kvm_call_hyp(__kvm_vcpu_run_nvhe, vcpu);
>  
>  		if (has_vhe())
>  			kvm_arm_vhe_guest_exit();

We can combine these has_vhe()'s

 if (has_vhe()) {
    kvm_arm_vhe_guest_enter();
    ret = kvm_vcpu_run_vhe(vcpu);
    kvm_arm_vhe_guest_exit();
 } else
    ret = kvm_call_hyp(__kvm_vcpu_run_nvhe, vcpu);

Thanks,
drew

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

* [PATCH v4 13/40] KVM: arm64: Introduce VHE-specific kvm_vcpu_run
@ 2018-02-21 17:43     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:05PM +0100, Christoffer Dall wrote:
> So far this is mostly (see below) a copy of the legacy non-VHE switch
> function, but we will start reworking these functions in separate
> directions to work on VHE and non-VHE in the most optimal way in later
> patches.
> 
> The only difference after this patch between the VHE and non-VHE run
> functions is that we omit the branch-predictor variant-2 hardening for
> QC Falkor CPUs, because this workaround is specific to a series of
> non-VHE ARMv8.0 CPUs.
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Added BUG() to 32-bit ARM VHE run function
>      - Omitted QC Falkor BP Hardening functionality from VHE-specific
>        function
>     
>     Changes since v2:
>      - Reworded commit message
>     
>     Changes since v1:
>      - Rename kvm_vcpu_run to kvm_vcpu_run_vhe and rename __kvm_vcpu_run to
>        __kvm_vcpu_run_nvhe
>      - Removed stray whitespace line
> 
>  arch/arm/include/asm/kvm_asm.h   |  5 ++-
>  arch/arm/kvm/hyp/switch.c        |  2 +-
>  arch/arm64/include/asm/kvm_asm.h |  4 ++-
>  arch/arm64/kvm/hyp/switch.c      | 66 +++++++++++++++++++++++++++++++++++++++-
>  virt/kvm/arm/arm.c               |  5 ++-
>  5 files changed, 77 insertions(+), 5 deletions(-)
> 

...

> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> index 2062d9357971..5bd879c78951 100644
> --- a/virt/kvm/arm/arm.c
> +++ b/virt/kvm/arm/arm.c
> @@ -736,7 +736,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  		if (has_vhe())
>  			kvm_arm_vhe_guest_enter();
>  
> -		ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);
> +		if (has_vhe())
> +			ret = kvm_vcpu_run_vhe(vcpu);
> +		else
> +			ret = kvm_call_hyp(__kvm_vcpu_run_nvhe, vcpu);
>  
>  		if (has_vhe())
>  			kvm_arm_vhe_guest_exit();

We can combine these has_vhe()'s

 if (has_vhe()) {
    kvm_arm_vhe_guest_enter();
    ret = kvm_vcpu_run_vhe(vcpu);
    kvm_arm_vhe_guest_exit();
 } else
    ret = kvm_call_hyp(__kvm_vcpu_run_nvhe, vcpu);

Thanks,
drew

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

* Re: [PATCH v4 16/40] KVM: arm64: Remove noop calls to timer save/restore from VHE switch
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 17:43     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:43 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:08PM +0100, Christoffer Dall wrote:
> The VHE switch function calls __timer_enable_traps and
> __timer_disable_traps which don't do anything on VHE systems.
> Therefore, simply remove these calls from the VHE switch function and
> make the functions non-conditional as they are now only called from the
> non-VHE switch path.
> 
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v2:
>      - Added comment explaining the timer enable/disable functions
>        are for !VHE only.
> 
>  arch/arm64/kvm/hyp/switch.c |  2 --
>  virt/kvm/arm/hyp/timer-sr.c | 44 ++++++++++++++++++++++----------------------
>  2 files changed, 22 insertions(+), 24 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 16/40] KVM: arm64: Remove noop calls to timer save/restore from VHE switch
@ 2018-02-21 17:43     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:08PM +0100, Christoffer Dall wrote:
> The VHE switch function calls __timer_enable_traps and
> __timer_disable_traps which don't do anything on VHE systems.
> Therefore, simply remove these calls from the VHE switch function and
> make the functions non-conditional as they are now only called from the
> non-VHE switch path.
> 
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v2:
>      - Added comment explaining the timer enable/disable functions
>        are for !VHE only.
> 
>  arch/arm64/kvm/hyp/switch.c |  2 --
>  virt/kvm/arm/hyp/timer-sr.c | 44 ++++++++++++++++++++++----------------------
>  2 files changed, 22 insertions(+), 24 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 18/40] KVM: arm64: Rewrite sysreg alternatives to static keys
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 17:44     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:44 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, kvmarm, Yury Norov, linux-arm-kernel,
	Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:10PM +0100, Christoffer Dall wrote:
> As we are about to move calls around in the sysreg save/restore logic,
> let's first rewrite the alternative function callers, because it is
> going to make the next patches much easier to read.
> 
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/kvm/hyp/sysreg-sr.c | 17 ++++-------------
>  1 file changed, 4 insertions(+), 13 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 18/40] KVM: arm64: Rewrite sysreg alternatives to static keys
@ 2018-02-21 17:44     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:10PM +0100, Christoffer Dall wrote:
> As we are about to move calls around in the sysreg save/restore logic,
> let's first rewrite the alternative function callers, because it is
> going to make the next patches much easier to read.
> 
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/kvm/hyp/sysreg-sr.c | 17 ++++-------------
>  1 file changed, 4 insertions(+), 13 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 20/40] KVM: arm/arm64: Remove leftover comment from kvm_vcpu_run_vhe
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 17:47     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:47 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, kvmarm, Yury Norov, linux-arm-kernel,
	Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:12PM +0100, Christoffer Dall wrote:
> The comment only applied to SPE on non-VHE systems, so we simply remove
> it.
> 
> Suggested-by: Andrew Jones <drjones@redhat.com>
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/kvm/hyp/switch.c | 4 ----
>  1 file changed, 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 717c8f5c6be7..a99224996e33 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -410,10 +410,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
>  	}
>  
> -	/*
> -	 * This must come after restoring the host sysregs, since a non-VHE
> -	 * system may enable SPE here and make use of the TTBRs.
> -	 */
>  	__debug_switch_to_host(vcpu);
>  
>  	return exit_code;
> -- 
> 2.14.2
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 20/40] KVM: arm/arm64: Remove leftover comment from kvm_vcpu_run_vhe
@ 2018-02-21 17:47     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:12PM +0100, Christoffer Dall wrote:
> The comment only applied to SPE on non-VHE systems, so we simply remove
> it.
> 
> Suggested-by: Andrew Jones <drjones@redhat.com>
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/kvm/hyp/switch.c | 4 ----
>  1 file changed, 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 717c8f5c6be7..a99224996e33 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -410,10 +410,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
>  	}
>  
> -	/*
> -	 * This must come after restoring the host sysregs, since a non-VHE
> -	 * system may enable SPE here and make use of the TTBRs.
> -	 */
>  	__debug_switch_to_host(vcpu);
>  
>  	return exit_code;
> -- 
> 2.14.2
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 22/40] KVM: arm64: Don't save the host ELR_EL2 and SPSR_EL2 on VHE systems
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 17:49     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:49 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:14PM +0100, Christoffer Dall wrote:
> On non-VHE systems we need to save the ELR_EL2 and SPSR_EL2 so that we can
> return to the host in EL1 in the same state and location where we issued a
> hypercall to EL2, but on VHE ELR_EL2 and SPSR_EL2 are not useful because we
> never enter a guest as a result of an exception entry that would be directly
> handled by KVM. The kernel entry code already saves ELR_EL1/SPSR_EL1 on
> exception entry, which is enough.  Therefore, factor out these registers into
> separate save/restore functions, making it easy to exclude them from the VHE
> world-switch path later on.
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/kvm/hyp/sysreg-sr.c | 13 +++++++++++++
>  1 file changed, 13 insertions(+)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 22/40] KVM: arm64: Don't save the host ELR_EL2 and SPSR_EL2 on VHE systems
@ 2018-02-21 17:49     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 17:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:14PM +0100, Christoffer Dall wrote:
> On non-VHE systems we need to save the ELR_EL2 and SPSR_EL2 so that we can
> return to the host in EL1 in the same state and location where we issued a
> hypercall to EL2, but on VHE ELR_EL2 and SPSR_EL2 are not useful because we
> never enter a guest as a result of an exception entry that would be directly
> handled by KVM. The kernel entry code already saves ELR_EL1/SPSR_EL1 on
> exception entry, which is enough.  Therefore, factor out these registers into
> separate save/restore functions, making it easy to exclude them from the VHE
> world-switch path later on.
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/kvm/hyp/sysreg-sr.c | 13 +++++++++++++
>  1 file changed, 13 insertions(+)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 10/40] KVM: arm64: Slightly improve debug save/restore functions
  2018-02-21 17:39     ` Andrew Jones
@ 2018-02-21 17:52       ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 17:52 UTC (permalink / raw)
  To: Andrew Jones, Christoffer Dall
  Cc: kvm, Tomasz Nowicki, kvmarm, Julien Grall, Yury Norov,
	linux-arm-kernel, Dave Martin, Shih-Wei Li

On 21/02/18 17:39, Andrew Jones wrote:
> On Thu, Feb 15, 2018 at 10:03:02PM +0100, Christoffer Dall wrote:
>> The debug save/restore functions can be improved by using the has_vhe()
>> static key instead of the instruction alternative.  Using the static key
>> uses the same paradigm as we're going to use elsewhere, it makes the
>> code more readable, and it generates slightly better code (no
>> stack setups and function calls unless necessary).
>>
>> We also use a static key on the restore path, because it will be
>> marginally faster than loading a value from memory.
>>
>> Finally, we don't have to conditionally clear the debug dirty flag if
>> it's set, we can just clear it.
>>
>> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> ---
>>
>> Notes:
>>     Changes since v1:
>>      - Change dot to comma in comment
>>      - Rename __debug_restore_spe to __debug_restore_spe_nvhe
>>
>>  arch/arm64/kvm/hyp/debug-sr.c | 26 ++++++++++++--------------
>>  1 file changed, 12 insertions(+), 14 deletions(-)
>>
> 
> Maybe after this series is merged, if there are any hyp_alternate_select's
> left, we can replace all the remaining ones with has_vhe() and then just
> completely remove hyp_alternate_select.

Note that older compilers (such as GCC 4.8) will generate horrible code
with static keys, as they do not support "asm goto". Not that I want to
preserve the home brew hyp_alternate_select mechanism, but I just want
to make it plain that some distros will definitely suffer from the
transition.

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v4 10/40] KVM: arm64: Slightly improve debug save/restore functions
@ 2018-02-21 17:52       ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 17:52 UTC (permalink / raw)
  To: linux-arm-kernel

On 21/02/18 17:39, Andrew Jones wrote:
> On Thu, Feb 15, 2018 at 10:03:02PM +0100, Christoffer Dall wrote:
>> The debug save/restore functions can be improved by using the has_vhe()
>> static key instead of the instruction alternative.  Using the static key
>> uses the same paradigm as we're going to use elsewhere, it makes the
>> code more readable, and it generates slightly better code (no
>> stack setups and function calls unless necessary).
>>
>> We also use a static key on the restore path, because it will be
>> marginally faster than loading a value from memory.
>>
>> Finally, we don't have to conditionally clear the debug dirty flag if
>> it's set, we can just clear it.
>>
>> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>> ---
>>
>> Notes:
>>     Changes since v1:
>>      - Change dot to comma in comment
>>      - Rename __debug_restore_spe to __debug_restore_spe_nvhe
>>
>>  arch/arm64/kvm/hyp/debug-sr.c | 26 ++++++++++++--------------
>>  1 file changed, 12 insertions(+), 14 deletions(-)
>>
> 
> Maybe after this series is merged, if there are any hyp_alternate_select's
> left, we can replace all the remaining ones with has_vhe() and then just
> completely remove hyp_alternate_select.

Note that older compilers (such as GCC 4.8) will generate horrible code
with static keys, as they do not support "asm goto". Not that I want to
preserve the home brew hyp_alternate_select mechanism, but I just want
to make it plain that some distros will definitely suffer from the
transition.

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 31/40] KVM: arm64: Move common VHE/non-VHE trap config in separate functions
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 17:59     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 17:59 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, 15 Feb 2018 21:03:23 +0000,
Christoffer Dall wrote:
> 
> As we are about to be more lazy with some of the trap configuration
> register read/writes for VHE systems, move the logic that is currently
> shared between VHE and non-VHE into a separate function which can be
> called from either the world-switch path or from vcpu_load/vcpu_put.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Separate fpsimd32 trap configuration into a separate function
>        which is still called from __activate_traps, because we no longer
>        defer saving/restoring of VFP registers to load/put.
> 
>  arch/arm64/kvm/hyp/switch.c | 76 +++++++++++++++++++++++++++------------------
>  1 file changed, 45 insertions(+), 31 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 909aa3fe9196..17e3c6f26a34 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -56,7 +56,45 @@ static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
>  	vcpu->arch.ctxt.sys_regs[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
>  }
>  
> -static void __hyp_text __activate_traps_vhe(void)
> +static void __hyp_text __activate_traps_fpsimd32(struct kvm_vcpu *vcpu)
> +{
> +	/*
> +	 * We are about to set CPTR_EL2.TFP to trap all floating point
> +	 * register accesses to EL2, however, the ARM ARM clearly states that
> +	 * traps are only taken to EL2 if the operation would not otherwise
> +	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> +	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> +	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> +	 * it will cause an exception.
> +	 */
> +	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> +		write_sysreg(1 << 30, fpexc32_el2);
> +		isb();
> +	}
> +}
> +
> +static void __hyp_text __activate_traps_common(struct kvm_vcpu *vcpu)
> +{
> +	/* Trap on AArch32 cp15 c15 (impdef sysregs) accesses (EL1 or EL0) */
> +	write_sysreg(1 << 15, hstr_el2);
> +	/*
> +	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> +	 * PMSELR_EL0 to make sure it never contains the cycle
> +	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> +	 * EL1 instead of being trapped to EL2.
> +	 */
> +	write_sysreg(0, pmselr_el0);
> +	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> +	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> +}
> +
> +static void __hyp_text __deactivate_traps_common(void)
> +{
> +	write_sysreg(0, hstr_el2);
> +	write_sysreg(0, pmuserenr_el0);
> +}
> +
> +static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
>  {
>  	u64 val;
>  
> @@ -68,7 +106,7 @@ static void __hyp_text __activate_traps_vhe(void)
>  	write_sysreg(kvm_get_hyp_vector(), vbar_el1);
>  }
>  
> -static void __hyp_text __activate_traps_nvhe(void)
> +static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)

I have the ugly feeling that this hunk should not be in this
patch. Have you tried bisecting the compilation of this series?

>  {
>  	u64 val;
>  
> @@ -85,37 +123,14 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
>  {
>  	u64 hcr = vcpu->arch.hcr_el2;
>  
> -	/*
> -	 * We are about to set CPTR_EL2.TFP to trap all floating point
> -	 * register accesses to EL2, however, the ARM ARM clearly states that
> -	 * traps are only taken to EL2 if the operation would not otherwise
> -	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> -	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> -	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> -	 * it will cause an exception.
> -	 */
> -	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> -		write_sysreg(1 << 30, fpexc32_el2);
> -		isb();
> -	}
> +	write_sysreg(hcr, hcr_el2);
>  
>  	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
>  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
>  
> -	write_sysreg(hcr, hcr_el2);
> -
> -	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
> -	write_sysreg(1 << 15, hstr_el2);
> -	/*
> -	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> -	 * PMSELR_EL0 to make sure it never contains the cycle
> -	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> -	 * EL1 instead of being trapped to EL2.
> -	 */
> -	write_sysreg(0, pmselr_el0);
> -	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> -	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> -	__activate_traps_arch()();
> +	__activate_traps_fpsimd32(vcpu);
> +	__activate_traps_common(vcpu);
> +	__activate_traps_arch()(vcpu);
>  }
>  
>  static void __hyp_text __deactivate_traps_vhe(void)
> @@ -160,9 +175,8 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
>  	if (vcpu->arch.hcr_el2 & HCR_VSE)
>  		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
>  
> +	__deactivate_traps_common();
>  	__deactivate_traps_arch()();
> -	write_sysreg(0, hstr_el2);
> -	write_sysreg(0, pmuserenr_el0);
>  }
>  
>  static void __hyp_text __activate_vm(struct kvm *kvm)
> -- 
> 2.14.2
> 

Otherwise:

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 31/40] KVM: arm64: Move common VHE/non-VHE trap config in separate functions
@ 2018-02-21 17:59     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 17:59 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 15 Feb 2018 21:03:23 +0000,
Christoffer Dall wrote:
> 
> As we are about to be more lazy with some of the trap configuration
> register read/writes for VHE systems, move the logic that is currently
> shared between VHE and non-VHE into a separate function which can be
> called from either the world-switch path or from vcpu_load/vcpu_put.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Separate fpsimd32 trap configuration into a separate function
>        which is still called from __activate_traps, because we no longer
>        defer saving/restoring of VFP registers to load/put.
> 
>  arch/arm64/kvm/hyp/switch.c | 76 +++++++++++++++++++++++++++------------------
>  1 file changed, 45 insertions(+), 31 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 909aa3fe9196..17e3c6f26a34 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -56,7 +56,45 @@ static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
>  	vcpu->arch.ctxt.sys_regs[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
>  }
>  
> -static void __hyp_text __activate_traps_vhe(void)
> +static void __hyp_text __activate_traps_fpsimd32(struct kvm_vcpu *vcpu)
> +{
> +	/*
> +	 * We are about to set CPTR_EL2.TFP to trap all floating point
> +	 * register accesses to EL2, however, the ARM ARM clearly states that
> +	 * traps are only taken to EL2 if the operation would not otherwise
> +	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> +	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> +	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> +	 * it will cause an exception.
> +	 */
> +	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> +		write_sysreg(1 << 30, fpexc32_el2);
> +		isb();
> +	}
> +}
> +
> +static void __hyp_text __activate_traps_common(struct kvm_vcpu *vcpu)
> +{
> +	/* Trap on AArch32 cp15 c15 (impdef sysregs) accesses (EL1 or EL0) */
> +	write_sysreg(1 << 15, hstr_el2);
> +	/*
> +	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> +	 * PMSELR_EL0 to make sure it never contains the cycle
> +	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> +	 * EL1 instead of being trapped to EL2.
> +	 */
> +	write_sysreg(0, pmselr_el0);
> +	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> +	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> +}
> +
> +static void __hyp_text __deactivate_traps_common(void)
> +{
> +	write_sysreg(0, hstr_el2);
> +	write_sysreg(0, pmuserenr_el0);
> +}
> +
> +static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
>  {
>  	u64 val;
>  
> @@ -68,7 +106,7 @@ static void __hyp_text __activate_traps_vhe(void)
>  	write_sysreg(kvm_get_hyp_vector(), vbar_el1);
>  }
>  
> -static void __hyp_text __activate_traps_nvhe(void)
> +static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)

I have the ugly feeling that this hunk should not be in this
patch. Have you tried bisecting the compilation of this series?

>  {
>  	u64 val;
>  
> @@ -85,37 +123,14 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
>  {
>  	u64 hcr = vcpu->arch.hcr_el2;
>  
> -	/*
> -	 * We are about to set CPTR_EL2.TFP to trap all floating point
> -	 * register accesses to EL2, however, the ARM ARM clearly states that
> -	 * traps are only taken to EL2 if the operation would not otherwise
> -	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> -	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> -	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> -	 * it will cause an exception.
> -	 */
> -	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> -		write_sysreg(1 << 30, fpexc32_el2);
> -		isb();
> -	}
> +	write_sysreg(hcr, hcr_el2);
>  
>  	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
>  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
>  
> -	write_sysreg(hcr, hcr_el2);
> -
> -	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
> -	write_sysreg(1 << 15, hstr_el2);
> -	/*
> -	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> -	 * PMSELR_EL0 to make sure it never contains the cycle
> -	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> -	 * EL1 instead of being trapped to EL2.
> -	 */
> -	write_sysreg(0, pmselr_el0);
> -	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> -	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> -	__activate_traps_arch()();
> +	__activate_traps_fpsimd32(vcpu);
> +	__activate_traps_common(vcpu);
> +	__activate_traps_arch()(vcpu);
>  }
>  
>  static void __hyp_text __deactivate_traps_vhe(void)
> @@ -160,9 +175,8 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
>  	if (vcpu->arch.hcr_el2 & HCR_VSE)
>  		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
>  
> +	__deactivate_traps_common();
>  	__deactivate_traps_arch()();
> -	write_sysreg(0, hstr_el2);
> -	write_sysreg(0, pmuserenr_el0);
>  }
>  
>  static void __hyp_text __activate_vm(struct kvm *kvm)
> -- 
> 2.14.2
> 

Otherwise:

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 32/40] KVM: arm64: Directly call VHE and non-VHE FPSIMD enabled functions
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 18:11     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 18:11 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, 15 Feb 2018 21:03:24 +0000,
Christoffer Dall wrote:
> 
> There is no longer a need for an alternative to choose the right
> function to tell us whether or not FPSIMD was enabled for the VM,
> because we can simply cann the appropriate functions directly fromwithin

from within

> the _vhe and _nvhe run functions.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - New patch since we no longer defer FPSIMD handling to load/put
> 
>  arch/arm64/kvm/hyp/switch.c | 15 +++------------
>  1 file changed, 3 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 17e3c6f26a34..9c40e203bd09 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -33,20 +33,11 @@ static bool __hyp_text __fpsimd_enabled_nvhe(void)
>  	return !(read_sysreg(cptr_el2) & CPTR_EL2_TFP);
>  }
>  
> -static bool __hyp_text __fpsimd_enabled_vhe(void)
> +static bool fpsimd_enabled_vhe(void)
>  {
>  	return !!(read_sysreg(cpacr_el1) & CPACR_EL1_FPEN);
>  }
>  
> -static hyp_alternate_select(__fpsimd_is_enabled,
> -			    __fpsimd_enabled_nvhe, __fpsimd_enabled_vhe,
> -			    ARM64_HAS_VIRT_HOST_EXTN);
> -
> -bool __hyp_text __fpsimd_enabled(void)
> -{
> -	return __fpsimd_is_enabled()();
> -}
> -
>  /* Save the 32-bit only FPSIMD system register state */
>  static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
>  {
> @@ -413,7 +404,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  		/* And we're baaack! */
>  	} while (fixup_guest_exit(vcpu, &exit_code));
>  
> -	fp_enabled = __fpsimd_enabled();
> +	fp_enabled = fpsimd_enabled_vhe();
>  
>  	sysreg_save_guest_state_vhe(guest_ctxt);
>  	__vgic_save_state(vcpu);
> @@ -478,7 +469,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
>  			__qcom_hyp_sanitize_btac_predictors();
>  	}
>  
> -	fp_enabled = __fpsimd_enabled();
> +	fp_enabled = __fpsimd_enabled_nvhe();
>  
>  	__sysreg_save_state_nvhe(guest_ctxt);
>  	__sysreg32_save_state(vcpu);
> -- 
> 2.14.2
> 

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 32/40] KVM: arm64: Directly call VHE and non-VHE FPSIMD enabled functions
@ 2018-02-21 18:11     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 18:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 15 Feb 2018 21:03:24 +0000,
Christoffer Dall wrote:
> 
> There is no longer a need for an alternative to choose the right
> function to tell us whether or not FPSIMD was enabled for the VM,
> because we can simply cann the appropriate functions directly fromwithin

from within

> the _vhe and _nvhe run functions.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - New patch since we no longer defer FPSIMD handling to load/put
> 
>  arch/arm64/kvm/hyp/switch.c | 15 +++------------
>  1 file changed, 3 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 17e3c6f26a34..9c40e203bd09 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -33,20 +33,11 @@ static bool __hyp_text __fpsimd_enabled_nvhe(void)
>  	return !(read_sysreg(cptr_el2) & CPTR_EL2_TFP);
>  }
>  
> -static bool __hyp_text __fpsimd_enabled_vhe(void)
> +static bool fpsimd_enabled_vhe(void)
>  {
>  	return !!(read_sysreg(cpacr_el1) & CPACR_EL1_FPEN);
>  }
>  
> -static hyp_alternate_select(__fpsimd_is_enabled,
> -			    __fpsimd_enabled_nvhe, __fpsimd_enabled_vhe,
> -			    ARM64_HAS_VIRT_HOST_EXTN);
> -
> -bool __hyp_text __fpsimd_enabled(void)
> -{
> -	return __fpsimd_is_enabled()();
> -}
> -
>  /* Save the 32-bit only FPSIMD system register state */
>  static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
>  {
> @@ -413,7 +404,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  		/* And we're baaack! */
>  	} while (fixup_guest_exit(vcpu, &exit_code));
>  
> -	fp_enabled = __fpsimd_enabled();
> +	fp_enabled = fpsimd_enabled_vhe();
>  
>  	sysreg_save_guest_state_vhe(guest_ctxt);
>  	__vgic_save_state(vcpu);
> @@ -478,7 +469,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
>  			__qcom_hyp_sanitize_btac_predictors();
>  	}
>  
> -	fp_enabled = __fpsimd_enabled();
> +	fp_enabled = __fpsimd_enabled_nvhe();
>  
>  	__sysreg_save_state_nvhe(guest_ctxt);
>  	__sysreg32_save_state(vcpu);
> -- 
> 2.14.2
> 

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 13/40] KVM: arm64: Introduce VHE-specific kvm_vcpu_run
  2018-02-21 17:43     ` Andrew Jones
@ 2018-02-21 18:18       ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 18:18 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, kvmarm, Yury Norov, linux-arm-kernel,
	Dave Martin, Shih-Wei Li

On Wed, Feb 21, 2018 at 06:43:00PM +0100, Andrew Jones wrote:
> On Thu, Feb 15, 2018 at 10:03:05PM +0100, Christoffer Dall wrote:
> > So far this is mostly (see below) a copy of the legacy non-VHE switch
> > function, but we will start reworking these functions in separate
> > directions to work on VHE and non-VHE in the most optimal way in later
> > patches.
> > 
> > The only difference after this patch between the VHE and non-VHE run
> > functions is that we omit the branch-predictor variant-2 hardening for
> > QC Falkor CPUs, because this workaround is specific to a series of
> > non-VHE ARMv8.0 CPUs.
> > 
> > Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v3:
> >      - Added BUG() to 32-bit ARM VHE run function
> >      - Omitted QC Falkor BP Hardening functionality from VHE-specific
> >        function
> >     
> >     Changes since v2:
> >      - Reworded commit message
> >     
> >     Changes since v1:
> >      - Rename kvm_vcpu_run to kvm_vcpu_run_vhe and rename __kvm_vcpu_run to
> >        __kvm_vcpu_run_nvhe
> >      - Removed stray whitespace line
> > 
> >  arch/arm/include/asm/kvm_asm.h   |  5 ++-
> >  arch/arm/kvm/hyp/switch.c        |  2 +-
> >  arch/arm64/include/asm/kvm_asm.h |  4 ++-
> >  arch/arm64/kvm/hyp/switch.c      | 66 +++++++++++++++++++++++++++++++++++++++-
> >  virt/kvm/arm/arm.c               |  5 ++-
> >  5 files changed, 77 insertions(+), 5 deletions(-)
> > 
> 
> ...
> 
> > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > index 2062d9357971..5bd879c78951 100644
> > --- a/virt/kvm/arm/arm.c
> > +++ b/virt/kvm/arm/arm.c
> > @@ -736,7 +736,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> >  		if (has_vhe())
> >  			kvm_arm_vhe_guest_enter();
> >  
> > -		ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);
> > +		if (has_vhe())
> > +			ret = kvm_vcpu_run_vhe(vcpu);
> > +		else
> > +			ret = kvm_call_hyp(__kvm_vcpu_run_nvhe, vcpu);
> >  
> >  		if (has_vhe())
> >  			kvm_arm_vhe_guest_exit();
> 
> We can combine these has_vhe()'s
> 
>  if (has_vhe()) {
>     kvm_arm_vhe_guest_enter();
>     ret = kvm_vcpu_run_vhe(vcpu);
>     kvm_arm_vhe_guest_exit();
>  } else
>     ret = kvm_call_hyp(__kvm_vcpu_run_nvhe, vcpu);

Maybe even do a cleanup patch that removes
kvm_arm_vhe_guest_enter/exit by putting the daif
masking/restoring directly into kvm_vcpu_run_vhe()?

Thanks,
drew

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

* [PATCH v4 13/40] KVM: arm64: Introduce VHE-specific kvm_vcpu_run
@ 2018-02-21 18:18       ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-21 18:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 21, 2018 at 06:43:00PM +0100, Andrew Jones wrote:
> On Thu, Feb 15, 2018 at 10:03:05PM +0100, Christoffer Dall wrote:
> > So far this is mostly (see below) a copy of the legacy non-VHE switch
> > function, but we will start reworking these functions in separate
> > directions to work on VHE and non-VHE in the most optimal way in later
> > patches.
> > 
> > The only difference after this patch between the VHE and non-VHE run
> > functions is that we omit the branch-predictor variant-2 hardening for
> > QC Falkor CPUs, because this workaround is specific to a series of
> > non-VHE ARMv8.0 CPUs.
> > 
> > Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v3:
> >      - Added BUG() to 32-bit ARM VHE run function
> >      - Omitted QC Falkor BP Hardening functionality from VHE-specific
> >        function
> >     
> >     Changes since v2:
> >      - Reworded commit message
> >     
> >     Changes since v1:
> >      - Rename kvm_vcpu_run to kvm_vcpu_run_vhe and rename __kvm_vcpu_run to
> >        __kvm_vcpu_run_nvhe
> >      - Removed stray whitespace line
> > 
> >  arch/arm/include/asm/kvm_asm.h   |  5 ++-
> >  arch/arm/kvm/hyp/switch.c        |  2 +-
> >  arch/arm64/include/asm/kvm_asm.h |  4 ++-
> >  arch/arm64/kvm/hyp/switch.c      | 66 +++++++++++++++++++++++++++++++++++++++-
> >  virt/kvm/arm/arm.c               |  5 ++-
> >  5 files changed, 77 insertions(+), 5 deletions(-)
> > 
> 
> ...
> 
> > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > index 2062d9357971..5bd879c78951 100644
> > --- a/virt/kvm/arm/arm.c
> > +++ b/virt/kvm/arm/arm.c
> > @@ -736,7 +736,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> >  		if (has_vhe())
> >  			kvm_arm_vhe_guest_enter();
> >  
> > -		ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);
> > +		if (has_vhe())
> > +			ret = kvm_vcpu_run_vhe(vcpu);
> > +		else
> > +			ret = kvm_call_hyp(__kvm_vcpu_run_nvhe, vcpu);
> >  
> >  		if (has_vhe())
> >  			kvm_arm_vhe_guest_exit();
> 
> We can combine these has_vhe()'s
> 
>  if (has_vhe()) {
>     kvm_arm_vhe_guest_enter();
>     ret = kvm_vcpu_run_vhe(vcpu);
>     kvm_arm_vhe_guest_exit();
>  } else
>     ret = kvm_call_hyp(__kvm_vcpu_run_nvhe, vcpu);

Maybe even do a cleanup patch that removes
kvm_arm_vhe_guest_enter/exit by putting the daif
masking/restoring directly into kvm_vcpu_run_vhe()?

Thanks,
drew

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

* Re: [PATCH v4 33/40] KVM: arm64: Configure c15, PMU, and debug register traps on cpu load/put for VHE
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 18:20     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 18:20 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, kvmarm, Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, 15 Feb 2018 21:03:25 +0000,
Christoffer Dall wrote:
> 
> We do not have to change the c15 trap setting on each switch to/from the
> guest on VHE systems, because this setting only affects EL0.

Did you mean EL1 instead?

> 
> The PMU and debug trap configuration can also be done on vcpu load/put
> instead, because they don't affect how the host kernel can access the
> debug registers while executing KVM kernel code.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/include/asm/kvm_hyp.h |  3 +++
>  arch/arm64/kvm/hyp/switch.c      | 31 ++++++++++++++++++++++---------
>  arch/arm64/kvm/hyp/sysreg-sr.c   |  4 ++++
>  3 files changed, 29 insertions(+), 9 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
> index 2b1fda90dde4..949f2e77ae58 100644
> --- a/arch/arm64/include/asm/kvm_hyp.h
> +++ b/arch/arm64/include/asm/kvm_hyp.h
> @@ -147,6 +147,9 @@ void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
>  void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
>  bool __fpsimd_enabled(void);
>  
> +void activate_traps_vhe_load(struct kvm_vcpu *vcpu);
> +void deactivate_traps_vhe_put(void);
> +
>  u64 __guest_enter(struct kvm_vcpu *vcpu, struct kvm_cpu_context *host_ctxt);
>  void __noreturn __hyp_do_panic(unsigned long, ...);
>  
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 9c40e203bd09..5e94955b89ea 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -101,6 +101,8 @@ static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
>  {
>  	u64 val;
>  
> +	__activate_traps_common(vcpu);
> +
>  	val = CPTR_EL2_DEFAULT;
>  	val |= CPTR_EL2_TTA | CPTR_EL2_TFP | CPTR_EL2_TZ;
>  	write_sysreg(val, cptr_el2);
> @@ -120,20 +122,12 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
>  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
>  
>  	__activate_traps_fpsimd32(vcpu);
> -	__activate_traps_common(vcpu);
>  	__activate_traps_arch()(vcpu);
>  }
>  
>  static void __hyp_text __deactivate_traps_vhe(void)
>  {
>  	extern char vectors[];	/* kernel exception vectors */
> -	u64 mdcr_el2 = read_sysreg(mdcr_el2);
> -
> -	mdcr_el2 &= MDCR_EL2_HPMN_MASK |
> -		    MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT |
> -		    MDCR_EL2_TPMS;
> -
> -	write_sysreg(mdcr_el2, mdcr_el2);
>  	write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
>  	write_sysreg(CPACR_EL1_DEFAULT, cpacr_el1);
>  	write_sysreg(vectors, vbar_el1);
> @@ -143,6 +137,8 @@ static void __hyp_text __deactivate_traps_nvhe(void)
>  {
>  	u64 mdcr_el2 = read_sysreg(mdcr_el2);
>  
> +	__deactivate_traps_common();
> +
>  	mdcr_el2 &= MDCR_EL2_HPMN_MASK;
>  	mdcr_el2 |= MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT;
>  
> @@ -166,10 +162,27 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
>  	if (vcpu->arch.hcr_el2 & HCR_VSE)
>  		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
>  
> -	__deactivate_traps_common();
>  	__deactivate_traps_arch()();
>  }
>  
> +void activate_traps_vhe_load(struct kvm_vcpu *vcpu)
> +{
> +	__activate_traps_common(vcpu);
> +}
> +
> +void deactivate_traps_vhe_put(void)
> +{
> +	u64 mdcr_el2 = read_sysreg(mdcr_el2);
> +
> +	mdcr_el2 &= MDCR_EL2_HPMN_MASK |
> +		    MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT |
> +		    MDCR_EL2_TPMS;
> +
> +	write_sysreg(mdcr_el2, mdcr_el2);
> +
> +	__deactivate_traps_common();
> +}
> +
>  static void __hyp_text __activate_vm(struct kvm *kvm)
>  {
>  	write_sysreg(kvm->arch.vttbr, vttbr_el2);
> diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> index aacba4636871..b3894df6bf1a 100644
> --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> @@ -254,6 +254,8 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
>  	__sysreg_restore_el1_state(guest_ctxt);
>  
>  	vcpu->arch.sysregs_loaded_on_cpu = true;
> +
> +	activate_traps_vhe_load(vcpu);
>  }
>  
>  /**
> @@ -275,6 +277,8 @@ void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
>  	if (!has_vhe())
>  		return;
>  
> +	deactivate_traps_vhe_put();
> +
>  	__sysreg_save_el1_state(guest_ctxt);
>  	__sysreg_save_user_state(guest_ctxt);
>  	__sysreg32_save_state(vcpu);
> -- 
> 2.14.2
> 

I must admit that I find these two layers of trap configuration mildly
confusing. I can see why it is done like this (there is hardly any
other way), but still...

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 33/40] KVM: arm64: Configure c15, PMU, and debug register traps on cpu load/put for VHE
@ 2018-02-21 18:20     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 18:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 15 Feb 2018 21:03:25 +0000,
Christoffer Dall wrote:
> 
> We do not have to change the c15 trap setting on each switch to/from the
> guest on VHE systems, because this setting only affects EL0.

Did you mean EL1 instead?

> 
> The PMU and debug trap configuration can also be done on vcpu load/put
> instead, because they don't affect how the host kernel can access the
> debug registers while executing KVM kernel code.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/include/asm/kvm_hyp.h |  3 +++
>  arch/arm64/kvm/hyp/switch.c      | 31 ++++++++++++++++++++++---------
>  arch/arm64/kvm/hyp/sysreg-sr.c   |  4 ++++
>  3 files changed, 29 insertions(+), 9 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
> index 2b1fda90dde4..949f2e77ae58 100644
> --- a/arch/arm64/include/asm/kvm_hyp.h
> +++ b/arch/arm64/include/asm/kvm_hyp.h
> @@ -147,6 +147,9 @@ void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
>  void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
>  bool __fpsimd_enabled(void);
>  
> +void activate_traps_vhe_load(struct kvm_vcpu *vcpu);
> +void deactivate_traps_vhe_put(void);
> +
>  u64 __guest_enter(struct kvm_vcpu *vcpu, struct kvm_cpu_context *host_ctxt);
>  void __noreturn __hyp_do_panic(unsigned long, ...);
>  
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 9c40e203bd09..5e94955b89ea 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -101,6 +101,8 @@ static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
>  {
>  	u64 val;
>  
> +	__activate_traps_common(vcpu);
> +
>  	val = CPTR_EL2_DEFAULT;
>  	val |= CPTR_EL2_TTA | CPTR_EL2_TFP | CPTR_EL2_TZ;
>  	write_sysreg(val, cptr_el2);
> @@ -120,20 +122,12 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
>  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
>  
>  	__activate_traps_fpsimd32(vcpu);
> -	__activate_traps_common(vcpu);
>  	__activate_traps_arch()(vcpu);
>  }
>  
>  static void __hyp_text __deactivate_traps_vhe(void)
>  {
>  	extern char vectors[];	/* kernel exception vectors */
> -	u64 mdcr_el2 = read_sysreg(mdcr_el2);
> -
> -	mdcr_el2 &= MDCR_EL2_HPMN_MASK |
> -		    MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT |
> -		    MDCR_EL2_TPMS;
> -
> -	write_sysreg(mdcr_el2, mdcr_el2);
>  	write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
>  	write_sysreg(CPACR_EL1_DEFAULT, cpacr_el1);
>  	write_sysreg(vectors, vbar_el1);
> @@ -143,6 +137,8 @@ static void __hyp_text __deactivate_traps_nvhe(void)
>  {
>  	u64 mdcr_el2 = read_sysreg(mdcr_el2);
>  
> +	__deactivate_traps_common();
> +
>  	mdcr_el2 &= MDCR_EL2_HPMN_MASK;
>  	mdcr_el2 |= MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT;
>  
> @@ -166,10 +162,27 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
>  	if (vcpu->arch.hcr_el2 & HCR_VSE)
>  		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
>  
> -	__deactivate_traps_common();
>  	__deactivate_traps_arch()();
>  }
>  
> +void activate_traps_vhe_load(struct kvm_vcpu *vcpu)
> +{
> +	__activate_traps_common(vcpu);
> +}
> +
> +void deactivate_traps_vhe_put(void)
> +{
> +	u64 mdcr_el2 = read_sysreg(mdcr_el2);
> +
> +	mdcr_el2 &= MDCR_EL2_HPMN_MASK |
> +		    MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT |
> +		    MDCR_EL2_TPMS;
> +
> +	write_sysreg(mdcr_el2, mdcr_el2);
> +
> +	__deactivate_traps_common();
> +}
> +
>  static void __hyp_text __activate_vm(struct kvm *kvm)
>  {
>  	write_sysreg(kvm->arch.vttbr, vttbr_el2);
> diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> index aacba4636871..b3894df6bf1a 100644
> --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> @@ -254,6 +254,8 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
>  	__sysreg_restore_el1_state(guest_ctxt);
>  
>  	vcpu->arch.sysregs_loaded_on_cpu = true;
> +
> +	activate_traps_vhe_load(vcpu);
>  }
>  
>  /**
> @@ -275,6 +277,8 @@ void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
>  	if (!has_vhe())
>  		return;
>  
> +	deactivate_traps_vhe_put();
> +
>  	__sysreg_save_el1_state(guest_ctxt);
>  	__sysreg_save_user_state(guest_ctxt);
>  	__sysreg32_save_state(vcpu);
> -- 
> 2.14.2
> 

I must admit that I find these two layers of trap configuration mildly
confusing. I can see why it is done like this (there is hardly any
other way), but still...

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 34/40] KVM: arm64: Cleanup __activate_traps and __deactive_traps for VHE and non-VHE
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-21 18:26     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 18:26 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, 15 Feb 2018 21:03:26 +0000,
Christoffer Dall wrote:
> 
> To make the code more readable and to avoid the overhead of a function
> call, let's get rid of a pair of the alternative function selectors and
> explicitly call the VHE and non-VHE functions using the has_vhe() static
> key based selector instead, telling the compiler to try to inline the
> static function if it can.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/kvm/hyp/switch.c | 30 ++++++++++++++----------------
>  1 file changed, 14 insertions(+), 16 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 5e94955b89ea..0e54fe2aab1c 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -85,7 +85,7 @@ static void __hyp_text __deactivate_traps_common(void)
>  	write_sysreg(0, pmuserenr_el0);
>  }
>  
> -static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
> +static inline void activate_traps_vhe(struct kvm_vcpu *vcpu)
>  {
>  	u64 val;
>  
> @@ -97,7 +97,7 @@ static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
>  	write_sysreg(kvm_get_hyp_vector(), vbar_el1);
>  }
>  
> -static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
> +static inline void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)

Having both inline and __hyp_text does not make much sense (the
function will be emitted in the section defined by the caller). I
suggest you drop the inline and let the compiler do its magic.

>  {
>  	u64 val;
>  
> @@ -108,11 +108,7 @@ static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
>  	write_sysreg(val, cptr_el2);
>  }
>  
> -static hyp_alternate_select(__activate_traps_arch,
> -			    __activate_traps_nvhe, __activate_traps_vhe,
> -			    ARM64_HAS_VIRT_HOST_EXTN);
> -
> -static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> +static inline void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)

Same here, and in other spots in this file.

>  {
>  	u64 hcr = vcpu->arch.hcr_el2;
>  
> @@ -122,10 +118,13 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
>  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
>  
>  	__activate_traps_fpsimd32(vcpu);
> -	__activate_traps_arch()(vcpu);
> +	if (has_vhe())
> +		activate_traps_vhe(vcpu);
> +	else
> +		__activate_traps_nvhe(vcpu);
>  }
>  
> -static void __hyp_text __deactivate_traps_vhe(void)
> +static inline void deactivate_traps_vhe(void)
>  {
>  	extern char vectors[];	/* kernel exception vectors */
>  	write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
> @@ -133,7 +132,7 @@ static void __hyp_text __deactivate_traps_vhe(void)
>  	write_sysreg(vectors, vbar_el1);
>  }
>  
> -static void __hyp_text __deactivate_traps_nvhe(void)
> +static inline void __hyp_text __deactivate_traps_nvhe(void)
>  {
>  	u64 mdcr_el2 = read_sysreg(mdcr_el2);
>  
> @@ -147,11 +146,7 @@ static void __hyp_text __deactivate_traps_nvhe(void)
>  	write_sysreg(CPTR_EL2_DEFAULT, cptr_el2);
>  }
>  
> -static hyp_alternate_select(__deactivate_traps_arch,
> -			    __deactivate_traps_nvhe, __deactivate_traps_vhe,
> -			    ARM64_HAS_VIRT_HOST_EXTN);
> -
> -static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
> +static inline void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
>  {
>  	/*
>  	 * If we pended a virtual abort, preserve it until it gets
> @@ -162,7 +157,10 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
>  	if (vcpu->arch.hcr_el2 & HCR_VSE)
>  		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
>  
> -	__deactivate_traps_arch()();
> +	if (has_vhe())
> +		deactivate_traps_vhe();
> +	else
> +		__deactivate_traps_nvhe();
>  }
>  
>  void activate_traps_vhe_load(struct kvm_vcpu *vcpu)
> -- 
> 2.14.2
> 

Thanks,

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 34/40] KVM: arm64: Cleanup __activate_traps and __deactive_traps for VHE and non-VHE
@ 2018-02-21 18:26     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-21 18:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 15 Feb 2018 21:03:26 +0000,
Christoffer Dall wrote:
> 
> To make the code more readable and to avoid the overhead of a function
> call, let's get rid of a pair of the alternative function selectors and
> explicitly call the VHE and non-VHE functions using the has_vhe() static
> key based selector instead, telling the compiler to try to inline the
> static function if it can.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/kvm/hyp/switch.c | 30 ++++++++++++++----------------
>  1 file changed, 14 insertions(+), 16 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 5e94955b89ea..0e54fe2aab1c 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -85,7 +85,7 @@ static void __hyp_text __deactivate_traps_common(void)
>  	write_sysreg(0, pmuserenr_el0);
>  }
>  
> -static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
> +static inline void activate_traps_vhe(struct kvm_vcpu *vcpu)
>  {
>  	u64 val;
>  
> @@ -97,7 +97,7 @@ static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
>  	write_sysreg(kvm_get_hyp_vector(), vbar_el1);
>  }
>  
> -static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
> +static inline void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)

Having both inline and __hyp_text does not make much sense (the
function will be emitted in the section defined by the caller). I
suggest you drop the inline and let the compiler do its magic.

>  {
>  	u64 val;
>  
> @@ -108,11 +108,7 @@ static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
>  	write_sysreg(val, cptr_el2);
>  }
>  
> -static hyp_alternate_select(__activate_traps_arch,
> -			    __activate_traps_nvhe, __activate_traps_vhe,
> -			    ARM64_HAS_VIRT_HOST_EXTN);
> -
> -static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> +static inline void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)

Same here, and in other spots in this file.

>  {
>  	u64 hcr = vcpu->arch.hcr_el2;
>  
> @@ -122,10 +118,13 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
>  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
>  
>  	__activate_traps_fpsimd32(vcpu);
> -	__activate_traps_arch()(vcpu);
> +	if (has_vhe())
> +		activate_traps_vhe(vcpu);
> +	else
> +		__activate_traps_nvhe(vcpu);
>  }
>  
> -static void __hyp_text __deactivate_traps_vhe(void)
> +static inline void deactivate_traps_vhe(void)
>  {
>  	extern char vectors[];	/* kernel exception vectors */
>  	write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
> @@ -133,7 +132,7 @@ static void __hyp_text __deactivate_traps_vhe(void)
>  	write_sysreg(vectors, vbar_el1);
>  }
>  
> -static void __hyp_text __deactivate_traps_nvhe(void)
> +static inline void __hyp_text __deactivate_traps_nvhe(void)
>  {
>  	u64 mdcr_el2 = read_sysreg(mdcr_el2);
>  
> @@ -147,11 +146,7 @@ static void __hyp_text __deactivate_traps_nvhe(void)
>  	write_sysreg(CPTR_EL2_DEFAULT, cptr_el2);
>  }
>  
> -static hyp_alternate_select(__deactivate_traps_arch,
> -			    __deactivate_traps_nvhe, __deactivate_traps_vhe,
> -			    ARM64_HAS_VIRT_HOST_EXTN);
> -
> -static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
> +static inline void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
>  {
>  	/*
>  	 * If we pended a virtual abort, preserve it until it gets
> @@ -162,7 +157,10 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
>  	if (vcpu->arch.hcr_el2 & HCR_VSE)
>  		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
>  
> -	__deactivate_traps_arch()();
> +	if (has_vhe())
> +		deactivate_traps_vhe();
> +	else
> +		__deactivate_traps_nvhe();
>  }
>  
>  void activate_traps_vhe_load(struct kvm_vcpu *vcpu)
> -- 
> 2.14.2
> 

Thanks,

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 10/40] KVM: arm64: Slightly improve debug save/restore functions
  2018-02-21 17:52       ` Marc Zyngier
@ 2018-02-22  8:05         ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22  8:05 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm, Tomasz Nowicki, Christoffer Dall, kvmarm, Julien Grall,
	Yury Norov, Shih-Wei Li, Dave Martin, linux-arm-kernel

On Wed, Feb 21, 2018 at 05:52:41PM +0000, Marc Zyngier wrote:
> On 21/02/18 17:39, Andrew Jones wrote:
> > On Thu, Feb 15, 2018 at 10:03:02PM +0100, Christoffer Dall wrote:
> >> The debug save/restore functions can be improved by using the has_vhe()
> >> static key instead of the instruction alternative.  Using the static key
> >> uses the same paradigm as we're going to use elsewhere, it makes the
> >> code more readable, and it generates slightly better code (no
> >> stack setups and function calls unless necessary).
> >>
> >> We also use a static key on the restore path, because it will be
> >> marginally faster than loading a value from memory.
> >>
> >> Finally, we don't have to conditionally clear the debug dirty flag if
> >> it's set, we can just clear it.
> >>
> >> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> ---
> >>
> >> Notes:
> >>     Changes since v1:
> >>      - Change dot to comma in comment
> >>      - Rename __debug_restore_spe to __debug_restore_spe_nvhe
> >>
> >>  arch/arm64/kvm/hyp/debug-sr.c | 26 ++++++++++++--------------
> >>  1 file changed, 12 insertions(+), 14 deletions(-)
> >>
> > 
> > Maybe after this series is merged, if there are any hyp_alternate_select's
> > left, we can replace all the remaining ones with has_vhe() and then just
> > completely remove hyp_alternate_select.
> 
> Note that older compilers (such as GCC 4.8) will generate horrible code
> with static keys, as they do not support "asm goto". Not that I want to
> preserve the home brew hyp_alternate_select mechanism, but I just want
> to make it plain that some distros will definitely suffer from the
> transition.

Yeah, I've seen that. I even wrote some patches to try and deal with
it once, because RHEL currently has gcc 4.8, and static keys are now
used in kernel hot paths for kpti, and I knew this series was coming.
My patches didn't seem like something usptream would care about, so
I never posted them. Indeed, I see here[*] that at least x86 is saying
that at some point (soon?) asm-goto will be a hard requirement.

I just checked Christoffer's branch. The only hyp_alternate_select,
that couldn't be changed to a has_vhe is __check_arm_834220, but
that one can just be changed to
cpus_have_const_cap(ARM64_WORKAROUND_834220), since it's just acting
as a boolean anyway.

Thanks,
drew

[*] https://lkml.org/lkml/2018/2/20/51

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

* [PATCH v4 10/40] KVM: arm64: Slightly improve debug save/restore functions
@ 2018-02-22  8:05         ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22  8:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 21, 2018 at 05:52:41PM +0000, Marc Zyngier wrote:
> On 21/02/18 17:39, Andrew Jones wrote:
> > On Thu, Feb 15, 2018 at 10:03:02PM +0100, Christoffer Dall wrote:
> >> The debug save/restore functions can be improved by using the has_vhe()
> >> static key instead of the instruction alternative.  Using the static key
> >> uses the same paradigm as we're going to use elsewhere, it makes the
> >> code more readable, and it generates slightly better code (no
> >> stack setups and function calls unless necessary).
> >>
> >> We also use a static key on the restore path, because it will be
> >> marginally faster than loading a value from memory.
> >>
> >> Finally, we don't have to conditionally clear the debug dirty flag if
> >> it's set, we can just clear it.
> >>
> >> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> ---
> >>
> >> Notes:
> >>     Changes since v1:
> >>      - Change dot to comma in comment
> >>      - Rename __debug_restore_spe to __debug_restore_spe_nvhe
> >>
> >>  arch/arm64/kvm/hyp/debug-sr.c | 26 ++++++++++++--------------
> >>  1 file changed, 12 insertions(+), 14 deletions(-)
> >>
> > 
> > Maybe after this series is merged, if there are any hyp_alternate_select's
> > left, we can replace all the remaining ones with has_vhe() and then just
> > completely remove hyp_alternate_select.
> 
> Note that older compilers (such as GCC 4.8) will generate horrible code
> with static keys, as they do not support "asm goto". Not that I want to
> preserve the home brew hyp_alternate_select mechanism, but I just want
> to make it plain that some distros will definitely suffer from the
> transition.

Yeah, I've seen that. I even wrote some patches to try and deal with
it once, because RHEL currently has gcc 4.8, and static keys are now
used in kernel hot paths for kpti, and I knew this series was coming.
My patches didn't seem like something usptream would care about, so
I never posted them. Indeed, I see here[*] that at least x86 is saying
that at some point (soon?) asm-goto will be a hard requirement.

I just checked Christoffer's branch. The only hyp_alternate_select,
that couldn't be changed to a has_vhe is __check_arm_834220, but
that one can just be changed to
cpus_have_const_cap(ARM64_WORKAROUND_834220), since it's just acting
as a boolean anyway.

Thanks,
drew

[*] https://lkml.org/lkml/2018/2/20/51

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

* Re: [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
  2018-02-19 15:50     ` Julien Grall
@ 2018-02-22  8:43       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22  8:43 UTC (permalink / raw)
  To: Julien Grall
  Cc: Andrew Jones, kvm, Ard Biesheuvel, Marc Zyngier, Tomasz Nowicki,
	Dave Martin, Yury Norov, linux-arm-kernel, kvmarm, Shih-Wei Li

On Mon, Feb 19, 2018 at 03:50:20PM +0000, Julien Grall wrote:
> Hi Christoffer,
> 
> On 15/02/18 21:02, Christoffer Dall wrote:
> >We already have the percpu area for the host cpu state, which points to
> >the VCPU, so there's no need to store the VCPU pointer on the stack on
> >every context switch.  We can be a little more clever and just use
> >tpidr_el2 for the percpu offset and load the VCPU pointer from the host
> >context.
> >
> >This does require us to calculate the percpu offset without including
> >the offset from the kernel mapping of the percpu array to the linear
> >mapping of the array (which is what we store in tpidr_el1), because a
> >PC-relative generated address in EL2 is already giving us the hyp alias
> >of the linear mapping of a kernel address.  We do this in
> >__cpu_init_hyp_mode() by using kvm_ksym_ref().
> >
> >This change also requires us to have a scratch register, so we take the
> >chance to rearrange some of the el1_sync code to only look at the
> >vttbr_el2 to determine if this is a trap from the guest or an HVC from
> >the host.  We do add an extra check to call the panic code if the kernel
> >is configured with debugging enabled and we saw a trap from the host
> >which wasn't an HVC, indicating that we left some EL2 trap configured by
> >mistake.
> 
> You might want to remove this paragraph as you don't seem to have rework
> that part of the code in this version.
> 
Yes, will do.

Thanks,
-Christoffer

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

* [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
@ 2018-02-22  8:43       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22  8:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Feb 19, 2018 at 03:50:20PM +0000, Julien Grall wrote:
> Hi Christoffer,
> 
> On 15/02/18 21:02, Christoffer Dall wrote:
> >We already have the percpu area for the host cpu state, which points to
> >the VCPU, so there's no need to store the VCPU pointer on the stack on
> >every context switch.  We can be a little more clever and just use
> >tpidr_el2 for the percpu offset and load the VCPU pointer from the host
> >context.
> >
> >This does require us to calculate the percpu offset without including
> >the offset from the kernel mapping of the percpu array to the linear
> >mapping of the array (which is what we store in tpidr_el1), because a
> >PC-relative generated address in EL2 is already giving us the hyp alias
> >of the linear mapping of a kernel address.  We do this in
> >__cpu_init_hyp_mode() by using kvm_ksym_ref().
> >
> >This change also requires us to have a scratch register, so we take the
> >chance to rearrange some of the el1_sync code to only look at the
> >vttbr_el2 to determine if this is a trap from the guest or an HVC from
> >the host.  We do add an extra check to call the panic code if the kernel
> >is configured with debugging enabled and we saw a trap from the host
> >which wasn't an HVC, indicating that we left some EL2 trap configured by
> >mistake.
> 
> You might want to remove this paragraph as you don't seem to have rework
> that part of the code in this version.
> 
Yes, will do.

Thanks,
-Christoffer

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

* Re: [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
  2018-02-21 11:34     ` Marc Zyngier
@ 2018-02-22  9:02       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22  9:02 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Andrew Jones, kvm, Ard Biesheuvel, Tomasz Nowicki, kvmarm,
	Julien Grall, Yury Norov, linux-arm-kernel, Dave Martin,
	Shih-Wei Li

On Wed, Feb 21, 2018 at 11:34:07AM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:02:55 +0000,
> Christoffer Dall wrote:
> > 
> > We already have the percpu area for the host cpu state, which points to
> > the VCPU, so there's no need to store the VCPU pointer on the stack on
> > every context switch.  We can be a little more clever and just use
> > tpidr_el2 for the percpu offset and load the VCPU pointer from the host
> > context.
> > 
> > This does require us to calculate the percpu offset without including
> > the offset from the kernel mapping of the percpu array to the linear
> > mapping of the array (which is what we store in tpidr_el1), because a
> > PC-relative generated address in EL2 is already giving us the hyp alias
> > of the linear mapping of a kernel address.  We do this in
> > __cpu_init_hyp_mode() by using kvm_ksym_ref().
> > 
> > This change also requires us to have a scratch register, so we take the
> > chance to rearrange some of the el1_sync code to only look at the
> > vttbr_el2 to determine if this is a trap from the guest or an HVC from
> > the host.  We do add an extra check to call the panic code if the kernel
> > is configured with debugging enabled and we saw a trap from the host
> > which wasn't an HVC, indicating that we left some EL2 trap configured by
> > mistake.
> > 
> > The code that accesses ESR_EL2 was previously using an alternative to
> > use the _EL1 accessor on VHE systems, but this was actually unnecessary
> > as the _EL1 accessor aliases the ESR_EL2 register on VHE, and the _EL2
> > accessor does the same thing on both systems.
> > 
> > Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v3:
> >      - Reworked the assembly part of the patch after rebasing on v4.16-rc1
> >        which created a conflict with the variant 2 mitigations.
> >      - Removed Marc's reviewed-by due to the rework.
> >      - Removed unneeded extern keyword in declaration in header file
> >     
> >     Changes since v1:
> >      - Use PC-relative addressing to access per-cpu variables instead of
> >        using a load from the literal pool.
> >      - Remove stale comments as pointed out by Marc
> >      - Reworded the commit message as suggested by Drew
> > 
> >  arch/arm64/include/asm/kvm_asm.h  | 14 ++++++++++++++
> >  arch/arm64/include/asm/kvm_host.h | 15 +++++++++++++++
> >  arch/arm64/kernel/asm-offsets.c   |  1 +
> >  arch/arm64/kvm/hyp/entry.S        |  6 +-----
> >  arch/arm64/kvm/hyp/hyp-entry.S    | 31 +++++++++++++------------------
> >  arch/arm64/kvm/hyp/switch.c       |  5 +----
> >  arch/arm64/kvm/hyp/sysreg-sr.c    |  5 +++++
> >  7 files changed, 50 insertions(+), 27 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> > index 24961b732e65..6b626750b0a1 100644
> > --- a/arch/arm64/include/asm/kvm_asm.h
> > +++ b/arch/arm64/include/asm/kvm_asm.h
> > @@ -33,6 +33,7 @@
> >  #define KVM_ARM64_DEBUG_DIRTY_SHIFT	0
> >  #define KVM_ARM64_DEBUG_DIRTY		(1 << KVM_ARM64_DEBUG_DIRTY_SHIFT)
> >  
> > +/* Translate a kernel address of @sym into its equivalent linear mapping */
> >  #define kvm_ksym_ref(sym)						\
> >  	({								\
> >  		void *val = &sym;					\
> > @@ -70,6 +71,19 @@ extern u32 __init_stage2_translation(void);
> >  
> >  extern void __qcom_hyp_sanitize_btac_predictors(void);
> >  
> > +#else /* __ASSEMBLY__ */
> > +
> > +.macro get_host_ctxt reg, tmp
> > +	adr_l	\reg, kvm_host_cpu_state
> > +	mrs	\tmp, tpidr_el2
> > +	add	\reg, \reg, \tmp
> > +.endm
> > +
> > +.macro get_vcpu vcpu, ctxt
> > +	ldr	\vcpu, [\ctxt, #HOST_CONTEXT_VCPU]
> > +	kern_hyp_va	\vcpu
> > +.endm
> > +
> >  #endif
> >  
> >  #endif /* __ARM_KVM_ASM_H__ */
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 596f8e414a4c..618cfee7206a 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -358,10 +358,15 @@ int kvm_perf_teardown(void);
> >  
> >  struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
> >  
> > +void __kvm_set_tpidr_el2(u64 tpidr_el2);
> > +DECLARE_PER_CPU(kvm_cpu_context_t, kvm_host_cpu_state);
> > +
> >  static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
> >  				       unsigned long hyp_stack_ptr,
> >  				       unsigned long vector_ptr)
> >  {
> > +	u64 tpidr_el2;
> > +
> >  	/*
> >  	 * Call initialization code, and switch to the full blown HYP code.
> >  	 * If the cpucaps haven't been finalized yet, something has gone very
> > @@ -370,6 +375,16 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
> >  	 */
> >  	BUG_ON(!static_branch_likely(&arm64_const_caps_ready));
> >  	__kvm_call_hyp((void *)pgd_ptr, hyp_stack_ptr, vector_ptr);
> > +
> > +	/*
> > +	 * Calculate the raw per-cpu offset without a translation from the
> > +	 * kernel's mapping to the linear mapping, and store it in tpidr_el2
> > +	 * so that we can use adr_l to access per-cpu variables in EL2.
> > +	 */
> > +	tpidr_el2 = (u64)this_cpu_ptr(&kvm_host_cpu_state)
> > +		- (u64)kvm_ksym_ref(kvm_host_cpu_state);
> > +
> > +	kvm_call_hyp(__kvm_set_tpidr_el2, tpidr_el2);
> >  }
> >  
> >  static inline void kvm_arch_hardware_unsetup(void) {}
> > diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
> > index 1303e04110cd..78e1b0a70aaf 100644
> > --- a/arch/arm64/kernel/asm-offsets.c
> > +++ b/arch/arm64/kernel/asm-offsets.c
> > @@ -138,6 +138,7 @@ int main(void)
> >    DEFINE(CPU_FP_REGS,		offsetof(struct kvm_regs, fp_regs));
> >    DEFINE(VCPU_FPEXC32_EL2,	offsetof(struct kvm_vcpu, arch.ctxt.sys_regs[FPEXC32_EL2]));
> >    DEFINE(VCPU_HOST_CONTEXT,	offsetof(struct kvm_vcpu, arch.host_cpu_context));
> > +  DEFINE(HOST_CONTEXT_VCPU,	offsetof(struct kvm_cpu_context, __hyp_running_vcpu));
> >  #endif
> >  #ifdef CONFIG_CPU_PM
> >    DEFINE(CPU_SUSPEND_SZ,	sizeof(struct cpu_suspend_ctx));
> > diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
> > index fdd1068ee3a5..1f458f7c3b44 100644
> > --- a/arch/arm64/kvm/hyp/entry.S
> > +++ b/arch/arm64/kvm/hyp/entry.S
> > @@ -62,9 +62,6 @@ ENTRY(__guest_enter)
> >  	// Store the host regs
> >  	save_callee_saved_regs x1
> >  
> > -	// Store host_ctxt and vcpu for use at exit time
> > -	stp	x1, x0, [sp, #-16]!
> > -
> >  	add	x18, x0, #VCPU_CONTEXT
> >  
> >  	// Restore guest regs x0-x17
> > @@ -118,8 +115,7 @@ ENTRY(__guest_exit)
> >  	// Store the guest regs x19-x29, lr
> >  	save_callee_saved_regs x1
> >  
> > -	// Restore the host_ctxt from the stack
> > -	ldr	x2, [sp], #16
> > +	get_host_ctxt	x2, x3
> >  
> >  	// Now restore the host regs
> >  	restore_callee_saved_regs x2
> > diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
> > index f36464bd57c5..559b4d54bc42 100644
> > --- a/arch/arm64/kvm/hyp/hyp-entry.S
> > +++ b/arch/arm64/kvm/hyp/hyp-entry.S
> > @@ -57,13 +57,8 @@ ENDPROC(__vhe_hyp_call)
> >  el1_sync:				// Guest trapped into EL2
> >  	stp	x0, x1, [sp, #-16]!
> >  
> > -alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
> > -	mrs	x1, esr_el2
> > -alternative_else
> > -	mrs	x1, esr_el1
> > -alternative_endif
> > -	lsr	x0, x1, #ESR_ELx_EC_SHIFT
> > -
> > +	mrs	x0, esr_el2
> > +	lsr	x0, x0, #ESR_ELx_EC_SHIFT
> >  	cmp	x0, #ESR_ELx_EC_HVC64
> >  	ccmp	x0, #ESR_ELx_EC_HVC32, #4, ne
> >  	b.ne	el1_trap
> > @@ -117,10 +112,15 @@ el1_hvc_guest:
> >  	eret
> >  
> >  el1_trap:
> > +	get_host_ctxt	x0, x1
> > +	get_vcpu	x1, x0
> > +
> > +	mrs		x0, esr_el2
> > +	lsr		x0, x0, #ESR_ELx_EC_SHIFT
> >  	/*
> >  	 * x0: ESR_EC
> > +	 * x1: vcpu pointer
> >  	 */
> > -	ldr	x1, [sp, #16 + 8]	// vcpu stored by __guest_enter
> >  
> >  	/*
> >  	 * We trap the first access to the FP/SIMD to save the host context
> > @@ -138,13 +138,15 @@ alternative_else_nop_endif
> >  
> >  el1_irq:
> >  	stp     x0, x1, [sp, #-16]!
> > -	ldr	x1, [sp, #16 + 8]
> > +	get_host_ctxt	x0, x1
> > +	get_vcpu	x1, x0
> >  	mov	x0, #ARM_EXCEPTION_IRQ
> >  	b	__guest_exit
> >  
> >  el1_error:
> >  	stp     x0, x1, [sp, #-16]!
> > -	ldr	x1, [sp, #16 + 8]
> > +	get_host_ctxt	x0, x1
> > +	get_vcpu	x1, x0
> 
> Given how frequent this construct is, would there be a benefit in
> having something like "get_vcpu_ptr" that conflates the two macros? We
> don't seem to have a single case of using get_vcpu on its own.
> 

I think my intention was to make it obvious how we get to the vcpu
pointer, but looking at it now I don't think this adds anything, so I'm
happy to adjust.  How about adding a get_vcpu_ptr macro which calls the
other two macros?

> >  	mov	x0, #ARM_EXCEPTION_EL1_SERROR
> >  	b	__guest_exit
> >  
> > @@ -180,14 +182,7 @@ ENTRY(__hyp_do_panic)
> >  ENDPROC(__hyp_do_panic)
> >  
> >  ENTRY(__hyp_panic)
> > -	/*
> > -	 * '=kvm_host_cpu_state' is a host VA from the constant pool, it may
> > -	 * not be accessible by this address from EL2, hyp_panic() converts
> > -	 * it with kern_hyp_va() before use.
> > -	 */
> > -	ldr	x0, =kvm_host_cpu_state
> > -	mrs	x1, tpidr_el2
> > -	add	x0, x0, x1
> > +	get_host_ctxt x0, x1
> >  	b	hyp_panic
> >  ENDPROC(__hyp_panic)
> >  
> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index b991f85c1133..d1749fa0bfc3 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c
> > @@ -467,7 +467,7 @@ static hyp_alternate_select(__hyp_call_panic,
> >  			    __hyp_call_panic_nvhe, __hyp_call_panic_vhe,
> >  			    ARM64_HAS_VIRT_HOST_EXTN);
> >  
> > -void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt)
> > +void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *host_ctxt)
> >  {
> >  	struct kvm_vcpu *vcpu = NULL;
> >  
> > @@ -476,9 +476,6 @@ void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt)
> >  	u64 par = read_sysreg(par_el1);
> >  
> >  	if (read_sysreg(vttbr_el2)) {
> > -		struct kvm_cpu_context *host_ctxt;
> > -
> > -		host_ctxt = kern_hyp_va(__host_ctxt);
> >  		vcpu = host_ctxt->__hyp_running_vcpu;
> >  		__timer_disable_traps(vcpu);
> >  		__deactivate_traps(vcpu);
> > diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> > index 2c17afd2be96..43b7dd65e3e6 100644
> > --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> > +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> > @@ -189,3 +189,8 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
> >  	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> >  		write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
> >  }
> > +
> > +void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2)
> > +{
> > +	asm("msr tpidr_el2, %0": : "r" (tpidr_el2));
> 
> The paranoid in me says that we'd want an ISB here if we can possibly
> use tpidr_el2 on this path. If we had to manic, for example...
> 

I'm not sure I follow.  Are you not guaranteed that an mrs after msr
would reflect the latest written value, even without an ISB?

> > +}
> > -- 
> > 2.14.2
> > 
> 
> The above notwithstanding,
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> 
Thanks!
-Christoffer

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

* [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
@ 2018-02-22  9:02       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22  9:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 21, 2018 at 11:34:07AM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:02:55 +0000,
> Christoffer Dall wrote:
> > 
> > We already have the percpu area for the host cpu state, which points to
> > the VCPU, so there's no need to store the VCPU pointer on the stack on
> > every context switch.  We can be a little more clever and just use
> > tpidr_el2 for the percpu offset and load the VCPU pointer from the host
> > context.
> > 
> > This does require us to calculate the percpu offset without including
> > the offset from the kernel mapping of the percpu array to the linear
> > mapping of the array (which is what we store in tpidr_el1), because a
> > PC-relative generated address in EL2 is already giving us the hyp alias
> > of the linear mapping of a kernel address.  We do this in
> > __cpu_init_hyp_mode() by using kvm_ksym_ref().
> > 
> > This change also requires us to have a scratch register, so we take the
> > chance to rearrange some of the el1_sync code to only look at the
> > vttbr_el2 to determine if this is a trap from the guest or an HVC from
> > the host.  We do add an extra check to call the panic code if the kernel
> > is configured with debugging enabled and we saw a trap from the host
> > which wasn't an HVC, indicating that we left some EL2 trap configured by
> > mistake.
> > 
> > The code that accesses ESR_EL2 was previously using an alternative to
> > use the _EL1 accessor on VHE systems, but this was actually unnecessary
> > as the _EL1 accessor aliases the ESR_EL2 register on VHE, and the _EL2
> > accessor does the same thing on both systems.
> > 
> > Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v3:
> >      - Reworked the assembly part of the patch after rebasing on v4.16-rc1
> >        which created a conflict with the variant 2 mitigations.
> >      - Removed Marc's reviewed-by due to the rework.
> >      - Removed unneeded extern keyword in declaration in header file
> >     
> >     Changes since v1:
> >      - Use PC-relative addressing to access per-cpu variables instead of
> >        using a load from the literal pool.
> >      - Remove stale comments as pointed out by Marc
> >      - Reworded the commit message as suggested by Drew
> > 
> >  arch/arm64/include/asm/kvm_asm.h  | 14 ++++++++++++++
> >  arch/arm64/include/asm/kvm_host.h | 15 +++++++++++++++
> >  arch/arm64/kernel/asm-offsets.c   |  1 +
> >  arch/arm64/kvm/hyp/entry.S        |  6 +-----
> >  arch/arm64/kvm/hyp/hyp-entry.S    | 31 +++++++++++++------------------
> >  arch/arm64/kvm/hyp/switch.c       |  5 +----
> >  arch/arm64/kvm/hyp/sysreg-sr.c    |  5 +++++
> >  7 files changed, 50 insertions(+), 27 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> > index 24961b732e65..6b626750b0a1 100644
> > --- a/arch/arm64/include/asm/kvm_asm.h
> > +++ b/arch/arm64/include/asm/kvm_asm.h
> > @@ -33,6 +33,7 @@
> >  #define KVM_ARM64_DEBUG_DIRTY_SHIFT	0
> >  #define KVM_ARM64_DEBUG_DIRTY		(1 << KVM_ARM64_DEBUG_DIRTY_SHIFT)
> >  
> > +/* Translate a kernel address of @sym into its equivalent linear mapping */
> >  #define kvm_ksym_ref(sym)						\
> >  	({								\
> >  		void *val = &sym;					\
> > @@ -70,6 +71,19 @@ extern u32 __init_stage2_translation(void);
> >  
> >  extern void __qcom_hyp_sanitize_btac_predictors(void);
> >  
> > +#else /* __ASSEMBLY__ */
> > +
> > +.macro get_host_ctxt reg, tmp
> > +	adr_l	\reg, kvm_host_cpu_state
> > +	mrs	\tmp, tpidr_el2
> > +	add	\reg, \reg, \tmp
> > +.endm
> > +
> > +.macro get_vcpu vcpu, ctxt
> > +	ldr	\vcpu, [\ctxt, #HOST_CONTEXT_VCPU]
> > +	kern_hyp_va	\vcpu
> > +.endm
> > +
> >  #endif
> >  
> >  #endif /* __ARM_KVM_ASM_H__ */
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 596f8e414a4c..618cfee7206a 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -358,10 +358,15 @@ int kvm_perf_teardown(void);
> >  
> >  struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
> >  
> > +void __kvm_set_tpidr_el2(u64 tpidr_el2);
> > +DECLARE_PER_CPU(kvm_cpu_context_t, kvm_host_cpu_state);
> > +
> >  static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
> >  				       unsigned long hyp_stack_ptr,
> >  				       unsigned long vector_ptr)
> >  {
> > +	u64 tpidr_el2;
> > +
> >  	/*
> >  	 * Call initialization code, and switch to the full blown HYP code.
> >  	 * If the cpucaps haven't been finalized yet, something has gone very
> > @@ -370,6 +375,16 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
> >  	 */
> >  	BUG_ON(!static_branch_likely(&arm64_const_caps_ready));
> >  	__kvm_call_hyp((void *)pgd_ptr, hyp_stack_ptr, vector_ptr);
> > +
> > +	/*
> > +	 * Calculate the raw per-cpu offset without a translation from the
> > +	 * kernel's mapping to the linear mapping, and store it in tpidr_el2
> > +	 * so that we can use adr_l to access per-cpu variables in EL2.
> > +	 */
> > +	tpidr_el2 = (u64)this_cpu_ptr(&kvm_host_cpu_state)
> > +		- (u64)kvm_ksym_ref(kvm_host_cpu_state);
> > +
> > +	kvm_call_hyp(__kvm_set_tpidr_el2, tpidr_el2);
> >  }
> >  
> >  static inline void kvm_arch_hardware_unsetup(void) {}
> > diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
> > index 1303e04110cd..78e1b0a70aaf 100644
> > --- a/arch/arm64/kernel/asm-offsets.c
> > +++ b/arch/arm64/kernel/asm-offsets.c
> > @@ -138,6 +138,7 @@ int main(void)
> >    DEFINE(CPU_FP_REGS,		offsetof(struct kvm_regs, fp_regs));
> >    DEFINE(VCPU_FPEXC32_EL2,	offsetof(struct kvm_vcpu, arch.ctxt.sys_regs[FPEXC32_EL2]));
> >    DEFINE(VCPU_HOST_CONTEXT,	offsetof(struct kvm_vcpu, arch.host_cpu_context));
> > +  DEFINE(HOST_CONTEXT_VCPU,	offsetof(struct kvm_cpu_context, __hyp_running_vcpu));
> >  #endif
> >  #ifdef CONFIG_CPU_PM
> >    DEFINE(CPU_SUSPEND_SZ,	sizeof(struct cpu_suspend_ctx));
> > diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
> > index fdd1068ee3a5..1f458f7c3b44 100644
> > --- a/arch/arm64/kvm/hyp/entry.S
> > +++ b/arch/arm64/kvm/hyp/entry.S
> > @@ -62,9 +62,6 @@ ENTRY(__guest_enter)
> >  	// Store the host regs
> >  	save_callee_saved_regs x1
> >  
> > -	// Store host_ctxt and vcpu for use at exit time
> > -	stp	x1, x0, [sp, #-16]!
> > -
> >  	add	x18, x0, #VCPU_CONTEXT
> >  
> >  	// Restore guest regs x0-x17
> > @@ -118,8 +115,7 @@ ENTRY(__guest_exit)
> >  	// Store the guest regs x19-x29, lr
> >  	save_callee_saved_regs x1
> >  
> > -	// Restore the host_ctxt from the stack
> > -	ldr	x2, [sp], #16
> > +	get_host_ctxt	x2, x3
> >  
> >  	// Now restore the host regs
> >  	restore_callee_saved_regs x2
> > diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
> > index f36464bd57c5..559b4d54bc42 100644
> > --- a/arch/arm64/kvm/hyp/hyp-entry.S
> > +++ b/arch/arm64/kvm/hyp/hyp-entry.S
> > @@ -57,13 +57,8 @@ ENDPROC(__vhe_hyp_call)
> >  el1_sync:				// Guest trapped into EL2
> >  	stp	x0, x1, [sp, #-16]!
> >  
> > -alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
> > -	mrs	x1, esr_el2
> > -alternative_else
> > -	mrs	x1, esr_el1
> > -alternative_endif
> > -	lsr	x0, x1, #ESR_ELx_EC_SHIFT
> > -
> > +	mrs	x0, esr_el2
> > +	lsr	x0, x0, #ESR_ELx_EC_SHIFT
> >  	cmp	x0, #ESR_ELx_EC_HVC64
> >  	ccmp	x0, #ESR_ELx_EC_HVC32, #4, ne
> >  	b.ne	el1_trap
> > @@ -117,10 +112,15 @@ el1_hvc_guest:
> >  	eret
> >  
> >  el1_trap:
> > +	get_host_ctxt	x0, x1
> > +	get_vcpu	x1, x0
> > +
> > +	mrs		x0, esr_el2
> > +	lsr		x0, x0, #ESR_ELx_EC_SHIFT
> >  	/*
> >  	 * x0: ESR_EC
> > +	 * x1: vcpu pointer
> >  	 */
> > -	ldr	x1, [sp, #16 + 8]	// vcpu stored by __guest_enter
> >  
> >  	/*
> >  	 * We trap the first access to the FP/SIMD to save the host context
> > @@ -138,13 +138,15 @@ alternative_else_nop_endif
> >  
> >  el1_irq:
> >  	stp     x0, x1, [sp, #-16]!
> > -	ldr	x1, [sp, #16 + 8]
> > +	get_host_ctxt	x0, x1
> > +	get_vcpu	x1, x0
> >  	mov	x0, #ARM_EXCEPTION_IRQ
> >  	b	__guest_exit
> >  
> >  el1_error:
> >  	stp     x0, x1, [sp, #-16]!
> > -	ldr	x1, [sp, #16 + 8]
> > +	get_host_ctxt	x0, x1
> > +	get_vcpu	x1, x0
> 
> Given how frequent this construct is, would there be a benefit in
> having something like "get_vcpu_ptr" that conflates the two macros? We
> don't seem to have a single case of using get_vcpu on its own.
> 

I think my intention was to make it obvious how we get to the vcpu
pointer, but looking at it now I don't think this adds anything, so I'm
happy to adjust.  How about adding a get_vcpu_ptr macro which calls the
other two macros?

> >  	mov	x0, #ARM_EXCEPTION_EL1_SERROR
> >  	b	__guest_exit
> >  
> > @@ -180,14 +182,7 @@ ENTRY(__hyp_do_panic)
> >  ENDPROC(__hyp_do_panic)
> >  
> >  ENTRY(__hyp_panic)
> > -	/*
> > -	 * '=kvm_host_cpu_state' is a host VA from the constant pool, it may
> > -	 * not be accessible by this address from EL2, hyp_panic() converts
> > -	 * it with kern_hyp_va() before use.
> > -	 */
> > -	ldr	x0, =kvm_host_cpu_state
> > -	mrs	x1, tpidr_el2
> > -	add	x0, x0, x1
> > +	get_host_ctxt x0, x1
> >  	b	hyp_panic
> >  ENDPROC(__hyp_panic)
> >  
> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index b991f85c1133..d1749fa0bfc3 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c
> > @@ -467,7 +467,7 @@ static hyp_alternate_select(__hyp_call_panic,
> >  			    __hyp_call_panic_nvhe, __hyp_call_panic_vhe,
> >  			    ARM64_HAS_VIRT_HOST_EXTN);
> >  
> > -void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt)
> > +void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *host_ctxt)
> >  {
> >  	struct kvm_vcpu *vcpu = NULL;
> >  
> > @@ -476,9 +476,6 @@ void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt)
> >  	u64 par = read_sysreg(par_el1);
> >  
> >  	if (read_sysreg(vttbr_el2)) {
> > -		struct kvm_cpu_context *host_ctxt;
> > -
> > -		host_ctxt = kern_hyp_va(__host_ctxt);
> >  		vcpu = host_ctxt->__hyp_running_vcpu;
> >  		__timer_disable_traps(vcpu);
> >  		__deactivate_traps(vcpu);
> > diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> > index 2c17afd2be96..43b7dd65e3e6 100644
> > --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> > +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> > @@ -189,3 +189,8 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
> >  	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> >  		write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
> >  }
> > +
> > +void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2)
> > +{
> > +	asm("msr tpidr_el2, %0": : "r" (tpidr_el2));
> 
> The paranoid in me says that we'd want an ISB here if we can possibly
> use tpidr_el2 on this path. If we had to manic, for example...
> 

I'm not sure I follow.  Are you not guaranteed that an mrs after msr
would reflect the latest written value, even without an ISB?

> > +}
> > -- 
> > 2.14.2
> > 
> 
> The above notwithstanding,
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> 
Thanks!
-Christoffer

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

* Re: [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
  2018-02-21 17:32     ` Andrew Jones
@ 2018-02-22  9:10       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22  9:10 UTC (permalink / raw)
  To: Andrew Jones
  Cc: kvm, Ard Biesheuvel, Marc Zyngier, Tomasz Nowicki, kvmarm,
	Julien Grall, Yury Norov, linux-arm-kernel, Dave Martin,
	Shih-Wei Li

On Wed, Feb 21, 2018 at 06:32:00PM +0100, Andrew Jones wrote:
> On Thu, Feb 15, 2018 at 10:02:55PM +0100, Christoffer Dall wrote:
> > We already have the percpu area for the host cpu state, which points to
> > the VCPU, so there's no need to store the VCPU pointer on the stack on
> > every context switch.  We can be a little more clever and just use
> > tpidr_el2 for the percpu offset and load the VCPU pointer from the host
> > context.
> > 
> > This does require us to calculate the percpu offset without including
> > the offset from the kernel mapping of the percpu array to the linear
> > mapping of the array (which is what we store in tpidr_el1), because a
> > PC-relative generated address in EL2 is already giving us the hyp alias
> > of the linear mapping of a kernel address.  We do this in
> > __cpu_init_hyp_mode() by using kvm_ksym_ref().
> > 
> > This change also requires us to have a scratch register, so we take the
> > chance to rearrange some of the el1_sync code to only look at the
> > vttbr_el2 to determine if this is a trap from the guest or an HVC from
> > the host.  We do add an extra check to call the panic code if the kernel
> > is configured with debugging enabled and we saw a trap from the host
> > which wasn't an HVC, indicating that we left some EL2 trap configured by
> > mistake.
> > 
> > The code that accesses ESR_EL2 was previously using an alternative to
> > use the _EL1 accessor on VHE systems, but this was actually unnecessary
> > as the _EL1 accessor aliases the ESR_EL2 register on VHE, and the _EL2
> > accessor does the same thing on both systems.
> > 
> > Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v3:
> >      - Reworked the assembly part of the patch after rebasing on v4.16-rc1
> >        which created a conflict with the variant 2 mitigations.
> >      - Removed Marc's reviewed-by due to the rework.
> >      - Removed unneeded extern keyword in declaration in header file
> >     
> >     Changes since v1:
> >      - Use PC-relative addressing to access per-cpu variables instead of
> >        using a load from the literal pool.
> >      - Remove stale comments as pointed out by Marc
> >      - Reworded the commit message as suggested by Drew
> > 
> >  arch/arm64/include/asm/kvm_asm.h  | 14 ++++++++++++++
> >  arch/arm64/include/asm/kvm_host.h | 15 +++++++++++++++
> >  arch/arm64/kernel/asm-offsets.c   |  1 +
> >  arch/arm64/kvm/hyp/entry.S        |  6 +-----
> >  arch/arm64/kvm/hyp/hyp-entry.S    | 31 +++++++++++++------------------
> >  arch/arm64/kvm/hyp/switch.c       |  5 +----
> >  arch/arm64/kvm/hyp/sysreg-sr.c    |  5 +++++
> >  7 files changed, 50 insertions(+), 27 deletions(-)
> > 
> 
> I'm not clear on the motivation for this patch. I assumed it enabled
> simpler patches later in the series, but I did a bit of reading ahead
> and didn't see anything obvious. I doubt it gives a speedup, so is it
> just to avoid stack use? Making it easier to maintain these assembly
> functions that span a couple files? If so, should it be posted separately
> from this series? If not, could you please add some more text to the
> commit message helping me better understand the full motivation?

In the past we've had difficulties debugging things where we messed up
the stack because we couldn't get back to the normal world with no
reliable way to get the vcpu pointer.  That was the rationale for
storing the vcpu in a register as opposed to on the stack before.

We only recently changed that so that we could use tpidr_el2 to access
per-CPU variables.  Given that the vcpu pointer can already be found via
per-CPU variables, it makes sense to do that.

In terms of performance, your argument can be applied in isolation to
most patches in this series, and that was the initial approach I took in
the optimization work, only optimizing things that appeared significant
and would likely result in significant changes.  The results were
disappointing.  It was only when I included every micro-optimization for
the critical path that I could think of, that we were able to observe
order of magnitude improvements for some workloads.  Subsequent
measurements confirmed this, it was hard to measure individual benefits
from each patch, but overall the changes matter.

> 
> Besides my confusion on motivation, it looks good to me
> 

In that case, unless there's an argument that the code has become too
hard to understand, ...

> Reviewed-by: Andrew Jones <drjones@redhat.com>
> 
...then thanks!
-Christoffer

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

* [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
@ 2018-02-22  9:10       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22  9:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 21, 2018 at 06:32:00PM +0100, Andrew Jones wrote:
> On Thu, Feb 15, 2018 at 10:02:55PM +0100, Christoffer Dall wrote:
> > We already have the percpu area for the host cpu state, which points to
> > the VCPU, so there's no need to store the VCPU pointer on the stack on
> > every context switch.  We can be a little more clever and just use
> > tpidr_el2 for the percpu offset and load the VCPU pointer from the host
> > context.
> > 
> > This does require us to calculate the percpu offset without including
> > the offset from the kernel mapping of the percpu array to the linear
> > mapping of the array (which is what we store in tpidr_el1), because a
> > PC-relative generated address in EL2 is already giving us the hyp alias
> > of the linear mapping of a kernel address.  We do this in
> > __cpu_init_hyp_mode() by using kvm_ksym_ref().
> > 
> > This change also requires us to have a scratch register, so we take the
> > chance to rearrange some of the el1_sync code to only look at the
> > vttbr_el2 to determine if this is a trap from the guest or an HVC from
> > the host.  We do add an extra check to call the panic code if the kernel
> > is configured with debugging enabled and we saw a trap from the host
> > which wasn't an HVC, indicating that we left some EL2 trap configured by
> > mistake.
> > 
> > The code that accesses ESR_EL2 was previously using an alternative to
> > use the _EL1 accessor on VHE systems, but this was actually unnecessary
> > as the _EL1 accessor aliases the ESR_EL2 register on VHE, and the _EL2
> > accessor does the same thing on both systems.
> > 
> > Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v3:
> >      - Reworked the assembly part of the patch after rebasing on v4.16-rc1
> >        which created a conflict with the variant 2 mitigations.
> >      - Removed Marc's reviewed-by due to the rework.
> >      - Removed unneeded extern keyword in declaration in header file
> >     
> >     Changes since v1:
> >      - Use PC-relative addressing to access per-cpu variables instead of
> >        using a load from the literal pool.
> >      - Remove stale comments as pointed out by Marc
> >      - Reworded the commit message as suggested by Drew
> > 
> >  arch/arm64/include/asm/kvm_asm.h  | 14 ++++++++++++++
> >  arch/arm64/include/asm/kvm_host.h | 15 +++++++++++++++
> >  arch/arm64/kernel/asm-offsets.c   |  1 +
> >  arch/arm64/kvm/hyp/entry.S        |  6 +-----
> >  arch/arm64/kvm/hyp/hyp-entry.S    | 31 +++++++++++++------------------
> >  arch/arm64/kvm/hyp/switch.c       |  5 +----
> >  arch/arm64/kvm/hyp/sysreg-sr.c    |  5 +++++
> >  7 files changed, 50 insertions(+), 27 deletions(-)
> > 
> 
> I'm not clear on the motivation for this patch. I assumed it enabled
> simpler patches later in the series, but I did a bit of reading ahead
> and didn't see anything obvious. I doubt it gives a speedup, so is it
> just to avoid stack use? Making it easier to maintain these assembly
> functions that span a couple files? If so, should it be posted separately
> from this series? If not, could you please add some more text to the
> commit message helping me better understand the full motivation?

In the past we've had difficulties debugging things where we messed up
the stack because we couldn't get back to the normal world with no
reliable way to get the vcpu pointer.  That was the rationale for
storing the vcpu in a register as opposed to on the stack before.

We only recently changed that so that we could use tpidr_el2 to access
per-CPU variables.  Given that the vcpu pointer can already be found via
per-CPU variables, it makes sense to do that.

In terms of performance, your argument can be applied in isolation to
most patches in this series, and that was the initial approach I took in
the optimization work, only optimizing things that appeared significant
and would likely result in significant changes.  The results were
disappointing.  It was only when I included every micro-optimization for
the critical path that I could think of, that we were able to observe
order of magnitude improvements for some workloads.  Subsequent
measurements confirmed this, it was hard to measure individual benefits
from each patch, but overall the changes matter.

> 
> Besides my confusion on motivation, it looks good to me
> 

In that case, unless there's an argument that the code has become too
hard to understand, ...

> Reviewed-by: Andrew Jones <drjones@redhat.com>
> 
...then thanks!
-Christoffer

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

* Re: [PATCH v4 08/40] KVM: arm/arm64: Introduce vcpu_el1_is_32bit
  2018-02-21 12:05     ` Marc Zyngier
@ 2018-02-22  9:11       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22  9:11 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Wed, Feb 21, 2018 at 12:05:27PM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:03:00 +0000,
> Christoffer Dall wrote:
> > 
> > We have numerous checks around that checks if the HCR_EL2 has the RW bit
> > set to figure out if we're running an AArch64 or AArch32 VM.  In some
> > cases, directly checking the RW bit (given its unintuitive name), is a
> > bit confusing, and that's not going to improve as we move logic around
> > for the following patches that optimize KVM on AArch64 hosts with VHE.
> > 
> > Therefore, introduce a helper, vcpu_el1_is_32bit, and replace existing
> > direct checks of HCR_EL2.RW with the helper.
> > 
> > Reviewed-by: Julien Grall <julien.grall@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v2:
> >      - New patch
> >     
> >     Changes since v1:
> >      - Reworded comments as suggested by Drew
> > 
> >  arch/arm64/include/asm/kvm_emulate.h |  7 ++++++-
> >  arch/arm64/kvm/hyp/switch.c          | 11 +++++------
> >  arch/arm64/kvm/hyp/sysreg-sr.c       |  5 +++--
> >  arch/arm64/kvm/inject_fault.c        |  6 +++---
> >  4 files changed, 17 insertions(+), 12 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> > index 9ee316b962c8..3cc535591bdf 100644
> > --- a/arch/arm64/include/asm/kvm_emulate.h
> > +++ b/arch/arm64/include/asm/kvm_emulate.h
> > @@ -45,6 +45,11 @@ void kvm_inject_undef32(struct kvm_vcpu *vcpu);
> >  void kvm_inject_dabt32(struct kvm_vcpu *vcpu, unsigned long addr);
> >  void kvm_inject_pabt32(struct kvm_vcpu *vcpu, unsigned long addr);
> >  
> > +static inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
> > +{
> > +	return !(vcpu->arch.hcr_el2 & HCR_RW);
> > +}
> > +
> >  static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
> >  {
> >  	vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
> > @@ -65,7 +70,7 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
> >  	 * For now this is conditional, since no AArch32 feature regs
> >  	 * are currently virtualised.
> >  	 */
> > -	if (vcpu->arch.hcr_el2 & HCR_RW)
> > +	if (!vcpu_el1_is_32bit(vcpu))
> >  		vcpu->arch.hcr_el2 |= HCR_TID3;
> >  }
> >  
> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index b51638490d85..fbab9752a9f4 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c
> > @@ -74,7 +74,7 @@ static hyp_alternate_select(__activate_traps_arch,
> >  
> >  static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> >  {
> > -	u64 val;
> > +	u64 hcr = vcpu->arch.hcr_el2;
> >  
> >  	/*
> >  	 * We are about to set CPTR_EL2.TFP to trap all floating point
> > @@ -85,17 +85,16 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> >  	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> >  	 * it will cause an exception.
> >  	 */
> > -	val = vcpu->arch.hcr_el2;
> > -
> > -	if (!(val & HCR_RW) && system_supports_fpsimd()) {
> > +	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> >  		write_sysreg(1 << 30, fpexc32_el2);
> >  		isb();
> >  	}
> > -	write_sysreg(val, hcr_el2);
> >  
> > -	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (val & HCR_VSE))
> > +	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
> >  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
> >  
> > +	write_sysreg(hcr, hcr_el2);
> > +
> >  	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
> >  	write_sysreg(1 << 15, hstr_el2);
> >  	/*
> > diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> > index 434f0fc9cfb3..99fc60516103 100644
> > --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> > +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> > @@ -19,6 +19,7 @@
> >  #include <linux/kvm_host.h>
> >  
> >  #include <asm/kvm_asm.h>
> > +#include <asm/kvm_emulate.h>
> >  #include <asm/kvm_hyp.h>
> >  
> >  /* Yes, this does nothing, on purpose */
> > @@ -147,7 +148,7 @@ void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 *spsr, *sysreg;
> >  
> > -	if (read_sysreg(hcr_el2) & HCR_RW)
> > +	if (!vcpu_el1_is_32bit(vcpu))
> >  		return;
> >  
> >  	spsr = vcpu->arch.ctxt.gp_regs.spsr;
> > @@ -172,7 +173,7 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 *spsr, *sysreg;
> >  
> > -	if (read_sysreg(hcr_el2) & HCR_RW)
> > +	if (!vcpu_el1_is_32bit(vcpu))
> >  		return;
> >  
> >  	spsr = vcpu->arch.ctxt.gp_regs.spsr;
> > diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> > index c1e179d34e6a..30a3f58cdb7b 100644
> > --- a/arch/arm64/kvm/inject_fault.c
> > +++ b/arch/arm64/kvm/inject_fault.c
> > @@ -128,7 +128,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
> >   */
> >  void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
> >  {
> > -	if (!(vcpu->arch.hcr_el2 & HCR_RW))
> > +	if (vcpu_el1_is_32bit(vcpu))
> >  		kvm_inject_dabt32(vcpu, addr);
> >  	else
> >  		inject_abt64(vcpu, false, addr);
> > @@ -144,7 +144,7 @@ void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
> >   */
> >  void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
> >  {
> > -	if (!(vcpu->arch.hcr_el2 & HCR_RW))
> > +	if (vcpu_el1_is_32bit(vcpu))
> >  		kvm_inject_pabt32(vcpu, addr);
> >  	else
> >  		inject_abt64(vcpu, true, addr);
> > @@ -158,7 +158,7 @@ void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
> >   */
> >  void kvm_inject_undefined(struct kvm_vcpu *vcpu)
> >  {
> > -	if (!(vcpu->arch.hcr_el2 & HCR_RW))
> > +	if (vcpu_el1_is_32bit(vcpu))
> >  		kvm_inject_undef32(vcpu);
> >  	else
> >  		inject_undef64(vcpu);
> > -- 
> > 2.14.2
> > 
> 
> nit: not strictly necessary, but would it be worth adding a similar
> (and trivial) version of this predicate to the 32bit code? Just to
> keep things in sync?
> 

I could, but wouldn't that add unused code to the kernel at no immediate
benefit?

> Otherwise,
> 
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> 

Thanks,
-Christoffer

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

* [PATCH v4 08/40] KVM: arm/arm64: Introduce vcpu_el1_is_32bit
@ 2018-02-22  9:11       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22  9:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 21, 2018 at 12:05:27PM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:03:00 +0000,
> Christoffer Dall wrote:
> > 
> > We have numerous checks around that checks if the HCR_EL2 has the RW bit
> > set to figure out if we're running an AArch64 or AArch32 VM.  In some
> > cases, directly checking the RW bit (given its unintuitive name), is a
> > bit confusing, and that's not going to improve as we move logic around
> > for the following patches that optimize KVM on AArch64 hosts with VHE.
> > 
> > Therefore, introduce a helper, vcpu_el1_is_32bit, and replace existing
> > direct checks of HCR_EL2.RW with the helper.
> > 
> > Reviewed-by: Julien Grall <julien.grall@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v2:
> >      - New patch
> >     
> >     Changes since v1:
> >      - Reworded comments as suggested by Drew
> > 
> >  arch/arm64/include/asm/kvm_emulate.h |  7 ++++++-
> >  arch/arm64/kvm/hyp/switch.c          | 11 +++++------
> >  arch/arm64/kvm/hyp/sysreg-sr.c       |  5 +++--
> >  arch/arm64/kvm/inject_fault.c        |  6 +++---
> >  4 files changed, 17 insertions(+), 12 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> > index 9ee316b962c8..3cc535591bdf 100644
> > --- a/arch/arm64/include/asm/kvm_emulate.h
> > +++ b/arch/arm64/include/asm/kvm_emulate.h
> > @@ -45,6 +45,11 @@ void kvm_inject_undef32(struct kvm_vcpu *vcpu);
> >  void kvm_inject_dabt32(struct kvm_vcpu *vcpu, unsigned long addr);
> >  void kvm_inject_pabt32(struct kvm_vcpu *vcpu, unsigned long addr);
> >  
> > +static inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
> > +{
> > +	return !(vcpu->arch.hcr_el2 & HCR_RW);
> > +}
> > +
> >  static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
> >  {
> >  	vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
> > @@ -65,7 +70,7 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
> >  	 * For now this is conditional, since no AArch32 feature regs
> >  	 * are currently virtualised.
> >  	 */
> > -	if (vcpu->arch.hcr_el2 & HCR_RW)
> > +	if (!vcpu_el1_is_32bit(vcpu))
> >  		vcpu->arch.hcr_el2 |= HCR_TID3;
> >  }
> >  
> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index b51638490d85..fbab9752a9f4 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c
> > @@ -74,7 +74,7 @@ static hyp_alternate_select(__activate_traps_arch,
> >  
> >  static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> >  {
> > -	u64 val;
> > +	u64 hcr = vcpu->arch.hcr_el2;
> >  
> >  	/*
> >  	 * We are about to set CPTR_EL2.TFP to trap all floating point
> > @@ -85,17 +85,16 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> >  	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> >  	 * it will cause an exception.
> >  	 */
> > -	val = vcpu->arch.hcr_el2;
> > -
> > -	if (!(val & HCR_RW) && system_supports_fpsimd()) {
> > +	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> >  		write_sysreg(1 << 30, fpexc32_el2);
> >  		isb();
> >  	}
> > -	write_sysreg(val, hcr_el2);
> >  
> > -	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (val & HCR_VSE))
> > +	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
> >  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
> >  
> > +	write_sysreg(hcr, hcr_el2);
> > +
> >  	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
> >  	write_sysreg(1 << 15, hstr_el2);
> >  	/*
> > diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> > index 434f0fc9cfb3..99fc60516103 100644
> > --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> > +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> > @@ -19,6 +19,7 @@
> >  #include <linux/kvm_host.h>
> >  
> >  #include <asm/kvm_asm.h>
> > +#include <asm/kvm_emulate.h>
> >  #include <asm/kvm_hyp.h>
> >  
> >  /* Yes, this does nothing, on purpose */
> > @@ -147,7 +148,7 @@ void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 *spsr, *sysreg;
> >  
> > -	if (read_sysreg(hcr_el2) & HCR_RW)
> > +	if (!vcpu_el1_is_32bit(vcpu))
> >  		return;
> >  
> >  	spsr = vcpu->arch.ctxt.gp_regs.spsr;
> > @@ -172,7 +173,7 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 *spsr, *sysreg;
> >  
> > -	if (read_sysreg(hcr_el2) & HCR_RW)
> > +	if (!vcpu_el1_is_32bit(vcpu))
> >  		return;
> >  
> >  	spsr = vcpu->arch.ctxt.gp_regs.spsr;
> > diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> > index c1e179d34e6a..30a3f58cdb7b 100644
> > --- a/arch/arm64/kvm/inject_fault.c
> > +++ b/arch/arm64/kvm/inject_fault.c
> > @@ -128,7 +128,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
> >   */
> >  void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
> >  {
> > -	if (!(vcpu->arch.hcr_el2 & HCR_RW))
> > +	if (vcpu_el1_is_32bit(vcpu))
> >  		kvm_inject_dabt32(vcpu, addr);
> >  	else
> >  		inject_abt64(vcpu, false, addr);
> > @@ -144,7 +144,7 @@ void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
> >   */
> >  void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
> >  {
> > -	if (!(vcpu->arch.hcr_el2 & HCR_RW))
> > +	if (vcpu_el1_is_32bit(vcpu))
> >  		kvm_inject_pabt32(vcpu, addr);
> >  	else
> >  		inject_abt64(vcpu, true, addr);
> > @@ -158,7 +158,7 @@ void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
> >   */
> >  void kvm_inject_undefined(struct kvm_vcpu *vcpu)
> >  {
> > -	if (!(vcpu->arch.hcr_el2 & HCR_RW))
> > +	if (vcpu_el1_is_32bit(vcpu))
> >  		kvm_inject_undef32(vcpu);
> >  	else
> >  		inject_undef64(vcpu);
> > -- 
> > 2.14.2
> > 
> 
> nit: not strictly necessary, but would it be worth adding a similar
> (and trivial) version of this predicate to the 32bit code? Just to
> keep things in sync?
> 

I could, but wouldn't that add unused code to the kernel at no immediate
benefit?

> Otherwise,
> 
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> 

Thanks,
-Christoffer

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

* Re: [PATCH v4 13/40] KVM: arm64: Introduce VHE-specific kvm_vcpu_run
  2018-02-21 18:18       ` Andrew Jones
@ 2018-02-22  9:16         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22  9:16 UTC (permalink / raw)
  To: Andrew Jones
  Cc: kvm, Marc Zyngier, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Wed, Feb 21, 2018 at 07:18:32PM +0100, Andrew Jones wrote:
> On Wed, Feb 21, 2018 at 06:43:00PM +0100, Andrew Jones wrote:
> > On Thu, Feb 15, 2018 at 10:03:05PM +0100, Christoffer Dall wrote:
> > > So far this is mostly (see below) a copy of the legacy non-VHE switch
> > > function, but we will start reworking these functions in separate
> > > directions to work on VHE and non-VHE in the most optimal way in later
> > > patches.
> > > 
> > > The only difference after this patch between the VHE and non-VHE run
> > > functions is that we omit the branch-predictor variant-2 hardening for
> > > QC Falkor CPUs, because this workaround is specific to a series of
> > > non-VHE ARMv8.0 CPUs.
> > > 
> > > Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> > > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > > ---
> > > 
> > > Notes:
> > >     Changes since v3:
> > >      - Added BUG() to 32-bit ARM VHE run function
> > >      - Omitted QC Falkor BP Hardening functionality from VHE-specific
> > >        function
> > >     
> > >     Changes since v2:
> > >      - Reworded commit message
> > >     
> > >     Changes since v1:
> > >      - Rename kvm_vcpu_run to kvm_vcpu_run_vhe and rename __kvm_vcpu_run to
> > >        __kvm_vcpu_run_nvhe
> > >      - Removed stray whitespace line
> > > 
> > >  arch/arm/include/asm/kvm_asm.h   |  5 ++-
> > >  arch/arm/kvm/hyp/switch.c        |  2 +-
> > >  arch/arm64/include/asm/kvm_asm.h |  4 ++-
> > >  arch/arm64/kvm/hyp/switch.c      | 66 +++++++++++++++++++++++++++++++++++++++-
> > >  virt/kvm/arm/arm.c               |  5 ++-
> > >  5 files changed, 77 insertions(+), 5 deletions(-)
> > > 
> > 
> > ...
> > 
> > > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > > index 2062d9357971..5bd879c78951 100644
> > > --- a/virt/kvm/arm/arm.c
> > > +++ b/virt/kvm/arm/arm.c
> > > @@ -736,7 +736,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> > >  		if (has_vhe())
> > >  			kvm_arm_vhe_guest_enter();
> > >  
> > > -		ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);
> > > +		if (has_vhe())
> > > +			ret = kvm_vcpu_run_vhe(vcpu);
> > > +		else
> > > +			ret = kvm_call_hyp(__kvm_vcpu_run_nvhe, vcpu);
> > >  
> > >  		if (has_vhe())
> > >  			kvm_arm_vhe_guest_exit();
> > 
> > We can combine these has_vhe()'s
> > 
> >  if (has_vhe()) {
> >     kvm_arm_vhe_guest_enter();
> >     ret = kvm_vcpu_run_vhe(vcpu);
> >     kvm_arm_vhe_guest_exit();
> >  } else
> >     ret = kvm_call_hyp(__kvm_vcpu_run_nvhe, vcpu);
> 
> Maybe even do a cleanup patch that removes
> kvm_arm_vhe_guest_enter/exit by putting the daif
> masking/restoring directly into kvm_vcpu_run_vhe()?
> 
Yes, indeed.  This is a blind rebasing result on my part.

Thanks,
-Christoffer

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

* [PATCH v4 13/40] KVM: arm64: Introduce VHE-specific kvm_vcpu_run
@ 2018-02-22  9:16         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22  9:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 21, 2018 at 07:18:32PM +0100, Andrew Jones wrote:
> On Wed, Feb 21, 2018 at 06:43:00PM +0100, Andrew Jones wrote:
> > On Thu, Feb 15, 2018 at 10:03:05PM +0100, Christoffer Dall wrote:
> > > So far this is mostly (see below) a copy of the legacy non-VHE switch
> > > function, but we will start reworking these functions in separate
> > > directions to work on VHE and non-VHE in the most optimal way in later
> > > patches.
> > > 
> > > The only difference after this patch between the VHE and non-VHE run
> > > functions is that we omit the branch-predictor variant-2 hardening for
> > > QC Falkor CPUs, because this workaround is specific to a series of
> > > non-VHE ARMv8.0 CPUs.
> > > 
> > > Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> > > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > > ---
> > > 
> > > Notes:
> > >     Changes since v3:
> > >      - Added BUG() to 32-bit ARM VHE run function
> > >      - Omitted QC Falkor BP Hardening functionality from VHE-specific
> > >        function
> > >     
> > >     Changes since v2:
> > >      - Reworded commit message
> > >     
> > >     Changes since v1:
> > >      - Rename kvm_vcpu_run to kvm_vcpu_run_vhe and rename __kvm_vcpu_run to
> > >        __kvm_vcpu_run_nvhe
> > >      - Removed stray whitespace line
> > > 
> > >  arch/arm/include/asm/kvm_asm.h   |  5 ++-
> > >  arch/arm/kvm/hyp/switch.c        |  2 +-
> > >  arch/arm64/include/asm/kvm_asm.h |  4 ++-
> > >  arch/arm64/kvm/hyp/switch.c      | 66 +++++++++++++++++++++++++++++++++++++++-
> > >  virt/kvm/arm/arm.c               |  5 ++-
> > >  5 files changed, 77 insertions(+), 5 deletions(-)
> > > 
> > 
> > ...
> > 
> > > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > > index 2062d9357971..5bd879c78951 100644
> > > --- a/virt/kvm/arm/arm.c
> > > +++ b/virt/kvm/arm/arm.c
> > > @@ -736,7 +736,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> > >  		if (has_vhe())
> > >  			kvm_arm_vhe_guest_enter();
> > >  
> > > -		ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);
> > > +		if (has_vhe())
> > > +			ret = kvm_vcpu_run_vhe(vcpu);
> > > +		else
> > > +			ret = kvm_call_hyp(__kvm_vcpu_run_nvhe, vcpu);
> > >  
> > >  		if (has_vhe())
> > >  			kvm_arm_vhe_guest_exit();
> > 
> > We can combine these has_vhe()'s
> > 
> >  if (has_vhe()) {
> >     kvm_arm_vhe_guest_enter();
> >     ret = kvm_vcpu_run_vhe(vcpu);
> >     kvm_arm_vhe_guest_exit();
> >  } else
> >     ret = kvm_call_hyp(__kvm_vcpu_run_nvhe, vcpu);
> 
> Maybe even do a cleanup patch that removes
> kvm_arm_vhe_guest_enter/exit by putting the daif
> masking/restoring directly into kvm_vcpu_run_vhe()?
> 
Yes, indeed.  This is a blind rebasing result on my part.

Thanks,
-Christoffer

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

* Re: [PATCH v4 17/40] KVM: arm64: Move userspace system registers into separate function
  2018-02-19 17:21     ` Julien Grall
@ 2018-02-22  9:18       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22  9:18 UTC (permalink / raw)
  To: Julien Grall
  Cc: Andrew Jones, kvm, Marc Zyngier, Tomasz Nowicki, Dave Martin,
	Yury Norov, linux-arm-kernel, kvmarm, Shih-Wei Li

On Mon, Feb 19, 2018 at 05:21:17PM +0000, Julien Grall wrote:
> Hi Christoffer,
> 
> On 15/02/18 21:03, Christoffer Dall wrote:
> >There's a semantic difference between the EL1 registers that control
> >operation of a kernel running in EL1 and EL1 registers that only control
> >userspace execution in EL0.  Since we can defer saving/restoring the
> >latter, move them into their own function.
> >
> >ACTLR_EL1 is not used by a VHE host, so we can move this register into
> >the EL1 state which is not saved/restored for a VHE host.
> 
> Looking at D10.2.1 (ARM DDI 0487C.a), the statement regarding the use of
> ACTLR_EL1 seems to be less strong than what you state here. It looks like it
> would be possible to have hardware where ACTLR_EL1 would still have an
> effect on host EL0. I also read the comments on the version 2 of this patch
> but I wasn't able to find what I missing.
> 
As Marc points out, I'll add a reference to the spec that says that Arm
recommends ACTLR_EL1 not having an effect on VHE host EL0.  While
potentially possible, it's unlikely, and we can fix that later if anyone
builds a platform with VHE that we care about that uses ACTLR_EL1 for
VHE host EL0.

Thanks,
-Christoffer

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

* [PATCH v4 17/40] KVM: arm64: Move userspace system registers into separate function
@ 2018-02-22  9:18       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22  9:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Feb 19, 2018 at 05:21:17PM +0000, Julien Grall wrote:
> Hi Christoffer,
> 
> On 15/02/18 21:03, Christoffer Dall wrote:
> >There's a semantic difference between the EL1 registers that control
> >operation of a kernel running in EL1 and EL1 registers that only control
> >userspace execution in EL0.  Since we can defer saving/restoring the
> >latter, move them into their own function.
> >
> >ACTLR_EL1 is not used by a VHE host, so we can move this register into
> >the EL1 state which is not saved/restored for a VHE host.
> 
> Looking at D10.2.1 (ARM DDI 0487C.a), the statement regarding the use of
> ACTLR_EL1 seems to be less strong than what you state here. It looks like it
> would be possible to have hardware where ACTLR_EL1 would still have an
> effect on host EL0. I also read the comments on the version 2 of this patch
> but I wasn't able to find what I missing.
> 
As Marc points out, I'll add a reference to the spec that says that Arm
recommends ACTLR_EL1 not having an effect on VHE host EL0.  While
potentially possible, it's unlikely, and we can fix that later if anyone
builds a platform with VHE that we care about that uses ACTLR_EL1 for
VHE host EL0.

Thanks,
-Christoffer

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

* Re: [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
  2018-02-19 18:12     ` Julien Grall
@ 2018-02-22  9:18       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22  9:18 UTC (permalink / raw)
  To: Julien Grall
  Cc: Christoffer Dall, Andrew Jones, kvm, Marc Zyngier,
	Tomasz Nowicki, Dave Martin, Yury Norov, linux-arm-kernel,
	kvmarm, Shih-Wei Li

On Mon, Feb 19, 2018 at 06:12:29PM +0000, Julien Grall wrote:
> Hi Christoffer,
> 
> On 15/02/18 21:03, Christoffer Dall wrote:
> >From: Christoffer Dall <cdall@cs.columbia.edu>
> >
> >Currently we access the system registers array via the vcpu_sys_reg()
> >macro.  However, we are about to change the behavior to some times
> >modify the register file directly, so let's change this to two
> >primitives:
> >
> >  * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
> >  * Direct array access macro __vcpu_sys_reg()
> >
> >The first primitive should be used in places where the code needs to
> >access the currently loaded VCPU's state as observed by the guest.  For
> >example, when trapping on cache related registers, a write to a system
> >register should go directly to the VCPU version of the register.
> >
> >The second primitive can be used in places where the VCPU is known to
> 
> "second primitive" is a bit confusing here. I count 3 primitives above:
> (vcpu_write_sys_reg(), vcpu_read_sys_reg() and __vcpu_sys_reg(). From the
> description, I would say to refer to the latter (i.e third one).
> 

Good point.  I'll clarify.

> >never be running (for example userspace access) or for registers which
> >are never context switched (for example all the PMU system registers).
> >
> >This rewrites all users of vcpu_sys_regs to one of the two primitives
> >above.
> >
> >No functional change.
> >
> >Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> 
> [...]
> 
> >diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> >index f2a6f39aec87..68398bf7882f 100644
> >--- a/arch/arm64/include/asm/kvm_host.h
> >+++ b/arch/arm64/include/asm/kvm_host.h
> >@@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
> >  };
> >  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> >-#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> >+
> >+/*
> >+ * Only use __vcpu_sys_reg if you know you want the memory backed version of a
> >+ * register, and not the one most recently accessed by a runnning VCPU.  For
> 
> NIT: s/runnning/running/
> 
> >+ * example, for userpace access or for system registers that are never context
> 
> NIT: s/userpace/userspace/
> 
> >+ * switched, but only emulated.
> >+ */
> >+#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> >+
> >+#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> >+#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> >+
> >  /*
> >   * CP14 and CP15 live in the same array, as they are backed by the
> >   * same system registers.
> 
> [...]
> 
> >diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> >index b48af790615e..a05d2c01c786 100644
> >--- a/arch/arm64/kvm/sys_regs.c
> >+++ b/arch/arm64/kvm/sys_regs.c
> 
> [...]
> 
> >@@ -817,10 +818,10 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> >  			return false;
> >  		}
> >-		vcpu_sys_reg(vcpu, PMUSERENR_EL0) = p->regval
> >-						    & ARMV8_PMU_USERENR_MASK;
> >-	} else {
> >-		p->regval = vcpu_sys_reg(vcpu, PMUSERENR_EL0)
> >+		__vcpu_sys_reg(vcpu, PMUSERENR_EL0) =
> >+			       p->regval & ARMV8_PMU_USERENR_MASK;
> >+	} else  {
> 
> NIT: There is a double space between else and {.
> 
> >+		p->regval = __vcpu_sys_reg(vcpu, PMUSERENR_EL0)
> >  			    & ARMV8_PMU_USERENR_MASK;
> >  	}
> 
Thanks,
-Christoffer

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

* [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
@ 2018-02-22  9:18       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22  9:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Feb 19, 2018 at 06:12:29PM +0000, Julien Grall wrote:
> Hi Christoffer,
> 
> On 15/02/18 21:03, Christoffer Dall wrote:
> >From: Christoffer Dall <cdall@cs.columbia.edu>
> >
> >Currently we access the system registers array via the vcpu_sys_reg()
> >macro.  However, we are about to change the behavior to some times
> >modify the register file directly, so let's change this to two
> >primitives:
> >
> >  * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
> >  * Direct array access macro __vcpu_sys_reg()
> >
> >The first primitive should be used in places where the code needs to
> >access the currently loaded VCPU's state as observed by the guest.  For
> >example, when trapping on cache related registers, a write to a system
> >register should go directly to the VCPU version of the register.
> >
> >The second primitive can be used in places where the VCPU is known to
> 
> "second primitive" is a bit confusing here. I count 3 primitives above:
> (vcpu_write_sys_reg(), vcpu_read_sys_reg() and __vcpu_sys_reg(). From the
> description, I would say to refer to the latter (i.e third one).
> 

Good point.  I'll clarify.

> >never be running (for example userspace access) or for registers which
> >are never context switched (for example all the PMU system registers).
> >
> >This rewrites all users of vcpu_sys_regs to one of the two primitives
> >above.
> >
> >No functional change.
> >
> >Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> 
> [...]
> 
> >diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> >index f2a6f39aec87..68398bf7882f 100644
> >--- a/arch/arm64/include/asm/kvm_host.h
> >+++ b/arch/arm64/include/asm/kvm_host.h
> >@@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
> >  };
> >  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> >-#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> >+
> >+/*
> >+ * Only use __vcpu_sys_reg if you know you want the memory backed version of a
> >+ * register, and not the one most recently accessed by a runnning VCPU.  For
> 
> NIT: s/runnning/running/
> 
> >+ * example, for userpace access or for system registers that are never context
> 
> NIT: s/userpace/userspace/
> 
> >+ * switched, but only emulated.
> >+ */
> >+#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> >+
> >+#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> >+#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> >+
> >  /*
> >   * CP14 and CP15 live in the same array, as they are backed by the
> >   * same system registers.
> 
> [...]
> 
> >diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> >index b48af790615e..a05d2c01c786 100644
> >--- a/arch/arm64/kvm/sys_regs.c
> >+++ b/arch/arm64/kvm/sys_regs.c
> 
> [...]
> 
> >@@ -817,10 +818,10 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> >  			return false;
> >  		}
> >-		vcpu_sys_reg(vcpu, PMUSERENR_EL0) = p->regval
> >-						    & ARMV8_PMU_USERENR_MASK;
> >-	} else {
> >-		p->regval = vcpu_sys_reg(vcpu, PMUSERENR_EL0)
> >+		__vcpu_sys_reg(vcpu, PMUSERENR_EL0) =
> >+			       p->regval & ARMV8_PMU_USERENR_MASK;
> >+	} else  {
> 
> NIT: There is a double space between else and {.
> 
> >+		p->regval = __vcpu_sys_reg(vcpu, PMUSERENR_EL0)
> >  			    & ARMV8_PMU_USERENR_MASK;
> >  	}
> 
Thanks,
-Christoffer

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

* Re: [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
  2018-02-21 13:32     ` Marc Zyngier
@ 2018-02-22  9:22       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22  9:22 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, Andrew Jones, kvm, Tomasz Nowicki, kvmarm,
	Julien Grall, Yury Norov, linux-arm-kernel, Dave Martin,
	Shih-Wei Li

On Wed, Feb 21, 2018 at 01:32:45PM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:03:16 +0000,
> Christoffer Dall wrote:
> > 
> > From: Christoffer Dall <cdall@cs.columbia.edu>
> > 
> > Currently we access the system registers array via the vcpu_sys_reg()
> > macro.  However, we are about to change the behavior to some times
> > modify the register file directly, so let's change this to two
> > primitives:
> > 
> >  * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
> >  * Direct array access macro __vcpu_sys_reg()
> > 
> > The first primitive should be used in places where the code needs to
> > access the currently loaded VCPU's state as observed by the guest.  For
> > example, when trapping on cache related registers, a write to a system
> > register should go directly to the VCPU version of the register.
> > 
> > The second primitive can be used in places where the VCPU is known to
> > never be running (for example userspace access) or for registers which
> > are never context switched (for example all the PMU system registers).
> > 
> > This rewrites all users of vcpu_sys_regs to one of the two primitives
> > above.
> > 
> > No functional change.
> > 
> > Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> > ---
> > 
> > Notes:
> >     Changes since v2:
> >      - New patch (deferred register handling has been reworked)
> > 
> >  arch/arm64/include/asm/kvm_emulate.h | 13 ++++---
> >  arch/arm64/include/asm/kvm_host.h    | 13 ++++++-
> >  arch/arm64/include/asm/kvm_mmu.h     |  2 +-
> >  arch/arm64/kvm/debug.c               | 27 +++++++++-----
> >  arch/arm64/kvm/inject_fault.c        |  8 ++--
> >  arch/arm64/kvm/sys_regs.c            | 71 ++++++++++++++++++------------------
> >  arch/arm64/kvm/sys_regs.h            |  4 +-
> >  arch/arm64/kvm/sys_regs_generic_v8.c |  4 +-
> >  virt/kvm/arm/pmu.c                   | 37 ++++++++++---------
> >  9 files changed, 102 insertions(+), 77 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> > index 3cc535591bdf..d313aaae5c38 100644
> > --- a/arch/arm64/include/asm/kvm_emulate.h
> > +++ b/arch/arm64/include/asm/kvm_emulate.h
> > @@ -290,15 +290,18 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
> >  
> >  static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
> >  {
> > -	return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> > +	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> >  }
> >  
> >  static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
> >  {
> > -	if (vcpu_mode_is_32bit(vcpu))
> > +	if (vcpu_mode_is_32bit(vcpu)) {
> >  		*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
> > -	else
> > -		vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
> > +	} else {
> > +		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
> > +		sctlr |= (1 << 25);
> > +		vcpu_write_sys_reg(vcpu, SCTLR_EL1, sctlr);
> 
> General comment: it is slightly annoying that vcpu_write_sys_reg takes
> its parameters in an order different from that of write_sysreg
> (register followed with value, instead of value followed with
> register). Not a deal breaker, but slightly confusing.
> 

Ah, I didn't compare to write_sysreg, I was thinking that

  vcpu_read_sys_reg(vcpu, SCTLR_EL1);
  vcpu_write_sys_reg(vcpu, SCTLR_EL1, val);

looked more symmetrical because the write just takes an extra value, but
I can see your argument as well.

I don't mind changing it if it matters to you?

> > +	}
> >  }
> >  
> >  static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> > @@ -306,7 +309,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> >  	if (vcpu_mode_is_32bit(vcpu))
> >  		return !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_E_BIT);
> >  
> > -	return !!(vcpu_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> > +	return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> >  }
> >  
> >  static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index f2a6f39aec87..68398bf7882f 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
> >  };
> >  
> >  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> > -#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> > +
> > +/*
> > + * Only use __vcpu_sys_reg if you know you want the memory backed version of a
> > + * register, and not the one most recently accessed by a runnning VCPU.  For
> > + * example, for userpace access or for system registers that are never context
> > + * switched, but only emulated.
> > + */
> > +#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> > +
> > +#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> > +#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> > +
> >  /*
> >   * CP14 and CP15 live in the same array, as they are backed by the
> >   * same system registers.
> > diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> > index 9679067a1574..95f46e73c4dc 100644
> > --- a/arch/arm64/include/asm/kvm_mmu.h
> > +++ b/arch/arm64/include/asm/kvm_mmu.h
> > @@ -249,7 +249,7 @@ struct kvm;
> >  
> >  static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
> >  {
> > -	return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> > +	return (vcpu_read_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> >  }
> >  
> >  static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
> > diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> > index feedb877cff8..db32d10a56a1 100644
> > --- a/arch/arm64/kvm/debug.c
> > +++ b/arch/arm64/kvm/debug.c
> > @@ -46,7 +46,8 @@ static DEFINE_PER_CPU(u32, mdcr_el2);
> >   */
> >  static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
> >  {
> > -	vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1);
> > +	vcpu->arch.guest_debug_preserved.mdscr_el1 =
> > +		vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> >  
> >  	trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
> >  				vcpu->arch.guest_debug_preserved.mdscr_el1);
> > @@ -54,10 +55,11 @@ static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
> >  
> >  static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
> >  {
> > -	vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1;
> > +	vcpu_write_sys_reg(vcpu, MDSCR_EL1,
> > +			   vcpu->arch.guest_debug_preserved.mdscr_el1);
> >  
> >  	trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
> > -				vcpu_sys_reg(vcpu, MDSCR_EL1));
> > +				vcpu_read_sys_reg(vcpu, MDSCR_EL1));
> >  }
> >  
> >  /**
> > @@ -108,6 +110,7 @@ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
> >  void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> >  {
> >  	bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY);
> > +	unsigned long mdscr;
> >  
> >  	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
> >  
> > @@ -152,9 +155,13 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> >  		 */
> >  		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
> >  			*vcpu_cpsr(vcpu) |=  DBG_SPSR_SS;
> > -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_SS;
> > +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> > +			mdscr |= DBG_MDSCR_SS;
> > +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
> 
> I have the feeling that we're going to need some clearbits/setbits
> variants of vcpu_write_sysreg at some point.
> 

I can introduce these now if you prefer?

> It otherwise looks correct to me.
> 
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> 
Thanks,
-Christoffer

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

* [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
@ 2018-02-22  9:22       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22  9:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 21, 2018 at 01:32:45PM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:03:16 +0000,
> Christoffer Dall wrote:
> > 
> > From: Christoffer Dall <cdall@cs.columbia.edu>
> > 
> > Currently we access the system registers array via the vcpu_sys_reg()
> > macro.  However, we are about to change the behavior to some times
> > modify the register file directly, so let's change this to two
> > primitives:
> > 
> >  * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
> >  * Direct array access macro __vcpu_sys_reg()
> > 
> > The first primitive should be used in places where the code needs to
> > access the currently loaded VCPU's state as observed by the guest.  For
> > example, when trapping on cache related registers, a write to a system
> > register should go directly to the VCPU version of the register.
> > 
> > The second primitive can be used in places where the VCPU is known to
> > never be running (for example userspace access) or for registers which
> > are never context switched (for example all the PMU system registers).
> > 
> > This rewrites all users of vcpu_sys_regs to one of the two primitives
> > above.
> > 
> > No functional change.
> > 
> > Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> > ---
> > 
> > Notes:
> >     Changes since v2:
> >      - New patch (deferred register handling has been reworked)
> > 
> >  arch/arm64/include/asm/kvm_emulate.h | 13 ++++---
> >  arch/arm64/include/asm/kvm_host.h    | 13 ++++++-
> >  arch/arm64/include/asm/kvm_mmu.h     |  2 +-
> >  arch/arm64/kvm/debug.c               | 27 +++++++++-----
> >  arch/arm64/kvm/inject_fault.c        |  8 ++--
> >  arch/arm64/kvm/sys_regs.c            | 71 ++++++++++++++++++------------------
> >  arch/arm64/kvm/sys_regs.h            |  4 +-
> >  arch/arm64/kvm/sys_regs_generic_v8.c |  4 +-
> >  virt/kvm/arm/pmu.c                   | 37 ++++++++++---------
> >  9 files changed, 102 insertions(+), 77 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> > index 3cc535591bdf..d313aaae5c38 100644
> > --- a/arch/arm64/include/asm/kvm_emulate.h
> > +++ b/arch/arm64/include/asm/kvm_emulate.h
> > @@ -290,15 +290,18 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
> >  
> >  static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
> >  {
> > -	return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> > +	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> >  }
> >  
> >  static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
> >  {
> > -	if (vcpu_mode_is_32bit(vcpu))
> > +	if (vcpu_mode_is_32bit(vcpu)) {
> >  		*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
> > -	else
> > -		vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
> > +	} else {
> > +		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
> > +		sctlr |= (1 << 25);
> > +		vcpu_write_sys_reg(vcpu, SCTLR_EL1, sctlr);
> 
> General comment: it is slightly annoying that vcpu_write_sys_reg takes
> its parameters in an order different from that of write_sysreg
> (register followed with value, instead of value followed with
> register). Not a deal breaker, but slightly confusing.
> 

Ah, I didn't compare to write_sysreg, I was thinking that

  vcpu_read_sys_reg(vcpu, SCTLR_EL1);
  vcpu_write_sys_reg(vcpu, SCTLR_EL1, val);

looked more symmetrical because the write just takes an extra value, but
I can see your argument as well.

I don't mind changing it if it matters to you?

> > +	}
> >  }
> >  
> >  static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> > @@ -306,7 +309,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> >  	if (vcpu_mode_is_32bit(vcpu))
> >  		return !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_E_BIT);
> >  
> > -	return !!(vcpu_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> > +	return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> >  }
> >  
> >  static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index f2a6f39aec87..68398bf7882f 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
> >  };
> >  
> >  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> > -#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> > +
> > +/*
> > + * Only use __vcpu_sys_reg if you know you want the memory backed version of a
> > + * register, and not the one most recently accessed by a runnning VCPU.  For
> > + * example, for userpace access or for system registers that are never context
> > + * switched, but only emulated.
> > + */
> > +#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> > +
> > +#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> > +#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> > +
> >  /*
> >   * CP14 and CP15 live in the same array, as they are backed by the
> >   * same system registers.
> > diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> > index 9679067a1574..95f46e73c4dc 100644
> > --- a/arch/arm64/include/asm/kvm_mmu.h
> > +++ b/arch/arm64/include/asm/kvm_mmu.h
> > @@ -249,7 +249,7 @@ struct kvm;
> >  
> >  static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
> >  {
> > -	return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> > +	return (vcpu_read_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> >  }
> >  
> >  static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
> > diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> > index feedb877cff8..db32d10a56a1 100644
> > --- a/arch/arm64/kvm/debug.c
> > +++ b/arch/arm64/kvm/debug.c
> > @@ -46,7 +46,8 @@ static DEFINE_PER_CPU(u32, mdcr_el2);
> >   */
> >  static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
> >  {
> > -	vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1);
> > +	vcpu->arch.guest_debug_preserved.mdscr_el1 =
> > +		vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> >  
> >  	trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
> >  				vcpu->arch.guest_debug_preserved.mdscr_el1);
> > @@ -54,10 +55,11 @@ static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
> >  
> >  static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
> >  {
> > -	vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1;
> > +	vcpu_write_sys_reg(vcpu, MDSCR_EL1,
> > +			   vcpu->arch.guest_debug_preserved.mdscr_el1);
> >  
> >  	trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
> > -				vcpu_sys_reg(vcpu, MDSCR_EL1));
> > +				vcpu_read_sys_reg(vcpu, MDSCR_EL1));
> >  }
> >  
> >  /**
> > @@ -108,6 +110,7 @@ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
> >  void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> >  {
> >  	bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY);
> > +	unsigned long mdscr;
> >  
> >  	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
> >  
> > @@ -152,9 +155,13 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> >  		 */
> >  		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
> >  			*vcpu_cpsr(vcpu) |=  DBG_SPSR_SS;
> > -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_SS;
> > +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> > +			mdscr |= DBG_MDSCR_SS;
> > +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
> 
> I have the feeling that we're going to need some clearbits/setbits
> variants of vcpu_write_sysreg at some point.
> 

I can introduce these now if you prefer?

> It otherwise looks correct to me.
> 
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> 
Thanks,
-Christoffer

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

* Re: [PATCH v4 26/40] KVM: arm/arm64: Prepare to handle deferred save/restore of SPSR_EL1
  2018-02-21 14:47     ` Marc Zyngier
@ 2018-02-22  9:25       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22  9:25 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Wed, Feb 21, 2018 at 02:47:44PM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:03:18 +0000,
> Christoffer Dall wrote:
> > 
> > SPSR_EL1 is not used by a VHE host kernel and can be deferred, but we
> > need to rework the accesses to this register to access the latest value
> > depending on whether or not guest system registers are loaded on the CPU
> > or only reside in memory.
> > 
> > The handling of accessing the various banked SPSRs for 32-bit VMs is a
> > bit clunky, but this will be improved in following patches which will
> > first prepare and subsequently implement deferred save/restore of the
> > 32-bit registers, including the 32-bit SPSRs.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v2:
> >      - New patch (deferred register handling has been reworked)
> > 
> >  arch/arm/include/asm/kvm_emulate.h   | 12 ++++++++++-
> >  arch/arm/kvm/emulate.c               |  2 +-
> >  arch/arm64/include/asm/kvm_emulate.h | 41 +++++++++++++++++++++++++++++++-----
> >  arch/arm64/kvm/inject_fault.c        |  4 ++--
> >  virt/kvm/arm/aarch32.c               |  2 +-
> >  5 files changed, 51 insertions(+), 10 deletions(-)
> > 
> > diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h
> > index e27caa4b47a1..6493bd479ddc 100644
> > --- a/arch/arm/include/asm/kvm_emulate.h
> > +++ b/arch/arm/include/asm/kvm_emulate.h
> > @@ -41,7 +41,17 @@ static inline unsigned long *vcpu_reg32(struct kvm_vcpu *vcpu, u8 reg_num)
> >  	return vcpu_reg(vcpu, reg_num);
> >  }
> >  
> > -unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu);
> > +unsigned long *__vcpu_spsr(struct kvm_vcpu *vcpu);
> > +
> > +static inline unsigned long vpcu_read_spsr(struct kvm_vcpu *vcpu)
> > +{
> > +	return *__vcpu_spsr(vcpu);
> > +}
> > +
> > +static inline void vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long v)
> > +{
> > +	*__vcpu_spsr(vcpu) = v;
> > +}
> >  
> >  static inline unsigned long vcpu_get_reg(struct kvm_vcpu *vcpu,
> >  					 u8 reg_num)
> > diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
> > index fa501bf437f3..9046b53d87c1 100644
> > --- a/arch/arm/kvm/emulate.c
> > +++ b/arch/arm/kvm/emulate.c
> > @@ -142,7 +142,7 @@ unsigned long *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num)
> >  /*
> >   * Return the SPSR for the current mode of the virtual CPU.
> >   */
> > -unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu)
> > +unsigned long *__vcpu_spsr(struct kvm_vcpu *vcpu)
> >  {
> >  	unsigned long mode = *vcpu_cpsr(vcpu) & MODE_MASK;
> >  	switch (mode) {
> > diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> > index d313aaae5c38..47c2406755fa 100644
> > --- a/arch/arm64/include/asm/kvm_emulate.h
> > +++ b/arch/arm64/include/asm/kvm_emulate.h
> > @@ -26,6 +26,7 @@
> >  
> >  #include <asm/esr.h>
> >  #include <asm/kvm_arm.h>
> > +#include <asm/kvm_hyp.h>
> >  #include <asm/kvm_mmio.h>
> >  #include <asm/ptrace.h>
> >  #include <asm/cputype.h>
> > @@ -143,13 +144,43 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
> >  		vcpu_gp_regs(vcpu)->regs.regs[reg_num] = val;
> >  }
> >  
> > -/* Get vcpu SPSR for current mode */
> > -static inline unsigned long *vcpu_spsr(const struct kvm_vcpu *vcpu)
> > +static inline unsigned long vcpu_read_spsr(const struct kvm_vcpu *vcpu)
> >  {
> > -	if (vcpu_mode_is_32bit(vcpu))
> > -		return vcpu_spsr32(vcpu);
> > +	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> > +
> > +	if (vcpu_mode_is_32bit(vcpu)) {
> > +		unsigned long *p_32bit = vcpu_spsr32(vcpu);
> > +
> > +		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> > +		if (p_32bit != (unsigned long *)p)
> > +			return *p_32bit;
> 
> Clunky, you said? ;-) p is already an unsigned long *, so there's no
> need to cast it.
> 

Right, I think this is a leftover from some attempts at making this less
terrible, but this was eventually the least terrible.  Believe it or
not.

> > +	}
> > +
> > +	if (vcpu->arch.sysregs_loaded_on_cpu)
> > +		return read_sysreg_el1(spsr);
> > +	else
> > +		return *p;
> > +}
> >  
> > -	return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> > +static inline void vcpu_write_spsr(const struct kvm_vcpu *vcpu, unsigned long v)
> > +{
> > +	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> > +
> > +	/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> > +	if (vcpu_mode_is_32bit(vcpu)) {
> > +		unsigned long *p_32bit = vcpu_spsr32(vcpu);
> > +
> > +		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> > +		if (p_32bit != (unsigned long *)p) {
> > +			*p_32bit = v;
> > +			return;
> 
> Same remark.
> 
> > +		}
> > +	}
> > +
> > +	if (vcpu->arch.sysregs_loaded_on_cpu)
> > +		write_sysreg_el1(v, spsr);
> > +	else
> > +		*p = v;
> >  }
> >  
> >  static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
> > diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> > index e08db2f2dd75..8dda1edae727 100644
> > --- a/arch/arm64/kvm/inject_fault.c
> > +++ b/arch/arm64/kvm/inject_fault.c
> > @@ -71,7 +71,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
> >  	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
> >  
> >  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> > -	*vcpu_spsr(vcpu) = cpsr;
> > +	vcpu_write_spsr(vcpu, cpsr);
> >  
> >  	vcpu_write_sys_reg(vcpu, FAR_EL1, addr);
> >  
> > @@ -106,7 +106,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
> >  	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
> >  
> >  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> > -	*vcpu_spsr(vcpu) = cpsr;
> > +	vcpu_write_spsr(vcpu, cpsr);
> >  
> >  	/*
> >  	 * Build an unknown exception, depending on the instruction
> > diff --git a/virt/kvm/arm/aarch32.c b/virt/kvm/arm/aarch32.c
> > index 8bc479fa37e6..efc84cbe8277 100644
> > --- a/virt/kvm/arm/aarch32.c
> > +++ b/virt/kvm/arm/aarch32.c
> > @@ -178,7 +178,7 @@ static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
> >  	*vcpu_cpsr(vcpu) = cpsr;
> >  
> >  	/* Note: These now point to the banked copies */
> > -	*vcpu_spsr(vcpu) = new_spsr_value;
> > +	vcpu_write_spsr(vcpu, new_spsr_value);
> >  	*vcpu_reg32(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
> >  
> >  	/* Branch to exception vector */
> > -- 
> > 2.14.2
> > 
> 
> Otherwise:
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> 
> 	M.
> 
Thanks, I'll fix the above.
-Christoffer

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

* [PATCH v4 26/40] KVM: arm/arm64: Prepare to handle deferred save/restore of SPSR_EL1
@ 2018-02-22  9:25       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22  9:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 21, 2018 at 02:47:44PM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:03:18 +0000,
> Christoffer Dall wrote:
> > 
> > SPSR_EL1 is not used by a VHE host kernel and can be deferred, but we
> > need to rework the accesses to this register to access the latest value
> > depending on whether or not guest system registers are loaded on the CPU
> > or only reside in memory.
> > 
> > The handling of accessing the various banked SPSRs for 32-bit VMs is a
> > bit clunky, but this will be improved in following patches which will
> > first prepare and subsequently implement deferred save/restore of the
> > 32-bit registers, including the 32-bit SPSRs.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v2:
> >      - New patch (deferred register handling has been reworked)
> > 
> >  arch/arm/include/asm/kvm_emulate.h   | 12 ++++++++++-
> >  arch/arm/kvm/emulate.c               |  2 +-
> >  arch/arm64/include/asm/kvm_emulate.h | 41 +++++++++++++++++++++++++++++++-----
> >  arch/arm64/kvm/inject_fault.c        |  4 ++--
> >  virt/kvm/arm/aarch32.c               |  2 +-
> >  5 files changed, 51 insertions(+), 10 deletions(-)
> > 
> > diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h
> > index e27caa4b47a1..6493bd479ddc 100644
> > --- a/arch/arm/include/asm/kvm_emulate.h
> > +++ b/arch/arm/include/asm/kvm_emulate.h
> > @@ -41,7 +41,17 @@ static inline unsigned long *vcpu_reg32(struct kvm_vcpu *vcpu, u8 reg_num)
> >  	return vcpu_reg(vcpu, reg_num);
> >  }
> >  
> > -unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu);
> > +unsigned long *__vcpu_spsr(struct kvm_vcpu *vcpu);
> > +
> > +static inline unsigned long vpcu_read_spsr(struct kvm_vcpu *vcpu)
> > +{
> > +	return *__vcpu_spsr(vcpu);
> > +}
> > +
> > +static inline void vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long v)
> > +{
> > +	*__vcpu_spsr(vcpu) = v;
> > +}
> >  
> >  static inline unsigned long vcpu_get_reg(struct kvm_vcpu *vcpu,
> >  					 u8 reg_num)
> > diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
> > index fa501bf437f3..9046b53d87c1 100644
> > --- a/arch/arm/kvm/emulate.c
> > +++ b/arch/arm/kvm/emulate.c
> > @@ -142,7 +142,7 @@ unsigned long *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num)
> >  /*
> >   * Return the SPSR for the current mode of the virtual CPU.
> >   */
> > -unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu)
> > +unsigned long *__vcpu_spsr(struct kvm_vcpu *vcpu)
> >  {
> >  	unsigned long mode = *vcpu_cpsr(vcpu) & MODE_MASK;
> >  	switch (mode) {
> > diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> > index d313aaae5c38..47c2406755fa 100644
> > --- a/arch/arm64/include/asm/kvm_emulate.h
> > +++ b/arch/arm64/include/asm/kvm_emulate.h
> > @@ -26,6 +26,7 @@
> >  
> >  #include <asm/esr.h>
> >  #include <asm/kvm_arm.h>
> > +#include <asm/kvm_hyp.h>
> >  #include <asm/kvm_mmio.h>
> >  #include <asm/ptrace.h>
> >  #include <asm/cputype.h>
> > @@ -143,13 +144,43 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
> >  		vcpu_gp_regs(vcpu)->regs.regs[reg_num] = val;
> >  }
> >  
> > -/* Get vcpu SPSR for current mode */
> > -static inline unsigned long *vcpu_spsr(const struct kvm_vcpu *vcpu)
> > +static inline unsigned long vcpu_read_spsr(const struct kvm_vcpu *vcpu)
> >  {
> > -	if (vcpu_mode_is_32bit(vcpu))
> > -		return vcpu_spsr32(vcpu);
> > +	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> > +
> > +	if (vcpu_mode_is_32bit(vcpu)) {
> > +		unsigned long *p_32bit = vcpu_spsr32(vcpu);
> > +
> > +		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> > +		if (p_32bit != (unsigned long *)p)
> > +			return *p_32bit;
> 
> Clunky, you said? ;-) p is already an unsigned long *, so there's no
> need to cast it.
> 

Right, I think this is a leftover from some attempts at making this less
terrible, but this was eventually the least terrible.  Believe it or
not.

> > +	}
> > +
> > +	if (vcpu->arch.sysregs_loaded_on_cpu)
> > +		return read_sysreg_el1(spsr);
> > +	else
> > +		return *p;
> > +}
> >  
> > -	return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> > +static inline void vcpu_write_spsr(const struct kvm_vcpu *vcpu, unsigned long v)
> > +{
> > +	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> > +
> > +	/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> > +	if (vcpu_mode_is_32bit(vcpu)) {
> > +		unsigned long *p_32bit = vcpu_spsr32(vcpu);
> > +
> > +		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> > +		if (p_32bit != (unsigned long *)p) {
> > +			*p_32bit = v;
> > +			return;
> 
> Same remark.
> 
> > +		}
> > +	}
> > +
> > +	if (vcpu->arch.sysregs_loaded_on_cpu)
> > +		write_sysreg_el1(v, spsr);
> > +	else
> > +		*p = v;
> >  }
> >  
> >  static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
> > diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> > index e08db2f2dd75..8dda1edae727 100644
> > --- a/arch/arm64/kvm/inject_fault.c
> > +++ b/arch/arm64/kvm/inject_fault.c
> > @@ -71,7 +71,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
> >  	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
> >  
> >  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> > -	*vcpu_spsr(vcpu) = cpsr;
> > +	vcpu_write_spsr(vcpu, cpsr);
> >  
> >  	vcpu_write_sys_reg(vcpu, FAR_EL1, addr);
> >  
> > @@ -106,7 +106,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
> >  	*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
> >  
> >  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> > -	*vcpu_spsr(vcpu) = cpsr;
> > +	vcpu_write_spsr(vcpu, cpsr);
> >  
> >  	/*
> >  	 * Build an unknown exception, depending on the instruction
> > diff --git a/virt/kvm/arm/aarch32.c b/virt/kvm/arm/aarch32.c
> > index 8bc479fa37e6..efc84cbe8277 100644
> > --- a/virt/kvm/arm/aarch32.c
> > +++ b/virt/kvm/arm/aarch32.c
> > @@ -178,7 +178,7 @@ static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
> >  	*vcpu_cpsr(vcpu) = cpsr;
> >  
> >  	/* Note: These now point to the banked copies */
> > -	*vcpu_spsr(vcpu) = new_spsr_value;
> > +	vcpu_write_spsr(vcpu, new_spsr_value);
> >  	*vcpu_reg32(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
> >  
> >  	/* Branch to exception vector */
> > -- 
> > 2.14.2
> > 
> 
> Otherwise:
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> 
> 	M.
> 
Thanks, I'll fix the above.
-Christoffer

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

* Re: [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
  2018-02-22  9:02       ` Christoffer Dall
@ 2018-02-22  9:35         ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-22  9:35 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andrew Jones, kvm, Ard Biesheuvel, Tomasz Nowicki, kvmarm,
	Julien Grall, Yury Norov, linux-arm-kernel, Dave Martin,
	Shih-Wei Li

On Thu, 22 Feb 2018 09:02:48 +0000,
Christoffer Dall wrote:
> 
> On Wed, Feb 21, 2018 at 11:34:07AM +0000, Marc Zyngier wrote:
> > On Thu, 15 Feb 2018 21:02:55 +0000,
> > Christoffer Dall wrote:
> > > 
> > > We already have the percpu area for the host cpu state, which points to
> > > the VCPU, so there's no need to store the VCPU pointer on the stack on
> > > every context switch.  We can be a little more clever and just use
> > > tpidr_el2 for the percpu offset and load the VCPU pointer from the host
> > > context.
> > > 
> > > This does require us to calculate the percpu offset without including
> > > the offset from the kernel mapping of the percpu array to the linear
> > > mapping of the array (which is what we store in tpidr_el1), because a
> > > PC-relative generated address in EL2 is already giving us the hyp alias
> > > of the linear mapping of a kernel address.  We do this in
> > > __cpu_init_hyp_mode() by using kvm_ksym_ref().
> > > 
> > > This change also requires us to have a scratch register, so we take the
> > > chance to rearrange some of the el1_sync code to only look at the
> > > vttbr_el2 to determine if this is a trap from the guest or an HVC from
> > > the host.  We do add an extra check to call the panic code if the kernel
> > > is configured with debugging enabled and we saw a trap from the host
> > > which wasn't an HVC, indicating that we left some EL2 trap configured by
> > > mistake.
> > > 
> > > The code that accesses ESR_EL2 was previously using an alternative to
> > > use the _EL1 accessor on VHE systems, but this was actually unnecessary
> > > as the _EL1 accessor aliases the ESR_EL2 register on VHE, and the _EL2
> > > accessor does the same thing on both systems.
> > > 
> > > Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > > ---
> > > 
> > > Notes:
> > >     Changes since v3:
> > >      - Reworked the assembly part of the patch after rebasing on v4.16-rc1
> > >        which created a conflict with the variant 2 mitigations.
> > >      - Removed Marc's reviewed-by due to the rework.
> > >      - Removed unneeded extern keyword in declaration in header file
> > >     
> > >     Changes since v1:
> > >      - Use PC-relative addressing to access per-cpu variables instead of
> > >        using a load from the literal pool.
> > >      - Remove stale comments as pointed out by Marc
> > >      - Reworded the commit message as suggested by Drew
> > > 
> > >  arch/arm64/include/asm/kvm_asm.h  | 14 ++++++++++++++
> > >  arch/arm64/include/asm/kvm_host.h | 15 +++++++++++++++
> > >  arch/arm64/kernel/asm-offsets.c   |  1 +
> > >  arch/arm64/kvm/hyp/entry.S        |  6 +-----
> > >  arch/arm64/kvm/hyp/hyp-entry.S    | 31 +++++++++++++------------------
> > >  arch/arm64/kvm/hyp/switch.c       |  5 +----
> > >  arch/arm64/kvm/hyp/sysreg-sr.c    |  5 +++++
> > >  7 files changed, 50 insertions(+), 27 deletions(-)
> > > 
> > > diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> > > index 24961b732e65..6b626750b0a1 100644
> > > --- a/arch/arm64/include/asm/kvm_asm.h
> > > +++ b/arch/arm64/include/asm/kvm_asm.h
> > > @@ -33,6 +33,7 @@
> > >  #define KVM_ARM64_DEBUG_DIRTY_SHIFT	0
> > >  #define KVM_ARM64_DEBUG_DIRTY		(1 << KVM_ARM64_DEBUG_DIRTY_SHIFT)
> > >  
> > > +/* Translate a kernel address of @sym into its equivalent linear mapping */
> > >  #define kvm_ksym_ref(sym)						\
> > >  	({								\
> > >  		void *val = &sym;					\
> > > @@ -70,6 +71,19 @@ extern u32 __init_stage2_translation(void);
> > >  
> > >  extern void __qcom_hyp_sanitize_btac_predictors(void);
> > >  
> > > +#else /* __ASSEMBLY__ */
> > > +
> > > +.macro get_host_ctxt reg, tmp
> > > +	adr_l	\reg, kvm_host_cpu_state
> > > +	mrs	\tmp, tpidr_el2
> > > +	add	\reg, \reg, \tmp
> > > +.endm
> > > +
> > > +.macro get_vcpu vcpu, ctxt
> > > +	ldr	\vcpu, [\ctxt, #HOST_CONTEXT_VCPU]
> > > +	kern_hyp_va	\vcpu
> > > +.endm
> > > +
> > >  #endif
> > >  
> > >  #endif /* __ARM_KVM_ASM_H__ */
> > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > index 596f8e414a4c..618cfee7206a 100644
> > > --- a/arch/arm64/include/asm/kvm_host.h
> > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > @@ -358,10 +358,15 @@ int kvm_perf_teardown(void);
> > >  
> > >  struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
> > >  
> > > +void __kvm_set_tpidr_el2(u64 tpidr_el2);
> > > +DECLARE_PER_CPU(kvm_cpu_context_t, kvm_host_cpu_state);
> > > +
> > >  static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
> > >  				       unsigned long hyp_stack_ptr,
> > >  				       unsigned long vector_ptr)
> > >  {
> > > +	u64 tpidr_el2;
> > > +
> > >  	/*
> > >  	 * Call initialization code, and switch to the full blown HYP code.
> > >  	 * If the cpucaps haven't been finalized yet, something has gone very
> > > @@ -370,6 +375,16 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
> > >  	 */
> > >  	BUG_ON(!static_branch_likely(&arm64_const_caps_ready));
> > >  	__kvm_call_hyp((void *)pgd_ptr, hyp_stack_ptr, vector_ptr);
> > > +
> > > +	/*
> > > +	 * Calculate the raw per-cpu offset without a translation from the
> > > +	 * kernel's mapping to the linear mapping, and store it in tpidr_el2
> > > +	 * so that we can use adr_l to access per-cpu variables in EL2.
> > > +	 */
> > > +	tpidr_el2 = (u64)this_cpu_ptr(&kvm_host_cpu_state)
> > > +		- (u64)kvm_ksym_ref(kvm_host_cpu_state);
> > > +
> > > +	kvm_call_hyp(__kvm_set_tpidr_el2, tpidr_el2);
> > >  }
> > >  
> > >  static inline void kvm_arch_hardware_unsetup(void) {}
> > > diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
> > > index 1303e04110cd..78e1b0a70aaf 100644
> > > --- a/arch/arm64/kernel/asm-offsets.c
> > > +++ b/arch/arm64/kernel/asm-offsets.c
> > > @@ -138,6 +138,7 @@ int main(void)
> > >    DEFINE(CPU_FP_REGS,		offsetof(struct kvm_regs, fp_regs));
> > >    DEFINE(VCPU_FPEXC32_EL2,	offsetof(struct kvm_vcpu, arch.ctxt.sys_regs[FPEXC32_EL2]));
> > >    DEFINE(VCPU_HOST_CONTEXT,	offsetof(struct kvm_vcpu, arch.host_cpu_context));
> > > +  DEFINE(HOST_CONTEXT_VCPU,	offsetof(struct kvm_cpu_context, __hyp_running_vcpu));
> > >  #endif
> > >  #ifdef CONFIG_CPU_PM
> > >    DEFINE(CPU_SUSPEND_SZ,	sizeof(struct cpu_suspend_ctx));
> > > diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
> > > index fdd1068ee3a5..1f458f7c3b44 100644
> > > --- a/arch/arm64/kvm/hyp/entry.S
> > > +++ b/arch/arm64/kvm/hyp/entry.S
> > > @@ -62,9 +62,6 @@ ENTRY(__guest_enter)
> > >  	// Store the host regs
> > >  	save_callee_saved_regs x1
> > >  
> > > -	// Store host_ctxt and vcpu for use at exit time
> > > -	stp	x1, x0, [sp, #-16]!
> > > -
> > >  	add	x18, x0, #VCPU_CONTEXT
> > >  
> > >  	// Restore guest regs x0-x17
> > > @@ -118,8 +115,7 @@ ENTRY(__guest_exit)
> > >  	// Store the guest regs x19-x29, lr
> > >  	save_callee_saved_regs x1
> > >  
> > > -	// Restore the host_ctxt from the stack
> > > -	ldr	x2, [sp], #16
> > > +	get_host_ctxt	x2, x3
> > >  
> > >  	// Now restore the host regs
> > >  	restore_callee_saved_regs x2
> > > diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
> > > index f36464bd57c5..559b4d54bc42 100644
> > > --- a/arch/arm64/kvm/hyp/hyp-entry.S
> > > +++ b/arch/arm64/kvm/hyp/hyp-entry.S
> > > @@ -57,13 +57,8 @@ ENDPROC(__vhe_hyp_call)
> > >  el1_sync:				// Guest trapped into EL2
> > >  	stp	x0, x1, [sp, #-16]!
> > >  
> > > -alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
> > > -	mrs	x1, esr_el2
> > > -alternative_else
> > > -	mrs	x1, esr_el1
> > > -alternative_endif
> > > -	lsr	x0, x1, #ESR_ELx_EC_SHIFT
> > > -
> > > +	mrs	x0, esr_el2
> > > +	lsr	x0, x0, #ESR_ELx_EC_SHIFT
> > >  	cmp	x0, #ESR_ELx_EC_HVC64
> > >  	ccmp	x0, #ESR_ELx_EC_HVC32, #4, ne
> > >  	b.ne	el1_trap
> > > @@ -117,10 +112,15 @@ el1_hvc_guest:
> > >  	eret
> > >  
> > >  el1_trap:
> > > +	get_host_ctxt	x0, x1
> > > +	get_vcpu	x1, x0
> > > +
> > > +	mrs		x0, esr_el2
> > > +	lsr		x0, x0, #ESR_ELx_EC_SHIFT
> > >  	/*
> > >  	 * x0: ESR_EC
> > > +	 * x1: vcpu pointer
> > >  	 */
> > > -	ldr	x1, [sp, #16 + 8]	// vcpu stored by __guest_enter
> > >  
> > >  	/*
> > >  	 * We trap the first access to the FP/SIMD to save the host context
> > > @@ -138,13 +138,15 @@ alternative_else_nop_endif
> > >  
> > >  el1_irq:
> > >  	stp     x0, x1, [sp, #-16]!
> > > -	ldr	x1, [sp, #16 + 8]
> > > +	get_host_ctxt	x0, x1
> > > +	get_vcpu	x1, x0
> > >  	mov	x0, #ARM_EXCEPTION_IRQ
> > >  	b	__guest_exit
> > >  
> > >  el1_error:
> > >  	stp     x0, x1, [sp, #-16]!
> > > -	ldr	x1, [sp, #16 + 8]
> > > +	get_host_ctxt	x0, x1
> > > +	get_vcpu	x1, x0
> > 
> > Given how frequent this construct is, would there be a benefit in
> > having something like "get_vcpu_ptr" that conflates the two macros? We
> > don't seem to have a single case of using get_vcpu on its own.
> > 
> 
> I think my intention was to make it obvious how we get to the vcpu
> pointer, but looking at it now I don't think this adds anything, so I'm
> happy to adjust.  How about adding a get_vcpu_ptr macro which calls the
> other two macros?

Sure, that would make sense.

> 
> > >  	mov	x0, #ARM_EXCEPTION_EL1_SERROR
> > >  	b	__guest_exit
> > >  
> > > @@ -180,14 +182,7 @@ ENTRY(__hyp_do_panic)
> > >  ENDPROC(__hyp_do_panic)
> > >  
> > >  ENTRY(__hyp_panic)
> > > -	/*
> > > -	 * '=kvm_host_cpu_state' is a host VA from the constant pool, it may
> > > -	 * not be accessible by this address from EL2, hyp_panic() converts
> > > -	 * it with kern_hyp_va() before use.
> > > -	 */
> > > -	ldr	x0, =kvm_host_cpu_state
> > > -	mrs	x1, tpidr_el2
> > > -	add	x0, x0, x1
> > > +	get_host_ctxt x0, x1
> > >  	b	hyp_panic
> > >  ENDPROC(__hyp_panic)
> > >  
> > > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > > index b991f85c1133..d1749fa0bfc3 100644
> > > --- a/arch/arm64/kvm/hyp/switch.c
> > > +++ b/arch/arm64/kvm/hyp/switch.c
> > > @@ -467,7 +467,7 @@ static hyp_alternate_select(__hyp_call_panic,
> > >  			    __hyp_call_panic_nvhe, __hyp_call_panic_vhe,
> > >  			    ARM64_HAS_VIRT_HOST_EXTN);
> > >  
> > > -void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt)
> > > +void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *host_ctxt)
> > >  {
> > >  	struct kvm_vcpu *vcpu = NULL;
> > >  
> > > @@ -476,9 +476,6 @@ void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt)
> > >  	u64 par = read_sysreg(par_el1);
> > >  
> > >  	if (read_sysreg(vttbr_el2)) {
> > > -		struct kvm_cpu_context *host_ctxt;
> > > -
> > > -		host_ctxt = kern_hyp_va(__host_ctxt);
> > >  		vcpu = host_ctxt->__hyp_running_vcpu;
> > >  		__timer_disable_traps(vcpu);
> > >  		__deactivate_traps(vcpu);
> > > diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> > > index 2c17afd2be96..43b7dd65e3e6 100644
> > > --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> > > +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> > > @@ -189,3 +189,8 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
> > >  	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> > >  		write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
> > >  }
> > > +
> > > +void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2)
> > > +{
> > > +	asm("msr tpidr_el2, %0": : "r" (tpidr_el2));
> > 
> > The paranoid in me says that we'd want an ISB here if we can possibly
> > use tpidr_el2 on this path. If we had to manic, for example...
> > 
> 
> I'm not sure I follow.  Are you not guaranteed that an mrs after msr
> would reflect the latest written value, even without an ISB?

You're absolutely right. /me dropping paranoia levels.

Thanks,

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
@ 2018-02-22  9:35         ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-22  9:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 22 Feb 2018 09:02:48 +0000,
Christoffer Dall wrote:
> 
> On Wed, Feb 21, 2018 at 11:34:07AM +0000, Marc Zyngier wrote:
> > On Thu, 15 Feb 2018 21:02:55 +0000,
> > Christoffer Dall wrote:
> > > 
> > > We already have the percpu area for the host cpu state, which points to
> > > the VCPU, so there's no need to store the VCPU pointer on the stack on
> > > every context switch.  We can be a little more clever and just use
> > > tpidr_el2 for the percpu offset and load the VCPU pointer from the host
> > > context.
> > > 
> > > This does require us to calculate the percpu offset without including
> > > the offset from the kernel mapping of the percpu array to the linear
> > > mapping of the array (which is what we store in tpidr_el1), because a
> > > PC-relative generated address in EL2 is already giving us the hyp alias
> > > of the linear mapping of a kernel address.  We do this in
> > > __cpu_init_hyp_mode() by using kvm_ksym_ref().
> > > 
> > > This change also requires us to have a scratch register, so we take the
> > > chance to rearrange some of the el1_sync code to only look at the
> > > vttbr_el2 to determine if this is a trap from the guest or an HVC from
> > > the host.  We do add an extra check to call the panic code if the kernel
> > > is configured with debugging enabled and we saw a trap from the host
> > > which wasn't an HVC, indicating that we left some EL2 trap configured by
> > > mistake.
> > > 
> > > The code that accesses ESR_EL2 was previously using an alternative to
> > > use the _EL1 accessor on VHE systems, but this was actually unnecessary
> > > as the _EL1 accessor aliases the ESR_EL2 register on VHE, and the _EL2
> > > accessor does the same thing on both systems.
> > > 
> > > Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > > ---
> > > 
> > > Notes:
> > >     Changes since v3:
> > >      - Reworked the assembly part of the patch after rebasing on v4.16-rc1
> > >        which created a conflict with the variant 2 mitigations.
> > >      - Removed Marc's reviewed-by due to the rework.
> > >      - Removed unneeded extern keyword in declaration in header file
> > >     
> > >     Changes since v1:
> > >      - Use PC-relative addressing to access per-cpu variables instead of
> > >        using a load from the literal pool.
> > >      - Remove stale comments as pointed out by Marc
> > >      - Reworded the commit message as suggested by Drew
> > > 
> > >  arch/arm64/include/asm/kvm_asm.h  | 14 ++++++++++++++
> > >  arch/arm64/include/asm/kvm_host.h | 15 +++++++++++++++
> > >  arch/arm64/kernel/asm-offsets.c   |  1 +
> > >  arch/arm64/kvm/hyp/entry.S        |  6 +-----
> > >  arch/arm64/kvm/hyp/hyp-entry.S    | 31 +++++++++++++------------------
> > >  arch/arm64/kvm/hyp/switch.c       |  5 +----
> > >  arch/arm64/kvm/hyp/sysreg-sr.c    |  5 +++++
> > >  7 files changed, 50 insertions(+), 27 deletions(-)
> > > 
> > > diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> > > index 24961b732e65..6b626750b0a1 100644
> > > --- a/arch/arm64/include/asm/kvm_asm.h
> > > +++ b/arch/arm64/include/asm/kvm_asm.h
> > > @@ -33,6 +33,7 @@
> > >  #define KVM_ARM64_DEBUG_DIRTY_SHIFT	0
> > >  #define KVM_ARM64_DEBUG_DIRTY		(1 << KVM_ARM64_DEBUG_DIRTY_SHIFT)
> > >  
> > > +/* Translate a kernel address of @sym into its equivalent linear mapping */
> > >  #define kvm_ksym_ref(sym)						\
> > >  	({								\
> > >  		void *val = &sym;					\
> > > @@ -70,6 +71,19 @@ extern u32 __init_stage2_translation(void);
> > >  
> > >  extern void __qcom_hyp_sanitize_btac_predictors(void);
> > >  
> > > +#else /* __ASSEMBLY__ */
> > > +
> > > +.macro get_host_ctxt reg, tmp
> > > +	adr_l	\reg, kvm_host_cpu_state
> > > +	mrs	\tmp, tpidr_el2
> > > +	add	\reg, \reg, \tmp
> > > +.endm
> > > +
> > > +.macro get_vcpu vcpu, ctxt
> > > +	ldr	\vcpu, [\ctxt, #HOST_CONTEXT_VCPU]
> > > +	kern_hyp_va	\vcpu
> > > +.endm
> > > +
> > >  #endif
> > >  
> > >  #endif /* __ARM_KVM_ASM_H__ */
> > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > index 596f8e414a4c..618cfee7206a 100644
> > > --- a/arch/arm64/include/asm/kvm_host.h
> > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > @@ -358,10 +358,15 @@ int kvm_perf_teardown(void);
> > >  
> > >  struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
> > >  
> > > +void __kvm_set_tpidr_el2(u64 tpidr_el2);
> > > +DECLARE_PER_CPU(kvm_cpu_context_t, kvm_host_cpu_state);
> > > +
> > >  static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
> > >  				       unsigned long hyp_stack_ptr,
> > >  				       unsigned long vector_ptr)
> > >  {
> > > +	u64 tpidr_el2;
> > > +
> > >  	/*
> > >  	 * Call initialization code, and switch to the full blown HYP code.
> > >  	 * If the cpucaps haven't been finalized yet, something has gone very
> > > @@ -370,6 +375,16 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
> > >  	 */
> > >  	BUG_ON(!static_branch_likely(&arm64_const_caps_ready));
> > >  	__kvm_call_hyp((void *)pgd_ptr, hyp_stack_ptr, vector_ptr);
> > > +
> > > +	/*
> > > +	 * Calculate the raw per-cpu offset without a translation from the
> > > +	 * kernel's mapping to the linear mapping, and store it in tpidr_el2
> > > +	 * so that we can use adr_l to access per-cpu variables in EL2.
> > > +	 */
> > > +	tpidr_el2 = (u64)this_cpu_ptr(&kvm_host_cpu_state)
> > > +		- (u64)kvm_ksym_ref(kvm_host_cpu_state);
> > > +
> > > +	kvm_call_hyp(__kvm_set_tpidr_el2, tpidr_el2);
> > >  }
> > >  
> > >  static inline void kvm_arch_hardware_unsetup(void) {}
> > > diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
> > > index 1303e04110cd..78e1b0a70aaf 100644
> > > --- a/arch/arm64/kernel/asm-offsets.c
> > > +++ b/arch/arm64/kernel/asm-offsets.c
> > > @@ -138,6 +138,7 @@ int main(void)
> > >    DEFINE(CPU_FP_REGS,		offsetof(struct kvm_regs, fp_regs));
> > >    DEFINE(VCPU_FPEXC32_EL2,	offsetof(struct kvm_vcpu, arch.ctxt.sys_regs[FPEXC32_EL2]));
> > >    DEFINE(VCPU_HOST_CONTEXT,	offsetof(struct kvm_vcpu, arch.host_cpu_context));
> > > +  DEFINE(HOST_CONTEXT_VCPU,	offsetof(struct kvm_cpu_context, __hyp_running_vcpu));
> > >  #endif
> > >  #ifdef CONFIG_CPU_PM
> > >    DEFINE(CPU_SUSPEND_SZ,	sizeof(struct cpu_suspend_ctx));
> > > diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
> > > index fdd1068ee3a5..1f458f7c3b44 100644
> > > --- a/arch/arm64/kvm/hyp/entry.S
> > > +++ b/arch/arm64/kvm/hyp/entry.S
> > > @@ -62,9 +62,6 @@ ENTRY(__guest_enter)
> > >  	// Store the host regs
> > >  	save_callee_saved_regs x1
> > >  
> > > -	// Store host_ctxt and vcpu for use at exit time
> > > -	stp	x1, x0, [sp, #-16]!
> > > -
> > >  	add	x18, x0, #VCPU_CONTEXT
> > >  
> > >  	// Restore guest regs x0-x17
> > > @@ -118,8 +115,7 @@ ENTRY(__guest_exit)
> > >  	// Store the guest regs x19-x29, lr
> > >  	save_callee_saved_regs x1
> > >  
> > > -	// Restore the host_ctxt from the stack
> > > -	ldr	x2, [sp], #16
> > > +	get_host_ctxt	x2, x3
> > >  
> > >  	// Now restore the host regs
> > >  	restore_callee_saved_regs x2
> > > diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
> > > index f36464bd57c5..559b4d54bc42 100644
> > > --- a/arch/arm64/kvm/hyp/hyp-entry.S
> > > +++ b/arch/arm64/kvm/hyp/hyp-entry.S
> > > @@ -57,13 +57,8 @@ ENDPROC(__vhe_hyp_call)
> > >  el1_sync:				// Guest trapped into EL2
> > >  	stp	x0, x1, [sp, #-16]!
> > >  
> > > -alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
> > > -	mrs	x1, esr_el2
> > > -alternative_else
> > > -	mrs	x1, esr_el1
> > > -alternative_endif
> > > -	lsr	x0, x1, #ESR_ELx_EC_SHIFT
> > > -
> > > +	mrs	x0, esr_el2
> > > +	lsr	x0, x0, #ESR_ELx_EC_SHIFT
> > >  	cmp	x0, #ESR_ELx_EC_HVC64
> > >  	ccmp	x0, #ESR_ELx_EC_HVC32, #4, ne
> > >  	b.ne	el1_trap
> > > @@ -117,10 +112,15 @@ el1_hvc_guest:
> > >  	eret
> > >  
> > >  el1_trap:
> > > +	get_host_ctxt	x0, x1
> > > +	get_vcpu	x1, x0
> > > +
> > > +	mrs		x0, esr_el2
> > > +	lsr		x0, x0, #ESR_ELx_EC_SHIFT
> > >  	/*
> > >  	 * x0: ESR_EC
> > > +	 * x1: vcpu pointer
> > >  	 */
> > > -	ldr	x1, [sp, #16 + 8]	// vcpu stored by __guest_enter
> > >  
> > >  	/*
> > >  	 * We trap the first access to the FP/SIMD to save the host context
> > > @@ -138,13 +138,15 @@ alternative_else_nop_endif
> > >  
> > >  el1_irq:
> > >  	stp     x0, x1, [sp, #-16]!
> > > -	ldr	x1, [sp, #16 + 8]
> > > +	get_host_ctxt	x0, x1
> > > +	get_vcpu	x1, x0
> > >  	mov	x0, #ARM_EXCEPTION_IRQ
> > >  	b	__guest_exit
> > >  
> > >  el1_error:
> > >  	stp     x0, x1, [sp, #-16]!
> > > -	ldr	x1, [sp, #16 + 8]
> > > +	get_host_ctxt	x0, x1
> > > +	get_vcpu	x1, x0
> > 
> > Given how frequent this construct is, would there be a benefit in
> > having something like "get_vcpu_ptr" that conflates the two macros? We
> > don't seem to have a single case of using get_vcpu on its own.
> > 
> 
> I think my intention was to make it obvious how we get to the vcpu
> pointer, but looking at it now I don't think this adds anything, so I'm
> happy to adjust.  How about adding a get_vcpu_ptr macro which calls the
> other two macros?

Sure, that would make sense.

> 
> > >  	mov	x0, #ARM_EXCEPTION_EL1_SERROR
> > >  	b	__guest_exit
> > >  
> > > @@ -180,14 +182,7 @@ ENTRY(__hyp_do_panic)
> > >  ENDPROC(__hyp_do_panic)
> > >  
> > >  ENTRY(__hyp_panic)
> > > -	/*
> > > -	 * '=kvm_host_cpu_state' is a host VA from the constant pool, it may
> > > -	 * not be accessible by this address from EL2, hyp_panic() converts
> > > -	 * it with kern_hyp_va() before use.
> > > -	 */
> > > -	ldr	x0, =kvm_host_cpu_state
> > > -	mrs	x1, tpidr_el2
> > > -	add	x0, x0, x1
> > > +	get_host_ctxt x0, x1
> > >  	b	hyp_panic
> > >  ENDPROC(__hyp_panic)
> > >  
> > > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > > index b991f85c1133..d1749fa0bfc3 100644
> > > --- a/arch/arm64/kvm/hyp/switch.c
> > > +++ b/arch/arm64/kvm/hyp/switch.c
> > > @@ -467,7 +467,7 @@ static hyp_alternate_select(__hyp_call_panic,
> > >  			    __hyp_call_panic_nvhe, __hyp_call_panic_vhe,
> > >  			    ARM64_HAS_VIRT_HOST_EXTN);
> > >  
> > > -void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt)
> > > +void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *host_ctxt)
> > >  {
> > >  	struct kvm_vcpu *vcpu = NULL;
> > >  
> > > @@ -476,9 +476,6 @@ void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt)
> > >  	u64 par = read_sysreg(par_el1);
> > >  
> > >  	if (read_sysreg(vttbr_el2)) {
> > > -		struct kvm_cpu_context *host_ctxt;
> > > -
> > > -		host_ctxt = kern_hyp_va(__host_ctxt);
> > >  		vcpu = host_ctxt->__hyp_running_vcpu;
> > >  		__timer_disable_traps(vcpu);
> > >  		__deactivate_traps(vcpu);
> > > diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> > > index 2c17afd2be96..43b7dd65e3e6 100644
> > > --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> > > +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> > > @@ -189,3 +189,8 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
> > >  	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> > >  		write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
> > >  }
> > > +
> > > +void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2)
> > > +{
> > > +	asm("msr tpidr_el2, %0": : "r" (tpidr_el2));
> > 
> > The paranoid in me says that we'd want an ISB here if we can possibly
> > use tpidr_el2 on this path. If we had to manic, for example...
> > 
> 
> I'm not sure I follow.  Are you not guaranteed that an mrs after msr
> would reflect the latest written value, even without an ISB?

You're absolutely right. /me dropping paranoia levels.

Thanks,

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 35/40] KVM: arm/arm64: Get rid of vgic_elrsr
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-22  9:45     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-22  9:45 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, 15 Feb 2018 21:03:27 +0000,
Christoffer Dall wrote:
> 
> There is really no need to store the vgic_elrsr on the VGIC data
> structures as the only need we have for the elrsr is to figure out if an
> LR is inactive when we save the VGIC state upon returning from the
> guest.  We can might as well store this in a temporary local variable.
> 
> This also gets rid of the endianness conversion in the VGIC save
> function, which is completely unnecessary and would actually result in
> incorrect functionality on big-endian systems, because we are only using
> typed values here and not converting pointers and reading different
> types here.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 35/40] KVM: arm/arm64: Get rid of vgic_elrsr
@ 2018-02-22  9:45     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-22  9:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 15 Feb 2018 21:03:27 +0000,
Christoffer Dall wrote:
> 
> There is really no need to store the vgic_elrsr on the VGIC data
> structures as the only need we have for the elrsr is to figure out if an
> LR is inactive when we save the VGIC state upon returning from the
> guest.  We can might as well store this in a temporary local variable.
> 
> This also gets rid of the endianness conversion in the VGIC save
> function, which is completely unnecessary and would actually result in
> incorrect functionality on big-endian systems, because we are only using
> typed values here and not converting pointers and reading different
> types here.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
  2018-02-22  9:02       ` Christoffer Dall
@ 2018-02-22  9:49         ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22  9:49 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Ard Biesheuvel, Marc Zyngier, Tomasz Nowicki, kvmarm,
	Julien Grall, Yury Norov, linux-arm-kernel, Dave Martin,
	Shih-Wei Li

On Thu, Feb 22, 2018 at 10:02:48AM +0100, Christoffer Dall wrote:
> On Wed, Feb 21, 2018 at 11:34:07AM +0000, Marc Zyngier wrote:
> > On Thu, 15 Feb 2018 21:02:55 +0000,
> > Christoffer Dall wrote:
> > > @@ -138,13 +138,15 @@ alternative_else_nop_endif
> > >  
> > >  el1_irq:
> > >  	stp     x0, x1, [sp, #-16]!
> > > -	ldr	x1, [sp, #16 + 8]
> > > +	get_host_ctxt	x0, x1
> > > +	get_vcpu	x1, x0
> > >  	mov	x0, #ARM_EXCEPTION_IRQ
> > >  	b	__guest_exit
> > >  
> > >  el1_error:
> > >  	stp     x0, x1, [sp, #-16]!
> > > -	ldr	x1, [sp, #16 + 8]
> > > +	get_host_ctxt	x0, x1
> > > +	get_vcpu	x1, x0
> > 
> > Given how frequent this construct is, would there be a benefit in
> > having something like "get_vcpu_ptr" that conflates the two macros? We
> > don't seem to have a single case of using get_vcpu on its own.
> > 
> 
> I think my intention was to make it obvious how we get to the vcpu
> pointer, but looking at it now I don't think this adds anything, so I'm
> happy to adjust.  How about adding a get_vcpu_ptr macro which calls the
> other two macros?
>

Do we really need three macros, if get_vcpu is never used independently?
In the first round of reviews I suggested redefining get_vcpu like this

"""
 .macro get_vcpu vcpu, tmp
     get_host_ctxt \tmp, \vcpu
     ldr     \vcpu, [\tmp, #HOST_CONTEXT_VCPU]
     kern_hyp_va     \vcpu
 .endm

 which also has the side-effect of tmp being ctxt after the call.
"""

Thanks,
drew

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

* [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
@ 2018-02-22  9:49         ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22  9:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 22, 2018 at 10:02:48AM +0100, Christoffer Dall wrote:
> On Wed, Feb 21, 2018 at 11:34:07AM +0000, Marc Zyngier wrote:
> > On Thu, 15 Feb 2018 21:02:55 +0000,
> > Christoffer Dall wrote:
> > > @@ -138,13 +138,15 @@ alternative_else_nop_endif
> > >  
> > >  el1_irq:
> > >  	stp     x0, x1, [sp, #-16]!
> > > -	ldr	x1, [sp, #16 + 8]
> > > +	get_host_ctxt	x0, x1
> > > +	get_vcpu	x1, x0
> > >  	mov	x0, #ARM_EXCEPTION_IRQ
> > >  	b	__guest_exit
> > >  
> > >  el1_error:
> > >  	stp     x0, x1, [sp, #-16]!
> > > -	ldr	x1, [sp, #16 + 8]
> > > +	get_host_ctxt	x0, x1
> > > +	get_vcpu	x1, x0
> > 
> > Given how frequent this construct is, would there be a benefit in
> > having something like "get_vcpu_ptr" that conflates the two macros? We
> > don't seem to have a single case of using get_vcpu on its own.
> > 
> 
> I think my intention was to make it obvious how we get to the vcpu
> pointer, but looking at it now I don't think this adds anything, so I'm
> happy to adjust.  How about adding a get_vcpu_ptr macro which calls the
> other two macros?
>

Do we really need three macros, if get_vcpu is never used independently?
In the first round of reviews I suggested redefining get_vcpu like this

"""
 .macro get_vcpu vcpu, tmp
     get_host_ctxt \tmp, \vcpu
     ldr     \vcpu, [\tmp, #HOST_CONTEXT_VCPU]
     kern_hyp_va     \vcpu
 .endm

 which also has the side-effect of tmp being ctxt after the call.
"""

Thanks,
drew

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

* Re: [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
  2018-02-22  9:10       ` Christoffer Dall
@ 2018-02-22  9:56         ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22  9:56 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Ard Biesheuvel, Marc Zyngier, Tomasz Nowicki, kvmarm,
	Julien Grall, Yury Norov, linux-arm-kernel, Dave Martin,
	Shih-Wei Li

On Thu, Feb 22, 2018 at 10:10:34AM +0100, Christoffer Dall wrote:
> On Wed, Feb 21, 2018 at 06:32:00PM +0100, Andrew Jones wrote:
> > 
> > Besides my confusion on motivation, it looks good to me
> > 
> 
> In that case, unless there's an argument that the code has become too
> hard to understand, ...
>

On the contrary, I think it's easier to read now than before. I just
wasn't clear how it all tied together with this series. If its
combination with other patches enables a speedup, then it certainly
fits here. I was just comparing mrs+loads vs. a load from stack and
it seemed it would actually cause a micro-performance-decrease.

Thanks,
drew

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

* [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
@ 2018-02-22  9:56         ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22  9:56 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 22, 2018 at 10:10:34AM +0100, Christoffer Dall wrote:
> On Wed, Feb 21, 2018 at 06:32:00PM +0100, Andrew Jones wrote:
> > 
> > Besides my confusion on motivation, it looks good to me
> > 
> 
> In that case, unless there's an argument that the code has become too
> hard to understand, ...
>

On the contrary, I think it's easier to read now than before. I just
wasn't clear how it all tied together with this series. If its
combination with other patches enables a speedup, then it certainly
fits here. I was just comparing mrs+loads vs. a load from stack and
it seemed it would actually cause a micro-performance-decrease.

Thanks,
drew

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

* Re: [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
  2018-02-22  9:56         ` Andrew Jones
@ 2018-02-22 10:24           ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 10:24 UTC (permalink / raw)
  To: Andrew Jones
  Cc: kvm, Ard Biesheuvel, Marc Zyngier, kvmarm, Yury Norov,
	linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 22, 2018 at 10:56:41AM +0100, Andrew Jones wrote:
> On Thu, Feb 22, 2018 at 10:10:34AM +0100, Christoffer Dall wrote:
> > On Wed, Feb 21, 2018 at 06:32:00PM +0100, Andrew Jones wrote:
> > > 
> > > Besides my confusion on motivation, it looks good to me
> > > 
> > 
> > In that case, unless there's an argument that the code has become too
> > hard to understand, ...
> >
> 
> On the contrary, I think it's easier to read now than before. I just
> wasn't clear how it all tied together with this series. If its
> combination with other patches enables a speedup, then it certainly
> fits here. I was just comparing mrs+loads vs. a load from stack and

The comparison should be mrs+load, vs. str+load (you save the store on
the stack).

> it seemed it would actually cause a micro-performance-decrease.
> 

Thanks,
-Christoffer

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

* [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack
@ 2018-02-22 10:24           ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 10:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 22, 2018 at 10:56:41AM +0100, Andrew Jones wrote:
> On Thu, Feb 22, 2018 at 10:10:34AM +0100, Christoffer Dall wrote:
> > On Wed, Feb 21, 2018 at 06:32:00PM +0100, Andrew Jones wrote:
> > > 
> > > Besides my confusion on motivation, it looks good to me
> > > 
> > 
> > In that case, unless there's an argument that the code has become too
> > hard to understand, ...
> >
> 
> On the contrary, I think it's easier to read now than before. I just
> wasn't clear how it all tied together with this series. If its
> combination with other patches enables a speedup, then it certainly
> fits here. I was just comparing mrs+loads vs. a load from stack and

The comparison should be mrs+load, vs. str+load (you save the store on
the stack).

> it seemed it would actually cause a micro-performance-decrease.
> 

Thanks,
-Christoffer

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

* Re: [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
  2018-02-22  9:22       ` Christoffer Dall
@ 2018-02-22 10:48         ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-22 10:48 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Christoffer Dall, Andrew Jones, kvm, Tomasz Nowicki, kvmarm,
	Julien Grall, Yury Norov, linux-arm-kernel, Dave Martin,
	Shih-Wei Li

On Thu, 22 Feb 2018 09:22:37 +0000,
Christoffer Dall wrote:
> 
> On Wed, Feb 21, 2018 at 01:32:45PM +0000, Marc Zyngier wrote:
> > On Thu, 15 Feb 2018 21:03:16 +0000,
> > Christoffer Dall wrote:
> > > 
> > > From: Christoffer Dall <cdall@cs.columbia.edu>
> > > 
> > > Currently we access the system registers array via the vcpu_sys_reg()
> > > macro.  However, we are about to change the behavior to some times
> > > modify the register file directly, so let's change this to two
> > > primitives:
> > > 
> > >  * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
> > >  * Direct array access macro __vcpu_sys_reg()
> > > 
> > > The first primitive should be used in places where the code needs to
> > > access the currently loaded VCPU's state as observed by the guest.  For
> > > example, when trapping on cache related registers, a write to a system
> > > register should go directly to the VCPU version of the register.
> > > 
> > > The second primitive can be used in places where the VCPU is known to
> > > never be running (for example userspace access) or for registers which
> > > are never context switched (for example all the PMU system registers).
> > > 
> > > This rewrites all users of vcpu_sys_regs to one of the two primitives
> > > above.
> > > 
> > > No functional change.
> > > 
> > > Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> > > ---
> > > 
> > > Notes:
> > >     Changes since v2:
> > >      - New patch (deferred register handling has been reworked)
> > > 
> > >  arch/arm64/include/asm/kvm_emulate.h | 13 ++++---
> > >  arch/arm64/include/asm/kvm_host.h    | 13 ++++++-
> > >  arch/arm64/include/asm/kvm_mmu.h     |  2 +-
> > >  arch/arm64/kvm/debug.c               | 27 +++++++++-----
> > >  arch/arm64/kvm/inject_fault.c        |  8 ++--
> > >  arch/arm64/kvm/sys_regs.c            | 71 ++++++++++++++++++------------------
> > >  arch/arm64/kvm/sys_regs.h            |  4 +-
> > >  arch/arm64/kvm/sys_regs_generic_v8.c |  4 +-
> > >  virt/kvm/arm/pmu.c                   | 37 ++++++++++---------
> > >  9 files changed, 102 insertions(+), 77 deletions(-)
> > > 
> > > diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> > > index 3cc535591bdf..d313aaae5c38 100644
> > > --- a/arch/arm64/include/asm/kvm_emulate.h
> > > +++ b/arch/arm64/include/asm/kvm_emulate.h
> > > @@ -290,15 +290,18 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
> > >  
> > >  static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
> > >  {
> > > -	return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> > > +	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> > >  }
> > >  
> > >  static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
> > >  {
> > > -	if (vcpu_mode_is_32bit(vcpu))
> > > +	if (vcpu_mode_is_32bit(vcpu)) {
> > >  		*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
> > > -	else
> > > -		vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
> > > +	} else {
> > > +		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
> > > +		sctlr |= (1 << 25);
> > > +		vcpu_write_sys_reg(vcpu, SCTLR_EL1, sctlr);
> > 
> > General comment: it is slightly annoying that vcpu_write_sys_reg takes
> > its parameters in an order different from that of write_sysreg
> > (register followed with value, instead of value followed with
> > register). Not a deal breaker, but slightly confusing.
> > 
> 
> Ah, I didn't compare to write_sysreg, I was thinking that
> 
>   vcpu_read_sys_reg(vcpu, SCTLR_EL1);
>   vcpu_write_sys_reg(vcpu, SCTLR_EL1, val);
> 
> looked more symmetrical because the write just takes an extra value, but
> I can see your argument as well.
> 
> I don't mind changing it if it matters to you?

I'd like to see that changed, but it doesn't have to be as part of
this series if it is going to cause a refactoring mess. We can address
it as a blanket fix after this series.

> 
> > > +	}
> > >  }
> > >  
> > >  static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> > > @@ -306,7 +309,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> > >  	if (vcpu_mode_is_32bit(vcpu))
> > >  		return !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_E_BIT);
> > >  
> > > -	return !!(vcpu_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> > > +	return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> > >  }
> > >  
> > >  static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
> > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > index f2a6f39aec87..68398bf7882f 100644
> > > --- a/arch/arm64/include/asm/kvm_host.h
> > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > @@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
> > >  };
> > >  
> > >  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> > > -#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> > > +
> > > +/*
> > > + * Only use __vcpu_sys_reg if you know you want the memory backed version of a
> > > + * register, and not the one most recently accessed by a runnning VCPU.  For
> > > + * example, for userpace access or for system registers that are never context
> > > + * switched, but only emulated.
> > > + */
> > > +#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> > > +
> > > +#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> > > +#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> > > +
> > >  /*
> > >   * CP14 and CP15 live in the same array, as they are backed by the
> > >   * same system registers.
> > > diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> > > index 9679067a1574..95f46e73c4dc 100644
> > > --- a/arch/arm64/include/asm/kvm_mmu.h
> > > +++ b/arch/arm64/include/asm/kvm_mmu.h
> > > @@ -249,7 +249,7 @@ struct kvm;
> > >  
> > >  static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
> > >  {
> > > -	return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> > > +	return (vcpu_read_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> > >  }
> > >  
> > >  static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
> > > diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> > > index feedb877cff8..db32d10a56a1 100644
> > > --- a/arch/arm64/kvm/debug.c
> > > +++ b/arch/arm64/kvm/debug.c
> > > @@ -46,7 +46,8 @@ static DEFINE_PER_CPU(u32, mdcr_el2);
> > >   */
> > >  static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
> > >  {
> > > -	vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1);
> > > +	vcpu->arch.guest_debug_preserved.mdscr_el1 =
> > > +		vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> > >  
> > >  	trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
> > >  				vcpu->arch.guest_debug_preserved.mdscr_el1);
> > > @@ -54,10 +55,11 @@ static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
> > >  
> > >  static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
> > >  {
> > > -	vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1;
> > > +	vcpu_write_sys_reg(vcpu, MDSCR_EL1,
> > > +			   vcpu->arch.guest_debug_preserved.mdscr_el1);
> > >  
> > >  	trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
> > > -				vcpu_sys_reg(vcpu, MDSCR_EL1));
> > > +				vcpu_read_sys_reg(vcpu, MDSCR_EL1));
> > >  }
> > >  
> > >  /**
> > > @@ -108,6 +110,7 @@ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
> > >  void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> > >  {
> > >  	bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY);
> > > +	unsigned long mdscr;
> > >  
> > >  	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
> > >  
> > > @@ -152,9 +155,13 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> > >  		 */
> > >  		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
> > >  			*vcpu_cpsr(vcpu) |=  DBG_SPSR_SS;
> > > -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_SS;
> > > +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> > > +			mdscr |= DBG_MDSCR_SS;
> > > +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
> > 
> > I have the feeling that we're going to need some clearbits/setbits
> > variants of vcpu_write_sysreg at some point.
> > 
> 
> I can introduce these now if you prefer?

Probably not yet. There is a number of places where we could do a
batter job at dealing with bitfields, the GICv3 cpuif emulation code
being a primary offender. If we start having these kind of primitives,
we can derive sysreg accessors from them in the long run.

Thanks,

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
@ 2018-02-22 10:48         ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-22 10:48 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 22 Feb 2018 09:22:37 +0000,
Christoffer Dall wrote:
> 
> On Wed, Feb 21, 2018 at 01:32:45PM +0000, Marc Zyngier wrote:
> > On Thu, 15 Feb 2018 21:03:16 +0000,
> > Christoffer Dall wrote:
> > > 
> > > From: Christoffer Dall <cdall@cs.columbia.edu>
> > > 
> > > Currently we access the system registers array via the vcpu_sys_reg()
> > > macro.  However, we are about to change the behavior to some times
> > > modify the register file directly, so let's change this to two
> > > primitives:
> > > 
> > >  * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
> > >  * Direct array access macro __vcpu_sys_reg()
> > > 
> > > The first primitive should be used in places where the code needs to
> > > access the currently loaded VCPU's state as observed by the guest.  For
> > > example, when trapping on cache related registers, a write to a system
> > > register should go directly to the VCPU version of the register.
> > > 
> > > The second primitive can be used in places where the VCPU is known to
> > > never be running (for example userspace access) or for registers which
> > > are never context switched (for example all the PMU system registers).
> > > 
> > > This rewrites all users of vcpu_sys_regs to one of the two primitives
> > > above.
> > > 
> > > No functional change.
> > > 
> > > Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> > > ---
> > > 
> > > Notes:
> > >     Changes since v2:
> > >      - New patch (deferred register handling has been reworked)
> > > 
> > >  arch/arm64/include/asm/kvm_emulate.h | 13 ++++---
> > >  arch/arm64/include/asm/kvm_host.h    | 13 ++++++-
> > >  arch/arm64/include/asm/kvm_mmu.h     |  2 +-
> > >  arch/arm64/kvm/debug.c               | 27 +++++++++-----
> > >  arch/arm64/kvm/inject_fault.c        |  8 ++--
> > >  arch/arm64/kvm/sys_regs.c            | 71 ++++++++++++++++++------------------
> > >  arch/arm64/kvm/sys_regs.h            |  4 +-
> > >  arch/arm64/kvm/sys_regs_generic_v8.c |  4 +-
> > >  virt/kvm/arm/pmu.c                   | 37 ++++++++++---------
> > >  9 files changed, 102 insertions(+), 77 deletions(-)
> > > 
> > > diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> > > index 3cc535591bdf..d313aaae5c38 100644
> > > --- a/arch/arm64/include/asm/kvm_emulate.h
> > > +++ b/arch/arm64/include/asm/kvm_emulate.h
> > > @@ -290,15 +290,18 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
> > >  
> > >  static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
> > >  {
> > > -	return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> > > +	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> > >  }
> > >  
> > >  static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
> > >  {
> > > -	if (vcpu_mode_is_32bit(vcpu))
> > > +	if (vcpu_mode_is_32bit(vcpu)) {
> > >  		*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
> > > -	else
> > > -		vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
> > > +	} else {
> > > +		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
> > > +		sctlr |= (1 << 25);
> > > +		vcpu_write_sys_reg(vcpu, SCTLR_EL1, sctlr);
> > 
> > General comment: it is slightly annoying that vcpu_write_sys_reg takes
> > its parameters in an order different from that of write_sysreg
> > (register followed with value, instead of value followed with
> > register). Not a deal breaker, but slightly confusing.
> > 
> 
> Ah, I didn't compare to write_sysreg, I was thinking that
> 
>   vcpu_read_sys_reg(vcpu, SCTLR_EL1);
>   vcpu_write_sys_reg(vcpu, SCTLR_EL1, val);
> 
> looked more symmetrical because the write just takes an extra value, but
> I can see your argument as well.
> 
> I don't mind changing it if it matters to you?

I'd like to see that changed, but it doesn't have to be as part of
this series if it is going to cause a refactoring mess. We can address
it as a blanket fix after this series.

> 
> > > +	}
> > >  }
> > >  
> > >  static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> > > @@ -306,7 +309,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> > >  	if (vcpu_mode_is_32bit(vcpu))
> > >  		return !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_E_BIT);
> > >  
> > > -	return !!(vcpu_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> > > +	return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> > >  }
> > >  
> > >  static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
> > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > index f2a6f39aec87..68398bf7882f 100644
> > > --- a/arch/arm64/include/asm/kvm_host.h
> > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > @@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
> > >  };
> > >  
> > >  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> > > -#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> > > +
> > > +/*
> > > + * Only use __vcpu_sys_reg if you know you want the memory backed version of a
> > > + * register, and not the one most recently accessed by a runnning VCPU.  For
> > > + * example, for userpace access or for system registers that are never context
> > > + * switched, but only emulated.
> > > + */
> > > +#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> > > +
> > > +#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> > > +#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> > > +
> > >  /*
> > >   * CP14 and CP15 live in the same array, as they are backed by the
> > >   * same system registers.
> > > diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> > > index 9679067a1574..95f46e73c4dc 100644
> > > --- a/arch/arm64/include/asm/kvm_mmu.h
> > > +++ b/arch/arm64/include/asm/kvm_mmu.h
> > > @@ -249,7 +249,7 @@ struct kvm;
> > >  
> > >  static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
> > >  {
> > > -	return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> > > +	return (vcpu_read_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> > >  }
> > >  
> > >  static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
> > > diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> > > index feedb877cff8..db32d10a56a1 100644
> > > --- a/arch/arm64/kvm/debug.c
> > > +++ b/arch/arm64/kvm/debug.c
> > > @@ -46,7 +46,8 @@ static DEFINE_PER_CPU(u32, mdcr_el2);
> > >   */
> > >  static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
> > >  {
> > > -	vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1);
> > > +	vcpu->arch.guest_debug_preserved.mdscr_el1 =
> > > +		vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> > >  
> > >  	trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
> > >  				vcpu->arch.guest_debug_preserved.mdscr_el1);
> > > @@ -54,10 +55,11 @@ static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
> > >  
> > >  static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
> > >  {
> > > -	vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1;
> > > +	vcpu_write_sys_reg(vcpu, MDSCR_EL1,
> > > +			   vcpu->arch.guest_debug_preserved.mdscr_el1);
> > >  
> > >  	trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
> > > -				vcpu_sys_reg(vcpu, MDSCR_EL1));
> > > +				vcpu_read_sys_reg(vcpu, MDSCR_EL1));
> > >  }
> > >  
> > >  /**
> > > @@ -108,6 +110,7 @@ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
> > >  void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> > >  {
> > >  	bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY);
> > > +	unsigned long mdscr;
> > >  
> > >  	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
> > >  
> > > @@ -152,9 +155,13 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> > >  		 */
> > >  		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
> > >  			*vcpu_cpsr(vcpu) |=  DBG_SPSR_SS;
> > > -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_SS;
> > > +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> > > +			mdscr |= DBG_MDSCR_SS;
> > > +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
> > 
> > I have the feeling that we're going to need some clearbits/setbits
> > variants of vcpu_write_sysreg at some point.
> > 
> 
> I can introduce these now if you prefer?

Probably not yet. There is a number of places where we could do a
batter job at dealing with bitfields, the GICv3 cpuif emulation code
being a primary offender. If we start having these kind of primitives,
we can derive sysreg accessors from them in the long run.

Thanks,

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
  2018-02-22 10:48         ` Marc Zyngier
@ 2018-02-22 11:10           ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 11:10 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, Andrew Jones, kvm, Tomasz Nowicki, kvmarm,
	Julien Grall, Yury Norov, linux-arm-kernel, Dave Martin,
	Shih-Wei Li

On Thu, Feb 22, 2018 at 10:48:10AM +0000, Marc Zyngier wrote:
> On Thu, 22 Feb 2018 09:22:37 +0000,
> Christoffer Dall wrote:
> > 
> > On Wed, Feb 21, 2018 at 01:32:45PM +0000, Marc Zyngier wrote:
> > > On Thu, 15 Feb 2018 21:03:16 +0000,
> > > Christoffer Dall wrote:
> > > > 
> > > > From: Christoffer Dall <cdall@cs.columbia.edu>
> > > > 
> > > > Currently we access the system registers array via the vcpu_sys_reg()
> > > > macro.  However, we are about to change the behavior to some times
> > > > modify the register file directly, so let's change this to two
> > > > primitives:
> > > > 
> > > >  * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
> > > >  * Direct array access macro __vcpu_sys_reg()
> > > > 
> > > > The first primitive should be used in places where the code needs to
> > > > access the currently loaded VCPU's state as observed by the guest.  For
> > > > example, when trapping on cache related registers, a write to a system
> > > > register should go directly to the VCPU version of the register.
> > > > 
> > > > The second primitive can be used in places where the VCPU is known to
> > > > never be running (for example userspace access) or for registers which
> > > > are never context switched (for example all the PMU system registers).
> > > > 
> > > > This rewrites all users of vcpu_sys_regs to one of the two primitives
> > > > above.
> > > > 
> > > > No functional change.
> > > > 
> > > > Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> > > > ---
> > > > 
> > > > Notes:
> > > >     Changes since v2:
> > > >      - New patch (deferred register handling has been reworked)
> > > > 
> > > >  arch/arm64/include/asm/kvm_emulate.h | 13 ++++---
> > > >  arch/arm64/include/asm/kvm_host.h    | 13 ++++++-
> > > >  arch/arm64/include/asm/kvm_mmu.h     |  2 +-
> > > >  arch/arm64/kvm/debug.c               | 27 +++++++++-----
> > > >  arch/arm64/kvm/inject_fault.c        |  8 ++--
> > > >  arch/arm64/kvm/sys_regs.c            | 71 ++++++++++++++++++------------------
> > > >  arch/arm64/kvm/sys_regs.h            |  4 +-
> > > >  arch/arm64/kvm/sys_regs_generic_v8.c |  4 +-
> > > >  virt/kvm/arm/pmu.c                   | 37 ++++++++++---------
> > > >  9 files changed, 102 insertions(+), 77 deletions(-)
> > > > 
> > > > diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> > > > index 3cc535591bdf..d313aaae5c38 100644
> > > > --- a/arch/arm64/include/asm/kvm_emulate.h
> > > > +++ b/arch/arm64/include/asm/kvm_emulate.h
> > > > @@ -290,15 +290,18 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
> > > >  
> > > >  static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
> > > >  {
> > > > -	return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> > > > +	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> > > >  }
> > > >  
> > > >  static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
> > > >  {
> > > > -	if (vcpu_mode_is_32bit(vcpu))
> > > > +	if (vcpu_mode_is_32bit(vcpu)) {
> > > >  		*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
> > > > -	else
> > > > -		vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
> > > > +	} else {
> > > > +		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
> > > > +		sctlr |= (1 << 25);
> > > > +		vcpu_write_sys_reg(vcpu, SCTLR_EL1, sctlr);
> > > 
> > > General comment: it is slightly annoying that vcpu_write_sys_reg takes
> > > its parameters in an order different from that of write_sysreg
> > > (register followed with value, instead of value followed with
> > > register). Not a deal breaker, but slightly confusing.
> > > 
> > 
> > Ah, I didn't compare to write_sysreg, I was thinking that
> > 
> >   vcpu_read_sys_reg(vcpu, SCTLR_EL1);
> >   vcpu_write_sys_reg(vcpu, SCTLR_EL1, val);
> > 
> > looked more symmetrical because the write just takes an extra value, but
> > I can see your argument as well.
> > 
> > I don't mind changing it if it matters to you?
> 
> I'd like to see that changed, but it doesn't have to be as part of
> this series if it is going to cause a refactoring mess. We can address
> it as a blanket fix after this series.
> 

I think it's reasonably self-contained.

Just so I'm sure, are these the primitives you'd like to see?

vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg);
vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg);

> > 
> > > > +	}
> > > >  }
> > > >  
> > > >  static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> > > > @@ -306,7 +309,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> > > >  	if (vcpu_mode_is_32bit(vcpu))
> > > >  		return !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_E_BIT);
> > > >  
> > > > -	return !!(vcpu_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> > > > +	return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> > > >  }
> > > >  
> > > >  static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
> > > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > > index f2a6f39aec87..68398bf7882f 100644
> > > > --- a/arch/arm64/include/asm/kvm_host.h
> > > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > > @@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
> > > >  };
> > > >  
> > > >  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> > > > -#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> > > > +
> > > > +/*
> > > > + * Only use __vcpu_sys_reg if you know you want the memory backed version of a
> > > > + * register, and not the one most recently accessed by a runnning VCPU.  For
> > > > + * example, for userpace access or for system registers that are never context
> > > > + * switched, but only emulated.
> > > > + */
> > > > +#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> > > > +
> > > > +#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> > > > +#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> > > > +
> > > >  /*
> > > >   * CP14 and CP15 live in the same array, as they are backed by the
> > > >   * same system registers.
> > > > diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> > > > index 9679067a1574..95f46e73c4dc 100644
> > > > --- a/arch/arm64/include/asm/kvm_mmu.h
> > > > +++ b/arch/arm64/include/asm/kvm_mmu.h
> > > > @@ -249,7 +249,7 @@ struct kvm;
> > > >  
> > > >  static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
> > > >  {
> > > > -	return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> > > > +	return (vcpu_read_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> > > >  }
> > > >  
> > > >  static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
> > > > diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> > > > index feedb877cff8..db32d10a56a1 100644
> > > > --- a/arch/arm64/kvm/debug.c
> > > > +++ b/arch/arm64/kvm/debug.c
> > > > @@ -46,7 +46,8 @@ static DEFINE_PER_CPU(u32, mdcr_el2);
> > > >   */
> > > >  static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
> > > >  {
> > > > -	vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1);
> > > > +	vcpu->arch.guest_debug_preserved.mdscr_el1 =
> > > > +		vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> > > >  
> > > >  	trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
> > > >  				vcpu->arch.guest_debug_preserved.mdscr_el1);
> > > > @@ -54,10 +55,11 @@ static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
> > > >  
> > > >  static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
> > > >  {
> > > > -	vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1;
> > > > +	vcpu_write_sys_reg(vcpu, MDSCR_EL1,
> > > > +			   vcpu->arch.guest_debug_preserved.mdscr_el1);
> > > >  
> > > >  	trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
> > > > -				vcpu_sys_reg(vcpu, MDSCR_EL1));
> > > > +				vcpu_read_sys_reg(vcpu, MDSCR_EL1));
> > > >  }
> > > >  
> > > >  /**
> > > > @@ -108,6 +110,7 @@ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
> > > >  void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> > > >  {
> > > >  	bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY);
> > > > +	unsigned long mdscr;
> > > >  
> > > >  	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
> > > >  
> > > > @@ -152,9 +155,13 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> > > >  		 */
> > > >  		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
> > > >  			*vcpu_cpsr(vcpu) |=  DBG_SPSR_SS;
> > > > -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_SS;
> > > > +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> > > > +			mdscr |= DBG_MDSCR_SS;
> > > > +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
> > > 
> > > I have the feeling that we're going to need some clearbits/setbits
> > > variants of vcpu_write_sysreg at some point.
> > > 
> > 
> > I can introduce these now if you prefer?
> 
> Probably not yet. There is a number of places where we could do a
> batter job at dealing with bitfields, the GICv3 cpuif emulation code
> being a primary offender. If we start having these kind of primitives,
> we can derive sysreg accessors from them in the long run.
> 

Ok, I'll leave this alone for now then.

Thanks,
-Christoffer

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

* [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
@ 2018-02-22 11:10           ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 11:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 22, 2018 at 10:48:10AM +0000, Marc Zyngier wrote:
> On Thu, 22 Feb 2018 09:22:37 +0000,
> Christoffer Dall wrote:
> > 
> > On Wed, Feb 21, 2018 at 01:32:45PM +0000, Marc Zyngier wrote:
> > > On Thu, 15 Feb 2018 21:03:16 +0000,
> > > Christoffer Dall wrote:
> > > > 
> > > > From: Christoffer Dall <cdall@cs.columbia.edu>
> > > > 
> > > > Currently we access the system registers array via the vcpu_sys_reg()
> > > > macro.  However, we are about to change the behavior to some times
> > > > modify the register file directly, so let's change this to two
> > > > primitives:
> > > > 
> > > >  * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
> > > >  * Direct array access macro __vcpu_sys_reg()
> > > > 
> > > > The first primitive should be used in places where the code needs to
> > > > access the currently loaded VCPU's state as observed by the guest.  For
> > > > example, when trapping on cache related registers, a write to a system
> > > > register should go directly to the VCPU version of the register.
> > > > 
> > > > The second primitive can be used in places where the VCPU is known to
> > > > never be running (for example userspace access) or for registers which
> > > > are never context switched (for example all the PMU system registers).
> > > > 
> > > > This rewrites all users of vcpu_sys_regs to one of the two primitives
> > > > above.
> > > > 
> > > > No functional change.
> > > > 
> > > > Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> > > > ---
> > > > 
> > > > Notes:
> > > >     Changes since v2:
> > > >      - New patch (deferred register handling has been reworked)
> > > > 
> > > >  arch/arm64/include/asm/kvm_emulate.h | 13 ++++---
> > > >  arch/arm64/include/asm/kvm_host.h    | 13 ++++++-
> > > >  arch/arm64/include/asm/kvm_mmu.h     |  2 +-
> > > >  arch/arm64/kvm/debug.c               | 27 +++++++++-----
> > > >  arch/arm64/kvm/inject_fault.c        |  8 ++--
> > > >  arch/arm64/kvm/sys_regs.c            | 71 ++++++++++++++++++------------------
> > > >  arch/arm64/kvm/sys_regs.h            |  4 +-
> > > >  arch/arm64/kvm/sys_regs_generic_v8.c |  4 +-
> > > >  virt/kvm/arm/pmu.c                   | 37 ++++++++++---------
> > > >  9 files changed, 102 insertions(+), 77 deletions(-)
> > > > 
> > > > diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> > > > index 3cc535591bdf..d313aaae5c38 100644
> > > > --- a/arch/arm64/include/asm/kvm_emulate.h
> > > > +++ b/arch/arm64/include/asm/kvm_emulate.h
> > > > @@ -290,15 +290,18 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
> > > >  
> > > >  static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
> > > >  {
> > > > -	return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> > > > +	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> > > >  }
> > > >  
> > > >  static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
> > > >  {
> > > > -	if (vcpu_mode_is_32bit(vcpu))
> > > > +	if (vcpu_mode_is_32bit(vcpu)) {
> > > >  		*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
> > > > -	else
> > > > -		vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
> > > > +	} else {
> > > > +		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
> > > > +		sctlr |= (1 << 25);
> > > > +		vcpu_write_sys_reg(vcpu, SCTLR_EL1, sctlr);
> > > 
> > > General comment: it is slightly annoying that vcpu_write_sys_reg takes
> > > its parameters in an order different from that of write_sysreg
> > > (register followed with value, instead of value followed with
> > > register). Not a deal breaker, but slightly confusing.
> > > 
> > 
> > Ah, I didn't compare to write_sysreg, I was thinking that
> > 
> >   vcpu_read_sys_reg(vcpu, SCTLR_EL1);
> >   vcpu_write_sys_reg(vcpu, SCTLR_EL1, val);
> > 
> > looked more symmetrical because the write just takes an extra value, but
> > I can see your argument as well.
> > 
> > I don't mind changing it if it matters to you?
> 
> I'd like to see that changed, but it doesn't have to be as part of
> this series if it is going to cause a refactoring mess. We can address
> it as a blanket fix after this series.
> 

I think it's reasonably self-contained.

Just so I'm sure, are these the primitives you'd like to see?

vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg);
vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg);

> > 
> > > > +	}
> > > >  }
> > > >  
> > > >  static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> > > > @@ -306,7 +309,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> > > >  	if (vcpu_mode_is_32bit(vcpu))
> > > >  		return !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_E_BIT);
> > > >  
> > > > -	return !!(vcpu_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> > > > +	return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> > > >  }
> > > >  
> > > >  static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
> > > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > > index f2a6f39aec87..68398bf7882f 100644
> > > > --- a/arch/arm64/include/asm/kvm_host.h
> > > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > > @@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
> > > >  };
> > > >  
> > > >  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> > > > -#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> > > > +
> > > > +/*
> > > > + * Only use __vcpu_sys_reg if you know you want the memory backed version of a
> > > > + * register, and not the one most recently accessed by a runnning VCPU.  For
> > > > + * example, for userpace access or for system registers that are never context
> > > > + * switched, but only emulated.
> > > > + */
> > > > +#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> > > > +
> > > > +#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> > > > +#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> > > > +
> > > >  /*
> > > >   * CP14 and CP15 live in the same array, as they are backed by the
> > > >   * same system registers.
> > > > diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> > > > index 9679067a1574..95f46e73c4dc 100644
> > > > --- a/arch/arm64/include/asm/kvm_mmu.h
> > > > +++ b/arch/arm64/include/asm/kvm_mmu.h
> > > > @@ -249,7 +249,7 @@ struct kvm;
> > > >  
> > > >  static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
> > > >  {
> > > > -	return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> > > > +	return (vcpu_read_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> > > >  }
> > > >  
> > > >  static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
> > > > diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> > > > index feedb877cff8..db32d10a56a1 100644
> > > > --- a/arch/arm64/kvm/debug.c
> > > > +++ b/arch/arm64/kvm/debug.c
> > > > @@ -46,7 +46,8 @@ static DEFINE_PER_CPU(u32, mdcr_el2);
> > > >   */
> > > >  static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
> > > >  {
> > > > -	vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1);
> > > > +	vcpu->arch.guest_debug_preserved.mdscr_el1 =
> > > > +		vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> > > >  
> > > >  	trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
> > > >  				vcpu->arch.guest_debug_preserved.mdscr_el1);
> > > > @@ -54,10 +55,11 @@ static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
> > > >  
> > > >  static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
> > > >  {
> > > > -	vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1;
> > > > +	vcpu_write_sys_reg(vcpu, MDSCR_EL1,
> > > > +			   vcpu->arch.guest_debug_preserved.mdscr_el1);
> > > >  
> > > >  	trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
> > > > -				vcpu_sys_reg(vcpu, MDSCR_EL1));
> > > > +				vcpu_read_sys_reg(vcpu, MDSCR_EL1));
> > > >  }
> > > >  
> > > >  /**
> > > > @@ -108,6 +110,7 @@ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
> > > >  void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> > > >  {
> > > >  	bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY);
> > > > +	unsigned long mdscr;
> > > >  
> > > >  	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
> > > >  
> > > > @@ -152,9 +155,13 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> > > >  		 */
> > > >  		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
> > > >  			*vcpu_cpsr(vcpu) |=  DBG_SPSR_SS;
> > > > -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_SS;
> > > > +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> > > > +			mdscr |= DBG_MDSCR_SS;
> > > > +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
> > > 
> > > I have the feeling that we're going to need some clearbits/setbits
> > > variants of vcpu_write_sysreg at some point.
> > > 
> > 
> > I can introduce these now if you prefer?
> 
> Probably not yet. There is a number of places where we could do a
> batter job at dealing with bitfields, the GICv3 cpuif emulation code
> being a primary offender. If we start having these kind of primitives,
> we can derive sysreg accessors from them in the long run.
> 

Ok, I'll leave this alone for now then.

Thanks,
-Christoffer

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

* Re: [PATCH v4 38/40] KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on VHE
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-22 12:32     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-22 12:32 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: Andrew Jones, kvm, Tomasz Nowicki, Julien Grall, Yury Norov,
	Dave Martin, Shih-Wei Li

On 15/02/18 21:03, Christoffer Dall wrote:
> Just like we can program the GICv2 hypervisor control interface directly
> from the core vgic code, we can do the same for the GICv3 hypervisor
> control interface on VHE systems.
> 
> We do this by simply calling the save/restore functions when we have VHE
> and we can then get rid of the save/restore function calls from the VHE
> world switch function.
> 
> One caveat is that we now write GICv3 system register state before the
> potential early exit path in the run loop, and because we sync back
> state in the early exit path, we have to ensure that we read a
> consistent GIC state from the sync path, even though we have never
> actually run the guest with the newly written GIC state.  We solve this
> by inserting an ISB in the early exit path.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v2:
>      - Added ISB in the early exit path in the run loop as explained
>        in the commit message.
> 
>  arch/arm64/kvm/hyp/switch.c | 3 ---
>  virt/kvm/arm/arm.c          | 1 +
>  virt/kvm/arm/vgic/vgic.c    | 5 +++++
>  3 files changed, 6 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index cbafc27a617b..466cfcdbcaf3 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -399,8 +399,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  	__activate_traps(vcpu);
>  	__activate_vm(vcpu->kvm);
>  
> -	__vgic_restore_state(vcpu);
> -
>  	sysreg_restore_guest_state_vhe(guest_ctxt);
>  	__debug_switch_to_guest(vcpu);
>  
> @@ -414,7 +412,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  	fp_enabled = fpsimd_enabled_vhe();
>  
>  	sysreg_save_guest_state_vhe(guest_ctxt);
> -	__vgic_save_state(vcpu);
>  
>  	__deactivate_traps(vcpu);
>  
> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> index 5bd879c78951..6de7641f3ff2 100644
> --- a/virt/kvm/arm/arm.c
> +++ b/virt/kvm/arm/arm.c
> @@ -717,6 +717,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
>  		    kvm_request_pending(vcpu)) {
>  			vcpu->mode = OUTSIDE_GUEST_MODE;
> +			isb(); /* Ensure work in x_flush_hwstate is committed */
>  			kvm_pmu_sync_hwstate(vcpu);
>  			if (static_branch_unlikely(&userspace_irqchip_in_use))
>  				kvm_timer_sync_hwstate(vcpu);
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 12e2a28f437e..d0a19a8c196a 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -19,6 +19,7 @@
>  #include <linux/list_sort.h>
>  #include <linux/interrupt.h>
>  #include <linux/irq.h>
> +#include <asm/kvm_hyp.h>
>  
>  #include "vgic.h"
>  
> @@ -753,6 +754,8 @@ static inline void vgic_save_state(struct kvm_vcpu *vcpu)
>  {
>  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
>  		vgic_v2_save_state(vcpu);
> +	else if (has_vhe())
> +		__vgic_v3_save_state(vcpu);
>  }
>  
>  /* Sync back the hardware VGIC state into our emulation after a guest's run. */
> @@ -777,6 +780,8 @@ static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
>  {
>  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
>  		vgic_v2_restore_state(vcpu);
> +	else if (has_vhe())
> +		__vgic_v3_restore_state(vcpu);
>  }
>  
>  /* Flush our emulation state into the GIC hardware before entering the guest. */
> 

I'm slowly wrapping my brain around this thing again. If I grasp the
general idea, we end up with two cases:

(1) The GIC is accessible from the kernel, and we save/restore it
outside of the HYP code.

(2) The GIC is only accessible from the HYP code, and we do it there.

Maybe we should bite the bullet and introduce that primitive instead?

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v4 38/40] KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on VHE
@ 2018-02-22 12:32     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-22 12:32 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/02/18 21:03, Christoffer Dall wrote:
> Just like we can program the GICv2 hypervisor control interface directly
> from the core vgic code, we can do the same for the GICv3 hypervisor
> control interface on VHE systems.
> 
> We do this by simply calling the save/restore functions when we have VHE
> and we can then get rid of the save/restore function calls from the VHE
> world switch function.
> 
> One caveat is that we now write GICv3 system register state before the
> potential early exit path in the run loop, and because we sync back
> state in the early exit path, we have to ensure that we read a
> consistent GIC state from the sync path, even though we have never
> actually run the guest with the newly written GIC state.  We solve this
> by inserting an ISB in the early exit path.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v2:
>      - Added ISB in the early exit path in the run loop as explained
>        in the commit message.
> 
>  arch/arm64/kvm/hyp/switch.c | 3 ---
>  virt/kvm/arm/arm.c          | 1 +
>  virt/kvm/arm/vgic/vgic.c    | 5 +++++
>  3 files changed, 6 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index cbafc27a617b..466cfcdbcaf3 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -399,8 +399,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  	__activate_traps(vcpu);
>  	__activate_vm(vcpu->kvm);
>  
> -	__vgic_restore_state(vcpu);
> -
>  	sysreg_restore_guest_state_vhe(guest_ctxt);
>  	__debug_switch_to_guest(vcpu);
>  
> @@ -414,7 +412,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  	fp_enabled = fpsimd_enabled_vhe();
>  
>  	sysreg_save_guest_state_vhe(guest_ctxt);
> -	__vgic_save_state(vcpu);
>  
>  	__deactivate_traps(vcpu);
>  
> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> index 5bd879c78951..6de7641f3ff2 100644
> --- a/virt/kvm/arm/arm.c
> +++ b/virt/kvm/arm/arm.c
> @@ -717,6 +717,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
>  		    kvm_request_pending(vcpu)) {
>  			vcpu->mode = OUTSIDE_GUEST_MODE;
> +			isb(); /* Ensure work in x_flush_hwstate is committed */
>  			kvm_pmu_sync_hwstate(vcpu);
>  			if (static_branch_unlikely(&userspace_irqchip_in_use))
>  				kvm_timer_sync_hwstate(vcpu);
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 12e2a28f437e..d0a19a8c196a 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -19,6 +19,7 @@
>  #include <linux/list_sort.h>
>  #include <linux/interrupt.h>
>  #include <linux/irq.h>
> +#include <asm/kvm_hyp.h>
>  
>  #include "vgic.h"
>  
> @@ -753,6 +754,8 @@ static inline void vgic_save_state(struct kvm_vcpu *vcpu)
>  {
>  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
>  		vgic_v2_save_state(vcpu);
> +	else if (has_vhe())
> +		__vgic_v3_save_state(vcpu);
>  }
>  
>  /* Sync back the hardware VGIC state into our emulation after a guest's run. */
> @@ -777,6 +780,8 @@ static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
>  {
>  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
>  		vgic_v2_restore_state(vcpu);
> +	else if (has_vhe())
> +		__vgic_v3_restore_state(vcpu);
>  }
>  
>  /* Flush our emulation state into the GIC hardware before entering the guest. */
> 

I'm slowly wrapping my brain around this thing again. If I grasp the
general idea, we end up with two cases:

(1) The GIC is accessible from the kernel, and we save/restore it
outside of the HYP code.

(2) The GIC is only accessible from the HYP code, and we do it there.

Maybe we should bite the bullet and introduce that primitive instead?

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 37/40] KVM: arm/arm64: Move arm64-only vgic-v2-sr.c file to arm64
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-22 12:33     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-22 12:33 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: kvm, Yury Norov, Dave Martin, Shih-Wei Li

On 15/02/18 21:03, Christoffer Dall wrote:
> The vgic-v2-sr.c file now only contains the logic to replay unaligned
> accesses to the virtual CPU interface on 16K and 64K page systems, which
> is only relevant on 64-bit platforms.  Therefore move this file to the
> arm64 KVM tree, remove the compile directive from the 32-bit side
> makefile, and remove the ifdef in the C file.
> 
> Reviewed-by: Andre Przywara <andre.przywara@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm/kvm/hyp/Makefile                         | 1 -
>  arch/arm64/kvm/hyp/Makefile                       | 2 +-
>  {virt/kvm/arm => arch/arm64/kvm}/hyp/vgic-v2-sr.c | 2 --
>  3 files changed, 1 insertion(+), 4 deletions(-)
>  rename {virt/kvm/arm => arch/arm64/kvm}/hyp/vgic-v2-sr.c (98%)
> 
> diff --git a/arch/arm/kvm/hyp/Makefile b/arch/arm/kvm/hyp/Makefile
> index 5638ce0c9524..1964111c984a 100644
> --- a/arch/arm/kvm/hyp/Makefile
> +++ b/arch/arm/kvm/hyp/Makefile
> @@ -7,7 +7,6 @@ ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
>  
>  KVM=../../../../virt/kvm
>  
> -obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o
>  obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v3-sr.o
>  obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/timer-sr.o
>  
> diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
> index f04400d494b7..7e8d41210288 100644
> --- a/arch/arm64/kvm/hyp/Makefile
> +++ b/arch/arm64/kvm/hyp/Makefile
> @@ -7,10 +7,10 @@ ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
>  
>  KVM=../../../../virt/kvm
>  
> -obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o
>  obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v3-sr.o
>  obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/timer-sr.o
>  
> +obj-$(CONFIG_KVM_ARM_HOST) += vgic-v2-sr.o

How about renaming the file to vgic-v2-cpuif-proxy.c? It doesn't have
anything to do with save/restore anymore...

>  obj-$(CONFIG_KVM_ARM_HOST) += sysreg-sr.o
>  obj-$(CONFIG_KVM_ARM_HOST) += debug-sr.o
>  obj-$(CONFIG_KVM_ARM_HOST) += entry.o
> diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/arch/arm64/kvm/hyp/vgic-v2-sr.c
> similarity index 98%
> rename from virt/kvm/arm/hyp/vgic-v2-sr.c
> rename to arch/arm64/kvm/hyp/vgic-v2-sr.c
> index 0bbafdfd4adb..97f357ea9c72 100644
> --- a/virt/kvm/arm/hyp/vgic-v2-sr.c
> +++ b/arch/arm64/kvm/hyp/vgic-v2-sr.c
> @@ -23,7 +23,6 @@
>  #include <asm/kvm_hyp.h>
>  #include <asm/kvm_mmu.h>
>  
> -#ifdef CONFIG_ARM64
>  /*
>   * __vgic_v2_perform_cpuif_access -- perform a GICV access on behalf of the
>   *				     guest.
> @@ -77,4 +76,3 @@ int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  
>  	return 1;
>  }
> -#endif
> 

Otherwise looks good.

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v4 37/40] KVM: arm/arm64: Move arm64-only vgic-v2-sr.c file to arm64
@ 2018-02-22 12:33     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-22 12:33 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/02/18 21:03, Christoffer Dall wrote:
> The vgic-v2-sr.c file now only contains the logic to replay unaligned
> accesses to the virtual CPU interface on 16K and 64K page systems, which
> is only relevant on 64-bit platforms.  Therefore move this file to the
> arm64 KVM tree, remove the compile directive from the 32-bit side
> makefile, and remove the ifdef in the C file.
> 
> Reviewed-by: Andre Przywara <andre.przywara@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm/kvm/hyp/Makefile                         | 1 -
>  arch/arm64/kvm/hyp/Makefile                       | 2 +-
>  {virt/kvm/arm => arch/arm64/kvm}/hyp/vgic-v2-sr.c | 2 --
>  3 files changed, 1 insertion(+), 4 deletions(-)
>  rename {virt/kvm/arm => arch/arm64/kvm}/hyp/vgic-v2-sr.c (98%)
> 
> diff --git a/arch/arm/kvm/hyp/Makefile b/arch/arm/kvm/hyp/Makefile
> index 5638ce0c9524..1964111c984a 100644
> --- a/arch/arm/kvm/hyp/Makefile
> +++ b/arch/arm/kvm/hyp/Makefile
> @@ -7,7 +7,6 @@ ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
>  
>  KVM=../../../../virt/kvm
>  
> -obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o
>  obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v3-sr.o
>  obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/timer-sr.o
>  
> diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
> index f04400d494b7..7e8d41210288 100644
> --- a/arch/arm64/kvm/hyp/Makefile
> +++ b/arch/arm64/kvm/hyp/Makefile
> @@ -7,10 +7,10 @@ ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
>  
>  KVM=../../../../virt/kvm
>  
> -obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o
>  obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v3-sr.o
>  obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/timer-sr.o
>  
> +obj-$(CONFIG_KVM_ARM_HOST) += vgic-v2-sr.o

How about renaming the file to vgic-v2-cpuif-proxy.c? It doesn't have
anything to do with save/restore anymore...

>  obj-$(CONFIG_KVM_ARM_HOST) += sysreg-sr.o
>  obj-$(CONFIG_KVM_ARM_HOST) += debug-sr.o
>  obj-$(CONFIG_KVM_ARM_HOST) += entry.o
> diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/arch/arm64/kvm/hyp/vgic-v2-sr.c
> similarity index 98%
> rename from virt/kvm/arm/hyp/vgic-v2-sr.c
> rename to arch/arm64/kvm/hyp/vgic-v2-sr.c
> index 0bbafdfd4adb..97f357ea9c72 100644
> --- a/virt/kvm/arm/hyp/vgic-v2-sr.c
> +++ b/arch/arm64/kvm/hyp/vgic-v2-sr.c
> @@ -23,7 +23,6 @@
>  #include <asm/kvm_hyp.h>
>  #include <asm/kvm_mmu.h>
>  
> -#ifdef CONFIG_ARM64
>  /*
>   * __vgic_v2_perform_cpuif_access -- perform a GICV access on behalf of the
>   *				     guest.
> @@ -77,4 +76,3 @@ int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  
>  	return 1;
>  }
> -#endif
> 

Otherwise looks good.

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 39/40] KVM: arm/arm64: Move VGIC APR save/restore to vgic put/load
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-22 13:11     ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-22 13:11 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: kvm, Yury Norov, Dave Martin, Shih-Wei Li

On 15/02/18 21:03, Christoffer Dall wrote:
> The APRs can only have bits set when the guest acknowledges an interrupt
> in the LR and can only have a bit cleared when the guest EOIs an
> interrupt in the LR.  Therefore, if we have no LRs with any
> pending/active interrupts, the APR cannot change value and there is no
> need to clear it on every exit from the VM (hint: it will have already
> been cleared when we exited the guest the last time with the LRs all
> EOIed).
> 
> The only case we need to take care of is when we migrate the VCPU away
> from a CPU or migrate a new VCPU onto a CPU, or when we return to
> userspace to capture the state of the VCPU for migration.  To make sure
> this works, factor out the APR save/restore functionality into separate
> functions called from the VCPU (and by extension VGIC) put/load hooks.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm/include/asm/kvm_hyp.h   |   2 +
>  arch/arm64/include/asm/kvm_hyp.h |   2 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c    | 124 +++++++++++++++++++++------------------
>  virt/kvm/arm/vgic/vgic-v2.c      |   7 +--
>  virt/kvm/arm/vgic/vgic-v3.c      |   5 ++
>  5 files changed, 78 insertions(+), 62 deletions(-)
> 
> diff --git a/arch/arm/include/asm/kvm_hyp.h b/arch/arm/include/asm/kvm_hyp.h
> index 1ab8329e9ff7..530a3c1cfe6f 100644
> --- a/arch/arm/include/asm/kvm_hyp.h
> +++ b/arch/arm/include/asm/kvm_hyp.h
> @@ -110,6 +110,8 @@ void __sysreg_restore_state(struct kvm_cpu_context *ctxt);
>  
>  void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
>  void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
> +void __vgic_v3_save_aprs(struct kvm_vcpu *vcpu);
> +void __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu);
>  
>  asmlinkage void __vfp_save_state(struct vfp_hard_struct *vfp);
>  asmlinkage void __vfp_restore_state(struct vfp_hard_struct *vfp);
> diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
> index febe417b8b4e..6f3929b2fcf7 100644
> --- a/arch/arm64/include/asm/kvm_hyp.h
> +++ b/arch/arm64/include/asm/kvm_hyp.h
> @@ -124,6 +124,8 @@ int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
>  
>  void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
>  void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
> +void __vgic_v3_save_aprs(struct kvm_vcpu *vcpu);
> +void __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu);
>  int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
>  
>  void __timer_enable_traps(struct kvm_vcpu *vcpu);
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 9abf2f3c12b5..437d7af08683 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -21,6 +21,7 @@
>  
>  #include <asm/kvm_emulate.h>
>  #include <asm/kvm_hyp.h>
> +#include <asm/kvm_mmu.h>
>  
>  #define vtr_to_max_lr_idx(v)		((v) & 0xf)
>  #define vtr_to_nr_pre_bits(v)		((((u32)(v) >> 26) & 7) + 1)
> @@ -221,14 +222,11 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
>  
>  	if (used_lrs) {
>  		int i;
> -		u32 nr_pre_bits;
>  		u32 elrsr;
>  
>  		elrsr = read_gicreg(ICH_ELSR_EL2);
>  
>  		write_gicreg(0, ICH_HCR_EL2);
> -		val = read_gicreg(ICH_VTR_EL2);
> -		nr_pre_bits = vtr_to_nr_pre_bits(val);
>  
>  		for (i = 0; i < used_lrs; i++) {
>  			if (elrsr & (1 << i))
> @@ -238,39 +236,10 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
>  
>  			__gic_v3_set_lr(0, i);
>  		}
> -
> -		switch (nr_pre_bits) {
> -		case 7:
> -			cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3);
> -			cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2);
> -		case 6:
> -			cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1);
> -		default:
> -			cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0);
> -		}
> -
> -		switch (nr_pre_bits) {
> -		case 7:
> -			cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3);
> -			cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2);
> -		case 6:
> -			cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1);
> -		default:
> -			cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
> -		}
>  	} else {
>  		if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
>  		    cpu_if->its_vpe.its_vm)
>  			write_gicreg(0, ICH_HCR_EL2);
> -
> -		cpu_if->vgic_ap0r[0] = 0;
> -		cpu_if->vgic_ap0r[1] = 0;
> -		cpu_if->vgic_ap0r[2] = 0;
> -		cpu_if->vgic_ap0r[3] = 0;
> -		cpu_if->vgic_ap1r[0] = 0;
> -		cpu_if->vgic_ap1r[1] = 0;
> -		cpu_if->vgic_ap1r[2] = 0;
> -		cpu_if->vgic_ap1r[3] = 0;
>  	}
>  
>  	val = read_gicreg(ICC_SRE_EL2);
> @@ -287,8 +256,6 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
>  {
>  	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
>  	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
> -	u64 val;
> -	u32 nr_pre_bits;
>  	int i;
>  
>  	/*
> @@ -306,32 +273,9 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
>  		write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
>  	}
>  
> -	val = read_gicreg(ICH_VTR_EL2);
> -	nr_pre_bits = vtr_to_nr_pre_bits(val);
> -
>  	if (used_lrs) {
>  		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
>  
> -		switch (nr_pre_bits) {
> -		case 7:
> -			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3);
> -			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2);
> -		case 6:
> -			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1);
> -		default:
> -			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0);
> -		}
> -
> -		switch (nr_pre_bits) {
> -		case 7:
> -			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3);
> -			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2);
> -		case 6:
> -			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1);
> -		default:
> -			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0);
> -		}
> -
>  		for (i = 0; i < used_lrs; i++)
>  			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
>  	} else {
> @@ -364,6 +308,72 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
>  		     ICC_SRE_EL2);
>  }
>  
> +void __hyp_text __vgic_v3_save_aprs(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpu_if;
> +	u64 val;
> +	u32 nr_pre_bits;
> +
> +	vcpu = kern_hyp_va(vcpu);
> +	cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
> +
> +	val = read_gicreg(ICH_VTR_EL2);
> +	nr_pre_bits = vtr_to_nr_pre_bits(val);
> +
> +	switch (nr_pre_bits) {
> +	case 7:
> +		cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3);
> +		cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2);
> +	case 6:
> +		cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1);
> +	default:
> +		cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0);
> +	}
> +
> +	switch (nr_pre_bits) {
> +	case 7:
> +		cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3);
> +		cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2);
> +	case 6:
> +		cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1);
> +	default:
> +		cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
> +	}
> +}
> +
> +void __hyp_text __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpu_if;
> +	u64 val;
> +	u32 nr_pre_bits;
> +
> +	vcpu = kern_hyp_va(vcpu);
> +	cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
> +
> +	val = read_gicreg(ICH_VTR_EL2);
> +	nr_pre_bits = vtr_to_nr_pre_bits(val);
> +
> +	switch (nr_pre_bits) {
> +	case 7:
> +		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3);
> +		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2);
> +	case 6:
> +		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1);
> +	default:
> +		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0);
> +	}
> +
> +	switch (nr_pre_bits) {
> +	case 7:
> +		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3);
> +		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2);
> +	case 6:
> +		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1);
> +	default:
> +		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0);
> +	}
> +}
> +
>  void __hyp_text __vgic_v3_init_lrs(void)
>  {
>  	int max_lr_idx = vtr_to_max_lr_idx(read_gicreg(ICH_VTR_EL2));
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 1e5f3eb6973d..ca7cfee9f353 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -446,7 +446,6 @@ void vgic_v2_save_state(struct kvm_vcpu *vcpu)
>  {
>  	struct kvm *kvm = vcpu->kvm;
>  	struct vgic_dist *vgic = &kvm->arch.vgic;
> -	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
>  	void __iomem *base = vgic->vctrl_base;
>  	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
>  
> @@ -454,11 +453,8 @@ void vgic_v2_save_state(struct kvm_vcpu *vcpu)
>  		return;
>  
>  	if (used_lrs) {
> -		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
>  		save_lrs(vcpu, base);
>  		writel_relaxed(0, base + GICH_HCR);
> -	} else {
> -		cpu_if->vgic_apr = 0;
>  	}
>  }
>  
> @@ -476,7 +472,6 @@ void vgic_v2_restore_state(struct kvm_vcpu *vcpu)
>  
>  	if (used_lrs) {
>  		writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
> -		writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
>  		for (i = 0; i < used_lrs; i++) {
>  			writel_relaxed(cpu_if->vgic_lr[i],
>  				       base + GICH_LR0 + (i * 4));
> @@ -490,6 +485,7 @@ void vgic_v2_load(struct kvm_vcpu *vcpu)
>  	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
>  
>  	writel_relaxed(cpu_if->vgic_vmcr, vgic->vctrl_base + GICH_VMCR);
> +	writel_relaxed(cpu_if->vgic_apr, vgic->vctrl_base + GICH_APR);
>  }
>  
>  void vgic_v2_put(struct kvm_vcpu *vcpu)
> @@ -498,4 +494,5 @@ void vgic_v2_put(struct kvm_vcpu *vcpu)
>  	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
>  
>  	cpu_if->vgic_vmcr = readl_relaxed(vgic->vctrl_base + GICH_VMCR);
> +	cpu_if->vgic_apr = readl_relaxed(vgic->vctrl_base + GICH_APR);
>  }
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index b76e21f3e6bd..4bafcd1e6bb8 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -16,6 +16,7 @@
>  #include <linux/kvm.h>
>  #include <linux/kvm_host.h>
>  #include <kvm/arm_vgic.h>
> +#include <asm/kvm_hyp.h>
>  #include <asm/kvm_mmu.h>
>  #include <asm/kvm_asm.h>
>  
> @@ -587,6 +588,8 @@ void vgic_v3_load(struct kvm_vcpu *vcpu)
>  	 */
>  	if (likely(cpu_if->vgic_sre))
>  		kvm_call_hyp(__vgic_v3_write_vmcr, cpu_if->vgic_vmcr);
> +
> +	kvm_call_hyp(__vgic_v3_restore_aprs, vcpu);
>  }
>  
>  void vgic_v3_put(struct kvm_vcpu *vcpu)
> @@ -595,4 +598,6 @@ void vgic_v3_put(struct kvm_vcpu *vcpu)
>  
>  	if (likely(cpu_if->vgic_sre))
>  		cpu_if->vgic_vmcr = kvm_call_hyp(__vgic_v3_read_vmcr);
> +
> +	kvm_call_hyp(__vgic_v3_save_aprs, vcpu);
>  }
> 

An unfortunate consequence of the save/restore de-aggregation process in
this series is that we end-up doing quite a few EL2 calls in the !VHE
case. We should probably think of consolidating those behind a single
EL2 call if they have a measurable impact.

In the meantime:

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v4 39/40] KVM: arm/arm64: Move VGIC APR save/restore to vgic put/load
@ 2018-02-22 13:11     ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-22 13:11 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/02/18 21:03, Christoffer Dall wrote:
> The APRs can only have bits set when the guest acknowledges an interrupt
> in the LR and can only have a bit cleared when the guest EOIs an
> interrupt in the LR.  Therefore, if we have no LRs with any
> pending/active interrupts, the APR cannot change value and there is no
> need to clear it on every exit from the VM (hint: it will have already
> been cleared when we exited the guest the last time with the LRs all
> EOIed).
> 
> The only case we need to take care of is when we migrate the VCPU away
> from a CPU or migrate a new VCPU onto a CPU, or when we return to
> userspace to capture the state of the VCPU for migration.  To make sure
> this works, factor out the APR save/restore functionality into separate
> functions called from the VCPU (and by extension VGIC) put/load hooks.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm/include/asm/kvm_hyp.h   |   2 +
>  arch/arm64/include/asm/kvm_hyp.h |   2 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c    | 124 +++++++++++++++++++++------------------
>  virt/kvm/arm/vgic/vgic-v2.c      |   7 +--
>  virt/kvm/arm/vgic/vgic-v3.c      |   5 ++
>  5 files changed, 78 insertions(+), 62 deletions(-)
> 
> diff --git a/arch/arm/include/asm/kvm_hyp.h b/arch/arm/include/asm/kvm_hyp.h
> index 1ab8329e9ff7..530a3c1cfe6f 100644
> --- a/arch/arm/include/asm/kvm_hyp.h
> +++ b/arch/arm/include/asm/kvm_hyp.h
> @@ -110,6 +110,8 @@ void __sysreg_restore_state(struct kvm_cpu_context *ctxt);
>  
>  void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
>  void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
> +void __vgic_v3_save_aprs(struct kvm_vcpu *vcpu);
> +void __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu);
>  
>  asmlinkage void __vfp_save_state(struct vfp_hard_struct *vfp);
>  asmlinkage void __vfp_restore_state(struct vfp_hard_struct *vfp);
> diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
> index febe417b8b4e..6f3929b2fcf7 100644
> --- a/arch/arm64/include/asm/kvm_hyp.h
> +++ b/arch/arm64/include/asm/kvm_hyp.h
> @@ -124,6 +124,8 @@ int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
>  
>  void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
>  void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
> +void __vgic_v3_save_aprs(struct kvm_vcpu *vcpu);
> +void __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu);
>  int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
>  
>  void __timer_enable_traps(struct kvm_vcpu *vcpu);
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 9abf2f3c12b5..437d7af08683 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -21,6 +21,7 @@
>  
>  #include <asm/kvm_emulate.h>
>  #include <asm/kvm_hyp.h>
> +#include <asm/kvm_mmu.h>
>  
>  #define vtr_to_max_lr_idx(v)		((v) & 0xf)
>  #define vtr_to_nr_pre_bits(v)		((((u32)(v) >> 26) & 7) + 1)
> @@ -221,14 +222,11 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
>  
>  	if (used_lrs) {
>  		int i;
> -		u32 nr_pre_bits;
>  		u32 elrsr;
>  
>  		elrsr = read_gicreg(ICH_ELSR_EL2);
>  
>  		write_gicreg(0, ICH_HCR_EL2);
> -		val = read_gicreg(ICH_VTR_EL2);
> -		nr_pre_bits = vtr_to_nr_pre_bits(val);
>  
>  		for (i = 0; i < used_lrs; i++) {
>  			if (elrsr & (1 << i))
> @@ -238,39 +236,10 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
>  
>  			__gic_v3_set_lr(0, i);
>  		}
> -
> -		switch (nr_pre_bits) {
> -		case 7:
> -			cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3);
> -			cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2);
> -		case 6:
> -			cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1);
> -		default:
> -			cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0);
> -		}
> -
> -		switch (nr_pre_bits) {
> -		case 7:
> -			cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3);
> -			cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2);
> -		case 6:
> -			cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1);
> -		default:
> -			cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
> -		}
>  	} else {
>  		if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
>  		    cpu_if->its_vpe.its_vm)
>  			write_gicreg(0, ICH_HCR_EL2);
> -
> -		cpu_if->vgic_ap0r[0] = 0;
> -		cpu_if->vgic_ap0r[1] = 0;
> -		cpu_if->vgic_ap0r[2] = 0;
> -		cpu_if->vgic_ap0r[3] = 0;
> -		cpu_if->vgic_ap1r[0] = 0;
> -		cpu_if->vgic_ap1r[1] = 0;
> -		cpu_if->vgic_ap1r[2] = 0;
> -		cpu_if->vgic_ap1r[3] = 0;
>  	}
>  
>  	val = read_gicreg(ICC_SRE_EL2);
> @@ -287,8 +256,6 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
>  {
>  	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
>  	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
> -	u64 val;
> -	u32 nr_pre_bits;
>  	int i;
>  
>  	/*
> @@ -306,32 +273,9 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
>  		write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
>  	}
>  
> -	val = read_gicreg(ICH_VTR_EL2);
> -	nr_pre_bits = vtr_to_nr_pre_bits(val);
> -
>  	if (used_lrs) {
>  		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
>  
> -		switch (nr_pre_bits) {
> -		case 7:
> -			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3);
> -			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2);
> -		case 6:
> -			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1);
> -		default:
> -			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0);
> -		}
> -
> -		switch (nr_pre_bits) {
> -		case 7:
> -			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3);
> -			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2);
> -		case 6:
> -			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1);
> -		default:
> -			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0);
> -		}
> -
>  		for (i = 0; i < used_lrs; i++)
>  			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
>  	} else {
> @@ -364,6 +308,72 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
>  		     ICC_SRE_EL2);
>  }
>  
> +void __hyp_text __vgic_v3_save_aprs(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpu_if;
> +	u64 val;
> +	u32 nr_pre_bits;
> +
> +	vcpu = kern_hyp_va(vcpu);
> +	cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
> +
> +	val = read_gicreg(ICH_VTR_EL2);
> +	nr_pre_bits = vtr_to_nr_pre_bits(val);
> +
> +	switch (nr_pre_bits) {
> +	case 7:
> +		cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3);
> +		cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2);
> +	case 6:
> +		cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1);
> +	default:
> +		cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0);
> +	}
> +
> +	switch (nr_pre_bits) {
> +	case 7:
> +		cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3);
> +		cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2);
> +	case 6:
> +		cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1);
> +	default:
> +		cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
> +	}
> +}
> +
> +void __hyp_text __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu)
> +{
> +	struct vgic_v3_cpu_if *cpu_if;
> +	u64 val;
> +	u32 nr_pre_bits;
> +
> +	vcpu = kern_hyp_va(vcpu);
> +	cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
> +
> +	val = read_gicreg(ICH_VTR_EL2);
> +	nr_pre_bits = vtr_to_nr_pre_bits(val);
> +
> +	switch (nr_pre_bits) {
> +	case 7:
> +		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3);
> +		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2);
> +	case 6:
> +		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1);
> +	default:
> +		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0);
> +	}
> +
> +	switch (nr_pre_bits) {
> +	case 7:
> +		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3);
> +		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2);
> +	case 6:
> +		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1);
> +	default:
> +		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0);
> +	}
> +}
> +
>  void __hyp_text __vgic_v3_init_lrs(void)
>  {
>  	int max_lr_idx = vtr_to_max_lr_idx(read_gicreg(ICH_VTR_EL2));
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index 1e5f3eb6973d..ca7cfee9f353 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -446,7 +446,6 @@ void vgic_v2_save_state(struct kvm_vcpu *vcpu)
>  {
>  	struct kvm *kvm = vcpu->kvm;
>  	struct vgic_dist *vgic = &kvm->arch.vgic;
> -	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
>  	void __iomem *base = vgic->vctrl_base;
>  	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
>  
> @@ -454,11 +453,8 @@ void vgic_v2_save_state(struct kvm_vcpu *vcpu)
>  		return;
>  
>  	if (used_lrs) {
> -		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
>  		save_lrs(vcpu, base);
>  		writel_relaxed(0, base + GICH_HCR);
> -	} else {
> -		cpu_if->vgic_apr = 0;
>  	}
>  }
>  
> @@ -476,7 +472,6 @@ void vgic_v2_restore_state(struct kvm_vcpu *vcpu)
>  
>  	if (used_lrs) {
>  		writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
> -		writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
>  		for (i = 0; i < used_lrs; i++) {
>  			writel_relaxed(cpu_if->vgic_lr[i],
>  				       base + GICH_LR0 + (i * 4));
> @@ -490,6 +485,7 @@ void vgic_v2_load(struct kvm_vcpu *vcpu)
>  	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
>  
>  	writel_relaxed(cpu_if->vgic_vmcr, vgic->vctrl_base + GICH_VMCR);
> +	writel_relaxed(cpu_if->vgic_apr, vgic->vctrl_base + GICH_APR);
>  }
>  
>  void vgic_v2_put(struct kvm_vcpu *vcpu)
> @@ -498,4 +494,5 @@ void vgic_v2_put(struct kvm_vcpu *vcpu)
>  	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
>  
>  	cpu_if->vgic_vmcr = readl_relaxed(vgic->vctrl_base + GICH_VMCR);
> +	cpu_if->vgic_apr = readl_relaxed(vgic->vctrl_base + GICH_APR);
>  }
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index b76e21f3e6bd..4bafcd1e6bb8 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -16,6 +16,7 @@
>  #include <linux/kvm.h>
>  #include <linux/kvm_host.h>
>  #include <kvm/arm_vgic.h>
> +#include <asm/kvm_hyp.h>
>  #include <asm/kvm_mmu.h>
>  #include <asm/kvm_asm.h>
>  
> @@ -587,6 +588,8 @@ void vgic_v3_load(struct kvm_vcpu *vcpu)
>  	 */
>  	if (likely(cpu_if->vgic_sre))
>  		kvm_call_hyp(__vgic_v3_write_vmcr, cpu_if->vgic_vmcr);
> +
> +	kvm_call_hyp(__vgic_v3_restore_aprs, vcpu);
>  }
>  
>  void vgic_v3_put(struct kvm_vcpu *vcpu)
> @@ -595,4 +598,6 @@ void vgic_v3_put(struct kvm_vcpu *vcpu)
>  
>  	if (likely(cpu_if->vgic_sre))
>  		cpu_if->vgic_vmcr = kvm_call_hyp(__vgic_v3_read_vmcr);
> +
> +	kvm_call_hyp(__vgic_v3_save_aprs, vcpu);
>  }
> 

An unfortunate consequence of the save/restore de-aggregation process in
this series is that we end-up doing quite a few EL2 calls in the !VHE
case. We should probably think of consolidating those behind a single
EL2 call if they have a measurable impact.

In the meantime:

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
  2018-02-22 11:10           ` Christoffer Dall
@ 2018-02-22 13:26             ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-22 13:26 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Christoffer Dall, Andrew Jones, kvm, Tomasz Nowicki, kvmarm,
	Julien Grall, Yury Norov, linux-arm-kernel, Dave Martin,
	Shih-Wei Li

On 22/02/18 11:10, Christoffer Dall wrote:
> On Thu, Feb 22, 2018 at 10:48:10AM +0000, Marc Zyngier wrote:
>> On Thu, 22 Feb 2018 09:22:37 +0000,
>> Christoffer Dall wrote:
>>>
>>> On Wed, Feb 21, 2018 at 01:32:45PM +0000, Marc Zyngier wrote:
>>>> On Thu, 15 Feb 2018 21:03:16 +0000,
>>>> Christoffer Dall wrote:
>>>>>
>>>>> From: Christoffer Dall <cdall@cs.columbia.edu>
>>>>>
>>>>> Currently we access the system registers array via the vcpu_sys_reg()
>>>>> macro.  However, we are about to change the behavior to some times
>>>>> modify the register file directly, so let's change this to two
>>>>> primitives:
>>>>>
>>>>>  * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
>>>>>  * Direct array access macro __vcpu_sys_reg()
>>>>>
>>>>> The first primitive should be used in places where the code needs to
>>>>> access the currently loaded VCPU's state as observed by the guest.  For
>>>>> example, when trapping on cache related registers, a write to a system
>>>>> register should go directly to the VCPU version of the register.
>>>>>
>>>>> The second primitive can be used in places where the VCPU is known to
>>>>> never be running (for example userspace access) or for registers which
>>>>> are never context switched (for example all the PMU system registers).
>>>>>
>>>>> This rewrites all users of vcpu_sys_regs to one of the two primitives
>>>>> above.
>>>>>
>>>>> No functional change.
>>>>>
>>>>> Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
>>>>> ---
>>>>>
>>>>> Notes:
>>>>>     Changes since v2:
>>>>>      - New patch (deferred register handling has been reworked)
>>>>>
>>>>>  arch/arm64/include/asm/kvm_emulate.h | 13 ++++---
>>>>>  arch/arm64/include/asm/kvm_host.h    | 13 ++++++-
>>>>>  arch/arm64/include/asm/kvm_mmu.h     |  2 +-
>>>>>  arch/arm64/kvm/debug.c               | 27 +++++++++-----
>>>>>  arch/arm64/kvm/inject_fault.c        |  8 ++--
>>>>>  arch/arm64/kvm/sys_regs.c            | 71 ++++++++++++++++++------------------
>>>>>  arch/arm64/kvm/sys_regs.h            |  4 +-
>>>>>  arch/arm64/kvm/sys_regs_generic_v8.c |  4 +-
>>>>>  virt/kvm/arm/pmu.c                   | 37 ++++++++++---------
>>>>>  9 files changed, 102 insertions(+), 77 deletions(-)
>>>>>
>>>>> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
>>>>> index 3cc535591bdf..d313aaae5c38 100644
>>>>> --- a/arch/arm64/include/asm/kvm_emulate.h
>>>>> +++ b/arch/arm64/include/asm/kvm_emulate.h
>>>>> @@ -290,15 +290,18 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
>>>>>  
>>>>>  static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
>>>>>  {
>>>>> -	return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
>>>>> +	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
>>>>>  }
>>>>>  
>>>>>  static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
>>>>>  {
>>>>> -	if (vcpu_mode_is_32bit(vcpu))
>>>>> +	if (vcpu_mode_is_32bit(vcpu)) {
>>>>>  		*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
>>>>> -	else
>>>>> -		vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
>>>>> +	} else {
>>>>> +		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
>>>>> +		sctlr |= (1 << 25);
>>>>> +		vcpu_write_sys_reg(vcpu, SCTLR_EL1, sctlr);
>>>>
>>>> General comment: it is slightly annoying that vcpu_write_sys_reg takes
>>>> its parameters in an order different from that of write_sysreg
>>>> (register followed with value, instead of value followed with
>>>> register). Not a deal breaker, but slightly confusing.
>>>>
>>>
>>> Ah, I didn't compare to write_sysreg, I was thinking that
>>>
>>>   vcpu_read_sys_reg(vcpu, SCTLR_EL1);
>>>   vcpu_write_sys_reg(vcpu, SCTLR_EL1, val);
>>>
>>> looked more symmetrical because the write just takes an extra value, but
>>> I can see your argument as well.
>>>
>>> I don't mind changing it if it matters to you?
>>
>> I'd like to see that changed, but it doesn't have to be as part of
>> this series if it is going to cause a refactoring mess. We can address
>> it as a blanket fix after this series.
>>
> 
> I think it's reasonably self-contained.
> 
> Just so I'm sure, are these the primitives you'd like to see?
> 
> vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg);
> vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg);

That'd be my preference indeed.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
@ 2018-02-22 13:26             ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-22 13:26 UTC (permalink / raw)
  To: linux-arm-kernel

On 22/02/18 11:10, Christoffer Dall wrote:
> On Thu, Feb 22, 2018 at 10:48:10AM +0000, Marc Zyngier wrote:
>> On Thu, 22 Feb 2018 09:22:37 +0000,
>> Christoffer Dall wrote:
>>>
>>> On Wed, Feb 21, 2018 at 01:32:45PM +0000, Marc Zyngier wrote:
>>>> On Thu, 15 Feb 2018 21:03:16 +0000,
>>>> Christoffer Dall wrote:
>>>>>
>>>>> From: Christoffer Dall <cdall@cs.columbia.edu>
>>>>>
>>>>> Currently we access the system registers array via the vcpu_sys_reg()
>>>>> macro.  However, we are about to change the behavior to some times
>>>>> modify the register file directly, so let's change this to two
>>>>> primitives:
>>>>>
>>>>>  * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
>>>>>  * Direct array access macro __vcpu_sys_reg()
>>>>>
>>>>> The first primitive should be used in places where the code needs to
>>>>> access the currently loaded VCPU's state as observed by the guest.  For
>>>>> example, when trapping on cache related registers, a write to a system
>>>>> register should go directly to the VCPU version of the register.
>>>>>
>>>>> The second primitive can be used in places where the VCPU is known to
>>>>> never be running (for example userspace access) or for registers which
>>>>> are never context switched (for example all the PMU system registers).
>>>>>
>>>>> This rewrites all users of vcpu_sys_regs to one of the two primitives
>>>>> above.
>>>>>
>>>>> No functional change.
>>>>>
>>>>> Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
>>>>> ---
>>>>>
>>>>> Notes:
>>>>>     Changes since v2:
>>>>>      - New patch (deferred register handling has been reworked)
>>>>>
>>>>>  arch/arm64/include/asm/kvm_emulate.h | 13 ++++---
>>>>>  arch/arm64/include/asm/kvm_host.h    | 13 ++++++-
>>>>>  arch/arm64/include/asm/kvm_mmu.h     |  2 +-
>>>>>  arch/arm64/kvm/debug.c               | 27 +++++++++-----
>>>>>  arch/arm64/kvm/inject_fault.c        |  8 ++--
>>>>>  arch/arm64/kvm/sys_regs.c            | 71 ++++++++++++++++++------------------
>>>>>  arch/arm64/kvm/sys_regs.h            |  4 +-
>>>>>  arch/arm64/kvm/sys_regs_generic_v8.c |  4 +-
>>>>>  virt/kvm/arm/pmu.c                   | 37 ++++++++++---------
>>>>>  9 files changed, 102 insertions(+), 77 deletions(-)
>>>>>
>>>>> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
>>>>> index 3cc535591bdf..d313aaae5c38 100644
>>>>> --- a/arch/arm64/include/asm/kvm_emulate.h
>>>>> +++ b/arch/arm64/include/asm/kvm_emulate.h
>>>>> @@ -290,15 +290,18 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
>>>>>  
>>>>>  static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
>>>>>  {
>>>>> -	return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
>>>>> +	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
>>>>>  }
>>>>>  
>>>>>  static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
>>>>>  {
>>>>> -	if (vcpu_mode_is_32bit(vcpu))
>>>>> +	if (vcpu_mode_is_32bit(vcpu)) {
>>>>>  		*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
>>>>> -	else
>>>>> -		vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
>>>>> +	} else {
>>>>> +		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
>>>>> +		sctlr |= (1 << 25);
>>>>> +		vcpu_write_sys_reg(vcpu, SCTLR_EL1, sctlr);
>>>>
>>>> General comment: it is slightly annoying that vcpu_write_sys_reg takes
>>>> its parameters in an order different from that of write_sysreg
>>>> (register followed with value, instead of value followed with
>>>> register). Not a deal breaker, but slightly confusing.
>>>>
>>>
>>> Ah, I didn't compare to write_sysreg, I was thinking that
>>>
>>>   vcpu_read_sys_reg(vcpu, SCTLR_EL1);
>>>   vcpu_write_sys_reg(vcpu, SCTLR_EL1, val);
>>>
>>> looked more symmetrical because the write just takes an extra value, but
>>> I can see your argument as well.
>>>
>>> I don't mind changing it if it matters to you?
>>
>> I'd like to see that changed, but it doesn't have to be as part of
>> this series if it is going to cause a refactoring mess. We can address
>> it as a blanket fix after this series.
>>
> 
> I think it's reasonably self-contained.
> 
> Just so I'm sure, are these the primitives you'd like to see?
> 
> vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg);
> vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg);

That'd be my preference indeed.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-22 13:34     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 13:34 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Christoffer Dall, kvm, Marc Zyngier, kvmarm, Yury Norov,
	linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:16PM +0100, Christoffer Dall wrote:
> From: Christoffer Dall <cdall@cs.columbia.edu>
> 
> Currently we access the system registers array via the vcpu_sys_reg()
> macro.  However, we are about to change the behavior to some times
> modify the register file directly, so let's change this to two
> primitives:
> 
>  * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
>  * Direct array access macro __vcpu_sys_reg()
> 
> The first primitive should be used in places where the code needs to
> access the currently loaded VCPU's state as observed by the guest.  For
> example, when trapping on cache related registers, a write to a system
> register should go directly to the VCPU version of the register.
> 
> The second primitive can be used in places where the VCPU is known to
> never be running (for example userspace access) or for registers which
> are never context switched (for example all the PMU system registers).
> 
> This rewrites all users of vcpu_sys_regs to one of the two primitives
> above.
> 
> No functional change.
> 
> Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> ---
> 
> Notes:
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm64/include/asm/kvm_emulate.h | 13 ++++---
>  arch/arm64/include/asm/kvm_host.h    | 13 ++++++-
>  arch/arm64/include/asm/kvm_mmu.h     |  2 +-
>  arch/arm64/kvm/debug.c               | 27 +++++++++-----
>  arch/arm64/kvm/inject_fault.c        |  8 ++--
>  arch/arm64/kvm/sys_regs.c            | 71 ++++++++++++++++++------------------
>  arch/arm64/kvm/sys_regs.h            |  4 +-
>  arch/arm64/kvm/sys_regs_generic_v8.c |  4 +-
>  virt/kvm/arm/pmu.c                   | 37 ++++++++++---------
>  9 files changed, 102 insertions(+), 77 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 3cc535591bdf..d313aaae5c38 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -290,15 +290,18 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
>  
>  static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
>  {
> -	return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> +	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
>  }
>  
>  static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
>  {
> -	if (vcpu_mode_is_32bit(vcpu))
> +	if (vcpu_mode_is_32bit(vcpu)) {
>  		*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
> -	else
> -		vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
> +	} else {
> +		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
> +		sctlr |= (1 << 25);
> +		vcpu_write_sys_reg(vcpu, SCTLR_EL1, sctlr);
> +	}
>  }
>  
>  static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> @@ -306,7 +309,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
>  	if (vcpu_mode_is_32bit(vcpu))
>  		return !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_E_BIT);
>  
> -	return !!(vcpu_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> +	return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
>  }
>  
>  static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index f2a6f39aec87..68398bf7882f 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
>  };
>  
>  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> -#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> +
> +/*
> + * Only use __vcpu_sys_reg if you know you want the memory backed version of a
> + * register, and not the one most recently accessed by a runnning VCPU.  For
> + * example, for userpace access or for system registers that are never context
> + * switched, but only emulated.
> + */
> +#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> +
> +#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> +#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> +
>  /*
>   * CP14 and CP15 live in the same array, as they are backed by the
>   * same system registers.
> diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> index 9679067a1574..95f46e73c4dc 100644
> --- a/arch/arm64/include/asm/kvm_mmu.h
> +++ b/arch/arm64/include/asm/kvm_mmu.h
> @@ -249,7 +249,7 @@ struct kvm;
>  
>  static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
>  {
> -	return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> +	return (vcpu_read_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
>  }
>  
>  static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
> diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> index feedb877cff8..db32d10a56a1 100644
> --- a/arch/arm64/kvm/debug.c
> +++ b/arch/arm64/kvm/debug.c
> @@ -46,7 +46,8 @@ static DEFINE_PER_CPU(u32, mdcr_el2);
>   */
>  static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
>  {
> -	vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1);
> +	vcpu->arch.guest_debug_preserved.mdscr_el1 =
> +		vcpu_read_sys_reg(vcpu, MDSCR_EL1);
>  
>  	trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
>  				vcpu->arch.guest_debug_preserved.mdscr_el1);
> @@ -54,10 +55,11 @@ static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
>  
>  static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
>  {
> -	vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1;
> +	vcpu_write_sys_reg(vcpu, MDSCR_EL1,
> +			   vcpu->arch.guest_debug_preserved.mdscr_el1);
>  
>  	trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
> -				vcpu_sys_reg(vcpu, MDSCR_EL1));
> +				vcpu_read_sys_reg(vcpu, MDSCR_EL1));
>  }
>  
>  /**
> @@ -108,6 +110,7 @@ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
>  void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  {
>  	bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY);
> +	unsigned long mdscr;
>  
>  	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
>  
> @@ -152,9 +155,13 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  		 */
>  		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
>  			*vcpu_cpsr(vcpu) |=  DBG_SPSR_SS;
> -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_SS;
> +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> +			mdscr |= DBG_MDSCR_SS;
> +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
>  		} else {
> -			vcpu_sys_reg(vcpu, MDSCR_EL1) &= ~DBG_MDSCR_SS;
> +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> +			mdscr &= ~DBG_MDSCR_SS;
> +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
>  		}
>  
>  		trace_kvm_arm_set_dreg32("SPSR_EL2", *vcpu_cpsr(vcpu));
> @@ -170,7 +177,9 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  		 */
>  		if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) {
>  			/* Enable breakpoints/watchpoints */
> -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_MDE;
> +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> +			mdscr |= DBG_MDSCR_MDE;
> +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
>  
>  			vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state;
>  			vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
> @@ -194,12 +203,12 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  		vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
>  
>  	/* If KDE or MDE are set, perform a full save/restore cycle. */
> -	if ((vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_KDE) ||
> -	    (vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_MDE))
> +	if (vcpu_read_sys_reg(vcpu, MDSCR_EL1) & (DBG_MDSCR_KDE | DBG_MDSCR_MDE))
>  		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
>  
>  	trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2);
> -	trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_sys_reg(vcpu, MDSCR_EL1));
> +	trace_kvm_arm_set_dreg32("MDSCR_EL1",
> +				 vcpu_read_sys_reg(vcpu, MDSCR_EL1));
>  }
>  
>  void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
> diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> index 30a3f58cdb7b..e08db2f2dd75 100644
> --- a/arch/arm64/kvm/inject_fault.c
> +++ b/arch/arm64/kvm/inject_fault.c
> @@ -58,7 +58,7 @@ static u64 get_except_vector(struct kvm_vcpu *vcpu, enum exception_type type)
>  		exc_offset = LOWER_EL_AArch32_VECTOR;
>  	}
>  
> -	return vcpu_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
> +	return vcpu_read_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
>  }
>  
>  static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
> @@ -73,7 +73,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
>  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
>  	*vcpu_spsr(vcpu) = cpsr;
>  
> -	vcpu_sys_reg(vcpu, FAR_EL1) = addr;
> +	vcpu_write_sys_reg(vcpu, FAR_EL1, addr);
>  
>  	/*
>  	 * Build an {i,d}abort, depending on the level and the
> @@ -94,7 +94,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
>  	if (!is_iabt)
>  		esr |= ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT;
>  
> -	vcpu_sys_reg(vcpu, ESR_EL1) = esr | ESR_ELx_FSC_EXTABT;
> +	vcpu_write_sys_reg(vcpu, ESR_EL1, esr | ESR_ELx_FSC_EXTABT);
>  }
>  
>  static void inject_undef64(struct kvm_vcpu *vcpu)
> @@ -115,7 +115,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
>  	if (kvm_vcpu_trap_il_is32bit(vcpu))
>  		esr |= ESR_ELx_IL;
>  
> -	vcpu_sys_reg(vcpu, ESR_EL1) = esr;
> +	vcpu_write_sys_reg(vcpu, ESR_EL1, esr);
>  }
>  
>  /**
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index b48af790615e..a05d2c01c786 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -133,14 +133,14 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
>  	if (!p->is_aarch32 || !p->is_32bit) {
>  		val = p->regval;
>  	} else {
> -		val = vcpu_sys_reg(vcpu, reg);
> +		val = vcpu_read_sys_reg(vcpu, reg);
>  		if (r->reg % 2)
>  			val = (p->regval << 32) | (u64)lower_32_bits(val);
>  		else
>  			val = ((u64)upper_32_bits(val) << 32) |
>  				lower_32_bits(p->regval);
>  	}
> -	vcpu_sys_reg(vcpu, reg) = val;
> +	vcpu_write_sys_reg(vcpu, reg, val);
>  
>  	kvm_toggle_cache(vcpu, was_enabled);
>  	return true;
> @@ -241,10 +241,10 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
>  			    const struct sys_reg_desc *r)
>  {
>  	if (p->is_write) {
> -		vcpu_sys_reg(vcpu, r->reg) = p->regval;
> +		vcpu_write_sys_reg(vcpu, r->reg, p->regval);
>  		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, r->reg);
> +		p->regval = vcpu_read_sys_reg(vcpu, r->reg);
>  	}
>  
>  	trace_trap_reg(__func__, r->reg, p->is_write, p->regval);
> @@ -457,7 +457,8 @@ static void reset_wcr(struct kvm_vcpu *vcpu,
>  
>  static void reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  {
> -	vcpu_sys_reg(vcpu, AMAIR_EL1) = read_sysreg(amair_el1);
> +	u64 amair = read_sysreg(amair_el1);
> +	vcpu_write_sys_reg(vcpu, AMAIR_EL1, amair);
>  }
>  
>  static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> @@ -474,7 +475,7 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  	mpidr = (vcpu->vcpu_id & 0x0f) << MPIDR_LEVEL_SHIFT(0);
>  	mpidr |= ((vcpu->vcpu_id >> 4) & 0xff) << MPIDR_LEVEL_SHIFT(1);
>  	mpidr |= ((vcpu->vcpu_id >> 12) & 0xff) << MPIDR_LEVEL_SHIFT(2);
> -	vcpu_sys_reg(vcpu, MPIDR_EL1) = (1ULL << 31) | mpidr;
> +	vcpu_write_sys_reg(vcpu, MPIDR_EL1, (1ULL << 31) | mpidr);
>  }
>  
>  static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> @@ -488,12 +489,12 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  	 */
>  	val = ((pmcr & ~ARMV8_PMU_PMCR_MASK)
>  	       | (ARMV8_PMU_PMCR_MASK & 0xdecafbad)) & (~ARMV8_PMU_PMCR_E);
> -	vcpu_sys_reg(vcpu, PMCR_EL0) = val;
> +	__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
>  }
>  
>  static bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags)
>  {
> -	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +	u64 reg = __vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>  	bool enabled = (reg & flags) || vcpu_mode_priv(vcpu);
>  
>  	if (!enabled)
> @@ -535,14 +536,14 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  
>  	if (p->is_write) {
>  		/* Only update writeable bits of PMCR */
> -		val = vcpu_sys_reg(vcpu, PMCR_EL0);
> +		val = __vcpu_sys_reg(vcpu, PMCR_EL0);
>  		val &= ~ARMV8_PMU_PMCR_MASK;
>  		val |= p->regval & ARMV8_PMU_PMCR_MASK;
> -		vcpu_sys_reg(vcpu, PMCR_EL0) = val;
> +		__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
>  		kvm_pmu_handle_pmcr(vcpu, val);
>  	} else {
>  		/* PMCR.P & PMCR.C are RAZ */
> -		val = vcpu_sys_reg(vcpu, PMCR_EL0)
> +		val = __vcpu_sys_reg(vcpu, PMCR_EL0)
>  		      & ~(ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C);
>  		p->regval = val;
>  	}
> @@ -560,10 +561,10 @@ static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  		return false;
>  
>  	if (p->is_write)
> -		vcpu_sys_reg(vcpu, PMSELR_EL0) = p->regval;
> +		__vcpu_sys_reg(vcpu, PMSELR_EL0) = p->regval;
>  	else
>  		/* return PMSELR.SEL field */
> -		p->regval = vcpu_sys_reg(vcpu, PMSELR_EL0)
> +		p->regval = __vcpu_sys_reg(vcpu, PMSELR_EL0)
>  			    & ARMV8_PMU_COUNTER_MASK;
>  
>  	return true;
> @@ -596,7 +597,7 @@ static bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
>  {
>  	u64 pmcr, val;
>  
> -	pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
> +	pmcr = __vcpu_sys_reg(vcpu, PMCR_EL0);
>  	val = (pmcr >> ARMV8_PMU_PMCR_N_SHIFT) & ARMV8_PMU_PMCR_N_MASK;
>  	if (idx >= val && idx != ARMV8_PMU_CYCLE_IDX) {
>  		kvm_inject_undefined(vcpu);
> @@ -621,7 +622,7 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
>  			if (pmu_access_event_counter_el0_disabled(vcpu))
>  				return false;
>  
> -			idx = vcpu_sys_reg(vcpu, PMSELR_EL0)
> +			idx = __vcpu_sys_reg(vcpu, PMSELR_EL0)
>  			      & ARMV8_PMU_COUNTER_MASK;
>  		} else if (r->Op2 == 0) {
>  			/* PMCCNTR_EL0 */
> @@ -676,7 +677,7 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  
>  	if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 1) {
>  		/* PMXEVTYPER_EL0 */
> -		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_PMU_COUNTER_MASK;
> +		idx = __vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_PMU_COUNTER_MASK;
>  		reg = PMEVTYPER0_EL0 + idx;
>  	} else if (r->CRn == 14 && (r->CRm & 12) == 12) {
>  		idx = ((r->CRm & 3) << 3) | (r->Op2 & 7);
> @@ -694,9 +695,9 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  
>  	if (p->is_write) {
>  		kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
> -		vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_PMU_EVTYPE_MASK;
> +		__vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_PMU_EVTYPE_MASK;
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK;
> +		p->regval = __vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK;
>  	}
>  
>  	return true;
> @@ -718,15 +719,15 @@ static bool access_pmcnten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  		val = p->regval & mask;
>  		if (r->Op2 & 0x1) {
>  			/* accessing PMCNTENSET_EL0 */
> -			vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val;
> +			__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val;
>  			kvm_pmu_enable_counter(vcpu, val);
>  		} else {
>  			/* accessing PMCNTENCLR_EL0 */
> -			vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val;
> +			__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val;
>  			kvm_pmu_disable_counter(vcpu, val);
>  		}
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask;
> +		p->regval = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask;
>  	}
>  
>  	return true;
> @@ -750,12 +751,12 @@ static bool access_pminten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  
>  		if (r->Op2 & 0x1)
>  			/* accessing PMINTENSET_EL1 */
> -			vcpu_sys_reg(vcpu, PMINTENSET_EL1) |= val;
> +			__vcpu_sys_reg(vcpu, PMINTENSET_EL1) |= val;
>  		else
>  			/* accessing PMINTENCLR_EL1 */
> -			vcpu_sys_reg(vcpu, PMINTENSET_EL1) &= ~val;
> +			__vcpu_sys_reg(vcpu, PMINTENSET_EL1) &= ~val;
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, PMINTENSET_EL1) & mask;
> +		p->regval = __vcpu_sys_reg(vcpu, PMINTENSET_EL1) & mask;
>  	}
>  
>  	return true;
> @@ -775,12 +776,12 @@ static bool access_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	if (p->is_write) {
>  		if (r->CRm & 0x2)
>  			/* accessing PMOVSSET_EL0 */
> -			vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= (p->regval & mask);
> +			__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= (p->regval & mask);
>  		else
>  			/* accessing PMOVSCLR_EL0 */
> -			vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= ~(p->regval & mask);
> +			__vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= ~(p->regval & mask);
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, PMOVSSET_EL0) & mask;
> +		p->regval = __vcpu_sys_reg(vcpu, PMOVSSET_EL0) & mask;
>  	}
>  
>  	return true;
> @@ -817,10 +818,10 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  			return false;
>  		}
>  
> -		vcpu_sys_reg(vcpu, PMUSERENR_EL0) = p->regval
> -						    & ARMV8_PMU_USERENR_MASK;
> -	} else {
> -		p->regval = vcpu_sys_reg(vcpu, PMUSERENR_EL0)
> +		__vcpu_sys_reg(vcpu, PMUSERENR_EL0) =
> +			       p->regval & ARMV8_PMU_USERENR_MASK;
> +	} else  {
> +		p->regval = __vcpu_sys_reg(vcpu, PMUSERENR_EL0)
>  			    & ARMV8_PMU_USERENR_MASK;
>  	}
>  
> @@ -2204,7 +2205,7 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
>  	if (r->get_user)
>  		return (r->get_user)(vcpu, r, reg, uaddr);
>  
> -	return reg_to_user(uaddr, &vcpu_sys_reg(vcpu, r->reg), reg->id);
> +	return reg_to_user(uaddr, &__vcpu_sys_reg(vcpu, r->reg), reg->id);
>  }
>  
>  int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> @@ -2225,7 +2226,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
>  	if (r->set_user)
>  		return (r->set_user)(vcpu, r, reg, uaddr);
>  
> -	return reg_from_user(&vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
> +	return reg_from_user(&__vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
>  }
>  
>  static unsigned int num_demux_regs(void)
> @@ -2431,6 +2432,6 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
>  	reset_sys_reg_descs(vcpu, table, num);
>  
>  	for (num = 1; num < NR_SYS_REGS; num++)
> -		if (vcpu_sys_reg(vcpu, num) == 0x4242424242424242)
> -			panic("Didn't reset vcpu_sys_reg(%zi)", num);
> +		if (__vcpu_sys_reg(vcpu, num) == 0x4242424242424242)
> +			panic("Didn't reset __vcpu_sys_reg(%zi)", num);

The only direct access to vcpu->arch.ctxt.sys_regs outside a save-restore
file is in this function, a bit above this hunk. Copied below

 /* Catch someone adding a register without putting in reset entry. */
 memset(&vcpu->arch.ctxt.sys_regs, 0x42, sizeof(vcpu->arch.ctxt.sys_regs));

Maybe we should change it to

 for (num = 0; num < NR_SYS_REGS; num++)
     __vcpu_sys_reg(vcpu, num) == 0x4242424242424242;

just to pedantically use the API?

>  }
> diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
> index 060f5348ef25..cd710f8b63e0 100644
> --- a/arch/arm64/kvm/sys_regs.h
> +++ b/arch/arm64/kvm/sys_regs.h
> @@ -89,14 +89,14 @@ static inline void reset_unknown(struct kvm_vcpu *vcpu,
>  {
>  	BUG_ON(!r->reg);
>  	BUG_ON(r->reg >= NR_SYS_REGS);
> -	vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
> +	__vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
>  }
>  
>  static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  {
>  	BUG_ON(!r->reg);
>  	BUG_ON(r->reg >= NR_SYS_REGS);
> -	vcpu_sys_reg(vcpu, r->reg) = r->val;
> +	__vcpu_sys_reg(vcpu, r->reg) = r->val;
>  }
>  
>  static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
> diff --git a/arch/arm64/kvm/sys_regs_generic_v8.c b/arch/arm64/kvm/sys_regs_generic_v8.c
> index 969ade1d333d..ddb8497d18d6 100644
> --- a/arch/arm64/kvm/sys_regs_generic_v8.c
> +++ b/arch/arm64/kvm/sys_regs_generic_v8.c
> @@ -38,13 +38,13 @@ static bool access_actlr(struct kvm_vcpu *vcpu,
>  	if (p->is_write)
>  		return ignore_write(vcpu, p);
>  
> -	p->regval = vcpu_sys_reg(vcpu, ACTLR_EL1);
> +	p->regval = vcpu_read_sys_reg(vcpu, ACTLR_EL1);
>  	return true;
>  }
>  
>  static void reset_actlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  {
> -	vcpu_sys_reg(vcpu, ACTLR_EL1) = read_sysreg(actlr_el1);
> +	__vcpu_sys_reg(vcpu, ACTLR_EL1) = read_sysreg(actlr_el1);
>  }
>  
>  /*
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 8a9c42366db7..29cb4a1ff26b 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -37,7 +37,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
>  
>  	reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
>  	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
> -	counter = vcpu_sys_reg(vcpu, reg);
> +	counter = __vcpu_sys_reg(vcpu, reg);
>  
>  	/* The real counter value is equal to the value of counter register plus
>  	 * the value perf event counts.
> @@ -61,7 +61,8 @@ void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val)
>  
>  	reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
>  	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
> -	vcpu_sys_reg(vcpu, reg) += (s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);
> +	__vcpu_sys_reg(vcpu, reg) +=
> +		(s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);
>  }
>  
>  /**
> @@ -78,7 +79,7 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
>  		counter = kvm_pmu_get_counter_value(vcpu, pmc->idx);
>  		reg = (pmc->idx == ARMV8_PMU_CYCLE_IDX)
>  		       ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + pmc->idx;
> -		vcpu_sys_reg(vcpu, reg) = counter;
> +		__vcpu_sys_reg(vcpu, reg) = counter;
>  		perf_event_disable(pmc->perf_event);
>  		perf_event_release_kernel(pmc->perf_event);
>  		pmc->perf_event = NULL;
> @@ -125,7 +126,7 @@ void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu)
>  
>  u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
>  {
> -	u64 val = vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMU_PMCR_N_SHIFT;
> +	u64 val = __vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMU_PMCR_N_SHIFT;
>  
>  	val &= ARMV8_PMU_PMCR_N_MASK;
>  	if (val == 0)
> @@ -147,7 +148,7 @@ void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val)
>  	struct kvm_pmu *pmu = &vcpu->arch.pmu;
>  	struct kvm_pmc *pmc;
>  
> -	if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) || !val)
> +	if (!(__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) || !val)
>  		return;
>  
>  	for (i = 0; i < ARMV8_PMU_MAX_COUNTERS; i++) {
> @@ -193,10 +194,10 @@ static u64 kvm_pmu_overflow_status(struct kvm_vcpu *vcpu)
>  {
>  	u64 reg = 0;
>  
> -	if ((vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E)) {
> -		reg = vcpu_sys_reg(vcpu, PMOVSSET_EL0);
> -		reg &= vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> -		reg &= vcpu_sys_reg(vcpu, PMINTENSET_EL1);
> +	if ((__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E)) {
> +		reg = __vcpu_sys_reg(vcpu, PMOVSSET_EL0);
> +		reg &= __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> +		reg &= __vcpu_sys_reg(vcpu, PMINTENSET_EL1);
>  		reg &= kvm_pmu_valid_counter_mask(vcpu);
>  	}
>  
> @@ -295,7 +296,7 @@ static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
>  	struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
>  	int idx = pmc->idx;
>  
> -	vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(idx);
> +	__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(idx);
>  
>  	if (kvm_pmu_overflow_status(vcpu)) {
>  		kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
> @@ -316,19 +317,19 @@ void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
>  	if (val == 0)
>  		return;
>  
> -	enable = vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> +	enable = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
>  	for (i = 0; i < ARMV8_PMU_CYCLE_IDX; i++) {
>  		if (!(val & BIT(i)))
>  			continue;
> -		type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
> +		type = __vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
>  		       & ARMV8_PMU_EVTYPE_EVENT;
>  		if ((type == ARMV8_PMUV3_PERFCTR_SW_INCR)
>  		    && (enable & BIT(i))) {
> -			reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
> +			reg = __vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
>  			reg = lower_32_bits(reg);
> -			vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
> +			__vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
>  			if (!reg)
> -				vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
> +				__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
>  		}
>  	}
>  }
> @@ -348,7 +349,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
>  	mask = kvm_pmu_valid_counter_mask(vcpu);
>  	if (val & ARMV8_PMU_PMCR_E) {
>  		kvm_pmu_enable_counter(vcpu,
> -				vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask);
> +		       __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask);
>  	} else {
>  		kvm_pmu_disable_counter(vcpu, mask);
>  	}
> @@ -369,8 +370,8 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
>  
>  static bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu, u64 select_idx)
>  {
> -	return (vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) &&
> -	       (vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
> +	return (__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) &&
> +	       (__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
>  }
>  
>  /**
> -- 
> 2.14.2
>

All the broken lines to honor the 80-char limit induces some sadness,
but at least people reading the code on their VT100's will be happy.

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
@ 2018-02-22 13:34     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 13:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:16PM +0100, Christoffer Dall wrote:
> From: Christoffer Dall <cdall@cs.columbia.edu>
> 
> Currently we access the system registers array via the vcpu_sys_reg()
> macro.  However, we are about to change the behavior to some times
> modify the register file directly, so let's change this to two
> primitives:
> 
>  * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
>  * Direct array access macro __vcpu_sys_reg()
> 
> The first primitive should be used in places where the code needs to
> access the currently loaded VCPU's state as observed by the guest.  For
> example, when trapping on cache related registers, a write to a system
> register should go directly to the VCPU version of the register.
> 
> The second primitive can be used in places where the VCPU is known to
> never be running (for example userspace access) or for registers which
> are never context switched (for example all the PMU system registers).
> 
> This rewrites all users of vcpu_sys_regs to one of the two primitives
> above.
> 
> No functional change.
> 
> Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> ---
> 
> Notes:
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm64/include/asm/kvm_emulate.h | 13 ++++---
>  arch/arm64/include/asm/kvm_host.h    | 13 ++++++-
>  arch/arm64/include/asm/kvm_mmu.h     |  2 +-
>  arch/arm64/kvm/debug.c               | 27 +++++++++-----
>  arch/arm64/kvm/inject_fault.c        |  8 ++--
>  arch/arm64/kvm/sys_regs.c            | 71 ++++++++++++++++++------------------
>  arch/arm64/kvm/sys_regs.h            |  4 +-
>  arch/arm64/kvm/sys_regs_generic_v8.c |  4 +-
>  virt/kvm/arm/pmu.c                   | 37 ++++++++++---------
>  9 files changed, 102 insertions(+), 77 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 3cc535591bdf..d313aaae5c38 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -290,15 +290,18 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
>  
>  static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
>  {
> -	return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> +	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
>  }
>  
>  static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
>  {
> -	if (vcpu_mode_is_32bit(vcpu))
> +	if (vcpu_mode_is_32bit(vcpu)) {
>  		*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
> -	else
> -		vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
> +	} else {
> +		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
> +		sctlr |= (1 << 25);
> +		vcpu_write_sys_reg(vcpu, SCTLR_EL1, sctlr);
> +	}
>  }
>  
>  static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> @@ -306,7 +309,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
>  	if (vcpu_mode_is_32bit(vcpu))
>  		return !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_E_BIT);
>  
> -	return !!(vcpu_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> +	return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
>  }
>  
>  static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index f2a6f39aec87..68398bf7882f 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
>  };
>  
>  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> -#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> +
> +/*
> + * Only use __vcpu_sys_reg if you know you want the memory backed version of a
> + * register, and not the one most recently accessed by a runnning VCPU.  For
> + * example, for userpace access or for system registers that are never context
> + * switched, but only emulated.
> + */
> +#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> +
> +#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> +#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> +
>  /*
>   * CP14 and CP15 live in the same array, as they are backed by the
>   * same system registers.
> diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> index 9679067a1574..95f46e73c4dc 100644
> --- a/arch/arm64/include/asm/kvm_mmu.h
> +++ b/arch/arm64/include/asm/kvm_mmu.h
> @@ -249,7 +249,7 @@ struct kvm;
>  
>  static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
>  {
> -	return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> +	return (vcpu_read_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
>  }
>  
>  static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
> diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> index feedb877cff8..db32d10a56a1 100644
> --- a/arch/arm64/kvm/debug.c
> +++ b/arch/arm64/kvm/debug.c
> @@ -46,7 +46,8 @@ static DEFINE_PER_CPU(u32, mdcr_el2);
>   */
>  static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
>  {
> -	vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1);
> +	vcpu->arch.guest_debug_preserved.mdscr_el1 =
> +		vcpu_read_sys_reg(vcpu, MDSCR_EL1);
>  
>  	trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
>  				vcpu->arch.guest_debug_preserved.mdscr_el1);
> @@ -54,10 +55,11 @@ static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
>  
>  static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
>  {
> -	vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1;
> +	vcpu_write_sys_reg(vcpu, MDSCR_EL1,
> +			   vcpu->arch.guest_debug_preserved.mdscr_el1);
>  
>  	trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
> -				vcpu_sys_reg(vcpu, MDSCR_EL1));
> +				vcpu_read_sys_reg(vcpu, MDSCR_EL1));
>  }
>  
>  /**
> @@ -108,6 +110,7 @@ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
>  void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  {
>  	bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY);
> +	unsigned long mdscr;
>  
>  	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
>  
> @@ -152,9 +155,13 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  		 */
>  		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
>  			*vcpu_cpsr(vcpu) |=  DBG_SPSR_SS;
> -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_SS;
> +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> +			mdscr |= DBG_MDSCR_SS;
> +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
>  		} else {
> -			vcpu_sys_reg(vcpu, MDSCR_EL1) &= ~DBG_MDSCR_SS;
> +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> +			mdscr &= ~DBG_MDSCR_SS;
> +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
>  		}
>  
>  		trace_kvm_arm_set_dreg32("SPSR_EL2", *vcpu_cpsr(vcpu));
> @@ -170,7 +177,9 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  		 */
>  		if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) {
>  			/* Enable breakpoints/watchpoints */
> -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_MDE;
> +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> +			mdscr |= DBG_MDSCR_MDE;
> +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
>  
>  			vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state;
>  			vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
> @@ -194,12 +203,12 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  		vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
>  
>  	/* If KDE or MDE are set, perform a full save/restore cycle. */
> -	if ((vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_KDE) ||
> -	    (vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_MDE))
> +	if (vcpu_read_sys_reg(vcpu, MDSCR_EL1) & (DBG_MDSCR_KDE | DBG_MDSCR_MDE))
>  		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
>  
>  	trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2);
> -	trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_sys_reg(vcpu, MDSCR_EL1));
> +	trace_kvm_arm_set_dreg32("MDSCR_EL1",
> +				 vcpu_read_sys_reg(vcpu, MDSCR_EL1));
>  }
>  
>  void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
> diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> index 30a3f58cdb7b..e08db2f2dd75 100644
> --- a/arch/arm64/kvm/inject_fault.c
> +++ b/arch/arm64/kvm/inject_fault.c
> @@ -58,7 +58,7 @@ static u64 get_except_vector(struct kvm_vcpu *vcpu, enum exception_type type)
>  		exc_offset = LOWER_EL_AArch32_VECTOR;
>  	}
>  
> -	return vcpu_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
> +	return vcpu_read_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
>  }
>  
>  static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
> @@ -73,7 +73,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
>  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
>  	*vcpu_spsr(vcpu) = cpsr;
>  
> -	vcpu_sys_reg(vcpu, FAR_EL1) = addr;
> +	vcpu_write_sys_reg(vcpu, FAR_EL1, addr);
>  
>  	/*
>  	 * Build an {i,d}abort, depending on the level and the
> @@ -94,7 +94,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
>  	if (!is_iabt)
>  		esr |= ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT;
>  
> -	vcpu_sys_reg(vcpu, ESR_EL1) = esr | ESR_ELx_FSC_EXTABT;
> +	vcpu_write_sys_reg(vcpu, ESR_EL1, esr | ESR_ELx_FSC_EXTABT);
>  }
>  
>  static void inject_undef64(struct kvm_vcpu *vcpu)
> @@ -115,7 +115,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
>  	if (kvm_vcpu_trap_il_is32bit(vcpu))
>  		esr |= ESR_ELx_IL;
>  
> -	vcpu_sys_reg(vcpu, ESR_EL1) = esr;
> +	vcpu_write_sys_reg(vcpu, ESR_EL1, esr);
>  }
>  
>  /**
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index b48af790615e..a05d2c01c786 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -133,14 +133,14 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
>  	if (!p->is_aarch32 || !p->is_32bit) {
>  		val = p->regval;
>  	} else {
> -		val = vcpu_sys_reg(vcpu, reg);
> +		val = vcpu_read_sys_reg(vcpu, reg);
>  		if (r->reg % 2)
>  			val = (p->regval << 32) | (u64)lower_32_bits(val);
>  		else
>  			val = ((u64)upper_32_bits(val) << 32) |
>  				lower_32_bits(p->regval);
>  	}
> -	vcpu_sys_reg(vcpu, reg) = val;
> +	vcpu_write_sys_reg(vcpu, reg, val);
>  
>  	kvm_toggle_cache(vcpu, was_enabled);
>  	return true;
> @@ -241,10 +241,10 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
>  			    const struct sys_reg_desc *r)
>  {
>  	if (p->is_write) {
> -		vcpu_sys_reg(vcpu, r->reg) = p->regval;
> +		vcpu_write_sys_reg(vcpu, r->reg, p->regval);
>  		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, r->reg);
> +		p->regval = vcpu_read_sys_reg(vcpu, r->reg);
>  	}
>  
>  	trace_trap_reg(__func__, r->reg, p->is_write, p->regval);
> @@ -457,7 +457,8 @@ static void reset_wcr(struct kvm_vcpu *vcpu,
>  
>  static void reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  {
> -	vcpu_sys_reg(vcpu, AMAIR_EL1) = read_sysreg(amair_el1);
> +	u64 amair = read_sysreg(amair_el1);
> +	vcpu_write_sys_reg(vcpu, AMAIR_EL1, amair);
>  }
>  
>  static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> @@ -474,7 +475,7 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  	mpidr = (vcpu->vcpu_id & 0x0f) << MPIDR_LEVEL_SHIFT(0);
>  	mpidr |= ((vcpu->vcpu_id >> 4) & 0xff) << MPIDR_LEVEL_SHIFT(1);
>  	mpidr |= ((vcpu->vcpu_id >> 12) & 0xff) << MPIDR_LEVEL_SHIFT(2);
> -	vcpu_sys_reg(vcpu, MPIDR_EL1) = (1ULL << 31) | mpidr;
> +	vcpu_write_sys_reg(vcpu, MPIDR_EL1, (1ULL << 31) | mpidr);
>  }
>  
>  static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> @@ -488,12 +489,12 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  	 */
>  	val = ((pmcr & ~ARMV8_PMU_PMCR_MASK)
>  	       | (ARMV8_PMU_PMCR_MASK & 0xdecafbad)) & (~ARMV8_PMU_PMCR_E);
> -	vcpu_sys_reg(vcpu, PMCR_EL0) = val;
> +	__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
>  }
>  
>  static bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags)
>  {
> -	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +	u64 reg = __vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>  	bool enabled = (reg & flags) || vcpu_mode_priv(vcpu);
>  
>  	if (!enabled)
> @@ -535,14 +536,14 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  
>  	if (p->is_write) {
>  		/* Only update writeable bits of PMCR */
> -		val = vcpu_sys_reg(vcpu, PMCR_EL0);
> +		val = __vcpu_sys_reg(vcpu, PMCR_EL0);
>  		val &= ~ARMV8_PMU_PMCR_MASK;
>  		val |= p->regval & ARMV8_PMU_PMCR_MASK;
> -		vcpu_sys_reg(vcpu, PMCR_EL0) = val;
> +		__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
>  		kvm_pmu_handle_pmcr(vcpu, val);
>  	} else {
>  		/* PMCR.P & PMCR.C are RAZ */
> -		val = vcpu_sys_reg(vcpu, PMCR_EL0)
> +		val = __vcpu_sys_reg(vcpu, PMCR_EL0)
>  		      & ~(ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C);
>  		p->regval = val;
>  	}
> @@ -560,10 +561,10 @@ static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  		return false;
>  
>  	if (p->is_write)
> -		vcpu_sys_reg(vcpu, PMSELR_EL0) = p->regval;
> +		__vcpu_sys_reg(vcpu, PMSELR_EL0) = p->regval;
>  	else
>  		/* return PMSELR.SEL field */
> -		p->regval = vcpu_sys_reg(vcpu, PMSELR_EL0)
> +		p->regval = __vcpu_sys_reg(vcpu, PMSELR_EL0)
>  			    & ARMV8_PMU_COUNTER_MASK;
>  
>  	return true;
> @@ -596,7 +597,7 @@ static bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
>  {
>  	u64 pmcr, val;
>  
> -	pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
> +	pmcr = __vcpu_sys_reg(vcpu, PMCR_EL0);
>  	val = (pmcr >> ARMV8_PMU_PMCR_N_SHIFT) & ARMV8_PMU_PMCR_N_MASK;
>  	if (idx >= val && idx != ARMV8_PMU_CYCLE_IDX) {
>  		kvm_inject_undefined(vcpu);
> @@ -621,7 +622,7 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
>  			if (pmu_access_event_counter_el0_disabled(vcpu))
>  				return false;
>  
> -			idx = vcpu_sys_reg(vcpu, PMSELR_EL0)
> +			idx = __vcpu_sys_reg(vcpu, PMSELR_EL0)
>  			      & ARMV8_PMU_COUNTER_MASK;
>  		} else if (r->Op2 == 0) {
>  			/* PMCCNTR_EL0 */
> @@ -676,7 +677,7 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  
>  	if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 1) {
>  		/* PMXEVTYPER_EL0 */
> -		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_PMU_COUNTER_MASK;
> +		idx = __vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_PMU_COUNTER_MASK;
>  		reg = PMEVTYPER0_EL0 + idx;
>  	} else if (r->CRn == 14 && (r->CRm & 12) == 12) {
>  		idx = ((r->CRm & 3) << 3) | (r->Op2 & 7);
> @@ -694,9 +695,9 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  
>  	if (p->is_write) {
>  		kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
> -		vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_PMU_EVTYPE_MASK;
> +		__vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_PMU_EVTYPE_MASK;
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK;
> +		p->regval = __vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK;
>  	}
>  
>  	return true;
> @@ -718,15 +719,15 @@ static bool access_pmcnten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  		val = p->regval & mask;
>  		if (r->Op2 & 0x1) {
>  			/* accessing PMCNTENSET_EL0 */
> -			vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val;
> +			__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val;
>  			kvm_pmu_enable_counter(vcpu, val);
>  		} else {
>  			/* accessing PMCNTENCLR_EL0 */
> -			vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val;
> +			__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val;
>  			kvm_pmu_disable_counter(vcpu, val);
>  		}
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask;
> +		p->regval = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask;
>  	}
>  
>  	return true;
> @@ -750,12 +751,12 @@ static bool access_pminten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  
>  		if (r->Op2 & 0x1)
>  			/* accessing PMINTENSET_EL1 */
> -			vcpu_sys_reg(vcpu, PMINTENSET_EL1) |= val;
> +			__vcpu_sys_reg(vcpu, PMINTENSET_EL1) |= val;
>  		else
>  			/* accessing PMINTENCLR_EL1 */
> -			vcpu_sys_reg(vcpu, PMINTENSET_EL1) &= ~val;
> +			__vcpu_sys_reg(vcpu, PMINTENSET_EL1) &= ~val;
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, PMINTENSET_EL1) & mask;
> +		p->regval = __vcpu_sys_reg(vcpu, PMINTENSET_EL1) & mask;
>  	}
>  
>  	return true;
> @@ -775,12 +776,12 @@ static bool access_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	if (p->is_write) {
>  		if (r->CRm & 0x2)
>  			/* accessing PMOVSSET_EL0 */
> -			vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= (p->regval & mask);
> +			__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= (p->regval & mask);
>  		else
>  			/* accessing PMOVSCLR_EL0 */
> -			vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= ~(p->regval & mask);
> +			__vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= ~(p->regval & mask);
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, PMOVSSET_EL0) & mask;
> +		p->regval = __vcpu_sys_reg(vcpu, PMOVSSET_EL0) & mask;
>  	}
>  
>  	return true;
> @@ -817,10 +818,10 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  			return false;
>  		}
>  
> -		vcpu_sys_reg(vcpu, PMUSERENR_EL0) = p->regval
> -						    & ARMV8_PMU_USERENR_MASK;
> -	} else {
> -		p->regval = vcpu_sys_reg(vcpu, PMUSERENR_EL0)
> +		__vcpu_sys_reg(vcpu, PMUSERENR_EL0) =
> +			       p->regval & ARMV8_PMU_USERENR_MASK;
> +	} else  {
> +		p->regval = __vcpu_sys_reg(vcpu, PMUSERENR_EL0)
>  			    & ARMV8_PMU_USERENR_MASK;
>  	}
>  
> @@ -2204,7 +2205,7 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
>  	if (r->get_user)
>  		return (r->get_user)(vcpu, r, reg, uaddr);
>  
> -	return reg_to_user(uaddr, &vcpu_sys_reg(vcpu, r->reg), reg->id);
> +	return reg_to_user(uaddr, &__vcpu_sys_reg(vcpu, r->reg), reg->id);
>  }
>  
>  int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> @@ -2225,7 +2226,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
>  	if (r->set_user)
>  		return (r->set_user)(vcpu, r, reg, uaddr);
>  
> -	return reg_from_user(&vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
> +	return reg_from_user(&__vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
>  }
>  
>  static unsigned int num_demux_regs(void)
> @@ -2431,6 +2432,6 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
>  	reset_sys_reg_descs(vcpu, table, num);
>  
>  	for (num = 1; num < NR_SYS_REGS; num++)
> -		if (vcpu_sys_reg(vcpu, num) == 0x4242424242424242)
> -			panic("Didn't reset vcpu_sys_reg(%zi)", num);
> +		if (__vcpu_sys_reg(vcpu, num) == 0x4242424242424242)
> +			panic("Didn't reset __vcpu_sys_reg(%zi)", num);

The only direct access to vcpu->arch.ctxt.sys_regs outside a save-restore
file is in this function, a bit above this hunk. Copied below

 /* Catch someone adding a register without putting in reset entry. */
 memset(&vcpu->arch.ctxt.sys_regs, 0x42, sizeof(vcpu->arch.ctxt.sys_regs));

Maybe we should change it to

 for (num = 0; num < NR_SYS_REGS; num++)
     __vcpu_sys_reg(vcpu, num) == 0x4242424242424242;

just to pedantically use the API?

>  }
> diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
> index 060f5348ef25..cd710f8b63e0 100644
> --- a/arch/arm64/kvm/sys_regs.h
> +++ b/arch/arm64/kvm/sys_regs.h
> @@ -89,14 +89,14 @@ static inline void reset_unknown(struct kvm_vcpu *vcpu,
>  {
>  	BUG_ON(!r->reg);
>  	BUG_ON(r->reg >= NR_SYS_REGS);
> -	vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
> +	__vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
>  }
>  
>  static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  {
>  	BUG_ON(!r->reg);
>  	BUG_ON(r->reg >= NR_SYS_REGS);
> -	vcpu_sys_reg(vcpu, r->reg) = r->val;
> +	__vcpu_sys_reg(vcpu, r->reg) = r->val;
>  }
>  
>  static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
> diff --git a/arch/arm64/kvm/sys_regs_generic_v8.c b/arch/arm64/kvm/sys_regs_generic_v8.c
> index 969ade1d333d..ddb8497d18d6 100644
> --- a/arch/arm64/kvm/sys_regs_generic_v8.c
> +++ b/arch/arm64/kvm/sys_regs_generic_v8.c
> @@ -38,13 +38,13 @@ static bool access_actlr(struct kvm_vcpu *vcpu,
>  	if (p->is_write)
>  		return ignore_write(vcpu, p);
>  
> -	p->regval = vcpu_sys_reg(vcpu, ACTLR_EL1);
> +	p->regval = vcpu_read_sys_reg(vcpu, ACTLR_EL1);
>  	return true;
>  }
>  
>  static void reset_actlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  {
> -	vcpu_sys_reg(vcpu, ACTLR_EL1) = read_sysreg(actlr_el1);
> +	__vcpu_sys_reg(vcpu, ACTLR_EL1) = read_sysreg(actlr_el1);
>  }
>  
>  /*
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 8a9c42366db7..29cb4a1ff26b 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -37,7 +37,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
>  
>  	reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
>  	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
> -	counter = vcpu_sys_reg(vcpu, reg);
> +	counter = __vcpu_sys_reg(vcpu, reg);
>  
>  	/* The real counter value is equal to the value of counter register plus
>  	 * the value perf event counts.
> @@ -61,7 +61,8 @@ void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val)
>  
>  	reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
>  	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
> -	vcpu_sys_reg(vcpu, reg) += (s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);
> +	__vcpu_sys_reg(vcpu, reg) +=
> +		(s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);
>  }
>  
>  /**
> @@ -78,7 +79,7 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
>  		counter = kvm_pmu_get_counter_value(vcpu, pmc->idx);
>  		reg = (pmc->idx == ARMV8_PMU_CYCLE_IDX)
>  		       ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + pmc->idx;
> -		vcpu_sys_reg(vcpu, reg) = counter;
> +		__vcpu_sys_reg(vcpu, reg) = counter;
>  		perf_event_disable(pmc->perf_event);
>  		perf_event_release_kernel(pmc->perf_event);
>  		pmc->perf_event = NULL;
> @@ -125,7 +126,7 @@ void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu)
>  
>  u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
>  {
> -	u64 val = vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMU_PMCR_N_SHIFT;
> +	u64 val = __vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMU_PMCR_N_SHIFT;
>  
>  	val &= ARMV8_PMU_PMCR_N_MASK;
>  	if (val == 0)
> @@ -147,7 +148,7 @@ void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val)
>  	struct kvm_pmu *pmu = &vcpu->arch.pmu;
>  	struct kvm_pmc *pmc;
>  
> -	if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) || !val)
> +	if (!(__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) || !val)
>  		return;
>  
>  	for (i = 0; i < ARMV8_PMU_MAX_COUNTERS; i++) {
> @@ -193,10 +194,10 @@ static u64 kvm_pmu_overflow_status(struct kvm_vcpu *vcpu)
>  {
>  	u64 reg = 0;
>  
> -	if ((vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E)) {
> -		reg = vcpu_sys_reg(vcpu, PMOVSSET_EL0);
> -		reg &= vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> -		reg &= vcpu_sys_reg(vcpu, PMINTENSET_EL1);
> +	if ((__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E)) {
> +		reg = __vcpu_sys_reg(vcpu, PMOVSSET_EL0);
> +		reg &= __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> +		reg &= __vcpu_sys_reg(vcpu, PMINTENSET_EL1);
>  		reg &= kvm_pmu_valid_counter_mask(vcpu);
>  	}
>  
> @@ -295,7 +296,7 @@ static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
>  	struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
>  	int idx = pmc->idx;
>  
> -	vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(idx);
> +	__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(idx);
>  
>  	if (kvm_pmu_overflow_status(vcpu)) {
>  		kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
> @@ -316,19 +317,19 @@ void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
>  	if (val == 0)
>  		return;
>  
> -	enable = vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> +	enable = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
>  	for (i = 0; i < ARMV8_PMU_CYCLE_IDX; i++) {
>  		if (!(val & BIT(i)))
>  			continue;
> -		type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
> +		type = __vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
>  		       & ARMV8_PMU_EVTYPE_EVENT;
>  		if ((type == ARMV8_PMUV3_PERFCTR_SW_INCR)
>  		    && (enable & BIT(i))) {
> -			reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
> +			reg = __vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
>  			reg = lower_32_bits(reg);
> -			vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
> +			__vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
>  			if (!reg)
> -				vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
> +				__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
>  		}
>  	}
>  }
> @@ -348,7 +349,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
>  	mask = kvm_pmu_valid_counter_mask(vcpu);
>  	if (val & ARMV8_PMU_PMCR_E) {
>  		kvm_pmu_enable_counter(vcpu,
> -				vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask);
> +		       __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask);
>  	} else {
>  		kvm_pmu_disable_counter(vcpu, mask);
>  	}
> @@ -369,8 +370,8 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
>  
>  static bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu, u64 select_idx)
>  {
> -	return (vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) &&
> -	       (vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
> +	return (__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) &&
> +	       (__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
>  }
>  
>  /**
> -- 
> 2.14.2
>

All the broken lines to honor the 80-char limit induces some sadness,
but at least people reading the code on their VT100's will be happy.

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 25/40] KVM: arm64: Introduce framework for accessing deferred sysregs
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-22 13:40     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 13:40 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:17PM +0100, Christoffer Dall wrote:
> We are about to defer saving and restoring some groups of system
> registers to vcpu_put and vcpu_load on supported systems.  This means
> that we need some infrastructure to access system registes which
> supports either accessing the memory backing of the register or directly
> accessing the system registers, depending on the state of the system
> when we access the register.
> 
> We do this by defining read/write accessor functions, which can handle
> both "immediate" and "deferrable" system registers.  Immediate registers
> are always saved/restored in the world-switch path, but deferrable
> registers are only saved/restored in vcpu_put/vcpu_load when supported
> and sysregs_loaded_on_cpu will be set in that case.
> 
> Note that we don't use the deferred mechanism yet in this patch, but only
> introduce infrastructure.  This is to improve convenience of review in
> the subsequent patches where it is clear which registers become
> deferred.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Changed to a switch-statement based approach to improve
>        readability.
>     
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm64/include/asm/kvm_host.h |  8 ++++++--
>  arch/arm64/kvm/sys_regs.c         | 33 +++++++++++++++++++++++++++++++++
>  2 files changed, 39 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 68398bf7882f..b463b5e28959 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -284,6 +284,10 @@ struct kvm_vcpu_arch {
>  
>  	/* Virtual SError ESR to restore when HCR_EL2.VSE is set */
>  	u64 vsesr_el2;
> +
> +	/* True when deferrable sysregs are loaded on the physical CPU,
> +	 * see kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs. */
> +	bool sysregs_loaded_on_cpu;
>  };
>  
>  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> @@ -296,8 +300,8 @@ struct kvm_vcpu_arch {
>   */
>  #define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
>  
> -#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> -#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> +u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg);
> +void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val);
>  
>  /*
>   * CP14 and CP15 live in the same array, as they are backed by the
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index a05d2c01c786..b3c3f014aa61 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -35,6 +35,7 @@
>  #include <asm/kvm_coproc.h>
>  #include <asm/kvm_emulate.h>
>  #include <asm/kvm_host.h>
> +#include <asm/kvm_hyp.h>
>  #include <asm/kvm_mmu.h>
>  #include <asm/perf_event.h>
>  #include <asm/sysreg.h>
> @@ -76,6 +77,38 @@ static bool write_to_read_only(struct kvm_vcpu *vcpu,
>  	return false;
>  }
>  
> +u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
> +{
> +	if (!vcpu->arch.sysregs_loaded_on_cpu)
> +		goto immediate_read;
> +
> +	/*
> +	 * All system registers listed in the switch are not saved on every
> +	 * exit from the guest but are only saved on vcpu_put.

The "All ... are not" doesn't flow well for me. How about

 /*
  * None of the system registers listed in the switch are saved on guest
  * exit. These registers are only saved on vcpu_put.
  */

> +	 */
> +	switch (reg) {
> +	}
> +
> +immediate_read:
> +	return __vcpu_sys_reg(vcpu, reg);
> +}
> +
> +void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
> +{
> +	if (!vcpu->arch.sysregs_loaded_on_cpu)
> +		goto immediate_write;
> +
> +	/*
> +	 * All system registers listed in the switch are not restored on every
> +	 * entry to the guest but are only restored on vcpu_load.
> +	 */

 /*
  * None of the system registers listed in the switch are restored on
  * guest entry. If these registers were saved due to a vcpu_put, then
  * they will be restored by vcpu_load.
  */

> +	switch (reg) {
> +	}
> +
> +immediate_write:
> +	 __vcpu_sys_reg(vcpu, reg) = val;
> +}
> +
>  /* 3 bits per cache level, as per CLIDR, but non-existent caches always 0 */
>  static u32 cache_levels;
>  
> -- 
> 2.14.2
>

Otherwise

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 25/40] KVM: arm64: Introduce framework for accessing deferred sysregs
@ 2018-02-22 13:40     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 13:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:17PM +0100, Christoffer Dall wrote:
> We are about to defer saving and restoring some groups of system
> registers to vcpu_put and vcpu_load on supported systems.  This means
> that we need some infrastructure to access system registes which
> supports either accessing the memory backing of the register or directly
> accessing the system registers, depending on the state of the system
> when we access the register.
> 
> We do this by defining read/write accessor functions, which can handle
> both "immediate" and "deferrable" system registers.  Immediate registers
> are always saved/restored in the world-switch path, but deferrable
> registers are only saved/restored in vcpu_put/vcpu_load when supported
> and sysregs_loaded_on_cpu will be set in that case.
> 
> Note that we don't use the deferred mechanism yet in this patch, but only
> introduce infrastructure.  This is to improve convenience of review in
> the subsequent patches where it is clear which registers become
> deferred.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Changed to a switch-statement based approach to improve
>        readability.
>     
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm64/include/asm/kvm_host.h |  8 ++++++--
>  arch/arm64/kvm/sys_regs.c         | 33 +++++++++++++++++++++++++++++++++
>  2 files changed, 39 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 68398bf7882f..b463b5e28959 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -284,6 +284,10 @@ struct kvm_vcpu_arch {
>  
>  	/* Virtual SError ESR to restore when HCR_EL2.VSE is set */
>  	u64 vsesr_el2;
> +
> +	/* True when deferrable sysregs are loaded on the physical CPU,
> +	 * see kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs. */
> +	bool sysregs_loaded_on_cpu;
>  };
>  
>  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> @@ -296,8 +300,8 @@ struct kvm_vcpu_arch {
>   */
>  #define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
>  
> -#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> -#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> +u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg);
> +void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val);
>  
>  /*
>   * CP14 and CP15 live in the same array, as they are backed by the
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index a05d2c01c786..b3c3f014aa61 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -35,6 +35,7 @@
>  #include <asm/kvm_coproc.h>
>  #include <asm/kvm_emulate.h>
>  #include <asm/kvm_host.h>
> +#include <asm/kvm_hyp.h>
>  #include <asm/kvm_mmu.h>
>  #include <asm/perf_event.h>
>  #include <asm/sysreg.h>
> @@ -76,6 +77,38 @@ static bool write_to_read_only(struct kvm_vcpu *vcpu,
>  	return false;
>  }
>  
> +u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
> +{
> +	if (!vcpu->arch.sysregs_loaded_on_cpu)
> +		goto immediate_read;
> +
> +	/*
> +	 * All system registers listed in the switch are not saved on every
> +	 * exit from the guest but are only saved on vcpu_put.

The "All ... are not" doesn't flow well for me. How about

 /*
  * None of the system registers listed in the switch are saved on guest
  * exit. These registers are only saved on vcpu_put.
  */

> +	 */
> +	switch (reg) {
> +	}
> +
> +immediate_read:
> +	return __vcpu_sys_reg(vcpu, reg);
> +}
> +
> +void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
> +{
> +	if (!vcpu->arch.sysregs_loaded_on_cpu)
> +		goto immediate_write;
> +
> +	/*
> +	 * All system registers listed in the switch are not restored on every
> +	 * entry to the guest but are only restored on vcpu_load.
> +	 */

 /*
  * None of the system registers listed in the switch are restored on
  * guest entry. If these registers were saved due to a vcpu_put, then
  * they will be restored by vcpu_load.
  */

> +	switch (reg) {
> +	}
> +
> +immediate_write:
> +	 __vcpu_sys_reg(vcpu, reg) = val;
> +}
> +
>  /* 3 bits per cache level, as per CLIDR, but non-existent caches always 0 */
>  static u32 cache_levels;
>  
> -- 
> 2.14.2
>

Otherwise

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 26/40] KVM: arm/arm64: Prepare to handle deferred save/restore of SPSR_EL1
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-22 13:49     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 13:49 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:18PM +0100, Christoffer Dall wrote:
> SPSR_EL1 is not used by a VHE host kernel and can be deferred, but we
> need to rework the accesses to this register to access the latest value
> depending on whether or not guest system registers are loaded on the CPU
> or only reside in memory.
> 
> The handling of accessing the various banked SPSRs for 32-bit VMs is a
> bit clunky, but this will be improved in following patches which will
> first prepare and subsequently implement deferred save/restore of the
> 32-bit registers, including the 32-bit SPSRs.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm/include/asm/kvm_emulate.h   | 12 ++++++++++-
>  arch/arm/kvm/emulate.c               |  2 +-
>  arch/arm64/include/asm/kvm_emulate.h | 41 +++++++++++++++++++++++++++++++-----
>  arch/arm64/kvm/inject_fault.c        |  4 ++--
>  virt/kvm/arm/aarch32.c               |  2 +-
>  5 files changed, 51 insertions(+), 10 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 26/40] KVM: arm/arm64: Prepare to handle deferred save/restore of SPSR_EL1
@ 2018-02-22 13:49     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 13:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:18PM +0100, Christoffer Dall wrote:
> SPSR_EL1 is not used by a VHE host kernel and can be deferred, but we
> need to rework the accesses to this register to access the latest value
> depending on whether or not guest system registers are loaded on the CPU
> or only reside in memory.
> 
> The handling of accessing the various banked SPSRs for 32-bit VMs is a
> bit clunky, but this will be improved in following patches which will
> first prepare and subsequently implement deferred save/restore of the
> 32-bit registers, including the 32-bit SPSRs.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm/include/asm/kvm_emulate.h   | 12 ++++++++++-
>  arch/arm/kvm/emulate.c               |  2 +-
>  arch/arm64/include/asm/kvm_emulate.h | 41 +++++++++++++++++++++++++++++++-----
>  arch/arm64/kvm/inject_fault.c        |  4 ++--
>  virt/kvm/arm/aarch32.c               |  2 +-
>  5 files changed, 51 insertions(+), 10 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 27/40] KVM: arm64: Prepare to handle deferred save/restore of ELR_EL1
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-22 13:51     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 13:51 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:19PM +0100, Christoffer Dall wrote:
> ELR_EL1 is not used by a VHE host kernel and can be deferred, but we
> need to rework the accesses to this register to access the latest value
> depending on whether or not guest system registers are loaded on the CPU
> or only reside in memory.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm64/include/asm/kvm_emulate.h | 18 +++++++++++++++++-
>  arch/arm64/kvm/inject_fault.c        |  4 ++--
>  2 files changed, 19 insertions(+), 3 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 27/40] KVM: arm64: Prepare to handle deferred save/restore of ELR_EL1
@ 2018-02-22 13:51     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 13:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:19PM +0100, Christoffer Dall wrote:
> ELR_EL1 is not used by a VHE host kernel and can be deferred, but we
> need to rework the accesses to this register to access the latest value
> depending on whether or not guest system registers are loaded on the CPU
> or only reside in memory.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm64/include/asm/kvm_emulate.h | 18 +++++++++++++++++-
>  arch/arm64/kvm/inject_fault.c        |  4 ++--
>  2 files changed, 19 insertions(+), 3 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 28/40] KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on VHE
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-22 14:04     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 14:04 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, kvmarm, Yury Norov, linux-arm-kernel,
	Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:20PM +0100, Christoffer Dall wrote:
> Some system registers do not affect the host kernel's execution and can
> therefore be loaded when we are about to run a VCPU and we don't have to
> restore the host state to the hardware before the time when we are
> actually about to return to userspace or schedule out the VCPU thread.
> 
> The EL1 system registers and the userspace state registers only
> affecting EL0 execution do not need to be saved and restored on every
> switch between the VM and the host, because they don't affect the host
> kernel's execution.
> 
> We mark all registers which are now deffered as such in the
> vcpu_{read,write}_sys_reg accessors in sys-regs.c to ensure the most
> up-to-date copy is always accessed.
> 
> Note MPIDR_EL1 (controlled via VMPIDR_EL2) is accessed from other vcpu
> threads, for example via the GIC emulation, and therefore must be
> declared as immediate, which is fine as the guest cannot modify this
> value.
> 
> The 32-bit sysregs can also be deferred but we do this in a separate
> patch as it requires a bit more infrastructure.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Changed to switch-based sysreg approach
> 
>  arch/arm64/kvm/hyp/sysreg-sr.c | 39 +++++++++++++++++++++++++++++++--------
>  arch/arm64/kvm/sys_regs.c      | 40 ++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 71 insertions(+), 8 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 28/40] KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on VHE
@ 2018-02-22 14:04     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 14:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:20PM +0100, Christoffer Dall wrote:
> Some system registers do not affect the host kernel's execution and can
> therefore be loaded when we are about to run a VCPU and we don't have to
> restore the host state to the hardware before the time when we are
> actually about to return to userspace or schedule out the VCPU thread.
> 
> The EL1 system registers and the userspace state registers only
> affecting EL0 execution do not need to be saved and restored on every
> switch between the VM and the host, because they don't affect the host
> kernel's execution.
> 
> We mark all registers which are now deffered as such in the
> vcpu_{read,write}_sys_reg accessors in sys-regs.c to ensure the most
> up-to-date copy is always accessed.
> 
> Note MPIDR_EL1 (controlled via VMPIDR_EL2) is accessed from other vcpu
> threads, for example via the GIC emulation, and therefore must be
> declared as immediate, which is fine as the guest cannot modify this
> value.
> 
> The 32-bit sysregs can also be deferred but we do this in a separate
> patch as it requires a bit more infrastructure.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Changed to switch-based sysreg approach
> 
>  arch/arm64/kvm/hyp/sysreg-sr.c | 39 +++++++++++++++++++++++++++++++--------
>  arch/arm64/kvm/sys_regs.c      | 40 ++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 71 insertions(+), 8 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 29/40] KVM: arm64: Prepare to handle deferred save/restore of 32-bit registers
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-22 14:30     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 14:30 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:21PM +0100, Christoffer Dall wrote:
> 32-bit registers are not used by a 64-bit host kernel and can be
> deferred, but we need to rework the accesses to this register to access

these registers

> the latest value depending on whether or not guest system registers are

values

> loaded on the CPU or only reside in memory.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Don't also try to write hardware spsr when sysregs are not loaded
>      - Adapted patch to use switch-based sysreg save/restore approach
>      - (Kept additional BUG_ON() in vcpu_read_spsr32() to keep the compiler happy)
>     
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm64/include/asm/kvm_emulate.h | 32 +++++------------
>  arch/arm64/kvm/regmap.c              | 67 +++++++++++++++++++++++++++---------
>  arch/arm64/kvm/sys_regs.c            |  6 ++++
>  3 files changed, 65 insertions(+), 40 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 9cb13b23c7a1..23b33e8ea03a 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -33,7 +33,8 @@
>  #include <asm/virt.h>
>  
>  unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num);
> -unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu);
> +unsigned long vcpu_read_spsr32(const struct kvm_vcpu *vcpu);
> +void vcpu_write_spsr32(struct kvm_vcpu *vcpu, unsigned long v);
>  
>  bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
>  void kvm_skip_instr32(struct kvm_vcpu *vcpu, bool is_wide_instr);
> @@ -162,41 +163,26 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
>  
>  static inline unsigned long vcpu_read_spsr(const struct kvm_vcpu *vcpu)
>  {
> -	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> -
> -	if (vcpu_mode_is_32bit(vcpu)) {
> -		unsigned long *p_32bit = vcpu_spsr32(vcpu);
> -
> -		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> -		if (p_32bit != (unsigned long *)p)
> -			return *p_32bit;
> -	}
> +	if (vcpu_mode_is_32bit(vcpu))
> +		return vcpu_read_spsr32(vcpu);
>  
>  	if (vcpu->arch.sysregs_loaded_on_cpu)
>  		return read_sysreg_el1(spsr);
>  	else
> -		return *p;
> +		return vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
>  }
>  
> -static inline void vcpu_write_spsr(const struct kvm_vcpu *vcpu, unsigned long v)
> +static inline void vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long v)
>  {
> -	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> -
> -	/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
>  	if (vcpu_mode_is_32bit(vcpu)) {
> -		unsigned long *p_32bit = vcpu_spsr32(vcpu);
> -
> -		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> -		if (p_32bit != (unsigned long *)p) {
> -			*p_32bit = v;
> -			return;
> -		}
> +		vcpu_write_spsr32(vcpu, v);
> +		return;
>  	}
>  
>  	if (vcpu->arch.sysregs_loaded_on_cpu)
>  		write_sysreg_el1(v, spsr);
>  	else
> -		*p = v;
> +		vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1] = v;
>  }
>  
>  static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
> diff --git a/arch/arm64/kvm/regmap.c b/arch/arm64/kvm/regmap.c
> index bbc6ae32e4af..eefe403a2e63 100644
> --- a/arch/arm64/kvm/regmap.c
> +++ b/arch/arm64/kvm/regmap.c
> @@ -141,28 +141,61 @@ unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num)
>  /*
>   * Return the SPSR for the current mode of the virtual CPU.
>   */
> -unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu)
> +static int vcpu_spsr32_mode(const struct kvm_vcpu *vcpu)
>  {
>  	unsigned long mode = *vcpu_cpsr(vcpu) & COMPAT_PSR_MODE_MASK;
>  	switch (mode) {
> -	case COMPAT_PSR_MODE_SVC:
> -		mode = KVM_SPSR_SVC;
> -		break;
> -	case COMPAT_PSR_MODE_ABT:
> -		mode = KVM_SPSR_ABT;
> -		break;
> -	case COMPAT_PSR_MODE_UND:
> -		mode = KVM_SPSR_UND;
> -		break;
> -	case COMPAT_PSR_MODE_IRQ:
> -		mode = KVM_SPSR_IRQ;
> -		break;
> -	case COMPAT_PSR_MODE_FIQ:
> -		mode = KVM_SPSR_FIQ;
> -		break;
> +	case COMPAT_PSR_MODE_SVC: return KVM_SPSR_SVC;
> +	case COMPAT_PSR_MODE_ABT: return KVM_SPSR_ABT;
> +	case COMPAT_PSR_MODE_UND: return KVM_SPSR_UND;
> +	case COMPAT_PSR_MODE_IRQ: return KVM_SPSR_IRQ;
> +	case COMPAT_PSR_MODE_FIQ: return KVM_SPSR_FIQ;
> +	default: BUG();
> +	}
> +}
> +
> +unsigned long vcpu_read_spsr32(const struct kvm_vcpu *vcpu)
> +{
> +	int spsr_idx = vcpu_spsr32_mode(vcpu);
> +
> +	if (!vcpu->arch.sysregs_loaded_on_cpu)
> +		return vcpu_gp_regs(vcpu)->spsr[spsr_idx];
> +
> +	switch (spsr_idx) {
> +	case KVM_SPSR_SVC:
> +		return read_sysreg_el1(spsr);
> +	case KVM_SPSR_ABT:
> +		return read_sysreg(spsr_abt);
> +	case KVM_SPSR_UND:
> +		return read_sysreg(spsr_und);
> +	case KVM_SPSR_IRQ:
> +		return read_sysreg(spsr_irq);
> +	case KVM_SPSR_FIQ:
> +		return read_sysreg(spsr_fiq);
>  	default:
>  		BUG();
>  	}
> +}
> +
> +void vcpu_write_spsr32(struct kvm_vcpu *vcpu, unsigned long v)
> +{
> +	int spsr_idx = vcpu_spsr32_mode(vcpu);
> +
> +	if (!vcpu->arch.sysregs_loaded_on_cpu) {
> +		vcpu_gp_regs(vcpu)->spsr[spsr_idx] = v;
> +		return;
> +	}
>  
> -	return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[mode];
> +	switch (spsr_idx) {
> +	case KVM_SPSR_SVC:
> +		write_sysreg_el1(v, spsr);
> +	case KVM_SPSR_ABT:
> +		write_sysreg(v, spsr_abt);
> +	case KVM_SPSR_UND:
> +		write_sysreg(v, spsr_und);
> +	case KVM_SPSR_IRQ:
> +		write_sysreg(v, spsr_irq);
> +	case KVM_SPSR_FIQ:
> +		write_sysreg(v, spsr_fiq);
> +	}
>  }
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index f060309337aa..d2324560c9f5 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -107,6 +107,9 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
>  	case AMAIR_EL1:		return read_sysreg_s(amair_EL12);
>  	case CNTKCTL_EL1:	return read_sysreg_s(cntkctl_EL12);
>  	case PAR_EL1:		return read_sysreg_s(SYS_PAR_EL1);
> +	case DACR32_EL2:	return read_sysreg_s(SYS_DACR32_EL2);
> +	case IFSR32_EL2:	return read_sysreg_s(SYS_IFSR32_EL2);
> +	case DBGVCR32_EL2:	return read_sysreg_s(SYS_DBGVCR32_EL2);
>  	}
>  
>  immediate_read:
> @@ -143,6 +146,9 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
>  	case AMAIR_EL1:		write_sysreg_s(val, amair_EL12);	return;
>  	case CNTKCTL_EL1:	write_sysreg_s(val, cntkctl_EL12);	return;
>  	case PAR_EL1:		write_sysreg_s(val, SYS_PAR_EL1);	return;
> +	case DACR32_EL2:	write_sysreg_s(val, SYS_DACR32_EL2);	return;
> +	case IFSR32_EL2:	write_sysreg_s(val, SYS_IFSR32_EL2);	return;
> +	case DBGVCR32_EL2:	write_sysreg_s(val, SYS_DBGVCR32_EL2);	return;
>  	}
>  
>  immediate_write:
> -- 
> 2.14.2
>

I think the last two hunks would fit better in the next patch. It's not a
huge deal, though. If they do get moved, then I guess the patch summary
and commit message should only focus on sprs32 - returning its grammar to
the singular case.

Reviewed-by: Andrew Jones <drjones@redhat.com>

Thanks,
drew

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

* [PATCH v4 29/40] KVM: arm64: Prepare to handle deferred save/restore of 32-bit registers
@ 2018-02-22 14:30     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 14:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:21PM +0100, Christoffer Dall wrote:
> 32-bit registers are not used by a 64-bit host kernel and can be
> deferred, but we need to rework the accesses to this register to access

these registers

> the latest value depending on whether or not guest system registers are

values

> loaded on the CPU or only reside in memory.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Don't also try to write hardware spsr when sysregs are not loaded
>      - Adapted patch to use switch-based sysreg save/restore approach
>      - (Kept additional BUG_ON() in vcpu_read_spsr32() to keep the compiler happy)
>     
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm64/include/asm/kvm_emulate.h | 32 +++++------------
>  arch/arm64/kvm/regmap.c              | 67 +++++++++++++++++++++++++++---------
>  arch/arm64/kvm/sys_regs.c            |  6 ++++
>  3 files changed, 65 insertions(+), 40 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 9cb13b23c7a1..23b33e8ea03a 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -33,7 +33,8 @@
>  #include <asm/virt.h>
>  
>  unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num);
> -unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu);
> +unsigned long vcpu_read_spsr32(const struct kvm_vcpu *vcpu);
> +void vcpu_write_spsr32(struct kvm_vcpu *vcpu, unsigned long v);
>  
>  bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
>  void kvm_skip_instr32(struct kvm_vcpu *vcpu, bool is_wide_instr);
> @@ -162,41 +163,26 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
>  
>  static inline unsigned long vcpu_read_spsr(const struct kvm_vcpu *vcpu)
>  {
> -	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> -
> -	if (vcpu_mode_is_32bit(vcpu)) {
> -		unsigned long *p_32bit = vcpu_spsr32(vcpu);
> -
> -		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> -		if (p_32bit != (unsigned long *)p)
> -			return *p_32bit;
> -	}
> +	if (vcpu_mode_is_32bit(vcpu))
> +		return vcpu_read_spsr32(vcpu);
>  
>  	if (vcpu->arch.sysregs_loaded_on_cpu)
>  		return read_sysreg_el1(spsr);
>  	else
> -		return *p;
> +		return vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
>  }
>  
> -static inline void vcpu_write_spsr(const struct kvm_vcpu *vcpu, unsigned long v)
> +static inline void vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long v)
>  {
> -	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> -
> -	/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
>  	if (vcpu_mode_is_32bit(vcpu)) {
> -		unsigned long *p_32bit = vcpu_spsr32(vcpu);
> -
> -		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> -		if (p_32bit != (unsigned long *)p) {
> -			*p_32bit = v;
> -			return;
> -		}
> +		vcpu_write_spsr32(vcpu, v);
> +		return;
>  	}
>  
>  	if (vcpu->arch.sysregs_loaded_on_cpu)
>  		write_sysreg_el1(v, spsr);
>  	else
> -		*p = v;
> +		vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1] = v;
>  }
>  
>  static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
> diff --git a/arch/arm64/kvm/regmap.c b/arch/arm64/kvm/regmap.c
> index bbc6ae32e4af..eefe403a2e63 100644
> --- a/arch/arm64/kvm/regmap.c
> +++ b/arch/arm64/kvm/regmap.c
> @@ -141,28 +141,61 @@ unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num)
>  /*
>   * Return the SPSR for the current mode of the virtual CPU.
>   */
> -unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu)
> +static int vcpu_spsr32_mode(const struct kvm_vcpu *vcpu)
>  {
>  	unsigned long mode = *vcpu_cpsr(vcpu) & COMPAT_PSR_MODE_MASK;
>  	switch (mode) {
> -	case COMPAT_PSR_MODE_SVC:
> -		mode = KVM_SPSR_SVC;
> -		break;
> -	case COMPAT_PSR_MODE_ABT:
> -		mode = KVM_SPSR_ABT;
> -		break;
> -	case COMPAT_PSR_MODE_UND:
> -		mode = KVM_SPSR_UND;
> -		break;
> -	case COMPAT_PSR_MODE_IRQ:
> -		mode = KVM_SPSR_IRQ;
> -		break;
> -	case COMPAT_PSR_MODE_FIQ:
> -		mode = KVM_SPSR_FIQ;
> -		break;
> +	case COMPAT_PSR_MODE_SVC: return KVM_SPSR_SVC;
> +	case COMPAT_PSR_MODE_ABT: return KVM_SPSR_ABT;
> +	case COMPAT_PSR_MODE_UND: return KVM_SPSR_UND;
> +	case COMPAT_PSR_MODE_IRQ: return KVM_SPSR_IRQ;
> +	case COMPAT_PSR_MODE_FIQ: return KVM_SPSR_FIQ;
> +	default: BUG();
> +	}
> +}
> +
> +unsigned long vcpu_read_spsr32(const struct kvm_vcpu *vcpu)
> +{
> +	int spsr_idx = vcpu_spsr32_mode(vcpu);
> +
> +	if (!vcpu->arch.sysregs_loaded_on_cpu)
> +		return vcpu_gp_regs(vcpu)->spsr[spsr_idx];
> +
> +	switch (spsr_idx) {
> +	case KVM_SPSR_SVC:
> +		return read_sysreg_el1(spsr);
> +	case KVM_SPSR_ABT:
> +		return read_sysreg(spsr_abt);
> +	case KVM_SPSR_UND:
> +		return read_sysreg(spsr_und);
> +	case KVM_SPSR_IRQ:
> +		return read_sysreg(spsr_irq);
> +	case KVM_SPSR_FIQ:
> +		return read_sysreg(spsr_fiq);
>  	default:
>  		BUG();
>  	}
> +}
> +
> +void vcpu_write_spsr32(struct kvm_vcpu *vcpu, unsigned long v)
> +{
> +	int spsr_idx = vcpu_spsr32_mode(vcpu);
> +
> +	if (!vcpu->arch.sysregs_loaded_on_cpu) {
> +		vcpu_gp_regs(vcpu)->spsr[spsr_idx] = v;
> +		return;
> +	}
>  
> -	return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[mode];
> +	switch (spsr_idx) {
> +	case KVM_SPSR_SVC:
> +		write_sysreg_el1(v, spsr);
> +	case KVM_SPSR_ABT:
> +		write_sysreg(v, spsr_abt);
> +	case KVM_SPSR_UND:
> +		write_sysreg(v, spsr_und);
> +	case KVM_SPSR_IRQ:
> +		write_sysreg(v, spsr_irq);
> +	case KVM_SPSR_FIQ:
> +		write_sysreg(v, spsr_fiq);
> +	}
>  }
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index f060309337aa..d2324560c9f5 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -107,6 +107,9 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
>  	case AMAIR_EL1:		return read_sysreg_s(amair_EL12);
>  	case CNTKCTL_EL1:	return read_sysreg_s(cntkctl_EL12);
>  	case PAR_EL1:		return read_sysreg_s(SYS_PAR_EL1);
> +	case DACR32_EL2:	return read_sysreg_s(SYS_DACR32_EL2);
> +	case IFSR32_EL2:	return read_sysreg_s(SYS_IFSR32_EL2);
> +	case DBGVCR32_EL2:	return read_sysreg_s(SYS_DBGVCR32_EL2);
>  	}
>  
>  immediate_read:
> @@ -143,6 +146,9 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
>  	case AMAIR_EL1:		write_sysreg_s(val, amair_EL12);	return;
>  	case CNTKCTL_EL1:	write_sysreg_s(val, cntkctl_EL12);	return;
>  	case PAR_EL1:		write_sysreg_s(val, SYS_PAR_EL1);	return;
> +	case DACR32_EL2:	write_sysreg_s(val, SYS_DACR32_EL2);	return;
> +	case IFSR32_EL2:	write_sysreg_s(val, SYS_IFSR32_EL2);	return;
> +	case DBGVCR32_EL2:	write_sysreg_s(val, SYS_DBGVCR32_EL2);	return;
>  	}
>  
>  immediate_write:
> -- 
> 2.14.2
>

I think the last two hunks would fit better in the next patch. It's not a
huge deal, though. If they do get moved, then I guess the patch summary
and commit message should only focus on sprs32 - returning its grammar to
the singular case.

Reviewed-by: Andrew Jones <drjones@redhat.com>

Thanks,
drew

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

* Re: [PATCH v4 30/40] KVM: arm64: Defer saving/restoring 32-bit sysregs to vcpu load/put
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-22 14:35     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 14:35 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, kvmarm, Yury Norov, linux-arm-kernel,
	Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:22PM +0100, Christoffer Dall wrote:
> When running a 32-bit VM (EL1 in AArch32), the AArch32 system registers
> can be deferred to vcpu load/put on VHE systems because neither
> the host kernel nor host userspace uses these registers.
> 
> Note that we can not defer saving DBGVCR32_EL2 conditionally based
> on the state of the debug dirty flag on VHE, but since we do the
> load/put pretty rarely, this comes out as a win anyway.
> 
> We can also not defer saving FPEXC32_32 because this register only holds
> a guest-valid value for 32-bit guests during the exit path when the
> guest has used FPSIMD registers and restored the register in the early
> assembly handler from taking the EL2 fault, and therefore we have to
> check if fpsimd is enabled for the guest in the exit path and save the
> register then, for both VHE and non-VHE guests.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Rework the FPEXC32 save/restore logic to no longer attempt to
>        save/restore this register lazily.
>     
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm64/kvm/hyp/switch.c    | 17 +++++++++++------
>  arch/arm64/kvm/hyp/sysreg-sr.c | 15 ++++++++++-----
>  2 files changed, 21 insertions(+), 11 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 22e77deb8e2e..909aa3fe9196 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -47,6 +47,15 @@ bool __hyp_text __fpsimd_enabled(void)
>  	return __fpsimd_is_enabled()();
>  }
>  
> +/* Save the 32-bit only FPSIMD system register state */
> +static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
> +{
> +	if (!vcpu_el1_is_32bit(vcpu))
> +		return;
> +
> +	vcpu->arch.ctxt.sys_regs[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
> +}
> +

I realize it's much more convenient to have this function here, but it
feels a bit out of place, being a _save_ function. Its logical place is
an -sr file.

>  static void __hyp_text __activate_traps_vhe(void)
>  {
>  	u64 val;
> @@ -380,11 +389,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  
>  	__vgic_restore_state(vcpu);
>  
> -	/*
> -	 * We must restore the 32-bit state before the sysregs, thanks
> -	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
> -	 */
> -	__sysreg32_restore_state(vcpu);
>  	sysreg_restore_guest_state_vhe(guest_ctxt);
>  	__debug_switch_to_guest(vcpu);
>  
> @@ -398,7 +402,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  	fp_enabled = __fpsimd_enabled();
>  
>  	sysreg_save_guest_state_vhe(guest_ctxt);
> -	__sysreg32_save_state(vcpu);
>  	__vgic_save_state(vcpu);
>  
>  	__deactivate_traps(vcpu);
> @@ -408,6 +411,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  	if (fp_enabled) {
>  		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
>  		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
> +		__fpsimd_save_fpexc32(vcpu);
>  	}
>  
>  	__debug_switch_to_host(vcpu);
> @@ -475,6 +479,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
>  	if (fp_enabled) {
>  		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
>  		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
> +		__fpsimd_save_fpexc32(vcpu);
>  	}
>  
>  	/*
> diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> index 9c60b8062724..aacba4636871 100644
> --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> @@ -196,10 +196,7 @@ void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
>  	sysreg[DACR32_EL2] = read_sysreg(dacr32_el2);
>  	sysreg[IFSR32_EL2] = read_sysreg(ifsr32_el2);
>  
> -	if (__fpsimd_enabled())
> -		sysreg[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
> -
> -	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> +	if (has_vhe() || vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
>  		sysreg[DBGVCR32_EL2] = read_sysreg(dbgvcr32_el2);
>  }
>  
> @@ -221,7 +218,7 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
>  	write_sysreg(sysreg[DACR32_EL2], dacr32_el2);
>  	write_sysreg(sysreg[IFSR32_EL2], ifsr32_el2);
>  
> -	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> +	if (has_vhe() || vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
>  		write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
>  }
>  
> @@ -246,6 +243,13 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
>  
>  	__sysreg_save_user_state(host_ctxt);
>  
> +	/*
> +	 * Load guest EL1 and user state
> +	 *
> +	 * We must restore the 32-bit state before the sysregs, thanks
> +	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
> +	 */
> +	__sysreg32_restore_state(vcpu);
>  	__sysreg_restore_user_state(guest_ctxt);
>  	__sysreg_restore_el1_state(guest_ctxt);
>  
> @@ -273,6 +277,7 @@ void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
>  
>  	__sysreg_save_el1_state(guest_ctxt);
>  	__sysreg_save_user_state(guest_ctxt);
> +	__sysreg32_save_state(vcpu);
>  
>  	/* Restore host user state */
>  	__sysreg_restore_user_state(host_ctxt);
> -- 
> 2.14.2
>

Besides the function location being a bit debatable, it looks good to me

Reviewed-by: Andrew Jones <drjones@redhat.com>

Thanks,
drew

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

* [PATCH v4 30/40] KVM: arm64: Defer saving/restoring 32-bit sysregs to vcpu load/put
@ 2018-02-22 14:35     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 14:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:22PM +0100, Christoffer Dall wrote:
> When running a 32-bit VM (EL1 in AArch32), the AArch32 system registers
> can be deferred to vcpu load/put on VHE systems because neither
> the host kernel nor host userspace uses these registers.
> 
> Note that we can not defer saving DBGVCR32_EL2 conditionally based
> on the state of the debug dirty flag on VHE, but since we do the
> load/put pretty rarely, this comes out as a win anyway.
> 
> We can also not defer saving FPEXC32_32 because this register only holds
> a guest-valid value for 32-bit guests during the exit path when the
> guest has used FPSIMD registers and restored the register in the early
> assembly handler from taking the EL2 fault, and therefore we have to
> check if fpsimd is enabled for the guest in the exit path and save the
> register then, for both VHE and non-VHE guests.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Rework the FPEXC32 save/restore logic to no longer attempt to
>        save/restore this register lazily.
>     
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm64/kvm/hyp/switch.c    | 17 +++++++++++------
>  arch/arm64/kvm/hyp/sysreg-sr.c | 15 ++++++++++-----
>  2 files changed, 21 insertions(+), 11 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 22e77deb8e2e..909aa3fe9196 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -47,6 +47,15 @@ bool __hyp_text __fpsimd_enabled(void)
>  	return __fpsimd_is_enabled()();
>  }
>  
> +/* Save the 32-bit only FPSIMD system register state */
> +static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
> +{
> +	if (!vcpu_el1_is_32bit(vcpu))
> +		return;
> +
> +	vcpu->arch.ctxt.sys_regs[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
> +}
> +

I realize it's much more convenient to have this function here, but it
feels a bit out of place, being a _save_ function. Its logical place is
an -sr file.

>  static void __hyp_text __activate_traps_vhe(void)
>  {
>  	u64 val;
> @@ -380,11 +389,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  
>  	__vgic_restore_state(vcpu);
>  
> -	/*
> -	 * We must restore the 32-bit state before the sysregs, thanks
> -	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
> -	 */
> -	__sysreg32_restore_state(vcpu);
>  	sysreg_restore_guest_state_vhe(guest_ctxt);
>  	__debug_switch_to_guest(vcpu);
>  
> @@ -398,7 +402,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  	fp_enabled = __fpsimd_enabled();
>  
>  	sysreg_save_guest_state_vhe(guest_ctxt);
> -	__sysreg32_save_state(vcpu);
>  	__vgic_save_state(vcpu);
>  
>  	__deactivate_traps(vcpu);
> @@ -408,6 +411,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  	if (fp_enabled) {
>  		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
>  		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
> +		__fpsimd_save_fpexc32(vcpu);
>  	}
>  
>  	__debug_switch_to_host(vcpu);
> @@ -475,6 +479,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
>  	if (fp_enabled) {
>  		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
>  		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
> +		__fpsimd_save_fpexc32(vcpu);
>  	}
>  
>  	/*
> diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> index 9c60b8062724..aacba4636871 100644
> --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> @@ -196,10 +196,7 @@ void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
>  	sysreg[DACR32_EL2] = read_sysreg(dacr32_el2);
>  	sysreg[IFSR32_EL2] = read_sysreg(ifsr32_el2);
>  
> -	if (__fpsimd_enabled())
> -		sysreg[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
> -
> -	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> +	if (has_vhe() || vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
>  		sysreg[DBGVCR32_EL2] = read_sysreg(dbgvcr32_el2);
>  }
>  
> @@ -221,7 +218,7 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
>  	write_sysreg(sysreg[DACR32_EL2], dacr32_el2);
>  	write_sysreg(sysreg[IFSR32_EL2], ifsr32_el2);
>  
> -	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> +	if (has_vhe() || vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
>  		write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
>  }
>  
> @@ -246,6 +243,13 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
>  
>  	__sysreg_save_user_state(host_ctxt);
>  
> +	/*
> +	 * Load guest EL1 and user state
> +	 *
> +	 * We must restore the 32-bit state before the sysregs, thanks
> +	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
> +	 */
> +	__sysreg32_restore_state(vcpu);
>  	__sysreg_restore_user_state(guest_ctxt);
>  	__sysreg_restore_el1_state(guest_ctxt);
>  
> @@ -273,6 +277,7 @@ void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
>  
>  	__sysreg_save_el1_state(guest_ctxt);
>  	__sysreg_save_user_state(guest_ctxt);
> +	__sysreg32_save_state(vcpu);
>  
>  	/* Restore host user state */
>  	__sysreg_restore_user_state(host_ctxt);
> -- 
> 2.14.2
>

Besides the function location being a bit debatable, it looks good to me

Reviewed-by: Andrew Jones <drjones@redhat.com>

Thanks,
drew

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

* Re: [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
  2018-02-22 13:34     ` Andrew Jones
@ 2018-02-22 14:35       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 14:35 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Christoffer Dall, kvm, Marc Zyngier, kvmarm, Yury Norov,
	linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 22, 2018 at 02:34:21PM +0100, Andrew Jones wrote:
> On Thu, Feb 15, 2018 at 10:03:16PM +0100, Christoffer Dall wrote:
> > From: Christoffer Dall <cdall@cs.columbia.edu>
> > 
> > Currently we access the system registers array via the vcpu_sys_reg()
> > macro.  However, we are about to change the behavior to some times
> > modify the register file directly, so let's change this to two
> > primitives:
> > 
> >  * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
> >  * Direct array access macro __vcpu_sys_reg()
> > 
> > The first primitive should be used in places where the code needs to
> > access the currently loaded VCPU's state as observed by the guest.  For
> > example, when trapping on cache related registers, a write to a system
> > register should go directly to the VCPU version of the register.
> > 
> > The second primitive can be used in places where the VCPU is known to
> > never be running (for example userspace access) or for registers which
> > are never context switched (for example all the PMU system registers).
> > 
> > This rewrites all users of vcpu_sys_regs to one of the two primitives
> > above.
> > 
> > No functional change.
> > 
> > Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> > ---
> > 
> > Notes:
> >     Changes since v2:
> >      - New patch (deferred register handling has been reworked)
> > 
> >  arch/arm64/include/asm/kvm_emulate.h | 13 ++++---
> >  arch/arm64/include/asm/kvm_host.h    | 13 ++++++-
> >  arch/arm64/include/asm/kvm_mmu.h     |  2 +-
> >  arch/arm64/kvm/debug.c               | 27 +++++++++-----
> >  arch/arm64/kvm/inject_fault.c        |  8 ++--
> >  arch/arm64/kvm/sys_regs.c            | 71 ++++++++++++++++++------------------
> >  arch/arm64/kvm/sys_regs.h            |  4 +-
> >  arch/arm64/kvm/sys_regs_generic_v8.c |  4 +-
> >  virt/kvm/arm/pmu.c                   | 37 ++++++++++---------
> >  9 files changed, 102 insertions(+), 77 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> > index 3cc535591bdf..d313aaae5c38 100644
> > --- a/arch/arm64/include/asm/kvm_emulate.h
> > +++ b/arch/arm64/include/asm/kvm_emulate.h
> > @@ -290,15 +290,18 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
> >  
> >  static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
> >  {
> > -	return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> > +	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> >  }
> >  
> >  static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
> >  {
> > -	if (vcpu_mode_is_32bit(vcpu))
> > +	if (vcpu_mode_is_32bit(vcpu)) {
> >  		*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
> > -	else
> > -		vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
> > +	} else {
> > +		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
> > +		sctlr |= (1 << 25);
> > +		vcpu_write_sys_reg(vcpu, SCTLR_EL1, sctlr);
> > +	}
> >  }
> >  
> >  static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> > @@ -306,7 +309,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> >  	if (vcpu_mode_is_32bit(vcpu))
> >  		return !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_E_BIT);
> >  
> > -	return !!(vcpu_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> > +	return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> >  }
> >  
> >  static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index f2a6f39aec87..68398bf7882f 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
> >  };
> >  
> >  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> > -#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> > +
> > +/*
> > + * Only use __vcpu_sys_reg if you know you want the memory backed version of a
> > + * register, and not the one most recently accessed by a runnning VCPU.  For
> > + * example, for userpace access or for system registers that are never context
> > + * switched, but only emulated.
> > + */
> > +#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> > +
> > +#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> > +#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> > +
> >  /*
> >   * CP14 and CP15 live in the same array, as they are backed by the
> >   * same system registers.
> > diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> > index 9679067a1574..95f46e73c4dc 100644
> > --- a/arch/arm64/include/asm/kvm_mmu.h
> > +++ b/arch/arm64/include/asm/kvm_mmu.h
> > @@ -249,7 +249,7 @@ struct kvm;
> >  
> >  static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
> >  {
> > -	return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> > +	return (vcpu_read_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> >  }
> >  
> >  static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
> > diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> > index feedb877cff8..db32d10a56a1 100644
> > --- a/arch/arm64/kvm/debug.c
> > +++ b/arch/arm64/kvm/debug.c
> > @@ -46,7 +46,8 @@ static DEFINE_PER_CPU(u32, mdcr_el2);
> >   */
> >  static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
> >  {
> > -	vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1);
> > +	vcpu->arch.guest_debug_preserved.mdscr_el1 =
> > +		vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> >  
> >  	trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
> >  				vcpu->arch.guest_debug_preserved.mdscr_el1);
> > @@ -54,10 +55,11 @@ static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
> >  
> >  static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
> >  {
> > -	vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1;
> > +	vcpu_write_sys_reg(vcpu, MDSCR_EL1,
> > +			   vcpu->arch.guest_debug_preserved.mdscr_el1);
> >  
> >  	trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
> > -				vcpu_sys_reg(vcpu, MDSCR_EL1));
> > +				vcpu_read_sys_reg(vcpu, MDSCR_EL1));
> >  }
> >  
> >  /**
> > @@ -108,6 +110,7 @@ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
> >  void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> >  {
> >  	bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY);
> > +	unsigned long mdscr;
> >  
> >  	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
> >  
> > @@ -152,9 +155,13 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> >  		 */
> >  		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
> >  			*vcpu_cpsr(vcpu) |=  DBG_SPSR_SS;
> > -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_SS;
> > +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> > +			mdscr |= DBG_MDSCR_SS;
> > +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
> >  		} else {
> > -			vcpu_sys_reg(vcpu, MDSCR_EL1) &= ~DBG_MDSCR_SS;
> > +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> > +			mdscr &= ~DBG_MDSCR_SS;
> > +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
> >  		}
> >  
> >  		trace_kvm_arm_set_dreg32("SPSR_EL2", *vcpu_cpsr(vcpu));
> > @@ -170,7 +177,9 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> >  		 */
> >  		if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) {
> >  			/* Enable breakpoints/watchpoints */
> > -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_MDE;
> > +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> > +			mdscr |= DBG_MDSCR_MDE;
> > +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
> >  
> >  			vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state;
> >  			vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
> > @@ -194,12 +203,12 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> >  		vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
> >  
> >  	/* If KDE or MDE are set, perform a full save/restore cycle. */
> > -	if ((vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_KDE) ||
> > -	    (vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_MDE))
> > +	if (vcpu_read_sys_reg(vcpu, MDSCR_EL1) & (DBG_MDSCR_KDE | DBG_MDSCR_MDE))
> >  		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
> >  
> >  	trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2);
> > -	trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_sys_reg(vcpu, MDSCR_EL1));
> > +	trace_kvm_arm_set_dreg32("MDSCR_EL1",
> > +				 vcpu_read_sys_reg(vcpu, MDSCR_EL1));
> >  }
> >  
> >  void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
> > diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> > index 30a3f58cdb7b..e08db2f2dd75 100644
> > --- a/arch/arm64/kvm/inject_fault.c
> > +++ b/arch/arm64/kvm/inject_fault.c
> > @@ -58,7 +58,7 @@ static u64 get_except_vector(struct kvm_vcpu *vcpu, enum exception_type type)
> >  		exc_offset = LOWER_EL_AArch32_VECTOR;
> >  	}
> >  
> > -	return vcpu_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
> > +	return vcpu_read_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
> >  }
> >  
> >  static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
> > @@ -73,7 +73,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
> >  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> >  	*vcpu_spsr(vcpu) = cpsr;
> >  
> > -	vcpu_sys_reg(vcpu, FAR_EL1) = addr;
> > +	vcpu_write_sys_reg(vcpu, FAR_EL1, addr);
> >  
> >  	/*
> >  	 * Build an {i,d}abort, depending on the level and the
> > @@ -94,7 +94,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
> >  	if (!is_iabt)
> >  		esr |= ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT;
> >  
> > -	vcpu_sys_reg(vcpu, ESR_EL1) = esr | ESR_ELx_FSC_EXTABT;
> > +	vcpu_write_sys_reg(vcpu, ESR_EL1, esr | ESR_ELx_FSC_EXTABT);
> >  }
> >  
> >  static void inject_undef64(struct kvm_vcpu *vcpu)
> > @@ -115,7 +115,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
> >  	if (kvm_vcpu_trap_il_is32bit(vcpu))
> >  		esr |= ESR_ELx_IL;
> >  
> > -	vcpu_sys_reg(vcpu, ESR_EL1) = esr;
> > +	vcpu_write_sys_reg(vcpu, ESR_EL1, esr);
> >  }
> >  
> >  /**
> > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> > index b48af790615e..a05d2c01c786 100644
> > --- a/arch/arm64/kvm/sys_regs.c
> > +++ b/arch/arm64/kvm/sys_regs.c
> > @@ -133,14 +133,14 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
> >  	if (!p->is_aarch32 || !p->is_32bit) {
> >  		val = p->regval;
> >  	} else {
> > -		val = vcpu_sys_reg(vcpu, reg);
> > +		val = vcpu_read_sys_reg(vcpu, reg);
> >  		if (r->reg % 2)
> >  			val = (p->regval << 32) | (u64)lower_32_bits(val);
> >  		else
> >  			val = ((u64)upper_32_bits(val) << 32) |
> >  				lower_32_bits(p->regval);
> >  	}
> > -	vcpu_sys_reg(vcpu, reg) = val;
> > +	vcpu_write_sys_reg(vcpu, reg, val);
> >  
> >  	kvm_toggle_cache(vcpu, was_enabled);
> >  	return true;
> > @@ -241,10 +241,10 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
> >  			    const struct sys_reg_desc *r)
> >  {
> >  	if (p->is_write) {
> > -		vcpu_sys_reg(vcpu, r->reg) = p->regval;
> > +		vcpu_write_sys_reg(vcpu, r->reg, p->regval);
> >  		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
> >  	} else {
> > -		p->regval = vcpu_sys_reg(vcpu, r->reg);
> > +		p->regval = vcpu_read_sys_reg(vcpu, r->reg);
> >  	}
> >  
> >  	trace_trap_reg(__func__, r->reg, p->is_write, p->regval);
> > @@ -457,7 +457,8 @@ static void reset_wcr(struct kvm_vcpu *vcpu,
> >  
> >  static void reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> >  {
> > -	vcpu_sys_reg(vcpu, AMAIR_EL1) = read_sysreg(amair_el1);
> > +	u64 amair = read_sysreg(amair_el1);
> > +	vcpu_write_sys_reg(vcpu, AMAIR_EL1, amair);
> >  }
> >  
> >  static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> > @@ -474,7 +475,7 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> >  	mpidr = (vcpu->vcpu_id & 0x0f) << MPIDR_LEVEL_SHIFT(0);
> >  	mpidr |= ((vcpu->vcpu_id >> 4) & 0xff) << MPIDR_LEVEL_SHIFT(1);
> >  	mpidr |= ((vcpu->vcpu_id >> 12) & 0xff) << MPIDR_LEVEL_SHIFT(2);
> > -	vcpu_sys_reg(vcpu, MPIDR_EL1) = (1ULL << 31) | mpidr;
> > +	vcpu_write_sys_reg(vcpu, MPIDR_EL1, (1ULL << 31) | mpidr);
> >  }
> >  
> >  static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> > @@ -488,12 +489,12 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> >  	 */
> >  	val = ((pmcr & ~ARMV8_PMU_PMCR_MASK)
> >  	       | (ARMV8_PMU_PMCR_MASK & 0xdecafbad)) & (~ARMV8_PMU_PMCR_E);
> > -	vcpu_sys_reg(vcpu, PMCR_EL0) = val;
> > +	__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
> >  }
> >  
> >  static bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags)
> >  {
> > -	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> > +	u64 reg = __vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> >  	bool enabled = (reg & flags) || vcpu_mode_priv(vcpu);
> >  
> >  	if (!enabled)
> > @@ -535,14 +536,14 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> >  
> >  	if (p->is_write) {
> >  		/* Only update writeable bits of PMCR */
> > -		val = vcpu_sys_reg(vcpu, PMCR_EL0);
> > +		val = __vcpu_sys_reg(vcpu, PMCR_EL0);
> >  		val &= ~ARMV8_PMU_PMCR_MASK;
> >  		val |= p->regval & ARMV8_PMU_PMCR_MASK;
> > -		vcpu_sys_reg(vcpu, PMCR_EL0) = val;
> > +		__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
> >  		kvm_pmu_handle_pmcr(vcpu, val);
> >  	} else {
> >  		/* PMCR.P & PMCR.C are RAZ */
> > -		val = vcpu_sys_reg(vcpu, PMCR_EL0)
> > +		val = __vcpu_sys_reg(vcpu, PMCR_EL0)
> >  		      & ~(ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C);
> >  		p->regval = val;
> >  	}
> > @@ -560,10 +561,10 @@ static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> >  		return false;
> >  
> >  	if (p->is_write)
> > -		vcpu_sys_reg(vcpu, PMSELR_EL0) = p->regval;
> > +		__vcpu_sys_reg(vcpu, PMSELR_EL0) = p->regval;
> >  	else
> >  		/* return PMSELR.SEL field */
> > -		p->regval = vcpu_sys_reg(vcpu, PMSELR_EL0)
> > +		p->regval = __vcpu_sys_reg(vcpu, PMSELR_EL0)
> >  			    & ARMV8_PMU_COUNTER_MASK;
> >  
> >  	return true;
> > @@ -596,7 +597,7 @@ static bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
> >  {
> >  	u64 pmcr, val;
> >  
> > -	pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
> > +	pmcr = __vcpu_sys_reg(vcpu, PMCR_EL0);
> >  	val = (pmcr >> ARMV8_PMU_PMCR_N_SHIFT) & ARMV8_PMU_PMCR_N_MASK;
> >  	if (idx >= val && idx != ARMV8_PMU_CYCLE_IDX) {
> >  		kvm_inject_undefined(vcpu);
> > @@ -621,7 +622,7 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
> >  			if (pmu_access_event_counter_el0_disabled(vcpu))
> >  				return false;
> >  
> > -			idx = vcpu_sys_reg(vcpu, PMSELR_EL0)
> > +			idx = __vcpu_sys_reg(vcpu, PMSELR_EL0)
> >  			      & ARMV8_PMU_COUNTER_MASK;
> >  		} else if (r->Op2 == 0) {
> >  			/* PMCCNTR_EL0 */
> > @@ -676,7 +677,7 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> >  
> >  	if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 1) {
> >  		/* PMXEVTYPER_EL0 */
> > -		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_PMU_COUNTER_MASK;
> > +		idx = __vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_PMU_COUNTER_MASK;
> >  		reg = PMEVTYPER0_EL0 + idx;
> >  	} else if (r->CRn == 14 && (r->CRm & 12) == 12) {
> >  		idx = ((r->CRm & 3) << 3) | (r->Op2 & 7);
> > @@ -694,9 +695,9 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> >  
> >  	if (p->is_write) {
> >  		kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
> > -		vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_PMU_EVTYPE_MASK;
> > +		__vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_PMU_EVTYPE_MASK;
> >  	} else {
> > -		p->regval = vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK;
> > +		p->regval = __vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK;
> >  	}
> >  
> >  	return true;
> > @@ -718,15 +719,15 @@ static bool access_pmcnten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> >  		val = p->regval & mask;
> >  		if (r->Op2 & 0x1) {
> >  			/* accessing PMCNTENSET_EL0 */
> > -			vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val;
> > +			__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val;
> >  			kvm_pmu_enable_counter(vcpu, val);
> >  		} else {
> >  			/* accessing PMCNTENCLR_EL0 */
> > -			vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val;
> > +			__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val;
> >  			kvm_pmu_disable_counter(vcpu, val);
> >  		}
> >  	} else {
> > -		p->regval = vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask;
> > +		p->regval = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask;
> >  	}
> >  
> >  	return true;
> > @@ -750,12 +751,12 @@ static bool access_pminten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> >  
> >  		if (r->Op2 & 0x1)
> >  			/* accessing PMINTENSET_EL1 */
> > -			vcpu_sys_reg(vcpu, PMINTENSET_EL1) |= val;
> > +			__vcpu_sys_reg(vcpu, PMINTENSET_EL1) |= val;
> >  		else
> >  			/* accessing PMINTENCLR_EL1 */
> > -			vcpu_sys_reg(vcpu, PMINTENSET_EL1) &= ~val;
> > +			__vcpu_sys_reg(vcpu, PMINTENSET_EL1) &= ~val;
> >  	} else {
> > -		p->regval = vcpu_sys_reg(vcpu, PMINTENSET_EL1) & mask;
> > +		p->regval = __vcpu_sys_reg(vcpu, PMINTENSET_EL1) & mask;
> >  	}
> >  
> >  	return true;
> > @@ -775,12 +776,12 @@ static bool access_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> >  	if (p->is_write) {
> >  		if (r->CRm & 0x2)
> >  			/* accessing PMOVSSET_EL0 */
> > -			vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= (p->regval & mask);
> > +			__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= (p->regval & mask);
> >  		else
> >  			/* accessing PMOVSCLR_EL0 */
> > -			vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= ~(p->regval & mask);
> > +			__vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= ~(p->regval & mask);
> >  	} else {
> > -		p->regval = vcpu_sys_reg(vcpu, PMOVSSET_EL0) & mask;
> > +		p->regval = __vcpu_sys_reg(vcpu, PMOVSSET_EL0) & mask;
> >  	}
> >  
> >  	return true;
> > @@ -817,10 +818,10 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> >  			return false;
> >  		}
> >  
> > -		vcpu_sys_reg(vcpu, PMUSERENR_EL0) = p->regval
> > -						    & ARMV8_PMU_USERENR_MASK;
> > -	} else {
> > -		p->regval = vcpu_sys_reg(vcpu, PMUSERENR_EL0)
> > +		__vcpu_sys_reg(vcpu, PMUSERENR_EL0) =
> > +			       p->regval & ARMV8_PMU_USERENR_MASK;
> > +	} else  {
> > +		p->regval = __vcpu_sys_reg(vcpu, PMUSERENR_EL0)
> >  			    & ARMV8_PMU_USERENR_MASK;
> >  	}
> >  
> > @@ -2204,7 +2205,7 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
> >  	if (r->get_user)
> >  		return (r->get_user)(vcpu, r, reg, uaddr);
> >  
> > -	return reg_to_user(uaddr, &vcpu_sys_reg(vcpu, r->reg), reg->id);
> > +	return reg_to_user(uaddr, &__vcpu_sys_reg(vcpu, r->reg), reg->id);
> >  }
> >  
> >  int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > @@ -2225,7 +2226,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
> >  	if (r->set_user)
> >  		return (r->set_user)(vcpu, r, reg, uaddr);
> >  
> > -	return reg_from_user(&vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
> > +	return reg_from_user(&__vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
> >  }
> >  
> >  static unsigned int num_demux_regs(void)
> > @@ -2431,6 +2432,6 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
> >  	reset_sys_reg_descs(vcpu, table, num);
> >  
> >  	for (num = 1; num < NR_SYS_REGS; num++)
> > -		if (vcpu_sys_reg(vcpu, num) == 0x4242424242424242)
> > -			panic("Didn't reset vcpu_sys_reg(%zi)", num);
> > +		if (__vcpu_sys_reg(vcpu, num) == 0x4242424242424242)
> > +			panic("Didn't reset __vcpu_sys_reg(%zi)", num);
> 
> The only direct access to vcpu->arch.ctxt.sys_regs outside a save-restore
> file is in this function, a bit above this hunk. Copied below
> 
>  /* Catch someone adding a register without putting in reset entry. */
>  memset(&vcpu->arch.ctxt.sys_regs, 0x42, sizeof(vcpu->arch.ctxt.sys_regs));
> 
> Maybe we should change it to
> 
>  for (num = 0; num < NR_SYS_REGS; num++)
>      __vcpu_sys_reg(vcpu, num) == 0x4242424242424242;
> 
> just to pedantically use the API?
> 

I wouldn't be opposed to that change, but I don't see it as being
required for this series.  We're already changing enough.

> >  }
> > diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
> > index 060f5348ef25..cd710f8b63e0 100644
> > --- a/arch/arm64/kvm/sys_regs.h
> > +++ b/arch/arm64/kvm/sys_regs.h
> > @@ -89,14 +89,14 @@ static inline void reset_unknown(struct kvm_vcpu *vcpu,
> >  {
> >  	BUG_ON(!r->reg);
> >  	BUG_ON(r->reg >= NR_SYS_REGS);
> > -	vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
> > +	__vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
> >  }
> >  
> >  static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> >  {
> >  	BUG_ON(!r->reg);
> >  	BUG_ON(r->reg >= NR_SYS_REGS);
> > -	vcpu_sys_reg(vcpu, r->reg) = r->val;
> > +	__vcpu_sys_reg(vcpu, r->reg) = r->val;
> >  }
> >  
> >  static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
> > diff --git a/arch/arm64/kvm/sys_regs_generic_v8.c b/arch/arm64/kvm/sys_regs_generic_v8.c
> > index 969ade1d333d..ddb8497d18d6 100644
> > --- a/arch/arm64/kvm/sys_regs_generic_v8.c
> > +++ b/arch/arm64/kvm/sys_regs_generic_v8.c
> > @@ -38,13 +38,13 @@ static bool access_actlr(struct kvm_vcpu *vcpu,
> >  	if (p->is_write)
> >  		return ignore_write(vcpu, p);
> >  
> > -	p->regval = vcpu_sys_reg(vcpu, ACTLR_EL1);
> > +	p->regval = vcpu_read_sys_reg(vcpu, ACTLR_EL1);
> >  	return true;
> >  }
> >  
> >  static void reset_actlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> >  {
> > -	vcpu_sys_reg(vcpu, ACTLR_EL1) = read_sysreg(actlr_el1);
> > +	__vcpu_sys_reg(vcpu, ACTLR_EL1) = read_sysreg(actlr_el1);
> >  }
> >  
> >  /*
> > diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> > index 8a9c42366db7..29cb4a1ff26b 100644
> > --- a/virt/kvm/arm/pmu.c
> > +++ b/virt/kvm/arm/pmu.c
> > @@ -37,7 +37,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
> >  
> >  	reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
> >  	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
> > -	counter = vcpu_sys_reg(vcpu, reg);
> > +	counter = __vcpu_sys_reg(vcpu, reg);
> >  
> >  	/* The real counter value is equal to the value of counter register plus
> >  	 * the value perf event counts.
> > @@ -61,7 +61,8 @@ void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val)
> >  
> >  	reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
> >  	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
> > -	vcpu_sys_reg(vcpu, reg) += (s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);
> > +	__vcpu_sys_reg(vcpu, reg) +=
> > +		(s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);
> >  }
> >  
> >  /**
> > @@ -78,7 +79,7 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
> >  		counter = kvm_pmu_get_counter_value(vcpu, pmc->idx);
> >  		reg = (pmc->idx == ARMV8_PMU_CYCLE_IDX)
> >  		       ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + pmc->idx;
> > -		vcpu_sys_reg(vcpu, reg) = counter;
> > +		__vcpu_sys_reg(vcpu, reg) = counter;
> >  		perf_event_disable(pmc->perf_event);
> >  		perf_event_release_kernel(pmc->perf_event);
> >  		pmc->perf_event = NULL;
> > @@ -125,7 +126,7 @@ void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu)
> >  
> >  u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
> >  {
> > -	u64 val = vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMU_PMCR_N_SHIFT;
> > +	u64 val = __vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMU_PMCR_N_SHIFT;
> >  
> >  	val &= ARMV8_PMU_PMCR_N_MASK;
> >  	if (val == 0)
> > @@ -147,7 +148,7 @@ void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val)
> >  	struct kvm_pmu *pmu = &vcpu->arch.pmu;
> >  	struct kvm_pmc *pmc;
> >  
> > -	if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) || !val)
> > +	if (!(__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) || !val)
> >  		return;
> >  
> >  	for (i = 0; i < ARMV8_PMU_MAX_COUNTERS; i++) {
> > @@ -193,10 +194,10 @@ static u64 kvm_pmu_overflow_status(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 reg = 0;
> >  
> > -	if ((vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E)) {
> > -		reg = vcpu_sys_reg(vcpu, PMOVSSET_EL0);
> > -		reg &= vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> > -		reg &= vcpu_sys_reg(vcpu, PMINTENSET_EL1);
> > +	if ((__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E)) {
> > +		reg = __vcpu_sys_reg(vcpu, PMOVSSET_EL0);
> > +		reg &= __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> > +		reg &= __vcpu_sys_reg(vcpu, PMINTENSET_EL1);
> >  		reg &= kvm_pmu_valid_counter_mask(vcpu);
> >  	}
> >  
> > @@ -295,7 +296,7 @@ static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
> >  	struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
> >  	int idx = pmc->idx;
> >  
> > -	vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(idx);
> > +	__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(idx);
> >  
> >  	if (kvm_pmu_overflow_status(vcpu)) {
> >  		kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
> > @@ -316,19 +317,19 @@ void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
> >  	if (val == 0)
> >  		return;
> >  
> > -	enable = vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> > +	enable = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> >  	for (i = 0; i < ARMV8_PMU_CYCLE_IDX; i++) {
> >  		if (!(val & BIT(i)))
> >  			continue;
> > -		type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
> > +		type = __vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
> >  		       & ARMV8_PMU_EVTYPE_EVENT;
> >  		if ((type == ARMV8_PMUV3_PERFCTR_SW_INCR)
> >  		    && (enable & BIT(i))) {
> > -			reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
> > +			reg = __vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
> >  			reg = lower_32_bits(reg);
> > -			vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
> > +			__vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
> >  			if (!reg)
> > -				vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
> > +				__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
> >  		}
> >  	}
> >  }
> > @@ -348,7 +349,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
> >  	mask = kvm_pmu_valid_counter_mask(vcpu);
> >  	if (val & ARMV8_PMU_PMCR_E) {
> >  		kvm_pmu_enable_counter(vcpu,
> > -				vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask);
> > +		       __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask);
> >  	} else {
> >  		kvm_pmu_disable_counter(vcpu, mask);
> >  	}
> > @@ -369,8 +370,8 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
> >  
> >  static bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu, u64 select_idx)
> >  {
> > -	return (vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) &&
> > -	       (vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
> > +	return (__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) &&
> > +	       (__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
> >  }
> >  
> >  /**
> > -- 
> > 2.14.2
> >
> 
> All the broken lines to honor the 80-char limit induces some sadness,
> but at least people reading the code on their VT100's will be happy.

The patch doesn't stick strictly to 80-chars, but tries to apply some
common sense.  The trace call above could be simplified indeed, but if
there are other changes that cause you particular sadness, I'm happy to
rework.

> 
> Reviewed-by: Andrew Jones <drjones@redhat.com>


Thanks,
-Christoffer

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

* [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
@ 2018-02-22 14:35       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 14:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 22, 2018 at 02:34:21PM +0100, Andrew Jones wrote:
> On Thu, Feb 15, 2018 at 10:03:16PM +0100, Christoffer Dall wrote:
> > From: Christoffer Dall <cdall@cs.columbia.edu>
> > 
> > Currently we access the system registers array via the vcpu_sys_reg()
> > macro.  However, we are about to change the behavior to some times
> > modify the register file directly, so let's change this to two
> > primitives:
> > 
> >  * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
> >  * Direct array access macro __vcpu_sys_reg()
> > 
> > The first primitive should be used in places where the code needs to
> > access the currently loaded VCPU's state as observed by the guest.  For
> > example, when trapping on cache related registers, a write to a system
> > register should go directly to the VCPU version of the register.
> > 
> > The second primitive can be used in places where the VCPU is known to
> > never be running (for example userspace access) or for registers which
> > are never context switched (for example all the PMU system registers).
> > 
> > This rewrites all users of vcpu_sys_regs to one of the two primitives
> > above.
> > 
> > No functional change.
> > 
> > Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> > ---
> > 
> > Notes:
> >     Changes since v2:
> >      - New patch (deferred register handling has been reworked)
> > 
> >  arch/arm64/include/asm/kvm_emulate.h | 13 ++++---
> >  arch/arm64/include/asm/kvm_host.h    | 13 ++++++-
> >  arch/arm64/include/asm/kvm_mmu.h     |  2 +-
> >  arch/arm64/kvm/debug.c               | 27 +++++++++-----
> >  arch/arm64/kvm/inject_fault.c        |  8 ++--
> >  arch/arm64/kvm/sys_regs.c            | 71 ++++++++++++++++++------------------
> >  arch/arm64/kvm/sys_regs.h            |  4 +-
> >  arch/arm64/kvm/sys_regs_generic_v8.c |  4 +-
> >  virt/kvm/arm/pmu.c                   | 37 ++++++++++---------
> >  9 files changed, 102 insertions(+), 77 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> > index 3cc535591bdf..d313aaae5c38 100644
> > --- a/arch/arm64/include/asm/kvm_emulate.h
> > +++ b/arch/arm64/include/asm/kvm_emulate.h
> > @@ -290,15 +290,18 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
> >  
> >  static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
> >  {
> > -	return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> > +	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> >  }
> >  
> >  static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
> >  {
> > -	if (vcpu_mode_is_32bit(vcpu))
> > +	if (vcpu_mode_is_32bit(vcpu)) {
> >  		*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
> > -	else
> > -		vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
> > +	} else {
> > +		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
> > +		sctlr |= (1 << 25);
> > +		vcpu_write_sys_reg(vcpu, SCTLR_EL1, sctlr);
> > +	}
> >  }
> >  
> >  static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> > @@ -306,7 +309,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> >  	if (vcpu_mode_is_32bit(vcpu))
> >  		return !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_E_BIT);
> >  
> > -	return !!(vcpu_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> > +	return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> >  }
> >  
> >  static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index f2a6f39aec87..68398bf7882f 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
> >  };
> >  
> >  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> > -#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> > +
> > +/*
> > + * Only use __vcpu_sys_reg if you know you want the memory backed version of a
> > + * register, and not the one most recently accessed by a runnning VCPU.  For
> > + * example, for userpace access or for system registers that are never context
> > + * switched, but only emulated.
> > + */
> > +#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> > +
> > +#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> > +#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> > +
> >  /*
> >   * CP14 and CP15 live in the same array, as they are backed by the
> >   * same system registers.
> > diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> > index 9679067a1574..95f46e73c4dc 100644
> > --- a/arch/arm64/include/asm/kvm_mmu.h
> > +++ b/arch/arm64/include/asm/kvm_mmu.h
> > @@ -249,7 +249,7 @@ struct kvm;
> >  
> >  static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
> >  {
> > -	return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> > +	return (vcpu_read_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> >  }
> >  
> >  static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
> > diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> > index feedb877cff8..db32d10a56a1 100644
> > --- a/arch/arm64/kvm/debug.c
> > +++ b/arch/arm64/kvm/debug.c
> > @@ -46,7 +46,8 @@ static DEFINE_PER_CPU(u32, mdcr_el2);
> >   */
> >  static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
> >  {
> > -	vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1);
> > +	vcpu->arch.guest_debug_preserved.mdscr_el1 =
> > +		vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> >  
> >  	trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
> >  				vcpu->arch.guest_debug_preserved.mdscr_el1);
> > @@ -54,10 +55,11 @@ static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
> >  
> >  static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
> >  {
> > -	vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1;
> > +	vcpu_write_sys_reg(vcpu, MDSCR_EL1,
> > +			   vcpu->arch.guest_debug_preserved.mdscr_el1);
> >  
> >  	trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
> > -				vcpu_sys_reg(vcpu, MDSCR_EL1));
> > +				vcpu_read_sys_reg(vcpu, MDSCR_EL1));
> >  }
> >  
> >  /**
> > @@ -108,6 +110,7 @@ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
> >  void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> >  {
> >  	bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY);
> > +	unsigned long mdscr;
> >  
> >  	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
> >  
> > @@ -152,9 +155,13 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> >  		 */
> >  		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
> >  			*vcpu_cpsr(vcpu) |=  DBG_SPSR_SS;
> > -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_SS;
> > +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> > +			mdscr |= DBG_MDSCR_SS;
> > +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
> >  		} else {
> > -			vcpu_sys_reg(vcpu, MDSCR_EL1) &= ~DBG_MDSCR_SS;
> > +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> > +			mdscr &= ~DBG_MDSCR_SS;
> > +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
> >  		}
> >  
> >  		trace_kvm_arm_set_dreg32("SPSR_EL2", *vcpu_cpsr(vcpu));
> > @@ -170,7 +177,9 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> >  		 */
> >  		if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) {
> >  			/* Enable breakpoints/watchpoints */
> > -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_MDE;
> > +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> > +			mdscr |= DBG_MDSCR_MDE;
> > +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
> >  
> >  			vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state;
> >  			vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
> > @@ -194,12 +203,12 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
> >  		vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
> >  
> >  	/* If KDE or MDE are set, perform a full save/restore cycle. */
> > -	if ((vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_KDE) ||
> > -	    (vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_MDE))
> > +	if (vcpu_read_sys_reg(vcpu, MDSCR_EL1) & (DBG_MDSCR_KDE | DBG_MDSCR_MDE))
> >  		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
> >  
> >  	trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2);
> > -	trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_sys_reg(vcpu, MDSCR_EL1));
> > +	trace_kvm_arm_set_dreg32("MDSCR_EL1",
> > +				 vcpu_read_sys_reg(vcpu, MDSCR_EL1));
> >  }
> >  
> >  void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
> > diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> > index 30a3f58cdb7b..e08db2f2dd75 100644
> > --- a/arch/arm64/kvm/inject_fault.c
> > +++ b/arch/arm64/kvm/inject_fault.c
> > @@ -58,7 +58,7 @@ static u64 get_except_vector(struct kvm_vcpu *vcpu, enum exception_type type)
> >  		exc_offset = LOWER_EL_AArch32_VECTOR;
> >  	}
> >  
> > -	return vcpu_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
> > +	return vcpu_read_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
> >  }
> >  
> >  static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
> > @@ -73,7 +73,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
> >  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
> >  	*vcpu_spsr(vcpu) = cpsr;
> >  
> > -	vcpu_sys_reg(vcpu, FAR_EL1) = addr;
> > +	vcpu_write_sys_reg(vcpu, FAR_EL1, addr);
> >  
> >  	/*
> >  	 * Build an {i,d}abort, depending on the level and the
> > @@ -94,7 +94,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
> >  	if (!is_iabt)
> >  		esr |= ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT;
> >  
> > -	vcpu_sys_reg(vcpu, ESR_EL1) = esr | ESR_ELx_FSC_EXTABT;
> > +	vcpu_write_sys_reg(vcpu, ESR_EL1, esr | ESR_ELx_FSC_EXTABT);
> >  }
> >  
> >  static void inject_undef64(struct kvm_vcpu *vcpu)
> > @@ -115,7 +115,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
> >  	if (kvm_vcpu_trap_il_is32bit(vcpu))
> >  		esr |= ESR_ELx_IL;
> >  
> > -	vcpu_sys_reg(vcpu, ESR_EL1) = esr;
> > +	vcpu_write_sys_reg(vcpu, ESR_EL1, esr);
> >  }
> >  
> >  /**
> > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> > index b48af790615e..a05d2c01c786 100644
> > --- a/arch/arm64/kvm/sys_regs.c
> > +++ b/arch/arm64/kvm/sys_regs.c
> > @@ -133,14 +133,14 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
> >  	if (!p->is_aarch32 || !p->is_32bit) {
> >  		val = p->regval;
> >  	} else {
> > -		val = vcpu_sys_reg(vcpu, reg);
> > +		val = vcpu_read_sys_reg(vcpu, reg);
> >  		if (r->reg % 2)
> >  			val = (p->regval << 32) | (u64)lower_32_bits(val);
> >  		else
> >  			val = ((u64)upper_32_bits(val) << 32) |
> >  				lower_32_bits(p->regval);
> >  	}
> > -	vcpu_sys_reg(vcpu, reg) = val;
> > +	vcpu_write_sys_reg(vcpu, reg, val);
> >  
> >  	kvm_toggle_cache(vcpu, was_enabled);
> >  	return true;
> > @@ -241,10 +241,10 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
> >  			    const struct sys_reg_desc *r)
> >  {
> >  	if (p->is_write) {
> > -		vcpu_sys_reg(vcpu, r->reg) = p->regval;
> > +		vcpu_write_sys_reg(vcpu, r->reg, p->regval);
> >  		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
> >  	} else {
> > -		p->regval = vcpu_sys_reg(vcpu, r->reg);
> > +		p->regval = vcpu_read_sys_reg(vcpu, r->reg);
> >  	}
> >  
> >  	trace_trap_reg(__func__, r->reg, p->is_write, p->regval);
> > @@ -457,7 +457,8 @@ static void reset_wcr(struct kvm_vcpu *vcpu,
> >  
> >  static void reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> >  {
> > -	vcpu_sys_reg(vcpu, AMAIR_EL1) = read_sysreg(amair_el1);
> > +	u64 amair = read_sysreg(amair_el1);
> > +	vcpu_write_sys_reg(vcpu, AMAIR_EL1, amair);
> >  }
> >  
> >  static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> > @@ -474,7 +475,7 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> >  	mpidr = (vcpu->vcpu_id & 0x0f) << MPIDR_LEVEL_SHIFT(0);
> >  	mpidr |= ((vcpu->vcpu_id >> 4) & 0xff) << MPIDR_LEVEL_SHIFT(1);
> >  	mpidr |= ((vcpu->vcpu_id >> 12) & 0xff) << MPIDR_LEVEL_SHIFT(2);
> > -	vcpu_sys_reg(vcpu, MPIDR_EL1) = (1ULL << 31) | mpidr;
> > +	vcpu_write_sys_reg(vcpu, MPIDR_EL1, (1ULL << 31) | mpidr);
> >  }
> >  
> >  static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> > @@ -488,12 +489,12 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> >  	 */
> >  	val = ((pmcr & ~ARMV8_PMU_PMCR_MASK)
> >  	       | (ARMV8_PMU_PMCR_MASK & 0xdecafbad)) & (~ARMV8_PMU_PMCR_E);
> > -	vcpu_sys_reg(vcpu, PMCR_EL0) = val;
> > +	__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
> >  }
> >  
> >  static bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags)
> >  {
> > -	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> > +	u64 reg = __vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> >  	bool enabled = (reg & flags) || vcpu_mode_priv(vcpu);
> >  
> >  	if (!enabled)
> > @@ -535,14 +536,14 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> >  
> >  	if (p->is_write) {
> >  		/* Only update writeable bits of PMCR */
> > -		val = vcpu_sys_reg(vcpu, PMCR_EL0);
> > +		val = __vcpu_sys_reg(vcpu, PMCR_EL0);
> >  		val &= ~ARMV8_PMU_PMCR_MASK;
> >  		val |= p->regval & ARMV8_PMU_PMCR_MASK;
> > -		vcpu_sys_reg(vcpu, PMCR_EL0) = val;
> > +		__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
> >  		kvm_pmu_handle_pmcr(vcpu, val);
> >  	} else {
> >  		/* PMCR.P & PMCR.C are RAZ */
> > -		val = vcpu_sys_reg(vcpu, PMCR_EL0)
> > +		val = __vcpu_sys_reg(vcpu, PMCR_EL0)
> >  		      & ~(ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C);
> >  		p->regval = val;
> >  	}
> > @@ -560,10 +561,10 @@ static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> >  		return false;
> >  
> >  	if (p->is_write)
> > -		vcpu_sys_reg(vcpu, PMSELR_EL0) = p->regval;
> > +		__vcpu_sys_reg(vcpu, PMSELR_EL0) = p->regval;
> >  	else
> >  		/* return PMSELR.SEL field */
> > -		p->regval = vcpu_sys_reg(vcpu, PMSELR_EL0)
> > +		p->regval = __vcpu_sys_reg(vcpu, PMSELR_EL0)
> >  			    & ARMV8_PMU_COUNTER_MASK;
> >  
> >  	return true;
> > @@ -596,7 +597,7 @@ static bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
> >  {
> >  	u64 pmcr, val;
> >  
> > -	pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
> > +	pmcr = __vcpu_sys_reg(vcpu, PMCR_EL0);
> >  	val = (pmcr >> ARMV8_PMU_PMCR_N_SHIFT) & ARMV8_PMU_PMCR_N_MASK;
> >  	if (idx >= val && idx != ARMV8_PMU_CYCLE_IDX) {
> >  		kvm_inject_undefined(vcpu);
> > @@ -621,7 +622,7 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
> >  			if (pmu_access_event_counter_el0_disabled(vcpu))
> >  				return false;
> >  
> > -			idx = vcpu_sys_reg(vcpu, PMSELR_EL0)
> > +			idx = __vcpu_sys_reg(vcpu, PMSELR_EL0)
> >  			      & ARMV8_PMU_COUNTER_MASK;
> >  		} else if (r->Op2 == 0) {
> >  			/* PMCCNTR_EL0 */
> > @@ -676,7 +677,7 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> >  
> >  	if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 1) {
> >  		/* PMXEVTYPER_EL0 */
> > -		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_PMU_COUNTER_MASK;
> > +		idx = __vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_PMU_COUNTER_MASK;
> >  		reg = PMEVTYPER0_EL0 + idx;
> >  	} else if (r->CRn == 14 && (r->CRm & 12) == 12) {
> >  		idx = ((r->CRm & 3) << 3) | (r->Op2 & 7);
> > @@ -694,9 +695,9 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> >  
> >  	if (p->is_write) {
> >  		kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
> > -		vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_PMU_EVTYPE_MASK;
> > +		__vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_PMU_EVTYPE_MASK;
> >  	} else {
> > -		p->regval = vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK;
> > +		p->regval = __vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK;
> >  	}
> >  
> >  	return true;
> > @@ -718,15 +719,15 @@ static bool access_pmcnten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> >  		val = p->regval & mask;
> >  		if (r->Op2 & 0x1) {
> >  			/* accessing PMCNTENSET_EL0 */
> > -			vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val;
> > +			__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val;
> >  			kvm_pmu_enable_counter(vcpu, val);
> >  		} else {
> >  			/* accessing PMCNTENCLR_EL0 */
> > -			vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val;
> > +			__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val;
> >  			kvm_pmu_disable_counter(vcpu, val);
> >  		}
> >  	} else {
> > -		p->regval = vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask;
> > +		p->regval = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask;
> >  	}
> >  
> >  	return true;
> > @@ -750,12 +751,12 @@ static bool access_pminten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> >  
> >  		if (r->Op2 & 0x1)
> >  			/* accessing PMINTENSET_EL1 */
> > -			vcpu_sys_reg(vcpu, PMINTENSET_EL1) |= val;
> > +			__vcpu_sys_reg(vcpu, PMINTENSET_EL1) |= val;
> >  		else
> >  			/* accessing PMINTENCLR_EL1 */
> > -			vcpu_sys_reg(vcpu, PMINTENSET_EL1) &= ~val;
> > +			__vcpu_sys_reg(vcpu, PMINTENSET_EL1) &= ~val;
> >  	} else {
> > -		p->regval = vcpu_sys_reg(vcpu, PMINTENSET_EL1) & mask;
> > +		p->regval = __vcpu_sys_reg(vcpu, PMINTENSET_EL1) & mask;
> >  	}
> >  
> >  	return true;
> > @@ -775,12 +776,12 @@ static bool access_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> >  	if (p->is_write) {
> >  		if (r->CRm & 0x2)
> >  			/* accessing PMOVSSET_EL0 */
> > -			vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= (p->regval & mask);
> > +			__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= (p->regval & mask);
> >  		else
> >  			/* accessing PMOVSCLR_EL0 */
> > -			vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= ~(p->regval & mask);
> > +			__vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= ~(p->regval & mask);
> >  	} else {
> > -		p->regval = vcpu_sys_reg(vcpu, PMOVSSET_EL0) & mask;
> > +		p->regval = __vcpu_sys_reg(vcpu, PMOVSSET_EL0) & mask;
> >  	}
> >  
> >  	return true;
> > @@ -817,10 +818,10 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> >  			return false;
> >  		}
> >  
> > -		vcpu_sys_reg(vcpu, PMUSERENR_EL0) = p->regval
> > -						    & ARMV8_PMU_USERENR_MASK;
> > -	} else {
> > -		p->regval = vcpu_sys_reg(vcpu, PMUSERENR_EL0)
> > +		__vcpu_sys_reg(vcpu, PMUSERENR_EL0) =
> > +			       p->regval & ARMV8_PMU_USERENR_MASK;
> > +	} else  {
> > +		p->regval = __vcpu_sys_reg(vcpu, PMUSERENR_EL0)
> >  			    & ARMV8_PMU_USERENR_MASK;
> >  	}
> >  
> > @@ -2204,7 +2205,7 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
> >  	if (r->get_user)
> >  		return (r->get_user)(vcpu, r, reg, uaddr);
> >  
> > -	return reg_to_user(uaddr, &vcpu_sys_reg(vcpu, r->reg), reg->id);
> > +	return reg_to_user(uaddr, &__vcpu_sys_reg(vcpu, r->reg), reg->id);
> >  }
> >  
> >  int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > @@ -2225,7 +2226,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
> >  	if (r->set_user)
> >  		return (r->set_user)(vcpu, r, reg, uaddr);
> >  
> > -	return reg_from_user(&vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
> > +	return reg_from_user(&__vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
> >  }
> >  
> >  static unsigned int num_demux_regs(void)
> > @@ -2431,6 +2432,6 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
> >  	reset_sys_reg_descs(vcpu, table, num);
> >  
> >  	for (num = 1; num < NR_SYS_REGS; num++)
> > -		if (vcpu_sys_reg(vcpu, num) == 0x4242424242424242)
> > -			panic("Didn't reset vcpu_sys_reg(%zi)", num);
> > +		if (__vcpu_sys_reg(vcpu, num) == 0x4242424242424242)
> > +			panic("Didn't reset __vcpu_sys_reg(%zi)", num);
> 
> The only direct access to vcpu->arch.ctxt.sys_regs outside a save-restore
> file is in this function, a bit above this hunk. Copied below
> 
>  /* Catch someone adding a register without putting in reset entry. */
>  memset(&vcpu->arch.ctxt.sys_regs, 0x42, sizeof(vcpu->arch.ctxt.sys_regs));
> 
> Maybe we should change it to
> 
>  for (num = 0; num < NR_SYS_REGS; num++)
>      __vcpu_sys_reg(vcpu, num) == 0x4242424242424242;
> 
> just to pedantically use the API?
> 

I wouldn't be opposed to that change, but I don't see it as being
required for this series.  We're already changing enough.

> >  }
> > diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
> > index 060f5348ef25..cd710f8b63e0 100644
> > --- a/arch/arm64/kvm/sys_regs.h
> > +++ b/arch/arm64/kvm/sys_regs.h
> > @@ -89,14 +89,14 @@ static inline void reset_unknown(struct kvm_vcpu *vcpu,
> >  {
> >  	BUG_ON(!r->reg);
> >  	BUG_ON(r->reg >= NR_SYS_REGS);
> > -	vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
> > +	__vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
> >  }
> >  
> >  static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> >  {
> >  	BUG_ON(!r->reg);
> >  	BUG_ON(r->reg >= NR_SYS_REGS);
> > -	vcpu_sys_reg(vcpu, r->reg) = r->val;
> > +	__vcpu_sys_reg(vcpu, r->reg) = r->val;
> >  }
> >  
> >  static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
> > diff --git a/arch/arm64/kvm/sys_regs_generic_v8.c b/arch/arm64/kvm/sys_regs_generic_v8.c
> > index 969ade1d333d..ddb8497d18d6 100644
> > --- a/arch/arm64/kvm/sys_regs_generic_v8.c
> > +++ b/arch/arm64/kvm/sys_regs_generic_v8.c
> > @@ -38,13 +38,13 @@ static bool access_actlr(struct kvm_vcpu *vcpu,
> >  	if (p->is_write)
> >  		return ignore_write(vcpu, p);
> >  
> > -	p->regval = vcpu_sys_reg(vcpu, ACTLR_EL1);
> > +	p->regval = vcpu_read_sys_reg(vcpu, ACTLR_EL1);
> >  	return true;
> >  }
> >  
> >  static void reset_actlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> >  {
> > -	vcpu_sys_reg(vcpu, ACTLR_EL1) = read_sysreg(actlr_el1);
> > +	__vcpu_sys_reg(vcpu, ACTLR_EL1) = read_sysreg(actlr_el1);
> >  }
> >  
> >  /*
> > diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> > index 8a9c42366db7..29cb4a1ff26b 100644
> > --- a/virt/kvm/arm/pmu.c
> > +++ b/virt/kvm/arm/pmu.c
> > @@ -37,7 +37,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
> >  
> >  	reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
> >  	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
> > -	counter = vcpu_sys_reg(vcpu, reg);
> > +	counter = __vcpu_sys_reg(vcpu, reg);
> >  
> >  	/* The real counter value is equal to the value of counter register plus
> >  	 * the value perf event counts.
> > @@ -61,7 +61,8 @@ void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val)
> >  
> >  	reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
> >  	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
> > -	vcpu_sys_reg(vcpu, reg) += (s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);
> > +	__vcpu_sys_reg(vcpu, reg) +=
> > +		(s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);
> >  }
> >  
> >  /**
> > @@ -78,7 +79,7 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
> >  		counter = kvm_pmu_get_counter_value(vcpu, pmc->idx);
> >  		reg = (pmc->idx == ARMV8_PMU_CYCLE_IDX)
> >  		       ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + pmc->idx;
> > -		vcpu_sys_reg(vcpu, reg) = counter;
> > +		__vcpu_sys_reg(vcpu, reg) = counter;
> >  		perf_event_disable(pmc->perf_event);
> >  		perf_event_release_kernel(pmc->perf_event);
> >  		pmc->perf_event = NULL;
> > @@ -125,7 +126,7 @@ void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu)
> >  
> >  u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
> >  {
> > -	u64 val = vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMU_PMCR_N_SHIFT;
> > +	u64 val = __vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMU_PMCR_N_SHIFT;
> >  
> >  	val &= ARMV8_PMU_PMCR_N_MASK;
> >  	if (val == 0)
> > @@ -147,7 +148,7 @@ void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val)
> >  	struct kvm_pmu *pmu = &vcpu->arch.pmu;
> >  	struct kvm_pmc *pmc;
> >  
> > -	if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) || !val)
> > +	if (!(__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) || !val)
> >  		return;
> >  
> >  	for (i = 0; i < ARMV8_PMU_MAX_COUNTERS; i++) {
> > @@ -193,10 +194,10 @@ static u64 kvm_pmu_overflow_status(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 reg = 0;
> >  
> > -	if ((vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E)) {
> > -		reg = vcpu_sys_reg(vcpu, PMOVSSET_EL0);
> > -		reg &= vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> > -		reg &= vcpu_sys_reg(vcpu, PMINTENSET_EL1);
> > +	if ((__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E)) {
> > +		reg = __vcpu_sys_reg(vcpu, PMOVSSET_EL0);
> > +		reg &= __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> > +		reg &= __vcpu_sys_reg(vcpu, PMINTENSET_EL1);
> >  		reg &= kvm_pmu_valid_counter_mask(vcpu);
> >  	}
> >  
> > @@ -295,7 +296,7 @@ static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
> >  	struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
> >  	int idx = pmc->idx;
> >  
> > -	vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(idx);
> > +	__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(idx);
> >  
> >  	if (kvm_pmu_overflow_status(vcpu)) {
> >  		kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
> > @@ -316,19 +317,19 @@ void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
> >  	if (val == 0)
> >  		return;
> >  
> > -	enable = vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> > +	enable = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> >  	for (i = 0; i < ARMV8_PMU_CYCLE_IDX; i++) {
> >  		if (!(val & BIT(i)))
> >  			continue;
> > -		type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
> > +		type = __vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
> >  		       & ARMV8_PMU_EVTYPE_EVENT;
> >  		if ((type == ARMV8_PMUV3_PERFCTR_SW_INCR)
> >  		    && (enable & BIT(i))) {
> > -			reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
> > +			reg = __vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
> >  			reg = lower_32_bits(reg);
> > -			vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
> > +			__vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
> >  			if (!reg)
> > -				vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
> > +				__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
> >  		}
> >  	}
> >  }
> > @@ -348,7 +349,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
> >  	mask = kvm_pmu_valid_counter_mask(vcpu);
> >  	if (val & ARMV8_PMU_PMCR_E) {
> >  		kvm_pmu_enable_counter(vcpu,
> > -				vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask);
> > +		       __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask);
> >  	} else {
> >  		kvm_pmu_disable_counter(vcpu, mask);
> >  	}
> > @@ -369,8 +370,8 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
> >  
> >  static bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu, u64 select_idx)
> >  {
> > -	return (vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) &&
> > -	       (vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
> > +	return (__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) &&
> > +	       (__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
> >  }
> >  
> >  /**
> > -- 
> > 2.14.2
> >
> 
> All the broken lines to honor the 80-char limit induces some sadness,
> but at least people reading the code on their VT100's will be happy.

The patch doesn't stick strictly to 80-chars, but tries to apply some
common sense.  The trace call above could be simplified indeed, but if
there are other changes that cause you particular sadness, I'm happy to
rework.

> 
> Reviewed-by: Andrew Jones <drjones@redhat.com>


Thanks,
-Christoffer

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

* Re: [PATCH v4 37/40] KVM: arm/arm64: Move arm64-only vgic-v2-sr.c file to arm64
  2018-02-22 12:33     ` Marc Zyngier
@ 2018-02-22 14:37       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 14:37 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm, kvmarm, Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 22, 2018 at 12:33:20PM +0000, Marc Zyngier wrote:
> On 15/02/18 21:03, Christoffer Dall wrote:
> > The vgic-v2-sr.c file now only contains the logic to replay unaligned
> > accesses to the virtual CPU interface on 16K and 64K page systems, which
> > is only relevant on 64-bit platforms.  Therefore move this file to the
> > arm64 KVM tree, remove the compile directive from the 32-bit side
> > makefile, and remove the ifdef in the C file.
> > 
> > Reviewed-by: Andre Przywara <andre.przywara@arm.com>
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> >  arch/arm/kvm/hyp/Makefile                         | 1 -
> >  arch/arm64/kvm/hyp/Makefile                       | 2 +-
> >  {virt/kvm/arm => arch/arm64/kvm}/hyp/vgic-v2-sr.c | 2 --
> >  3 files changed, 1 insertion(+), 4 deletions(-)
> >  rename {virt/kvm/arm => arch/arm64/kvm}/hyp/vgic-v2-sr.c (98%)
> > 
> > diff --git a/arch/arm/kvm/hyp/Makefile b/arch/arm/kvm/hyp/Makefile
> > index 5638ce0c9524..1964111c984a 100644
> > --- a/arch/arm/kvm/hyp/Makefile
> > +++ b/arch/arm/kvm/hyp/Makefile
> > @@ -7,7 +7,6 @@ ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
> >  
> >  KVM=../../../../virt/kvm
> >  
> > -obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o
> >  obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v3-sr.o
> >  obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/timer-sr.o
> >  
> > diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
> > index f04400d494b7..7e8d41210288 100644
> > --- a/arch/arm64/kvm/hyp/Makefile
> > +++ b/arch/arm64/kvm/hyp/Makefile
> > @@ -7,10 +7,10 @@ ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
> >  
> >  KVM=../../../../virt/kvm
> >  
> > -obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o
> >  obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v3-sr.o
> >  obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/timer-sr.o
> >  
> > +obj-$(CONFIG_KVM_ARM_HOST) += vgic-v2-sr.o
> 
> How about renaming the file to vgic-v2-cpuif-proxy.c? It doesn't have
> anything to do with save/restore anymore...
> 

Yes, good idea.

> >  obj-$(CONFIG_KVM_ARM_HOST) += sysreg-sr.o
> >  obj-$(CONFIG_KVM_ARM_HOST) += debug-sr.o
> >  obj-$(CONFIG_KVM_ARM_HOST) += entry.o
> > diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/arch/arm64/kvm/hyp/vgic-v2-sr.c
> > similarity index 98%
> > rename from virt/kvm/arm/hyp/vgic-v2-sr.c
> > rename to arch/arm64/kvm/hyp/vgic-v2-sr.c
> > index 0bbafdfd4adb..97f357ea9c72 100644
> > --- a/virt/kvm/arm/hyp/vgic-v2-sr.c
> > +++ b/arch/arm64/kvm/hyp/vgic-v2-sr.c
> > @@ -23,7 +23,6 @@
> >  #include <asm/kvm_hyp.h>
> >  #include <asm/kvm_mmu.h>
> >  
> > -#ifdef CONFIG_ARM64
> >  /*
> >   * __vgic_v2_perform_cpuif_access -- perform a GICV access on behalf of the
> >   *				     guest.
> > @@ -77,4 +76,3 @@ int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
> >  
> >  	return 1;
> >  }
> > -#endif
> > 
> 
> Otherwise looks good.
> 
Thanks,
-Christoffer

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

* [PATCH v4 37/40] KVM: arm/arm64: Move arm64-only vgic-v2-sr.c file to arm64
@ 2018-02-22 14:37       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 14:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 22, 2018 at 12:33:20PM +0000, Marc Zyngier wrote:
> On 15/02/18 21:03, Christoffer Dall wrote:
> > The vgic-v2-sr.c file now only contains the logic to replay unaligned
> > accesses to the virtual CPU interface on 16K and 64K page systems, which
> > is only relevant on 64-bit platforms.  Therefore move this file to the
> > arm64 KVM tree, remove the compile directive from the 32-bit side
> > makefile, and remove the ifdef in the C file.
> > 
> > Reviewed-by: Andre Przywara <andre.przywara@arm.com>
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> >  arch/arm/kvm/hyp/Makefile                         | 1 -
> >  arch/arm64/kvm/hyp/Makefile                       | 2 +-
> >  {virt/kvm/arm => arch/arm64/kvm}/hyp/vgic-v2-sr.c | 2 --
> >  3 files changed, 1 insertion(+), 4 deletions(-)
> >  rename {virt/kvm/arm => arch/arm64/kvm}/hyp/vgic-v2-sr.c (98%)
> > 
> > diff --git a/arch/arm/kvm/hyp/Makefile b/arch/arm/kvm/hyp/Makefile
> > index 5638ce0c9524..1964111c984a 100644
> > --- a/arch/arm/kvm/hyp/Makefile
> > +++ b/arch/arm/kvm/hyp/Makefile
> > @@ -7,7 +7,6 @@ ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
> >  
> >  KVM=../../../../virt/kvm
> >  
> > -obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o
> >  obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v3-sr.o
> >  obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/timer-sr.o
> >  
> > diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
> > index f04400d494b7..7e8d41210288 100644
> > --- a/arch/arm64/kvm/hyp/Makefile
> > +++ b/arch/arm64/kvm/hyp/Makefile
> > @@ -7,10 +7,10 @@ ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
> >  
> >  KVM=../../../../virt/kvm
> >  
> > -obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o
> >  obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v3-sr.o
> >  obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/timer-sr.o
> >  
> > +obj-$(CONFIG_KVM_ARM_HOST) += vgic-v2-sr.o
> 
> How about renaming the file to vgic-v2-cpuif-proxy.c? It doesn't have
> anything to do with save/restore anymore...
> 

Yes, good idea.

> >  obj-$(CONFIG_KVM_ARM_HOST) += sysreg-sr.o
> >  obj-$(CONFIG_KVM_ARM_HOST) += debug-sr.o
> >  obj-$(CONFIG_KVM_ARM_HOST) += entry.o
> > diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/arch/arm64/kvm/hyp/vgic-v2-sr.c
> > similarity index 98%
> > rename from virt/kvm/arm/hyp/vgic-v2-sr.c
> > rename to arch/arm64/kvm/hyp/vgic-v2-sr.c
> > index 0bbafdfd4adb..97f357ea9c72 100644
> > --- a/virt/kvm/arm/hyp/vgic-v2-sr.c
> > +++ b/arch/arm64/kvm/hyp/vgic-v2-sr.c
> > @@ -23,7 +23,6 @@
> >  #include <asm/kvm_hyp.h>
> >  #include <asm/kvm_mmu.h>
> >  
> > -#ifdef CONFIG_ARM64
> >  /*
> >   * __vgic_v2_perform_cpuif_access -- perform a GICV access on behalf of the
> >   *				     guest.
> > @@ -77,4 +76,3 @@ int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
> >  
> >  	return 1;
> >  }
> > -#endif
> > 
> 
> Otherwise looks good.
> 
Thanks,
-Christoffer

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

* Re: [PATCH v4 38/40] KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on VHE
  2018-02-22 12:32     ` Marc Zyngier
@ 2018-02-22 14:42       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 14:42 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 22, 2018 at 12:32:11PM +0000, Marc Zyngier wrote:
> On 15/02/18 21:03, Christoffer Dall wrote:
> > Just like we can program the GICv2 hypervisor control interface directly
> > from the core vgic code, we can do the same for the GICv3 hypervisor
> > control interface on VHE systems.
> > 
> > We do this by simply calling the save/restore functions when we have VHE
> > and we can then get rid of the save/restore function calls from the VHE
> > world switch function.
> > 
> > One caveat is that we now write GICv3 system register state before the
> > potential early exit path in the run loop, and because we sync back
> > state in the early exit path, we have to ensure that we read a
> > consistent GIC state from the sync path, even though we have never
> > actually run the guest with the newly written GIC state.  We solve this
> > by inserting an ISB in the early exit path.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v2:
> >      - Added ISB in the early exit path in the run loop as explained
> >        in the commit message.
> > 
> >  arch/arm64/kvm/hyp/switch.c | 3 ---
> >  virt/kvm/arm/arm.c          | 1 +
> >  virt/kvm/arm/vgic/vgic.c    | 5 +++++
> >  3 files changed, 6 insertions(+), 3 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index cbafc27a617b..466cfcdbcaf3 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c
> > @@ -399,8 +399,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> >  	__activate_traps(vcpu);
> >  	__activate_vm(vcpu->kvm);
> >  
> > -	__vgic_restore_state(vcpu);
> > -
> >  	sysreg_restore_guest_state_vhe(guest_ctxt);
> >  	__debug_switch_to_guest(vcpu);
> >  
> > @@ -414,7 +412,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> >  	fp_enabled = fpsimd_enabled_vhe();
> >  
> >  	sysreg_save_guest_state_vhe(guest_ctxt);
> > -	__vgic_save_state(vcpu);
> >  
> >  	__deactivate_traps(vcpu);
> >  
> > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > index 5bd879c78951..6de7641f3ff2 100644
> > --- a/virt/kvm/arm/arm.c
> > +++ b/virt/kvm/arm/arm.c
> > @@ -717,6 +717,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> >  		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
> >  		    kvm_request_pending(vcpu)) {
> >  			vcpu->mode = OUTSIDE_GUEST_MODE;
> > +			isb(); /* Ensure work in x_flush_hwstate is committed */
> >  			kvm_pmu_sync_hwstate(vcpu);
> >  			if (static_branch_unlikely(&userspace_irqchip_in_use))
> >  				kvm_timer_sync_hwstate(vcpu);
> > diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> > index 12e2a28f437e..d0a19a8c196a 100644
> > --- a/virt/kvm/arm/vgic/vgic.c
> > +++ b/virt/kvm/arm/vgic/vgic.c
> > @@ -19,6 +19,7 @@
> >  #include <linux/list_sort.h>
> >  #include <linux/interrupt.h>
> >  #include <linux/irq.h>
> > +#include <asm/kvm_hyp.h>
> >  
> >  #include "vgic.h"
> >  
> > @@ -753,6 +754,8 @@ static inline void vgic_save_state(struct kvm_vcpu *vcpu)
> >  {
> >  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> >  		vgic_v2_save_state(vcpu);
> > +	else if (has_vhe())
> > +		__vgic_v3_save_state(vcpu);
> >  }
> >  
> >  /* Sync back the hardware VGIC state into our emulation after a guest's run. */
> > @@ -777,6 +780,8 @@ static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
> >  {
> >  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> >  		vgic_v2_restore_state(vcpu);
> > +	else if (has_vhe())
> > +		__vgic_v3_restore_state(vcpu);
> >  }
> >  
> >  /* Flush our emulation state into the GIC hardware before entering the guest. */
> > 
> 
> I'm slowly wrapping my brain around this thing again. If I grasp the
> general idea, we end up with two cases:
> 
> (1) The GIC is accessible from the kernel, and we save/restore it
> outside of the HYP code.
> 
> (2) The GIC is only accessible from the HYP code, and we do it there.
> 
> Maybe we should bite the bullet and introduce that primitive instead?
> 

You mean something the following?

static inline bool can_access_vgic_from_kernel(void)
{
	/*
	 * GICv2 can always be accessed from the kernel because it is
	 * memory-mapped, and VHE systems can access GICv3 EL2 system
	 * registers.
	 */
	return !static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) || has_vhe();
}

Thanks,
-Christoffer

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

* [PATCH v4 38/40] KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on VHE
@ 2018-02-22 14:42       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 14:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 22, 2018 at 12:32:11PM +0000, Marc Zyngier wrote:
> On 15/02/18 21:03, Christoffer Dall wrote:
> > Just like we can program the GICv2 hypervisor control interface directly
> > from the core vgic code, we can do the same for the GICv3 hypervisor
> > control interface on VHE systems.
> > 
> > We do this by simply calling the save/restore functions when we have VHE
> > and we can then get rid of the save/restore function calls from the VHE
> > world switch function.
> > 
> > One caveat is that we now write GICv3 system register state before the
> > potential early exit path in the run loop, and because we sync back
> > state in the early exit path, we have to ensure that we read a
> > consistent GIC state from the sync path, even though we have never
> > actually run the guest with the newly written GIC state.  We solve this
> > by inserting an ISB in the early exit path.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v2:
> >      - Added ISB in the early exit path in the run loop as explained
> >        in the commit message.
> > 
> >  arch/arm64/kvm/hyp/switch.c | 3 ---
> >  virt/kvm/arm/arm.c          | 1 +
> >  virt/kvm/arm/vgic/vgic.c    | 5 +++++
> >  3 files changed, 6 insertions(+), 3 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index cbafc27a617b..466cfcdbcaf3 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c
> > @@ -399,8 +399,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> >  	__activate_traps(vcpu);
> >  	__activate_vm(vcpu->kvm);
> >  
> > -	__vgic_restore_state(vcpu);
> > -
> >  	sysreg_restore_guest_state_vhe(guest_ctxt);
> >  	__debug_switch_to_guest(vcpu);
> >  
> > @@ -414,7 +412,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> >  	fp_enabled = fpsimd_enabled_vhe();
> >  
> >  	sysreg_save_guest_state_vhe(guest_ctxt);
> > -	__vgic_save_state(vcpu);
> >  
> >  	__deactivate_traps(vcpu);
> >  
> > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > index 5bd879c78951..6de7641f3ff2 100644
> > --- a/virt/kvm/arm/arm.c
> > +++ b/virt/kvm/arm/arm.c
> > @@ -717,6 +717,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> >  		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
> >  		    kvm_request_pending(vcpu)) {
> >  			vcpu->mode = OUTSIDE_GUEST_MODE;
> > +			isb(); /* Ensure work in x_flush_hwstate is committed */
> >  			kvm_pmu_sync_hwstate(vcpu);
> >  			if (static_branch_unlikely(&userspace_irqchip_in_use))
> >  				kvm_timer_sync_hwstate(vcpu);
> > diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> > index 12e2a28f437e..d0a19a8c196a 100644
> > --- a/virt/kvm/arm/vgic/vgic.c
> > +++ b/virt/kvm/arm/vgic/vgic.c
> > @@ -19,6 +19,7 @@
> >  #include <linux/list_sort.h>
> >  #include <linux/interrupt.h>
> >  #include <linux/irq.h>
> > +#include <asm/kvm_hyp.h>
> >  
> >  #include "vgic.h"
> >  
> > @@ -753,6 +754,8 @@ static inline void vgic_save_state(struct kvm_vcpu *vcpu)
> >  {
> >  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> >  		vgic_v2_save_state(vcpu);
> > +	else if (has_vhe())
> > +		__vgic_v3_save_state(vcpu);
> >  }
> >  
> >  /* Sync back the hardware VGIC state into our emulation after a guest's run. */
> > @@ -777,6 +780,8 @@ static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
> >  {
> >  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> >  		vgic_v2_restore_state(vcpu);
> > +	else if (has_vhe())
> > +		__vgic_v3_restore_state(vcpu);
> >  }
> >  
> >  /* Flush our emulation state into the GIC hardware before entering the guest. */
> > 
> 
> I'm slowly wrapping my brain around this thing again. If I grasp the
> general idea, we end up with two cases:
> 
> (1) The GIC is accessible from the kernel, and we save/restore it
> outside of the HYP code.
> 
> (2) The GIC is only accessible from the HYP code, and we do it there.
> 
> Maybe we should bite the bullet and introduce that primitive instead?
> 

You mean something the following?

static inline bool can_access_vgic_from_kernel(void)
{
	/*
	 * GICv2 can always be accessed from the kernel because it is
	 * memory-mapped, and VHE systems can access GICv3 EL2 system
	 * registers.
	 */
	return !static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) || has_vhe();
}

Thanks,
-Christoffer

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

* Re: [PATCH v4 39/40] KVM: arm/arm64: Move VGIC APR save/restore to vgic put/load
  2018-02-22 13:11     ` Marc Zyngier
@ 2018-02-22 14:44       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 14:44 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 22, 2018 at 01:11:55PM +0000, Marc Zyngier wrote:
> On 15/02/18 21:03, Christoffer Dall wrote:
> > The APRs can only have bits set when the guest acknowledges an interrupt
> > in the LR and can only have a bit cleared when the guest EOIs an
> > interrupt in the LR.  Therefore, if we have no LRs with any
> > pending/active interrupts, the APR cannot change value and there is no
> > need to clear it on every exit from the VM (hint: it will have already
> > been cleared when we exited the guest the last time with the LRs all
> > EOIed).
> > 
> > The only case we need to take care of is when we migrate the VCPU away
> > from a CPU or migrate a new VCPU onto a CPU, or when we return to
> > userspace to capture the state of the VCPU for migration.  To make sure
> > this works, factor out the APR save/restore functionality into separate
> > functions called from the VCPU (and by extension VGIC) put/load hooks.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> >  arch/arm/include/asm/kvm_hyp.h   |   2 +
> >  arch/arm64/include/asm/kvm_hyp.h |   2 +
> >  virt/kvm/arm/hyp/vgic-v3-sr.c    | 124 +++++++++++++++++++++------------------
> >  virt/kvm/arm/vgic/vgic-v2.c      |   7 +--
> >  virt/kvm/arm/vgic/vgic-v3.c      |   5 ++
> >  5 files changed, 78 insertions(+), 62 deletions(-)
> > 
> > diff --git a/arch/arm/include/asm/kvm_hyp.h b/arch/arm/include/asm/kvm_hyp.h
> > index 1ab8329e9ff7..530a3c1cfe6f 100644
> > --- a/arch/arm/include/asm/kvm_hyp.h
> > +++ b/arch/arm/include/asm/kvm_hyp.h
> > @@ -110,6 +110,8 @@ void __sysreg_restore_state(struct kvm_cpu_context *ctxt);
> >  
> >  void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
> >  void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
> > +void __vgic_v3_save_aprs(struct kvm_vcpu *vcpu);
> > +void __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu);
> >  
> >  asmlinkage void __vfp_save_state(struct vfp_hard_struct *vfp);
> >  asmlinkage void __vfp_restore_state(struct vfp_hard_struct *vfp);
> > diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
> > index febe417b8b4e..6f3929b2fcf7 100644
> > --- a/arch/arm64/include/asm/kvm_hyp.h
> > +++ b/arch/arm64/include/asm/kvm_hyp.h
> > @@ -124,6 +124,8 @@ int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
> >  
> >  void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
> >  void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
> > +void __vgic_v3_save_aprs(struct kvm_vcpu *vcpu);
> > +void __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu);
> >  int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
> >  
> >  void __timer_enable_traps(struct kvm_vcpu *vcpu);
> > diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> > index 9abf2f3c12b5..437d7af08683 100644
> > --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> > +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> > @@ -21,6 +21,7 @@
> >  
> >  #include <asm/kvm_emulate.h>
> >  #include <asm/kvm_hyp.h>
> > +#include <asm/kvm_mmu.h>
> >  
> >  #define vtr_to_max_lr_idx(v)		((v) & 0xf)
> >  #define vtr_to_nr_pre_bits(v)		((((u32)(v) >> 26) & 7) + 1)
> > @@ -221,14 +222,11 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
> >  
> >  	if (used_lrs) {
> >  		int i;
> > -		u32 nr_pre_bits;
> >  		u32 elrsr;
> >  
> >  		elrsr = read_gicreg(ICH_ELSR_EL2);
> >  
> >  		write_gicreg(0, ICH_HCR_EL2);
> > -		val = read_gicreg(ICH_VTR_EL2);
> > -		nr_pre_bits = vtr_to_nr_pre_bits(val);
> >  
> >  		for (i = 0; i < used_lrs; i++) {
> >  			if (elrsr & (1 << i))
> > @@ -238,39 +236,10 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
> >  
> >  			__gic_v3_set_lr(0, i);
> >  		}
> > -
> > -		switch (nr_pre_bits) {
> > -		case 7:
> > -			cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3);
> > -			cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2);
> > -		case 6:
> > -			cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1);
> > -		default:
> > -			cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0);
> > -		}
> > -
> > -		switch (nr_pre_bits) {
> > -		case 7:
> > -			cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3);
> > -			cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2);
> > -		case 6:
> > -			cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1);
> > -		default:
> > -			cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
> > -		}
> >  	} else {
> >  		if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
> >  		    cpu_if->its_vpe.its_vm)
> >  			write_gicreg(0, ICH_HCR_EL2);
> > -
> > -		cpu_if->vgic_ap0r[0] = 0;
> > -		cpu_if->vgic_ap0r[1] = 0;
> > -		cpu_if->vgic_ap0r[2] = 0;
> > -		cpu_if->vgic_ap0r[3] = 0;
> > -		cpu_if->vgic_ap1r[0] = 0;
> > -		cpu_if->vgic_ap1r[1] = 0;
> > -		cpu_if->vgic_ap1r[2] = 0;
> > -		cpu_if->vgic_ap1r[3] = 0;
> >  	}
> >  
> >  	val = read_gicreg(ICC_SRE_EL2);
> > @@ -287,8 +256,6 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
> >  {
> >  	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
> >  	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
> > -	u64 val;
> > -	u32 nr_pre_bits;
> >  	int i;
> >  
> >  	/*
> > @@ -306,32 +273,9 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
> >  		write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
> >  	}
> >  
> > -	val = read_gicreg(ICH_VTR_EL2);
> > -	nr_pre_bits = vtr_to_nr_pre_bits(val);
> > -
> >  	if (used_lrs) {
> >  		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
> >  
> > -		switch (nr_pre_bits) {
> > -		case 7:
> > -			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3);
> > -			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2);
> > -		case 6:
> > -			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1);
> > -		default:
> > -			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0);
> > -		}
> > -
> > -		switch (nr_pre_bits) {
> > -		case 7:
> > -			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3);
> > -			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2);
> > -		case 6:
> > -			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1);
> > -		default:
> > -			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0);
> > -		}
> > -
> >  		for (i = 0; i < used_lrs; i++)
> >  			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
> >  	} else {
> > @@ -364,6 +308,72 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
> >  		     ICC_SRE_EL2);
> >  }
> >  
> > +void __hyp_text __vgic_v3_save_aprs(struct kvm_vcpu *vcpu)
> > +{
> > +	struct vgic_v3_cpu_if *cpu_if;
> > +	u64 val;
> > +	u32 nr_pre_bits;
> > +
> > +	vcpu = kern_hyp_va(vcpu);
> > +	cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
> > +
> > +	val = read_gicreg(ICH_VTR_EL2);
> > +	nr_pre_bits = vtr_to_nr_pre_bits(val);
> > +
> > +	switch (nr_pre_bits) {
> > +	case 7:
> > +		cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3);
> > +		cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2);
> > +	case 6:
> > +		cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1);
> > +	default:
> > +		cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0);
> > +	}
> > +
> > +	switch (nr_pre_bits) {
> > +	case 7:
> > +		cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3);
> > +		cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2);
> > +	case 6:
> > +		cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1);
> > +	default:
> > +		cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
> > +	}
> > +}
> > +
> > +void __hyp_text __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu)
> > +{
> > +	struct vgic_v3_cpu_if *cpu_if;
> > +	u64 val;
> > +	u32 nr_pre_bits;
> > +
> > +	vcpu = kern_hyp_va(vcpu);
> > +	cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
> > +
> > +	val = read_gicreg(ICH_VTR_EL2);
> > +	nr_pre_bits = vtr_to_nr_pre_bits(val);
> > +
> > +	switch (nr_pre_bits) {
> > +	case 7:
> > +		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3);
> > +		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2);
> > +	case 6:
> > +		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1);
> > +	default:
> > +		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0);
> > +	}
> > +
> > +	switch (nr_pre_bits) {
> > +	case 7:
> > +		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3);
> > +		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2);
> > +	case 6:
> > +		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1);
> > +	default:
> > +		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0);
> > +	}
> > +}
> > +
> >  void __hyp_text __vgic_v3_init_lrs(void)
> >  {
> >  	int max_lr_idx = vtr_to_max_lr_idx(read_gicreg(ICH_VTR_EL2));
> > diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> > index 1e5f3eb6973d..ca7cfee9f353 100644
> > --- a/virt/kvm/arm/vgic/vgic-v2.c
> > +++ b/virt/kvm/arm/vgic/vgic-v2.c
> > @@ -446,7 +446,6 @@ void vgic_v2_save_state(struct kvm_vcpu *vcpu)
> >  {
> >  	struct kvm *kvm = vcpu->kvm;
> >  	struct vgic_dist *vgic = &kvm->arch.vgic;
> > -	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
> >  	void __iomem *base = vgic->vctrl_base;
> >  	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
> >  
> > @@ -454,11 +453,8 @@ void vgic_v2_save_state(struct kvm_vcpu *vcpu)
> >  		return;
> >  
> >  	if (used_lrs) {
> > -		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
> >  		save_lrs(vcpu, base);
> >  		writel_relaxed(0, base + GICH_HCR);
> > -	} else {
> > -		cpu_if->vgic_apr = 0;
> >  	}
> >  }
> >  
> > @@ -476,7 +472,6 @@ void vgic_v2_restore_state(struct kvm_vcpu *vcpu)
> >  
> >  	if (used_lrs) {
> >  		writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
> > -		writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
> >  		for (i = 0; i < used_lrs; i++) {
> >  			writel_relaxed(cpu_if->vgic_lr[i],
> >  				       base + GICH_LR0 + (i * 4));
> > @@ -490,6 +485,7 @@ void vgic_v2_load(struct kvm_vcpu *vcpu)
> >  	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
> >  
> >  	writel_relaxed(cpu_if->vgic_vmcr, vgic->vctrl_base + GICH_VMCR);
> > +	writel_relaxed(cpu_if->vgic_apr, vgic->vctrl_base + GICH_APR);
> >  }
> >  
> >  void vgic_v2_put(struct kvm_vcpu *vcpu)
> > @@ -498,4 +494,5 @@ void vgic_v2_put(struct kvm_vcpu *vcpu)
> >  	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
> >  
> >  	cpu_if->vgic_vmcr = readl_relaxed(vgic->vctrl_base + GICH_VMCR);
> > +	cpu_if->vgic_apr = readl_relaxed(vgic->vctrl_base + GICH_APR);
> >  }
> > diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> > index b76e21f3e6bd..4bafcd1e6bb8 100644
> > --- a/virt/kvm/arm/vgic/vgic-v3.c
> > +++ b/virt/kvm/arm/vgic/vgic-v3.c
> > @@ -16,6 +16,7 @@
> >  #include <linux/kvm.h>
> >  #include <linux/kvm_host.h>
> >  #include <kvm/arm_vgic.h>
> > +#include <asm/kvm_hyp.h>
> >  #include <asm/kvm_mmu.h>
> >  #include <asm/kvm_asm.h>
> >  
> > @@ -587,6 +588,8 @@ void vgic_v3_load(struct kvm_vcpu *vcpu)
> >  	 */
> >  	if (likely(cpu_if->vgic_sre))
> >  		kvm_call_hyp(__vgic_v3_write_vmcr, cpu_if->vgic_vmcr);
> > +
> > +	kvm_call_hyp(__vgic_v3_restore_aprs, vcpu);
> >  }
> >  
> >  void vgic_v3_put(struct kvm_vcpu *vcpu)
> > @@ -595,4 +598,6 @@ void vgic_v3_put(struct kvm_vcpu *vcpu)
> >  
> >  	if (likely(cpu_if->vgic_sre))
> >  		cpu_if->vgic_vmcr = kvm_call_hyp(__vgic_v3_read_vmcr);
> > +
> > +	kvm_call_hyp(__vgic_v3_save_aprs, vcpu);
> >  }
> > 
> 
> An unfortunate consequence of the save/restore de-aggregation process in
> this series is that we end-up doing quite a few EL2 calls in the !VHE
> case. We should probably think of consolidating those behind a single
> EL2 call if they have a measurable impact.

We could, but the trap to EL2 (without saving all GP regs beyond the
normal calling convention) is really cheap, so I don't think it *is*
that bad, but it *feels* bad.  Also, few of these are in the criticial
path, right?

I'll admit that I haven't measured non-VHE GICv3 impact of this series
(only non-VHE GICv2 which saw a small improvement).

> 
> In the meantime:
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> 

Thanks,
-Christoffer

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

* [PATCH v4 39/40] KVM: arm/arm64: Move VGIC APR save/restore to vgic put/load
@ 2018-02-22 14:44       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 14:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 22, 2018 at 01:11:55PM +0000, Marc Zyngier wrote:
> On 15/02/18 21:03, Christoffer Dall wrote:
> > The APRs can only have bits set when the guest acknowledges an interrupt
> > in the LR and can only have a bit cleared when the guest EOIs an
> > interrupt in the LR.  Therefore, if we have no LRs with any
> > pending/active interrupts, the APR cannot change value and there is no
> > need to clear it on every exit from the VM (hint: it will have already
> > been cleared when we exited the guest the last time with the LRs all
> > EOIed).
> > 
> > The only case we need to take care of is when we migrate the VCPU away
> > from a CPU or migrate a new VCPU onto a CPU, or when we return to
> > userspace to capture the state of the VCPU for migration.  To make sure
> > this works, factor out the APR save/restore functionality into separate
> > functions called from the VCPU (and by extension VGIC) put/load hooks.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> >  arch/arm/include/asm/kvm_hyp.h   |   2 +
> >  arch/arm64/include/asm/kvm_hyp.h |   2 +
> >  virt/kvm/arm/hyp/vgic-v3-sr.c    | 124 +++++++++++++++++++++------------------
> >  virt/kvm/arm/vgic/vgic-v2.c      |   7 +--
> >  virt/kvm/arm/vgic/vgic-v3.c      |   5 ++
> >  5 files changed, 78 insertions(+), 62 deletions(-)
> > 
> > diff --git a/arch/arm/include/asm/kvm_hyp.h b/arch/arm/include/asm/kvm_hyp.h
> > index 1ab8329e9ff7..530a3c1cfe6f 100644
> > --- a/arch/arm/include/asm/kvm_hyp.h
> > +++ b/arch/arm/include/asm/kvm_hyp.h
> > @@ -110,6 +110,8 @@ void __sysreg_restore_state(struct kvm_cpu_context *ctxt);
> >  
> >  void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
> >  void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
> > +void __vgic_v3_save_aprs(struct kvm_vcpu *vcpu);
> > +void __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu);
> >  
> >  asmlinkage void __vfp_save_state(struct vfp_hard_struct *vfp);
> >  asmlinkage void __vfp_restore_state(struct vfp_hard_struct *vfp);
> > diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
> > index febe417b8b4e..6f3929b2fcf7 100644
> > --- a/arch/arm64/include/asm/kvm_hyp.h
> > +++ b/arch/arm64/include/asm/kvm_hyp.h
> > @@ -124,6 +124,8 @@ int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
> >  
> >  void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
> >  void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
> > +void __vgic_v3_save_aprs(struct kvm_vcpu *vcpu);
> > +void __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu);
> >  int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
> >  
> >  void __timer_enable_traps(struct kvm_vcpu *vcpu);
> > diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> > index 9abf2f3c12b5..437d7af08683 100644
> > --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> > +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> > @@ -21,6 +21,7 @@
> >  
> >  #include <asm/kvm_emulate.h>
> >  #include <asm/kvm_hyp.h>
> > +#include <asm/kvm_mmu.h>
> >  
> >  #define vtr_to_max_lr_idx(v)		((v) & 0xf)
> >  #define vtr_to_nr_pre_bits(v)		((((u32)(v) >> 26) & 7) + 1)
> > @@ -221,14 +222,11 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
> >  
> >  	if (used_lrs) {
> >  		int i;
> > -		u32 nr_pre_bits;
> >  		u32 elrsr;
> >  
> >  		elrsr = read_gicreg(ICH_ELSR_EL2);
> >  
> >  		write_gicreg(0, ICH_HCR_EL2);
> > -		val = read_gicreg(ICH_VTR_EL2);
> > -		nr_pre_bits = vtr_to_nr_pre_bits(val);
> >  
> >  		for (i = 0; i < used_lrs; i++) {
> >  			if (elrsr & (1 << i))
> > @@ -238,39 +236,10 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
> >  
> >  			__gic_v3_set_lr(0, i);
> >  		}
> > -
> > -		switch (nr_pre_bits) {
> > -		case 7:
> > -			cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3);
> > -			cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2);
> > -		case 6:
> > -			cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1);
> > -		default:
> > -			cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0);
> > -		}
> > -
> > -		switch (nr_pre_bits) {
> > -		case 7:
> > -			cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3);
> > -			cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2);
> > -		case 6:
> > -			cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1);
> > -		default:
> > -			cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
> > -		}
> >  	} else {
> >  		if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
> >  		    cpu_if->its_vpe.its_vm)
> >  			write_gicreg(0, ICH_HCR_EL2);
> > -
> > -		cpu_if->vgic_ap0r[0] = 0;
> > -		cpu_if->vgic_ap0r[1] = 0;
> > -		cpu_if->vgic_ap0r[2] = 0;
> > -		cpu_if->vgic_ap0r[3] = 0;
> > -		cpu_if->vgic_ap1r[0] = 0;
> > -		cpu_if->vgic_ap1r[1] = 0;
> > -		cpu_if->vgic_ap1r[2] = 0;
> > -		cpu_if->vgic_ap1r[3] = 0;
> >  	}
> >  
> >  	val = read_gicreg(ICC_SRE_EL2);
> > @@ -287,8 +256,6 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
> >  {
> >  	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
> >  	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
> > -	u64 val;
> > -	u32 nr_pre_bits;
> >  	int i;
> >  
> >  	/*
> > @@ -306,32 +273,9 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
> >  		write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
> >  	}
> >  
> > -	val = read_gicreg(ICH_VTR_EL2);
> > -	nr_pre_bits = vtr_to_nr_pre_bits(val);
> > -
> >  	if (used_lrs) {
> >  		write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
> >  
> > -		switch (nr_pre_bits) {
> > -		case 7:
> > -			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3);
> > -			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2);
> > -		case 6:
> > -			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1);
> > -		default:
> > -			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0);
> > -		}
> > -
> > -		switch (nr_pre_bits) {
> > -		case 7:
> > -			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3);
> > -			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2);
> > -		case 6:
> > -			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1);
> > -		default:
> > -			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0);
> > -		}
> > -
> >  		for (i = 0; i < used_lrs; i++)
> >  			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
> >  	} else {
> > @@ -364,6 +308,72 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
> >  		     ICC_SRE_EL2);
> >  }
> >  
> > +void __hyp_text __vgic_v3_save_aprs(struct kvm_vcpu *vcpu)
> > +{
> > +	struct vgic_v3_cpu_if *cpu_if;
> > +	u64 val;
> > +	u32 nr_pre_bits;
> > +
> > +	vcpu = kern_hyp_va(vcpu);
> > +	cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
> > +
> > +	val = read_gicreg(ICH_VTR_EL2);
> > +	nr_pre_bits = vtr_to_nr_pre_bits(val);
> > +
> > +	switch (nr_pre_bits) {
> > +	case 7:
> > +		cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3);
> > +		cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2);
> > +	case 6:
> > +		cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1);
> > +	default:
> > +		cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0);
> > +	}
> > +
> > +	switch (nr_pre_bits) {
> > +	case 7:
> > +		cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3);
> > +		cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2);
> > +	case 6:
> > +		cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1);
> > +	default:
> > +		cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
> > +	}
> > +}
> > +
> > +void __hyp_text __vgic_v3_restore_aprs(struct kvm_vcpu *vcpu)
> > +{
> > +	struct vgic_v3_cpu_if *cpu_if;
> > +	u64 val;
> > +	u32 nr_pre_bits;
> > +
> > +	vcpu = kern_hyp_va(vcpu);
> > +	cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
> > +
> > +	val = read_gicreg(ICH_VTR_EL2);
> > +	nr_pre_bits = vtr_to_nr_pre_bits(val);
> > +
> > +	switch (nr_pre_bits) {
> > +	case 7:
> > +		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3);
> > +		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2);
> > +	case 6:
> > +		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1);
> > +	default:
> > +		__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0);
> > +	}
> > +
> > +	switch (nr_pre_bits) {
> > +	case 7:
> > +		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3);
> > +		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2);
> > +	case 6:
> > +		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1);
> > +	default:
> > +		__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0);
> > +	}
> > +}
> > +
> >  void __hyp_text __vgic_v3_init_lrs(void)
> >  {
> >  	int max_lr_idx = vtr_to_max_lr_idx(read_gicreg(ICH_VTR_EL2));
> > diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> > index 1e5f3eb6973d..ca7cfee9f353 100644
> > --- a/virt/kvm/arm/vgic/vgic-v2.c
> > +++ b/virt/kvm/arm/vgic/vgic-v2.c
> > @@ -446,7 +446,6 @@ void vgic_v2_save_state(struct kvm_vcpu *vcpu)
> >  {
> >  	struct kvm *kvm = vcpu->kvm;
> >  	struct vgic_dist *vgic = &kvm->arch.vgic;
> > -	struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
> >  	void __iomem *base = vgic->vctrl_base;
> >  	u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
> >  
> > @@ -454,11 +453,8 @@ void vgic_v2_save_state(struct kvm_vcpu *vcpu)
> >  		return;
> >  
> >  	if (used_lrs) {
> > -		cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
> >  		save_lrs(vcpu, base);
> >  		writel_relaxed(0, base + GICH_HCR);
> > -	} else {
> > -		cpu_if->vgic_apr = 0;
> >  	}
> >  }
> >  
> > @@ -476,7 +472,6 @@ void vgic_v2_restore_state(struct kvm_vcpu *vcpu)
> >  
> >  	if (used_lrs) {
> >  		writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
> > -		writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
> >  		for (i = 0; i < used_lrs; i++) {
> >  			writel_relaxed(cpu_if->vgic_lr[i],
> >  				       base + GICH_LR0 + (i * 4));
> > @@ -490,6 +485,7 @@ void vgic_v2_load(struct kvm_vcpu *vcpu)
> >  	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
> >  
> >  	writel_relaxed(cpu_if->vgic_vmcr, vgic->vctrl_base + GICH_VMCR);
> > +	writel_relaxed(cpu_if->vgic_apr, vgic->vctrl_base + GICH_APR);
> >  }
> >  
> >  void vgic_v2_put(struct kvm_vcpu *vcpu)
> > @@ -498,4 +494,5 @@ void vgic_v2_put(struct kvm_vcpu *vcpu)
> >  	struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
> >  
> >  	cpu_if->vgic_vmcr = readl_relaxed(vgic->vctrl_base + GICH_VMCR);
> > +	cpu_if->vgic_apr = readl_relaxed(vgic->vctrl_base + GICH_APR);
> >  }
> > diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> > index b76e21f3e6bd..4bafcd1e6bb8 100644
> > --- a/virt/kvm/arm/vgic/vgic-v3.c
> > +++ b/virt/kvm/arm/vgic/vgic-v3.c
> > @@ -16,6 +16,7 @@
> >  #include <linux/kvm.h>
> >  #include <linux/kvm_host.h>
> >  #include <kvm/arm_vgic.h>
> > +#include <asm/kvm_hyp.h>
> >  #include <asm/kvm_mmu.h>
> >  #include <asm/kvm_asm.h>
> >  
> > @@ -587,6 +588,8 @@ void vgic_v3_load(struct kvm_vcpu *vcpu)
> >  	 */
> >  	if (likely(cpu_if->vgic_sre))
> >  		kvm_call_hyp(__vgic_v3_write_vmcr, cpu_if->vgic_vmcr);
> > +
> > +	kvm_call_hyp(__vgic_v3_restore_aprs, vcpu);
> >  }
> >  
> >  void vgic_v3_put(struct kvm_vcpu *vcpu)
> > @@ -595,4 +598,6 @@ void vgic_v3_put(struct kvm_vcpu *vcpu)
> >  
> >  	if (likely(cpu_if->vgic_sre))
> >  		cpu_if->vgic_vmcr = kvm_call_hyp(__vgic_v3_read_vmcr);
> > +
> > +	kvm_call_hyp(__vgic_v3_save_aprs, vcpu);
> >  }
> > 
> 
> An unfortunate consequence of the save/restore de-aggregation process in
> this series is that we end-up doing quite a few EL2 calls in the !VHE
> case. We should probably think of consolidating those behind a single
> EL2 call if they have a measurable impact.

We could, but the trap to EL2 (without saving all GP regs beyond the
normal calling convention) is really cheap, so I don't think it *is*
that bad, but it *feels* bad.  Also, few of these are in the criticial
path, right?

I'll admit that I haven't measured non-VHE GICv3 impact of this series
(only non-VHE GICv2 which saw a small improvement).

> 
> In the meantime:
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> 

Thanks,
-Christoffer

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

* Re: [PATCH v4 25/40] KVM: arm64: Introduce framework for accessing deferred sysregs
  2018-02-22 13:40     ` Andrew Jones
@ 2018-02-22 14:56       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 14:56 UTC (permalink / raw)
  To: Andrew Jones
  Cc: kvm, Marc Zyngier, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 22, 2018 at 02:40:52PM +0100, Andrew Jones wrote:
> On Thu, Feb 15, 2018 at 10:03:17PM +0100, Christoffer Dall wrote:
> > We are about to defer saving and restoring some groups of system
> > registers to vcpu_put and vcpu_load on supported systems.  This means
> > that we need some infrastructure to access system registes which
> > supports either accessing the memory backing of the register or directly
> > accessing the system registers, depending on the state of the system
> > when we access the register.
> > 
> > We do this by defining read/write accessor functions, which can handle
> > both "immediate" and "deferrable" system registers.  Immediate registers
> > are always saved/restored in the world-switch path, but deferrable
> > registers are only saved/restored in vcpu_put/vcpu_load when supported
> > and sysregs_loaded_on_cpu will be set in that case.
> > 
> > Note that we don't use the deferred mechanism yet in this patch, but only
> > introduce infrastructure.  This is to improve convenience of review in
> > the subsequent patches where it is clear which registers become
> > deferred.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v3:
> >      - Changed to a switch-statement based approach to improve
> >        readability.
> >     
> >     Changes since v2:
> >      - New patch (deferred register handling has been reworked)
> > 
> >  arch/arm64/include/asm/kvm_host.h |  8 ++++++--
> >  arch/arm64/kvm/sys_regs.c         | 33 +++++++++++++++++++++++++++++++++
> >  2 files changed, 39 insertions(+), 2 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 68398bf7882f..b463b5e28959 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -284,6 +284,10 @@ struct kvm_vcpu_arch {
> >  
> >  	/* Virtual SError ESR to restore when HCR_EL2.VSE is set */
> >  	u64 vsesr_el2;
> > +
> > +	/* True when deferrable sysregs are loaded on the physical CPU,
> > +	 * see kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs. */
> > +	bool sysregs_loaded_on_cpu;
> >  };
> >  
> >  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> > @@ -296,8 +300,8 @@ struct kvm_vcpu_arch {
> >   */
> >  #define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> >  
> > -#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> > -#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> > +u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg);
> > +void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val);
> >  
> >  /*
> >   * CP14 and CP15 live in the same array, as they are backed by the
> > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> > index a05d2c01c786..b3c3f014aa61 100644
> > --- a/arch/arm64/kvm/sys_regs.c
> > +++ b/arch/arm64/kvm/sys_regs.c
> > @@ -35,6 +35,7 @@
> >  #include <asm/kvm_coproc.h>
> >  #include <asm/kvm_emulate.h>
> >  #include <asm/kvm_host.h>
> > +#include <asm/kvm_hyp.h>
> >  #include <asm/kvm_mmu.h>
> >  #include <asm/perf_event.h>
> >  #include <asm/sysreg.h>
> > @@ -76,6 +77,38 @@ static bool write_to_read_only(struct kvm_vcpu *vcpu,
> >  	return false;
> >  }
> >  
> > +u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
> > +{
> > +	if (!vcpu->arch.sysregs_loaded_on_cpu)
> > +		goto immediate_read;
> > +
> > +	/*
> > +	 * All system registers listed in the switch are not saved on every
> > +	 * exit from the guest but are only saved on vcpu_put.
> 
> The "All ... are not" doesn't flow well for me. How about
> 
>  /*
>   * None of the system registers listed in the switch are saved on guest
>   * exit. These registers are only saved on vcpu_put.
>   */
> 
> > +	 */
> > +	switch (reg) {
> > +	}
> > +
> > +immediate_read:
> > +	return __vcpu_sys_reg(vcpu, reg);
> > +}
> > +
> > +void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
> > +{
> > +	if (!vcpu->arch.sysregs_loaded_on_cpu)
> > +		goto immediate_write;
> > +
> > +	/*
> > +	 * All system registers listed in the switch are not restored on every
> > +	 * entry to the guest but are only restored on vcpu_load.
> > +	 */
> 
>  /*
>   * None of the system registers listed in the switch are restored on
>   * guest entry. If these registers were saved due to a vcpu_put, then
>   * they will be restored by vcpu_load.
>   */
> 

Hmmm, not sure the last sentence helps here.

I'll think about some nicer wording for you for the next version.

> > +	switch (reg) {
> > +	}
> > +
> > +immediate_write:
> > +	 __vcpu_sys_reg(vcpu, reg) = val;
> > +}
> > +
> >  /* 3 bits per cache level, as per CLIDR, but non-existent caches always 0 */
> >  static u32 cache_levels;
> >  
> > -- 
> > 2.14.2
> >
> 
> Otherwise
> 
> Reviewed-by: Andrew Jones <drjones@redhat.com>

Thanks,
-Christoffer

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

* [PATCH v4 25/40] KVM: arm64: Introduce framework for accessing deferred sysregs
@ 2018-02-22 14:56       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 14:56 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 22, 2018 at 02:40:52PM +0100, Andrew Jones wrote:
> On Thu, Feb 15, 2018 at 10:03:17PM +0100, Christoffer Dall wrote:
> > We are about to defer saving and restoring some groups of system
> > registers to vcpu_put and vcpu_load on supported systems.  This means
> > that we need some infrastructure to access system registes which
> > supports either accessing the memory backing of the register or directly
> > accessing the system registers, depending on the state of the system
> > when we access the register.
> > 
> > We do this by defining read/write accessor functions, which can handle
> > both "immediate" and "deferrable" system registers.  Immediate registers
> > are always saved/restored in the world-switch path, but deferrable
> > registers are only saved/restored in vcpu_put/vcpu_load when supported
> > and sysregs_loaded_on_cpu will be set in that case.
> > 
> > Note that we don't use the deferred mechanism yet in this patch, but only
> > introduce infrastructure.  This is to improve convenience of review in
> > the subsequent patches where it is clear which registers become
> > deferred.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v3:
> >      - Changed to a switch-statement based approach to improve
> >        readability.
> >     
> >     Changes since v2:
> >      - New patch (deferred register handling has been reworked)
> > 
> >  arch/arm64/include/asm/kvm_host.h |  8 ++++++--
> >  arch/arm64/kvm/sys_regs.c         | 33 +++++++++++++++++++++++++++++++++
> >  2 files changed, 39 insertions(+), 2 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 68398bf7882f..b463b5e28959 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -284,6 +284,10 @@ struct kvm_vcpu_arch {
> >  
> >  	/* Virtual SError ESR to restore when HCR_EL2.VSE is set */
> >  	u64 vsesr_el2;
> > +
> > +	/* True when deferrable sysregs are loaded on the physical CPU,
> > +	 * see kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs. */
> > +	bool sysregs_loaded_on_cpu;
> >  };
> >  
> >  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> > @@ -296,8 +300,8 @@ struct kvm_vcpu_arch {
> >   */
> >  #define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> >  
> > -#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> > -#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> > +u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg);
> > +void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val);
> >  
> >  /*
> >   * CP14 and CP15 live in the same array, as they are backed by the
> > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> > index a05d2c01c786..b3c3f014aa61 100644
> > --- a/arch/arm64/kvm/sys_regs.c
> > +++ b/arch/arm64/kvm/sys_regs.c
> > @@ -35,6 +35,7 @@
> >  #include <asm/kvm_coproc.h>
> >  #include <asm/kvm_emulate.h>
> >  #include <asm/kvm_host.h>
> > +#include <asm/kvm_hyp.h>
> >  #include <asm/kvm_mmu.h>
> >  #include <asm/perf_event.h>
> >  #include <asm/sysreg.h>
> > @@ -76,6 +77,38 @@ static bool write_to_read_only(struct kvm_vcpu *vcpu,
> >  	return false;
> >  }
> >  
> > +u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
> > +{
> > +	if (!vcpu->arch.sysregs_loaded_on_cpu)
> > +		goto immediate_read;
> > +
> > +	/*
> > +	 * All system registers listed in the switch are not saved on every
> > +	 * exit from the guest but are only saved on vcpu_put.
> 
> The "All ... are not" doesn't flow well for me. How about
> 
>  /*
>   * None of the system registers listed in the switch are saved on guest
>   * exit. These registers are only saved on vcpu_put.
>   */
> 
> > +	 */
> > +	switch (reg) {
> > +	}
> > +
> > +immediate_read:
> > +	return __vcpu_sys_reg(vcpu, reg);
> > +}
> > +
> > +void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
> > +{
> > +	if (!vcpu->arch.sysregs_loaded_on_cpu)
> > +		goto immediate_write;
> > +
> > +	/*
> > +	 * All system registers listed in the switch are not restored on every
> > +	 * entry to the guest but are only restored on vcpu_load.
> > +	 */
> 
>  /*
>   * None of the system registers listed in the switch are restored on
>   * guest entry. If these registers were saved due to a vcpu_put, then
>   * they will be restored by vcpu_load.
>   */
> 

Hmmm, not sure the last sentence helps here.

I'll think about some nicer wording for you for the next version.

> > +	switch (reg) {
> > +	}
> > +
> > +immediate_write:
> > +	 __vcpu_sys_reg(vcpu, reg) = val;
> > +}
> > +
> >  /* 3 bits per cache level, as per CLIDR, but non-existent caches always 0 */
> >  static u32 cache_levels;
> >  
> > -- 
> > 2.14.2
> >
> 
> Otherwise
> 
> Reviewed-by: Andrew Jones <drjones@redhat.com>

Thanks,
-Christoffer

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

* Re: [PATCH v4 30/40] KVM: arm64: Defer saving/restoring 32-bit sysregs to vcpu load/put
  2018-02-22 14:35     ` Andrew Jones
@ 2018-02-22 14:58       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 14:58 UTC (permalink / raw)
  To: Andrew Jones
  Cc: kvm, Marc Zyngier, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 22, 2018 at 03:35:06PM +0100, Andrew Jones wrote:
> On Thu, Feb 15, 2018 at 10:03:22PM +0100, Christoffer Dall wrote:
> > When running a 32-bit VM (EL1 in AArch32), the AArch32 system registers
> > can be deferred to vcpu load/put on VHE systems because neither
> > the host kernel nor host userspace uses these registers.
> > 
> > Note that we can not defer saving DBGVCR32_EL2 conditionally based
> > on the state of the debug dirty flag on VHE, but since we do the
> > load/put pretty rarely, this comes out as a win anyway.
> > 
> > We can also not defer saving FPEXC32_32 because this register only holds
> > a guest-valid value for 32-bit guests during the exit path when the
> > guest has used FPSIMD registers and restored the register in the early
> > assembly handler from taking the EL2 fault, and therefore we have to
> > check if fpsimd is enabled for the guest in the exit path and save the
> > register then, for both VHE and non-VHE guests.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v3:
> >      - Rework the FPEXC32 save/restore logic to no longer attempt to
> >        save/restore this register lazily.
> >     
> >     Changes since v2:
> >      - New patch (deferred register handling has been reworked)
> > 
> >  arch/arm64/kvm/hyp/switch.c    | 17 +++++++++++------
> >  arch/arm64/kvm/hyp/sysreg-sr.c | 15 ++++++++++-----
> >  2 files changed, 21 insertions(+), 11 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index 22e77deb8e2e..909aa3fe9196 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c
> > @@ -47,6 +47,15 @@ bool __hyp_text __fpsimd_enabled(void)
> >  	return __fpsimd_is_enabled()();
> >  }
> >  
> > +/* Save the 32-bit only FPSIMD system register state */
> > +static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
> > +{
> > +	if (!vcpu_el1_is_32bit(vcpu))
> > +		return;
> > +
> > +	vcpu->arch.ctxt.sys_regs[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
> > +}
> > +
> 
> I realize it's much more convenient to have this function here, but it
> feels a bit out of place, being a _save_ function. Its logical place is
> an -sr file.
> 

Yes, maybe, but that would make it a function call to perform a mrs and
a store, which is a bit unfortunate.

> >  static void __hyp_text __activate_traps_vhe(void)
> >  {
> >  	u64 val;
> > @@ -380,11 +389,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> >  
> >  	__vgic_restore_state(vcpu);
> >  
> > -	/*
> > -	 * We must restore the 32-bit state before the sysregs, thanks
> > -	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
> > -	 */
> > -	__sysreg32_restore_state(vcpu);
> >  	sysreg_restore_guest_state_vhe(guest_ctxt);
> >  	__debug_switch_to_guest(vcpu);
> >  
> > @@ -398,7 +402,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> >  	fp_enabled = __fpsimd_enabled();
> >  
> >  	sysreg_save_guest_state_vhe(guest_ctxt);
> > -	__sysreg32_save_state(vcpu);
> >  	__vgic_save_state(vcpu);
> >  
> >  	__deactivate_traps(vcpu);
> > @@ -408,6 +411,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> >  	if (fp_enabled) {
> >  		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
> >  		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
> > +		__fpsimd_save_fpexc32(vcpu);
> >  	}
> >  
> >  	__debug_switch_to_host(vcpu);
> > @@ -475,6 +479,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
> >  	if (fp_enabled) {
> >  		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
> >  		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
> > +		__fpsimd_save_fpexc32(vcpu);
> >  	}
> >  
> >  	/*
> > diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> > index 9c60b8062724..aacba4636871 100644
> > --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> > +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> > @@ -196,10 +196,7 @@ void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
> >  	sysreg[DACR32_EL2] = read_sysreg(dacr32_el2);
> >  	sysreg[IFSR32_EL2] = read_sysreg(ifsr32_el2);
> >  
> > -	if (__fpsimd_enabled())
> > -		sysreg[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
> > -
> > -	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> > +	if (has_vhe() || vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> >  		sysreg[DBGVCR32_EL2] = read_sysreg(dbgvcr32_el2);
> >  }
> >  
> > @@ -221,7 +218,7 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
> >  	write_sysreg(sysreg[DACR32_EL2], dacr32_el2);
> >  	write_sysreg(sysreg[IFSR32_EL2], ifsr32_el2);
> >  
> > -	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> > +	if (has_vhe() || vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> >  		write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
> >  }
> >  
> > @@ -246,6 +243,13 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
> >  
> >  	__sysreg_save_user_state(host_ctxt);
> >  
> > +	/*
> > +	 * Load guest EL1 and user state
> > +	 *
> > +	 * We must restore the 32-bit state before the sysregs, thanks
> > +	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
> > +	 */
> > +	__sysreg32_restore_state(vcpu);
> >  	__sysreg_restore_user_state(guest_ctxt);
> >  	__sysreg_restore_el1_state(guest_ctxt);
> >  
> > @@ -273,6 +277,7 @@ void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
> >  
> >  	__sysreg_save_el1_state(guest_ctxt);
> >  	__sysreg_save_user_state(guest_ctxt);
> > +	__sysreg32_save_state(vcpu);
> >  
> >  	/* Restore host user state */
> >  	__sysreg_restore_user_state(host_ctxt);
> > -- 
> > 2.14.2
> >
> 
> Besides the function location being a bit debatable, it looks good to me
> 
> Reviewed-by: Andrew Jones <drjones@redhat.com>
> 
Thanks,
-Christoffer

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

* [PATCH v4 30/40] KVM: arm64: Defer saving/restoring 32-bit sysregs to vcpu load/put
@ 2018-02-22 14:58       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 14:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 22, 2018 at 03:35:06PM +0100, Andrew Jones wrote:
> On Thu, Feb 15, 2018 at 10:03:22PM +0100, Christoffer Dall wrote:
> > When running a 32-bit VM (EL1 in AArch32), the AArch32 system registers
> > can be deferred to vcpu load/put on VHE systems because neither
> > the host kernel nor host userspace uses these registers.
> > 
> > Note that we can not defer saving DBGVCR32_EL2 conditionally based
> > on the state of the debug dirty flag on VHE, but since we do the
> > load/put pretty rarely, this comes out as a win anyway.
> > 
> > We can also not defer saving FPEXC32_32 because this register only holds
> > a guest-valid value for 32-bit guests during the exit path when the
> > guest has used FPSIMD registers and restored the register in the early
> > assembly handler from taking the EL2 fault, and therefore we have to
> > check if fpsimd is enabled for the guest in the exit path and save the
> > register then, for both VHE and non-VHE guests.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v3:
> >      - Rework the FPEXC32 save/restore logic to no longer attempt to
> >        save/restore this register lazily.
> >     
> >     Changes since v2:
> >      - New patch (deferred register handling has been reworked)
> > 
> >  arch/arm64/kvm/hyp/switch.c    | 17 +++++++++++------
> >  arch/arm64/kvm/hyp/sysreg-sr.c | 15 ++++++++++-----
> >  2 files changed, 21 insertions(+), 11 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index 22e77deb8e2e..909aa3fe9196 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c
> > @@ -47,6 +47,15 @@ bool __hyp_text __fpsimd_enabled(void)
> >  	return __fpsimd_is_enabled()();
> >  }
> >  
> > +/* Save the 32-bit only FPSIMD system register state */
> > +static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
> > +{
> > +	if (!vcpu_el1_is_32bit(vcpu))
> > +		return;
> > +
> > +	vcpu->arch.ctxt.sys_regs[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
> > +}
> > +
> 
> I realize it's much more convenient to have this function here, but it
> feels a bit out of place, being a _save_ function. Its logical place is
> an -sr file.
> 

Yes, maybe, but that would make it a function call to perform a mrs and
a store, which is a bit unfortunate.

> >  static void __hyp_text __activate_traps_vhe(void)
> >  {
> >  	u64 val;
> > @@ -380,11 +389,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> >  
> >  	__vgic_restore_state(vcpu);
> >  
> > -	/*
> > -	 * We must restore the 32-bit state before the sysregs, thanks
> > -	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
> > -	 */
> > -	__sysreg32_restore_state(vcpu);
> >  	sysreg_restore_guest_state_vhe(guest_ctxt);
> >  	__debug_switch_to_guest(vcpu);
> >  
> > @@ -398,7 +402,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> >  	fp_enabled = __fpsimd_enabled();
> >  
> >  	sysreg_save_guest_state_vhe(guest_ctxt);
> > -	__sysreg32_save_state(vcpu);
> >  	__vgic_save_state(vcpu);
> >  
> >  	__deactivate_traps(vcpu);
> > @@ -408,6 +411,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> >  	if (fp_enabled) {
> >  		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
> >  		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
> > +		__fpsimd_save_fpexc32(vcpu);
> >  	}
> >  
> >  	__debug_switch_to_host(vcpu);
> > @@ -475,6 +479,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
> >  	if (fp_enabled) {
> >  		__fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
> >  		__fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
> > +		__fpsimd_save_fpexc32(vcpu);
> >  	}
> >  
> >  	/*
> > diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> > index 9c60b8062724..aacba4636871 100644
> > --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> > +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> > @@ -196,10 +196,7 @@ void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
> >  	sysreg[DACR32_EL2] = read_sysreg(dacr32_el2);
> >  	sysreg[IFSR32_EL2] = read_sysreg(ifsr32_el2);
> >  
> > -	if (__fpsimd_enabled())
> > -		sysreg[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
> > -
> > -	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> > +	if (has_vhe() || vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> >  		sysreg[DBGVCR32_EL2] = read_sysreg(dbgvcr32_el2);
> >  }
> >  
> > @@ -221,7 +218,7 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
> >  	write_sysreg(sysreg[DACR32_EL2], dacr32_el2);
> >  	write_sysreg(sysreg[IFSR32_EL2], ifsr32_el2);
> >  
> > -	if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> > +	if (has_vhe() || vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
> >  		write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
> >  }
> >  
> > @@ -246,6 +243,13 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
> >  
> >  	__sysreg_save_user_state(host_ctxt);
> >  
> > +	/*
> > +	 * Load guest EL1 and user state
> > +	 *
> > +	 * We must restore the 32-bit state before the sysregs, thanks
> > +	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
> > +	 */
> > +	__sysreg32_restore_state(vcpu);
> >  	__sysreg_restore_user_state(guest_ctxt);
> >  	__sysreg_restore_el1_state(guest_ctxt);
> >  
> > @@ -273,6 +277,7 @@ void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
> >  
> >  	__sysreg_save_el1_state(guest_ctxt);
> >  	__sysreg_save_user_state(guest_ctxt);
> > +	__sysreg32_save_state(vcpu);
> >  
> >  	/* Restore host user state */
> >  	__sysreg_restore_user_state(host_ctxt);
> > -- 
> > 2.14.2
> >
> 
> Besides the function location being a bit debatable, it looks good to me
> 
> Reviewed-by: Andrew Jones <drjones@redhat.com>
> 
Thanks,
-Christoffer

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

* Re: [PATCH v4 38/40] KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on VHE
  2018-02-22 14:42       ` Christoffer Dall
@ 2018-02-22 15:01         ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-22 15:01 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, 22 Feb 2018 14:42:27 +0000,
Christoffer Dall wrote:
> 
> On Thu, Feb 22, 2018 at 12:32:11PM +0000, Marc Zyngier wrote:
> > On 15/02/18 21:03, Christoffer Dall wrote:
> > > Just like we can program the GICv2 hypervisor control interface directly
> > > from the core vgic code, we can do the same for the GICv3 hypervisor
> > > control interface on VHE systems.
> > > 
> > > We do this by simply calling the save/restore functions when we have VHE
> > > and we can then get rid of the save/restore function calls from the VHE
> > > world switch function.
> > > 
> > > One caveat is that we now write GICv3 system register state before the
> > > potential early exit path in the run loop, and because we sync back
> > > state in the early exit path, we have to ensure that we read a
> > > consistent GIC state from the sync path, even though we have never
> > > actually run the guest with the newly written GIC state.  We solve this
> > > by inserting an ISB in the early exit path.
> > > 
> > > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > > ---
> > > 
> > > Notes:
> > >     Changes since v2:
> > >      - Added ISB in the early exit path in the run loop as explained
> > >        in the commit message.
> > > 
> > >  arch/arm64/kvm/hyp/switch.c | 3 ---
> > >  virt/kvm/arm/arm.c          | 1 +
> > >  virt/kvm/arm/vgic/vgic.c    | 5 +++++
> > >  3 files changed, 6 insertions(+), 3 deletions(-)
> > > 
> > > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > > index cbafc27a617b..466cfcdbcaf3 100644
> > > --- a/arch/arm64/kvm/hyp/switch.c
> > > +++ b/arch/arm64/kvm/hyp/switch.c
> > > @@ -399,8 +399,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> > >  	__activate_traps(vcpu);
> > >  	__activate_vm(vcpu->kvm);
> > >  
> > > -	__vgic_restore_state(vcpu);
> > > -
> > >  	sysreg_restore_guest_state_vhe(guest_ctxt);
> > >  	__debug_switch_to_guest(vcpu);
> > >  
> > > @@ -414,7 +412,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> > >  	fp_enabled = fpsimd_enabled_vhe();
> > >  
> > >  	sysreg_save_guest_state_vhe(guest_ctxt);
> > > -	__vgic_save_state(vcpu);
> > >  
> > >  	__deactivate_traps(vcpu);
> > >  
> > > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > > index 5bd879c78951..6de7641f3ff2 100644
> > > --- a/virt/kvm/arm/arm.c
> > > +++ b/virt/kvm/arm/arm.c
> > > @@ -717,6 +717,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> > >  		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
> > >  		    kvm_request_pending(vcpu)) {
> > >  			vcpu->mode = OUTSIDE_GUEST_MODE;
> > > +			isb(); /* Ensure work in x_flush_hwstate is committed */
> > >  			kvm_pmu_sync_hwstate(vcpu);
> > >  			if (static_branch_unlikely(&userspace_irqchip_in_use))
> > >  				kvm_timer_sync_hwstate(vcpu);
> > > diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> > > index 12e2a28f437e..d0a19a8c196a 100644
> > > --- a/virt/kvm/arm/vgic/vgic.c
> > > +++ b/virt/kvm/arm/vgic/vgic.c
> > > @@ -19,6 +19,7 @@
> > >  #include <linux/list_sort.h>
> > >  #include <linux/interrupt.h>
> > >  #include <linux/irq.h>
> > > +#include <asm/kvm_hyp.h>
> > >  
> > >  #include "vgic.h"
> > >  
> > > @@ -753,6 +754,8 @@ static inline void vgic_save_state(struct kvm_vcpu *vcpu)
> > >  {
> > >  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> > >  		vgic_v2_save_state(vcpu);
> > > +	else if (has_vhe())
> > > +		__vgic_v3_save_state(vcpu);
> > >  }
> > >  
> > >  /* Sync back the hardware VGIC state into our emulation after a guest's run. */
> > > @@ -777,6 +780,8 @@ static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
> > >  {
> > >  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> > >  		vgic_v2_restore_state(vcpu);
> > > +	else if (has_vhe())
> > > +		__vgic_v3_restore_state(vcpu);
> > >  }
> > >  
> > >  /* Flush our emulation state into the GIC hardware before entering the guest. */
> > > 
> > 
> > I'm slowly wrapping my brain around this thing again. If I grasp the
> > general idea, we end up with two cases:
> > 
> > (1) The GIC is accessible from the kernel, and we save/restore it
> > outside of the HYP code.
> > 
> > (2) The GIC is only accessible from the HYP code, and we do it there.
> > 
> > Maybe we should bite the bullet and introduce that primitive instead?
> > 
> 
> You mean something the following?
> 
> static inline bool can_access_vgic_from_kernel(void)
> {
> 	/*
> 	 * GICv2 can always be accessed from the kernel because it is
> 	 * memory-mapped, and VHE systems can access GICv3 EL2 system
> 	 * registers.
> 	 */
> 	return !static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) || has_vhe();
> }

Yes. I think this would go a long way in making this code easy to
understand. It also mean that we can have a unified save/restore
function that picks the right GIC back-end, resulting in less
code duplication.

Thoughts?

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 38/40] KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on VHE
@ 2018-02-22 15:01         ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-22 15:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 22 Feb 2018 14:42:27 +0000,
Christoffer Dall wrote:
> 
> On Thu, Feb 22, 2018 at 12:32:11PM +0000, Marc Zyngier wrote:
> > On 15/02/18 21:03, Christoffer Dall wrote:
> > > Just like we can program the GICv2 hypervisor control interface directly
> > > from the core vgic code, we can do the same for the GICv3 hypervisor
> > > control interface on VHE systems.
> > > 
> > > We do this by simply calling the save/restore functions when we have VHE
> > > and we can then get rid of the save/restore function calls from the VHE
> > > world switch function.
> > > 
> > > One caveat is that we now write GICv3 system register state before the
> > > potential early exit path in the run loop, and because we sync back
> > > state in the early exit path, we have to ensure that we read a
> > > consistent GIC state from the sync path, even though we have never
> > > actually run the guest with the newly written GIC state.  We solve this
> > > by inserting an ISB in the early exit path.
> > > 
> > > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > > ---
> > > 
> > > Notes:
> > >     Changes since v2:
> > >      - Added ISB in the early exit path in the run loop as explained
> > >        in the commit message.
> > > 
> > >  arch/arm64/kvm/hyp/switch.c | 3 ---
> > >  virt/kvm/arm/arm.c          | 1 +
> > >  virt/kvm/arm/vgic/vgic.c    | 5 +++++
> > >  3 files changed, 6 insertions(+), 3 deletions(-)
> > > 
> > > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > > index cbafc27a617b..466cfcdbcaf3 100644
> > > --- a/arch/arm64/kvm/hyp/switch.c
> > > +++ b/arch/arm64/kvm/hyp/switch.c
> > > @@ -399,8 +399,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> > >  	__activate_traps(vcpu);
> > >  	__activate_vm(vcpu->kvm);
> > >  
> > > -	__vgic_restore_state(vcpu);
> > > -
> > >  	sysreg_restore_guest_state_vhe(guest_ctxt);
> > >  	__debug_switch_to_guest(vcpu);
> > >  
> > > @@ -414,7 +412,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> > >  	fp_enabled = fpsimd_enabled_vhe();
> > >  
> > >  	sysreg_save_guest_state_vhe(guest_ctxt);
> > > -	__vgic_save_state(vcpu);
> > >  
> > >  	__deactivate_traps(vcpu);
> > >  
> > > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > > index 5bd879c78951..6de7641f3ff2 100644
> > > --- a/virt/kvm/arm/arm.c
> > > +++ b/virt/kvm/arm/arm.c
> > > @@ -717,6 +717,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> > >  		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
> > >  		    kvm_request_pending(vcpu)) {
> > >  			vcpu->mode = OUTSIDE_GUEST_MODE;
> > > +			isb(); /* Ensure work in x_flush_hwstate is committed */
> > >  			kvm_pmu_sync_hwstate(vcpu);
> > >  			if (static_branch_unlikely(&userspace_irqchip_in_use))
> > >  				kvm_timer_sync_hwstate(vcpu);
> > > diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> > > index 12e2a28f437e..d0a19a8c196a 100644
> > > --- a/virt/kvm/arm/vgic/vgic.c
> > > +++ b/virt/kvm/arm/vgic/vgic.c
> > > @@ -19,6 +19,7 @@
> > >  #include <linux/list_sort.h>
> > >  #include <linux/interrupt.h>
> > >  #include <linux/irq.h>
> > > +#include <asm/kvm_hyp.h>
> > >  
> > >  #include "vgic.h"
> > >  
> > > @@ -753,6 +754,8 @@ static inline void vgic_save_state(struct kvm_vcpu *vcpu)
> > >  {
> > >  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> > >  		vgic_v2_save_state(vcpu);
> > > +	else if (has_vhe())
> > > +		__vgic_v3_save_state(vcpu);
> > >  }
> > >  
> > >  /* Sync back the hardware VGIC state into our emulation after a guest's run. */
> > > @@ -777,6 +780,8 @@ static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
> > >  {
> > >  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> > >  		vgic_v2_restore_state(vcpu);
> > > +	else if (has_vhe())
> > > +		__vgic_v3_restore_state(vcpu);
> > >  }
> > >  
> > >  /* Flush our emulation state into the GIC hardware before entering the guest. */
> > > 
> > 
> > I'm slowly wrapping my brain around this thing again. If I grasp the
> > general idea, we end up with two cases:
> > 
> > (1) The GIC is accessible from the kernel, and we save/restore it
> > outside of the HYP code.
> > 
> > (2) The GIC is only accessible from the HYP code, and we do it there.
> > 
> > Maybe we should bite the bullet and introduce that primitive instead?
> > 
> 
> You mean something the following?
> 
> static inline bool can_access_vgic_from_kernel(void)
> {
> 	/*
> 	 * GICv2 can always be accessed from the kernel because it is
> 	 * memory-mapped, and VHE systems can access GICv3 EL2 system
> 	 * registers.
> 	 */
> 	return !static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) || has_vhe();
> }

Yes. I think this would go a long way in making this code easy to
understand. It also mean that we can have a unified save/restore
function that picks the right GIC back-end, resulting in less
code duplication.

Thoughts?

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-22 15:11     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 15:11 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Christoffer Dall, kvm, Marc Zyngier, kvmarm, Yury Norov,
	linux-arm-kernel, Dave Martin, Shih-Wei Li


Hi Christoffer,

I'm just pointing out some broken lines that we could maybe cheat the
80-char limit on. Naturally feel free to ignore.

On Thu, Feb 15, 2018 at 10:03:16PM +0100, Christoffer Dall wrote:
> From: Christoffer Dall <cdall@cs.columbia.edu>
> 
> Currently we access the system registers array via the vcpu_sys_reg()
> macro.  However, we are about to change the behavior to some times
> modify the register file directly, so let's change this to two
> primitives:
> 
>  * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
>  * Direct array access macro __vcpu_sys_reg()
> 
> The first primitive should be used in places where the code needs to
> access the currently loaded VCPU's state as observed by the guest.  For
> example, when trapping on cache related registers, a write to a system
> register should go directly to the VCPU version of the register.
> 
> The second primitive can be used in places where the VCPU is known to
> never be running (for example userspace access) or for registers which
> are never context switched (for example all the PMU system registers).
> 
> This rewrites all users of vcpu_sys_regs to one of the two primitives
> above.
> 
> No functional change.
> 
> Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> ---
> 
> Notes:
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm64/include/asm/kvm_emulate.h | 13 ++++---
>  arch/arm64/include/asm/kvm_host.h    | 13 ++++++-
>  arch/arm64/include/asm/kvm_mmu.h     |  2 +-
>  arch/arm64/kvm/debug.c               | 27 +++++++++-----
>  arch/arm64/kvm/inject_fault.c        |  8 ++--
>  arch/arm64/kvm/sys_regs.c            | 71 ++++++++++++++++++------------------
>  arch/arm64/kvm/sys_regs.h            |  4 +-
>  arch/arm64/kvm/sys_regs_generic_v8.c |  4 +-
>  virt/kvm/arm/pmu.c                   | 37 ++++++++++---------
>  9 files changed, 102 insertions(+), 77 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 3cc535591bdf..d313aaae5c38 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -290,15 +290,18 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
>  
>  static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
>  {
> -	return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> +	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
>  }
>  
>  static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
>  {
> -	if (vcpu_mode_is_32bit(vcpu))
> +	if (vcpu_mode_is_32bit(vcpu)) {
>  		*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
> -	else
> -		vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
> +	} else {
> +		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
> +		sctlr |= (1 << 25);
> +		vcpu_write_sys_reg(vcpu, SCTLR_EL1, sctlr);
> +	}
>  }
>  
>  static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> @@ -306,7 +309,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
>  	if (vcpu_mode_is_32bit(vcpu))
>  		return !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_E_BIT);
>  
> -	return !!(vcpu_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> +	return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
>  }
>  
>  static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index f2a6f39aec87..68398bf7882f 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
>  };
>  
>  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> -#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> +
> +/*
> + * Only use __vcpu_sys_reg if you know you want the memory backed version of a
> + * register, and not the one most recently accessed by a runnning VCPU.  For
> + * example, for userpace access or for system registers that are never context
> + * switched, but only emulated.
> + */
> +#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> +
> +#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> +#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> +
>  /*
>   * CP14 and CP15 live in the same array, as they are backed by the
>   * same system registers.
> diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> index 9679067a1574..95f46e73c4dc 100644
> --- a/arch/arm64/include/asm/kvm_mmu.h
> +++ b/arch/arm64/include/asm/kvm_mmu.h
> @@ -249,7 +249,7 @@ struct kvm;
>  
>  static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
>  {
> -	return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> +	return (vcpu_read_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
>  }
>  
>  static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
> diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> index feedb877cff8..db32d10a56a1 100644
> --- a/arch/arm64/kvm/debug.c
> +++ b/arch/arm64/kvm/debug.c
> @@ -46,7 +46,8 @@ static DEFINE_PER_CPU(u32, mdcr_el2);
>   */
>  static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
>  {
> -	vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1);
> +	vcpu->arch.guest_debug_preserved.mdscr_el1 =
> +		vcpu_read_sys_reg(vcpu, MDSCR_EL1);

This one would be 88 chars, but I won't tell if you don't tell :-)

>  
>  	trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
>  				vcpu->arch.guest_debug_preserved.mdscr_el1);
> @@ -54,10 +55,11 @@ static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
>  
>  static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
>  {
> -	vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1;
> +	vcpu_write_sys_reg(vcpu, MDSCR_EL1,
> +			   vcpu->arch.guest_debug_preserved.mdscr_el1);

Another 88...

>  
>  	trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
> -				vcpu_sys_reg(vcpu, MDSCR_EL1));
> +				vcpu_read_sys_reg(vcpu, MDSCR_EL1));
>  }
>  
>  /**
> @@ -108,6 +110,7 @@ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
>  void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  {
>  	bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY);
> +	unsigned long mdscr;
>  
>  	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
>  
> @@ -152,9 +155,13 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  		 */
>  		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
>  			*vcpu_cpsr(vcpu) |=  DBG_SPSR_SS;
> -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_SS;
> +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> +			mdscr |= DBG_MDSCR_SS;
> +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
>  		} else {
> -			vcpu_sys_reg(vcpu, MDSCR_EL1) &= ~DBG_MDSCR_SS;
> +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> +			mdscr &= ~DBG_MDSCR_SS;
> +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
>  		}
>  
>  		trace_kvm_arm_set_dreg32("SPSR_EL2", *vcpu_cpsr(vcpu));
> @@ -170,7 +177,9 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  		 */
>  		if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) {
>  			/* Enable breakpoints/watchpoints */
> -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_MDE;
> +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> +			mdscr |= DBG_MDSCR_MDE;
> +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
>  
>  			vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state;
>  			vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
> @@ -194,12 +203,12 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  		vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
>  
>  	/* If KDE or MDE are set, perform a full save/restore cycle. */
> -	if ((vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_KDE) ||
> -	    (vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_MDE))
> +	if (vcpu_read_sys_reg(vcpu, MDSCR_EL1) & (DBG_MDSCR_KDE | DBG_MDSCR_MDE))
>  		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
>  
>  	trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2);
> -	trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_sys_reg(vcpu, MDSCR_EL1));
> +	trace_kvm_arm_set_dreg32("MDSCR_EL1",
> +				 vcpu_read_sys_reg(vcpu, MDSCR_EL1));

Only 82. Maybe nobody would notice :-)

>  }
>  
>  void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
> diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> index 30a3f58cdb7b..e08db2f2dd75 100644
> --- a/arch/arm64/kvm/inject_fault.c
> +++ b/arch/arm64/kvm/inject_fault.c
> @@ -58,7 +58,7 @@ static u64 get_except_vector(struct kvm_vcpu *vcpu, enum exception_type type)
>  		exc_offset = LOWER_EL_AArch32_VECTOR;
>  	}
>  
> -	return vcpu_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
> +	return vcpu_read_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
>  }
>  
>  static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
> @@ -73,7 +73,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
>  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
>  	*vcpu_spsr(vcpu) = cpsr;
>  
> -	vcpu_sys_reg(vcpu, FAR_EL1) = addr;
> +	vcpu_write_sys_reg(vcpu, FAR_EL1, addr);
>  
>  	/*
>  	 * Build an {i,d}abort, depending on the level and the
> @@ -94,7 +94,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
>  	if (!is_iabt)
>  		esr |= ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT;
>  
> -	vcpu_sys_reg(vcpu, ESR_EL1) = esr | ESR_ELx_FSC_EXTABT;
> +	vcpu_write_sys_reg(vcpu, ESR_EL1, esr | ESR_ELx_FSC_EXTABT);
>  }
>  
>  static void inject_undef64(struct kvm_vcpu *vcpu)
> @@ -115,7 +115,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
>  	if (kvm_vcpu_trap_il_is32bit(vcpu))
>  		esr |= ESR_ELx_IL;
>  
> -	vcpu_sys_reg(vcpu, ESR_EL1) = esr;
> +	vcpu_write_sys_reg(vcpu, ESR_EL1, esr);
>  }
>  
>  /**
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index b48af790615e..a05d2c01c786 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -133,14 +133,14 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
>  	if (!p->is_aarch32 || !p->is_32bit) {
>  		val = p->regval;
>  	} else {
> -		val = vcpu_sys_reg(vcpu, reg);
> +		val = vcpu_read_sys_reg(vcpu, reg);
>  		if (r->reg % 2)
>  			val = (p->regval << 32) | (u64)lower_32_bits(val);
>  		else
>  			val = ((u64)upper_32_bits(val) << 32) |
>  				lower_32_bits(p->regval);
>  	}
> -	vcpu_sys_reg(vcpu, reg) = val;
> +	vcpu_write_sys_reg(vcpu, reg, val);
>  
>  	kvm_toggle_cache(vcpu, was_enabled);
>  	return true;
> @@ -241,10 +241,10 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
>  			    const struct sys_reg_desc *r)
>  {
>  	if (p->is_write) {
> -		vcpu_sys_reg(vcpu, r->reg) = p->regval;
> +		vcpu_write_sys_reg(vcpu, r->reg, p->regval);
>  		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, r->reg);
> +		p->regval = vcpu_read_sys_reg(vcpu, r->reg);
>  	}
>  
>  	trace_trap_reg(__func__, r->reg, p->is_write, p->regval);
> @@ -457,7 +457,8 @@ static void reset_wcr(struct kvm_vcpu *vcpu,
>  
>  static void reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  {
> -	vcpu_sys_reg(vcpu, AMAIR_EL1) = read_sysreg(amair_el1);
> +	u64 amair = read_sysreg(amair_el1);
> +	vcpu_write_sys_reg(vcpu, AMAIR_EL1, amair);
>  }
>  
>  static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> @@ -474,7 +475,7 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  	mpidr = (vcpu->vcpu_id & 0x0f) << MPIDR_LEVEL_SHIFT(0);
>  	mpidr |= ((vcpu->vcpu_id >> 4) & 0xff) << MPIDR_LEVEL_SHIFT(1);
>  	mpidr |= ((vcpu->vcpu_id >> 12) & 0xff) << MPIDR_LEVEL_SHIFT(2);
> -	vcpu_sys_reg(vcpu, MPIDR_EL1) = (1ULL << 31) | mpidr;
> +	vcpu_write_sys_reg(vcpu, MPIDR_EL1, (1ULL << 31) | mpidr);
>  }
>  
>  static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> @@ -488,12 +489,12 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  	 */
>  	val = ((pmcr & ~ARMV8_PMU_PMCR_MASK)
>  	       | (ARMV8_PMU_PMCR_MASK & 0xdecafbad)) & (~ARMV8_PMU_PMCR_E);
> -	vcpu_sys_reg(vcpu, PMCR_EL0) = val;
> +	__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
>  }
>  
>  static bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags)
>  {
> -	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +	u64 reg = __vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>  	bool enabled = (reg & flags) || vcpu_mode_priv(vcpu);
>  
>  	if (!enabled)
> @@ -535,14 +536,14 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  
>  	if (p->is_write) {
>  		/* Only update writeable bits of PMCR */
> -		val = vcpu_sys_reg(vcpu, PMCR_EL0);
> +		val = __vcpu_sys_reg(vcpu, PMCR_EL0);
>  		val &= ~ARMV8_PMU_PMCR_MASK;
>  		val |= p->regval & ARMV8_PMU_PMCR_MASK;
> -		vcpu_sys_reg(vcpu, PMCR_EL0) = val;
> +		__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
>  		kvm_pmu_handle_pmcr(vcpu, val);
>  	} else {
>  		/* PMCR.P & PMCR.C are RAZ */
> -		val = vcpu_sys_reg(vcpu, PMCR_EL0)
> +		val = __vcpu_sys_reg(vcpu, PMCR_EL0)
>  		      & ~(ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C);
>  		p->regval = val;
>  	}
> @@ -560,10 +561,10 @@ static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  		return false;
>  
>  	if (p->is_write)
> -		vcpu_sys_reg(vcpu, PMSELR_EL0) = p->regval;
> +		__vcpu_sys_reg(vcpu, PMSELR_EL0) = p->regval;
>  	else
>  		/* return PMSELR.SEL field */
> -		p->regval = vcpu_sys_reg(vcpu, PMSELR_EL0)
> +		p->regval = __vcpu_sys_reg(vcpu, PMSELR_EL0)
>  			    & ARMV8_PMU_COUNTER_MASK;

This isn't a new line break and would be 86, but...

>  
>  	return true;
> @@ -596,7 +597,7 @@ static bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
>  {
>  	u64 pmcr, val;
>  
> -	pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
> +	pmcr = __vcpu_sys_reg(vcpu, PMCR_EL0);
>  	val = (pmcr >> ARMV8_PMU_PMCR_N_SHIFT) & ARMV8_PMU_PMCR_N_MASK;
>  	if (idx >= val && idx != ARMV8_PMU_CYCLE_IDX) {
>  		kvm_inject_undefined(vcpu);
> @@ -621,7 +622,7 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
>  			if (pmu_access_event_counter_el0_disabled(vcpu))
>  				return false;
>  
> -			idx = vcpu_sys_reg(vcpu, PMSELR_EL0)
> +			idx = __vcpu_sys_reg(vcpu, PMSELR_EL0)
>  			      & ARMV8_PMU_COUNTER_MASK;

This old one would be 88.

>  		} else if (r->Op2 == 0) {
>  			/* PMCCNTR_EL0 */
> @@ -676,7 +677,7 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  
>  	if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 1) {
>  		/* PMXEVTYPER_EL0 */
> -		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_PMU_COUNTER_MASK;
> +		idx = __vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_PMU_COUNTER_MASK;
>  		reg = PMEVTYPER0_EL0 + idx;
>  	} else if (r->CRn == 14 && (r->CRm & 12) == 12) {
>  		idx = ((r->CRm & 3) << 3) | (r->Op2 & 7);
> @@ -694,9 +695,9 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  
>  	if (p->is_write) {
>  		kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
> -		vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_PMU_EVTYPE_MASK;
> +		__vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_PMU_EVTYPE_MASK;
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK;
> +		p->regval = __vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK;
>  	}
>  
>  	return true;
> @@ -718,15 +719,15 @@ static bool access_pmcnten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  		val = p->regval & mask;
>  		if (r->Op2 & 0x1) {
>  			/* accessing PMCNTENSET_EL0 */
> -			vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val;
> +			__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val;
>  			kvm_pmu_enable_counter(vcpu, val);
>  		} else {
>  			/* accessing PMCNTENCLR_EL0 */
> -			vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val;
> +			__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val;
>  			kvm_pmu_disable_counter(vcpu, val);
>  		}
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask;
> +		p->regval = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask;
>  	}
>  
>  	return true;
> @@ -750,12 +751,12 @@ static bool access_pminten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  
>  		if (r->Op2 & 0x1)
>  			/* accessing PMINTENSET_EL1 */
> -			vcpu_sys_reg(vcpu, PMINTENSET_EL1) |= val;
> +			__vcpu_sys_reg(vcpu, PMINTENSET_EL1) |= val;
>  		else
>  			/* accessing PMINTENCLR_EL1 */
> -			vcpu_sys_reg(vcpu, PMINTENSET_EL1) &= ~val;
> +			__vcpu_sys_reg(vcpu, PMINTENSET_EL1) &= ~val;
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, PMINTENSET_EL1) & mask;
> +		p->regval = __vcpu_sys_reg(vcpu, PMINTENSET_EL1) & mask;
>  	}
>  
>  	return true;
> @@ -775,12 +776,12 @@ static bool access_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	if (p->is_write) {
>  		if (r->CRm & 0x2)
>  			/* accessing PMOVSSET_EL0 */
> -			vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= (p->regval & mask);
> +			__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= (p->regval & mask);
>  		else
>  			/* accessing PMOVSCLR_EL0 */
> -			vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= ~(p->regval & mask);
> +			__vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= ~(p->regval & mask);
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, PMOVSSET_EL0) & mask;
> +		p->regval = __vcpu_sys_reg(vcpu, PMOVSSET_EL0) & mask;
>  	}
>  
>  	return true;
> @@ -817,10 +818,10 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  			return false;
>  		}
>  
> -		vcpu_sys_reg(vcpu, PMUSERENR_EL0) = p->regval
> -						    & ARMV8_PMU_USERENR_MASK;
> -	} else {
> -		p->regval = vcpu_sys_reg(vcpu, PMUSERENR_EL0)
> +		__vcpu_sys_reg(vcpu, PMUSERENR_EL0) =
> +			       p->regval & ARMV8_PMU_USERENR_MASK;

Just when I thought 88 could be the new 80, this one is 89.


> +	} else  {
> +		p->regval = __vcpu_sys_reg(vcpu, PMUSERENR_EL0)
>  			    & ARMV8_PMU_USERENR_MASK;

Old one, would be 89.

>  	}
>  
> @@ -2204,7 +2205,7 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
>  	if (r->get_user)
>  		return (r->get_user)(vcpu, r, reg, uaddr);
>  
> -	return reg_to_user(uaddr, &vcpu_sys_reg(vcpu, r->reg), reg->id);
> +	return reg_to_user(uaddr, &__vcpu_sys_reg(vcpu, r->reg), reg->id);
>  }
>  
>  int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> @@ -2225,7 +2226,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
>  	if (r->set_user)
>  		return (r->set_user)(vcpu, r, reg, uaddr);
>  
> -	return reg_from_user(&vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
> +	return reg_from_user(&__vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
>  }
>  
>  static unsigned int num_demux_regs(void)
> @@ -2431,6 +2432,6 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
>  	reset_sys_reg_descs(vcpu, table, num);
>  
>  	for (num = 1; num < NR_SYS_REGS; num++)
> -		if (vcpu_sys_reg(vcpu, num) == 0x4242424242424242)
> -			panic("Didn't reset vcpu_sys_reg(%zi)", num);
> +		if (__vcpu_sys_reg(vcpu, num) == 0x4242424242424242)
> +			panic("Didn't reset __vcpu_sys_reg(%zi)", num);
>  }
> diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
> index 060f5348ef25..cd710f8b63e0 100644
> --- a/arch/arm64/kvm/sys_regs.h
> +++ b/arch/arm64/kvm/sys_regs.h
> @@ -89,14 +89,14 @@ static inline void reset_unknown(struct kvm_vcpu *vcpu,
>  {
>  	BUG_ON(!r->reg);
>  	BUG_ON(r->reg >= NR_SYS_REGS);
> -	vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
> +	__vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
>  }
>  
>  static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  {
>  	BUG_ON(!r->reg);
>  	BUG_ON(r->reg >= NR_SYS_REGS);
> -	vcpu_sys_reg(vcpu, r->reg) = r->val;
> +	__vcpu_sys_reg(vcpu, r->reg) = r->val;
>  }
>  
>  static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
> diff --git a/arch/arm64/kvm/sys_regs_generic_v8.c b/arch/arm64/kvm/sys_regs_generic_v8.c
> index 969ade1d333d..ddb8497d18d6 100644
> --- a/arch/arm64/kvm/sys_regs_generic_v8.c
> +++ b/arch/arm64/kvm/sys_regs_generic_v8.c
> @@ -38,13 +38,13 @@ static bool access_actlr(struct kvm_vcpu *vcpu,
>  	if (p->is_write)
>  		return ignore_write(vcpu, p);
>  
> -	p->regval = vcpu_sys_reg(vcpu, ACTLR_EL1);
> +	p->regval = vcpu_read_sys_reg(vcpu, ACTLR_EL1);
>  	return true;
>  }
>  
>  static void reset_actlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  {
> -	vcpu_sys_reg(vcpu, ACTLR_EL1) = read_sysreg(actlr_el1);
> +	__vcpu_sys_reg(vcpu, ACTLR_EL1) = read_sysreg(actlr_el1);
>  }
>  
>  /*
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 8a9c42366db7..29cb4a1ff26b 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -37,7 +37,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
>  
>  	reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
>  	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
> -	counter = vcpu_sys_reg(vcpu, reg);
> +	counter = __vcpu_sys_reg(vcpu, reg);
>  
>  	/* The real counter value is equal to the value of counter register plus
>  	 * the value perf event counts.
> @@ -61,7 +61,8 @@ void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val)
>  
>  	reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
>  	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
> -	vcpu_sys_reg(vcpu, reg) += (s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);
> +	__vcpu_sys_reg(vcpu, reg) +=
> +		(s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);

I guess I won't complain about 92.

>  }
>  
>  /**
> @@ -78,7 +79,7 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
>  		counter = kvm_pmu_get_counter_value(vcpu, pmc->idx);
>  		reg = (pmc->idx == ARMV8_PMU_CYCLE_IDX)
>  		       ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + pmc->idx;
> -		vcpu_sys_reg(vcpu, reg) = counter;
> +		__vcpu_sys_reg(vcpu, reg) = counter;
>  		perf_event_disable(pmc->perf_event);
>  		perf_event_release_kernel(pmc->perf_event);
>  		pmc->perf_event = NULL;
> @@ -125,7 +126,7 @@ void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu)
>  
>  u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
>  {
> -	u64 val = vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMU_PMCR_N_SHIFT;
> +	u64 val = __vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMU_PMCR_N_SHIFT;
>  
>  	val &= ARMV8_PMU_PMCR_N_MASK;
>  	if (val == 0)
> @@ -147,7 +148,7 @@ void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val)
>  	struct kvm_pmu *pmu = &vcpu->arch.pmu;
>  	struct kvm_pmc *pmc;
>  
> -	if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) || !val)
> +	if (!(__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) || !val)
>  		return;
>  
>  	for (i = 0; i < ARMV8_PMU_MAX_COUNTERS; i++) {
> @@ -193,10 +194,10 @@ static u64 kvm_pmu_overflow_status(struct kvm_vcpu *vcpu)
>  {
>  	u64 reg = 0;
>  
> -	if ((vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E)) {
> -		reg = vcpu_sys_reg(vcpu, PMOVSSET_EL0);
> -		reg &= vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> -		reg &= vcpu_sys_reg(vcpu, PMINTENSET_EL1);
> +	if ((__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E)) {
> +		reg = __vcpu_sys_reg(vcpu, PMOVSSET_EL0);
> +		reg &= __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> +		reg &= __vcpu_sys_reg(vcpu, PMINTENSET_EL1);
>  		reg &= kvm_pmu_valid_counter_mask(vcpu);
>  	}
>  
> @@ -295,7 +296,7 @@ static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
>  	struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
>  	int idx = pmc->idx;
>  
> -	vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(idx);
> +	__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(idx);
>  
>  	if (kvm_pmu_overflow_status(vcpu)) {
>  		kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
> @@ -316,19 +317,19 @@ void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
>  	if (val == 0)
>  		return;
>  
> -	enable = vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> +	enable = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
>  	for (i = 0; i < ARMV8_PMU_CYCLE_IDX; i++) {
>  		if (!(val & BIT(i)))
>  			continue;
> -		type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
> +		type = __vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
>  		       & ARMV8_PMU_EVTYPE_EVENT;
>  		if ((type == ARMV8_PMUV3_PERFCTR_SW_INCR)
>  		    && (enable & BIT(i))) {
> -			reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
> +			reg = __vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
>  			reg = lower_32_bits(reg);
> -			vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
> +			__vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
>  			if (!reg)
> -				vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
> +				__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
>  		}
>  	}
>  }
> @@ -348,7 +349,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
>  	mask = kvm_pmu_valid_counter_mask(vcpu);
>  	if (val & ARMV8_PMU_PMCR_E) {
>  		kvm_pmu_enable_counter(vcpu,
> -				vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask);
> +		       __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask);

This one looks pretty OK, and would be 90 anyway.

>  	} else {
>  		kvm_pmu_disable_counter(vcpu, mask);
>  	}
> @@ -369,8 +370,8 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
>  
>  static bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu, u64 select_idx)
>  {
> -	return (vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) &&
> -	       (vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
> +	return (__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) &&
> +	       (__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
>  }
>  
>  /**
> -- 
> 2.14.2
>

Thanks,
drew 

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

* [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
@ 2018-02-22 15:11     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 15:11 UTC (permalink / raw)
  To: linux-arm-kernel


Hi Christoffer,

I'm just pointing out some broken lines that we could maybe cheat the
80-char limit on. Naturally feel free to ignore.

On Thu, Feb 15, 2018 at 10:03:16PM +0100, Christoffer Dall wrote:
> From: Christoffer Dall <cdall@cs.columbia.edu>
> 
> Currently we access the system registers array via the vcpu_sys_reg()
> macro.  However, we are about to change the behavior to some times
> modify the register file directly, so let's change this to two
> primitives:
> 
>  * Accessor macros vcpu_write_sys_reg() and vcpu_read_sys_reg()
>  * Direct array access macro __vcpu_sys_reg()
> 
> The first primitive should be used in places where the code needs to
> access the currently loaded VCPU's state as observed by the guest.  For
> example, when trapping on cache related registers, a write to a system
> register should go directly to the VCPU version of the register.
> 
> The second primitive can be used in places where the VCPU is known to
> never be running (for example userspace access) or for registers which
> are never context switched (for example all the PMU system registers).
> 
> This rewrites all users of vcpu_sys_regs to one of the two primitives
> above.
> 
> No functional change.
> 
> Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
> ---
> 
> Notes:
>     Changes since v2:
>      - New patch (deferred register handling has been reworked)
> 
>  arch/arm64/include/asm/kvm_emulate.h | 13 ++++---
>  arch/arm64/include/asm/kvm_host.h    | 13 ++++++-
>  arch/arm64/include/asm/kvm_mmu.h     |  2 +-
>  arch/arm64/kvm/debug.c               | 27 +++++++++-----
>  arch/arm64/kvm/inject_fault.c        |  8 ++--
>  arch/arm64/kvm/sys_regs.c            | 71 ++++++++++++++++++------------------
>  arch/arm64/kvm/sys_regs.h            |  4 +-
>  arch/arm64/kvm/sys_regs_generic_v8.c |  4 +-
>  virt/kvm/arm/pmu.c                   | 37 ++++++++++---------
>  9 files changed, 102 insertions(+), 77 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 3cc535591bdf..d313aaae5c38 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -290,15 +290,18 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
>  
>  static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
>  {
> -	return vcpu_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
> +	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
>  }
>  
>  static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
>  {
> -	if (vcpu_mode_is_32bit(vcpu))
> +	if (vcpu_mode_is_32bit(vcpu)) {
>  		*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
> -	else
> -		vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
> +	} else {
> +		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
> +		sctlr |= (1 << 25);
> +		vcpu_write_sys_reg(vcpu, SCTLR_EL1, sctlr);
> +	}
>  }
>  
>  static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
> @@ -306,7 +309,7 @@ static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
>  	if (vcpu_mode_is_32bit(vcpu))
>  		return !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_E_BIT);
>  
> -	return !!(vcpu_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
> +	return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
>  }
>  
>  static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index f2a6f39aec87..68398bf7882f 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -287,7 +287,18 @@ struct kvm_vcpu_arch {
>  };
>  
>  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
> -#define vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> +
> +/*
> + * Only use __vcpu_sys_reg if you know you want the memory backed version of a
> + * register, and not the one most recently accessed by a runnning VCPU.  For
> + * example, for userpace access or for system registers that are never context
> + * switched, but only emulated.
> + */
> +#define __vcpu_sys_reg(v,r)	((v)->arch.ctxt.sys_regs[(r)])
> +
> +#define vcpu_read_sys_reg(v,r)	__vcpu_sys_reg(v,r)
> +#define vcpu_write_sys_reg(v,r,n)	do { __vcpu_sys_reg(v,r) = n; } while (0)
> +
>  /*
>   * CP14 and CP15 live in the same array, as they are backed by the
>   * same system registers.
> diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> index 9679067a1574..95f46e73c4dc 100644
> --- a/arch/arm64/include/asm/kvm_mmu.h
> +++ b/arch/arm64/include/asm/kvm_mmu.h
> @@ -249,7 +249,7 @@ struct kvm;
>  
>  static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
>  {
> -	return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
> +	return (vcpu_read_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
>  }
>  
>  static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
> diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
> index feedb877cff8..db32d10a56a1 100644
> --- a/arch/arm64/kvm/debug.c
> +++ b/arch/arm64/kvm/debug.c
> @@ -46,7 +46,8 @@ static DEFINE_PER_CPU(u32, mdcr_el2);
>   */
>  static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
>  {
> -	vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1);
> +	vcpu->arch.guest_debug_preserved.mdscr_el1 =
> +		vcpu_read_sys_reg(vcpu, MDSCR_EL1);

This one would be 88 chars, but I won't tell if you don't tell :-)

>  
>  	trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
>  				vcpu->arch.guest_debug_preserved.mdscr_el1);
> @@ -54,10 +55,11 @@ static void save_guest_debug_regs(struct kvm_vcpu *vcpu)
>  
>  static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
>  {
> -	vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1;
> +	vcpu_write_sys_reg(vcpu, MDSCR_EL1,
> +			   vcpu->arch.guest_debug_preserved.mdscr_el1);

Another 88...

>  
>  	trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
> -				vcpu_sys_reg(vcpu, MDSCR_EL1));
> +				vcpu_read_sys_reg(vcpu, MDSCR_EL1));
>  }
>  
>  /**
> @@ -108,6 +110,7 @@ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
>  void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  {
>  	bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY);
> +	unsigned long mdscr;
>  
>  	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
>  
> @@ -152,9 +155,13 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  		 */
>  		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
>  			*vcpu_cpsr(vcpu) |=  DBG_SPSR_SS;
> -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_SS;
> +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> +			mdscr |= DBG_MDSCR_SS;
> +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
>  		} else {
> -			vcpu_sys_reg(vcpu, MDSCR_EL1) &= ~DBG_MDSCR_SS;
> +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> +			mdscr &= ~DBG_MDSCR_SS;
> +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
>  		}
>  
>  		trace_kvm_arm_set_dreg32("SPSR_EL2", *vcpu_cpsr(vcpu));
> @@ -170,7 +177,9 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  		 */
>  		if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) {
>  			/* Enable breakpoints/watchpoints */
> -			vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_MDE;
> +			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
> +			mdscr |= DBG_MDSCR_MDE;
> +			vcpu_write_sys_reg(vcpu, MDSCR_EL1, mdscr);
>  
>  			vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state;
>  			vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
> @@ -194,12 +203,12 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
>  		vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
>  
>  	/* If KDE or MDE are set, perform a full save/restore cycle. */
> -	if ((vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_KDE) ||
> -	    (vcpu_sys_reg(vcpu, MDSCR_EL1) & DBG_MDSCR_MDE))
> +	if (vcpu_read_sys_reg(vcpu, MDSCR_EL1) & (DBG_MDSCR_KDE | DBG_MDSCR_MDE))
>  		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
>  
>  	trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2);
> -	trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_sys_reg(vcpu, MDSCR_EL1));
> +	trace_kvm_arm_set_dreg32("MDSCR_EL1",
> +				 vcpu_read_sys_reg(vcpu, MDSCR_EL1));

Only 82. Maybe nobody would notice :-)

>  }
>  
>  void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
> diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> index 30a3f58cdb7b..e08db2f2dd75 100644
> --- a/arch/arm64/kvm/inject_fault.c
> +++ b/arch/arm64/kvm/inject_fault.c
> @@ -58,7 +58,7 @@ static u64 get_except_vector(struct kvm_vcpu *vcpu, enum exception_type type)
>  		exc_offset = LOWER_EL_AArch32_VECTOR;
>  	}
>  
> -	return vcpu_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
> +	return vcpu_read_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
>  }
>  
>  static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
> @@ -73,7 +73,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
>  	*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
>  	*vcpu_spsr(vcpu) = cpsr;
>  
> -	vcpu_sys_reg(vcpu, FAR_EL1) = addr;
> +	vcpu_write_sys_reg(vcpu, FAR_EL1, addr);
>  
>  	/*
>  	 * Build an {i,d}abort, depending on the level and the
> @@ -94,7 +94,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
>  	if (!is_iabt)
>  		esr |= ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT;
>  
> -	vcpu_sys_reg(vcpu, ESR_EL1) = esr | ESR_ELx_FSC_EXTABT;
> +	vcpu_write_sys_reg(vcpu, ESR_EL1, esr | ESR_ELx_FSC_EXTABT);
>  }
>  
>  static void inject_undef64(struct kvm_vcpu *vcpu)
> @@ -115,7 +115,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
>  	if (kvm_vcpu_trap_il_is32bit(vcpu))
>  		esr |= ESR_ELx_IL;
>  
> -	vcpu_sys_reg(vcpu, ESR_EL1) = esr;
> +	vcpu_write_sys_reg(vcpu, ESR_EL1, esr);
>  }
>  
>  /**
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index b48af790615e..a05d2c01c786 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -133,14 +133,14 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
>  	if (!p->is_aarch32 || !p->is_32bit) {
>  		val = p->regval;
>  	} else {
> -		val = vcpu_sys_reg(vcpu, reg);
> +		val = vcpu_read_sys_reg(vcpu, reg);
>  		if (r->reg % 2)
>  			val = (p->regval << 32) | (u64)lower_32_bits(val);
>  		else
>  			val = ((u64)upper_32_bits(val) << 32) |
>  				lower_32_bits(p->regval);
>  	}
> -	vcpu_sys_reg(vcpu, reg) = val;
> +	vcpu_write_sys_reg(vcpu, reg, val);
>  
>  	kvm_toggle_cache(vcpu, was_enabled);
>  	return true;
> @@ -241,10 +241,10 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
>  			    const struct sys_reg_desc *r)
>  {
>  	if (p->is_write) {
> -		vcpu_sys_reg(vcpu, r->reg) = p->regval;
> +		vcpu_write_sys_reg(vcpu, r->reg, p->regval);
>  		vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, r->reg);
> +		p->regval = vcpu_read_sys_reg(vcpu, r->reg);
>  	}
>  
>  	trace_trap_reg(__func__, r->reg, p->is_write, p->regval);
> @@ -457,7 +457,8 @@ static void reset_wcr(struct kvm_vcpu *vcpu,
>  
>  static void reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  {
> -	vcpu_sys_reg(vcpu, AMAIR_EL1) = read_sysreg(amair_el1);
> +	u64 amair = read_sysreg(amair_el1);
> +	vcpu_write_sys_reg(vcpu, AMAIR_EL1, amair);
>  }
>  
>  static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> @@ -474,7 +475,7 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  	mpidr = (vcpu->vcpu_id & 0x0f) << MPIDR_LEVEL_SHIFT(0);
>  	mpidr |= ((vcpu->vcpu_id >> 4) & 0xff) << MPIDR_LEVEL_SHIFT(1);
>  	mpidr |= ((vcpu->vcpu_id >> 12) & 0xff) << MPIDR_LEVEL_SHIFT(2);
> -	vcpu_sys_reg(vcpu, MPIDR_EL1) = (1ULL << 31) | mpidr;
> +	vcpu_write_sys_reg(vcpu, MPIDR_EL1, (1ULL << 31) | mpidr);
>  }
>  
>  static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
> @@ -488,12 +489,12 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  	 */
>  	val = ((pmcr & ~ARMV8_PMU_PMCR_MASK)
>  	       | (ARMV8_PMU_PMCR_MASK & 0xdecafbad)) & (~ARMV8_PMU_PMCR_E);
> -	vcpu_sys_reg(vcpu, PMCR_EL0) = val;
> +	__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
>  }
>  
>  static bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags)
>  {
> -	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +	u64 reg = __vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>  	bool enabled = (reg & flags) || vcpu_mode_priv(vcpu);
>  
>  	if (!enabled)
> @@ -535,14 +536,14 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  
>  	if (p->is_write) {
>  		/* Only update writeable bits of PMCR */
> -		val = vcpu_sys_reg(vcpu, PMCR_EL0);
> +		val = __vcpu_sys_reg(vcpu, PMCR_EL0);
>  		val &= ~ARMV8_PMU_PMCR_MASK;
>  		val |= p->regval & ARMV8_PMU_PMCR_MASK;
> -		vcpu_sys_reg(vcpu, PMCR_EL0) = val;
> +		__vcpu_sys_reg(vcpu, PMCR_EL0) = val;
>  		kvm_pmu_handle_pmcr(vcpu, val);
>  	} else {
>  		/* PMCR.P & PMCR.C are RAZ */
> -		val = vcpu_sys_reg(vcpu, PMCR_EL0)
> +		val = __vcpu_sys_reg(vcpu, PMCR_EL0)
>  		      & ~(ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C);
>  		p->regval = val;
>  	}
> @@ -560,10 +561,10 @@ static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  		return false;
>  
>  	if (p->is_write)
> -		vcpu_sys_reg(vcpu, PMSELR_EL0) = p->regval;
> +		__vcpu_sys_reg(vcpu, PMSELR_EL0) = p->regval;
>  	else
>  		/* return PMSELR.SEL field */
> -		p->regval = vcpu_sys_reg(vcpu, PMSELR_EL0)
> +		p->regval = __vcpu_sys_reg(vcpu, PMSELR_EL0)
>  			    & ARMV8_PMU_COUNTER_MASK;

This isn't a new line break and would be 86, but...

>  
>  	return true;
> @@ -596,7 +597,7 @@ static bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
>  {
>  	u64 pmcr, val;
>  
> -	pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
> +	pmcr = __vcpu_sys_reg(vcpu, PMCR_EL0);
>  	val = (pmcr >> ARMV8_PMU_PMCR_N_SHIFT) & ARMV8_PMU_PMCR_N_MASK;
>  	if (idx >= val && idx != ARMV8_PMU_CYCLE_IDX) {
>  		kvm_inject_undefined(vcpu);
> @@ -621,7 +622,7 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
>  			if (pmu_access_event_counter_el0_disabled(vcpu))
>  				return false;
>  
> -			idx = vcpu_sys_reg(vcpu, PMSELR_EL0)
> +			idx = __vcpu_sys_reg(vcpu, PMSELR_EL0)
>  			      & ARMV8_PMU_COUNTER_MASK;

This old one would be 88.

>  		} else if (r->Op2 == 0) {
>  			/* PMCCNTR_EL0 */
> @@ -676,7 +677,7 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  
>  	if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 1) {
>  		/* PMXEVTYPER_EL0 */
> -		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_PMU_COUNTER_MASK;
> +		idx = __vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_PMU_COUNTER_MASK;
>  		reg = PMEVTYPER0_EL0 + idx;
>  	} else if (r->CRn == 14 && (r->CRm & 12) == 12) {
>  		idx = ((r->CRm & 3) << 3) | (r->Op2 & 7);
> @@ -694,9 +695,9 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  
>  	if (p->is_write) {
>  		kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
> -		vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_PMU_EVTYPE_MASK;
> +		__vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_PMU_EVTYPE_MASK;
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK;
> +		p->regval = __vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK;
>  	}
>  
>  	return true;
> @@ -718,15 +719,15 @@ static bool access_pmcnten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  		val = p->regval & mask;
>  		if (r->Op2 & 0x1) {
>  			/* accessing PMCNTENSET_EL0 */
> -			vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val;
> +			__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val;
>  			kvm_pmu_enable_counter(vcpu, val);
>  		} else {
>  			/* accessing PMCNTENCLR_EL0 */
> -			vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val;
> +			__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val;
>  			kvm_pmu_disable_counter(vcpu, val);
>  		}
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask;
> +		p->regval = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask;
>  	}
>  
>  	return true;
> @@ -750,12 +751,12 @@ static bool access_pminten(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  
>  		if (r->Op2 & 0x1)
>  			/* accessing PMINTENSET_EL1 */
> -			vcpu_sys_reg(vcpu, PMINTENSET_EL1) |= val;
> +			__vcpu_sys_reg(vcpu, PMINTENSET_EL1) |= val;
>  		else
>  			/* accessing PMINTENCLR_EL1 */
> -			vcpu_sys_reg(vcpu, PMINTENSET_EL1) &= ~val;
> +			__vcpu_sys_reg(vcpu, PMINTENSET_EL1) &= ~val;
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, PMINTENSET_EL1) & mask;
> +		p->regval = __vcpu_sys_reg(vcpu, PMINTENSET_EL1) & mask;
>  	}
>  
>  	return true;
> @@ -775,12 +776,12 @@ static bool access_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	if (p->is_write) {
>  		if (r->CRm & 0x2)
>  			/* accessing PMOVSSET_EL0 */
> -			vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= (p->regval & mask);
> +			__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= (p->regval & mask);
>  		else
>  			/* accessing PMOVSCLR_EL0 */
> -			vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= ~(p->regval & mask);
> +			__vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= ~(p->regval & mask);
>  	} else {
> -		p->regval = vcpu_sys_reg(vcpu, PMOVSSET_EL0) & mask;
> +		p->regval = __vcpu_sys_reg(vcpu, PMOVSSET_EL0) & mask;
>  	}
>  
>  	return true;
> @@ -817,10 +818,10 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  			return false;
>  		}
>  
> -		vcpu_sys_reg(vcpu, PMUSERENR_EL0) = p->regval
> -						    & ARMV8_PMU_USERENR_MASK;
> -	} else {
> -		p->regval = vcpu_sys_reg(vcpu, PMUSERENR_EL0)
> +		__vcpu_sys_reg(vcpu, PMUSERENR_EL0) =
> +			       p->regval & ARMV8_PMU_USERENR_MASK;

Just when I thought 88 could be the new 80, this one is 89.


> +	} else  {
> +		p->regval = __vcpu_sys_reg(vcpu, PMUSERENR_EL0)
>  			    & ARMV8_PMU_USERENR_MASK;

Old one, would be 89.

>  	}
>  
> @@ -2204,7 +2205,7 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
>  	if (r->get_user)
>  		return (r->get_user)(vcpu, r, reg, uaddr);
>  
> -	return reg_to_user(uaddr, &vcpu_sys_reg(vcpu, r->reg), reg->id);
> +	return reg_to_user(uaddr, &__vcpu_sys_reg(vcpu, r->reg), reg->id);
>  }
>  
>  int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> @@ -2225,7 +2226,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
>  	if (r->set_user)
>  		return (r->set_user)(vcpu, r, reg, uaddr);
>  
> -	return reg_from_user(&vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
> +	return reg_from_user(&__vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
>  }
>  
>  static unsigned int num_demux_regs(void)
> @@ -2431,6 +2432,6 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
>  	reset_sys_reg_descs(vcpu, table, num);
>  
>  	for (num = 1; num < NR_SYS_REGS; num++)
> -		if (vcpu_sys_reg(vcpu, num) == 0x4242424242424242)
> -			panic("Didn't reset vcpu_sys_reg(%zi)", num);
> +		if (__vcpu_sys_reg(vcpu, num) == 0x4242424242424242)
> +			panic("Didn't reset __vcpu_sys_reg(%zi)", num);
>  }
> diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
> index 060f5348ef25..cd710f8b63e0 100644
> --- a/arch/arm64/kvm/sys_regs.h
> +++ b/arch/arm64/kvm/sys_regs.h
> @@ -89,14 +89,14 @@ static inline void reset_unknown(struct kvm_vcpu *vcpu,
>  {
>  	BUG_ON(!r->reg);
>  	BUG_ON(r->reg >= NR_SYS_REGS);
> -	vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
> +	__vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
>  }
>  
>  static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  {
>  	BUG_ON(!r->reg);
>  	BUG_ON(r->reg >= NR_SYS_REGS);
> -	vcpu_sys_reg(vcpu, r->reg) = r->val;
> +	__vcpu_sys_reg(vcpu, r->reg) = r->val;
>  }
>  
>  static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
> diff --git a/arch/arm64/kvm/sys_regs_generic_v8.c b/arch/arm64/kvm/sys_regs_generic_v8.c
> index 969ade1d333d..ddb8497d18d6 100644
> --- a/arch/arm64/kvm/sys_regs_generic_v8.c
> +++ b/arch/arm64/kvm/sys_regs_generic_v8.c
> @@ -38,13 +38,13 @@ static bool access_actlr(struct kvm_vcpu *vcpu,
>  	if (p->is_write)
>  		return ignore_write(vcpu, p);
>  
> -	p->regval = vcpu_sys_reg(vcpu, ACTLR_EL1);
> +	p->regval = vcpu_read_sys_reg(vcpu, ACTLR_EL1);
>  	return true;
>  }
>  
>  static void reset_actlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  {
> -	vcpu_sys_reg(vcpu, ACTLR_EL1) = read_sysreg(actlr_el1);
> +	__vcpu_sys_reg(vcpu, ACTLR_EL1) = read_sysreg(actlr_el1);
>  }
>  
>  /*
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 8a9c42366db7..29cb4a1ff26b 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -37,7 +37,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
>  
>  	reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
>  	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
> -	counter = vcpu_sys_reg(vcpu, reg);
> +	counter = __vcpu_sys_reg(vcpu, reg);
>  
>  	/* The real counter value is equal to the value of counter register plus
>  	 * the value perf event counts.
> @@ -61,7 +61,8 @@ void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val)
>  
>  	reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
>  	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
> -	vcpu_sys_reg(vcpu, reg) += (s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);
> +	__vcpu_sys_reg(vcpu, reg) +=
> +		(s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);

I guess I won't complain about 92.

>  }
>  
>  /**
> @@ -78,7 +79,7 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
>  		counter = kvm_pmu_get_counter_value(vcpu, pmc->idx);
>  		reg = (pmc->idx == ARMV8_PMU_CYCLE_IDX)
>  		       ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + pmc->idx;
> -		vcpu_sys_reg(vcpu, reg) = counter;
> +		__vcpu_sys_reg(vcpu, reg) = counter;
>  		perf_event_disable(pmc->perf_event);
>  		perf_event_release_kernel(pmc->perf_event);
>  		pmc->perf_event = NULL;
> @@ -125,7 +126,7 @@ void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu)
>  
>  u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
>  {
> -	u64 val = vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMU_PMCR_N_SHIFT;
> +	u64 val = __vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMU_PMCR_N_SHIFT;
>  
>  	val &= ARMV8_PMU_PMCR_N_MASK;
>  	if (val == 0)
> @@ -147,7 +148,7 @@ void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val)
>  	struct kvm_pmu *pmu = &vcpu->arch.pmu;
>  	struct kvm_pmc *pmc;
>  
> -	if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) || !val)
> +	if (!(__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) || !val)
>  		return;
>  
>  	for (i = 0; i < ARMV8_PMU_MAX_COUNTERS; i++) {
> @@ -193,10 +194,10 @@ static u64 kvm_pmu_overflow_status(struct kvm_vcpu *vcpu)
>  {
>  	u64 reg = 0;
>  
> -	if ((vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E)) {
> -		reg = vcpu_sys_reg(vcpu, PMOVSSET_EL0);
> -		reg &= vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> -		reg &= vcpu_sys_reg(vcpu, PMINTENSET_EL1);
> +	if ((__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E)) {
> +		reg = __vcpu_sys_reg(vcpu, PMOVSSET_EL0);
> +		reg &= __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> +		reg &= __vcpu_sys_reg(vcpu, PMINTENSET_EL1);
>  		reg &= kvm_pmu_valid_counter_mask(vcpu);
>  	}
>  
> @@ -295,7 +296,7 @@ static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
>  	struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
>  	int idx = pmc->idx;
>  
> -	vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(idx);
> +	__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(idx);
>  
>  	if (kvm_pmu_overflow_status(vcpu)) {
>  		kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
> @@ -316,19 +317,19 @@ void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
>  	if (val == 0)
>  		return;
>  
> -	enable = vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> +	enable = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
>  	for (i = 0; i < ARMV8_PMU_CYCLE_IDX; i++) {
>  		if (!(val & BIT(i)))
>  			continue;
> -		type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
> +		type = __vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
>  		       & ARMV8_PMU_EVTYPE_EVENT;
>  		if ((type == ARMV8_PMUV3_PERFCTR_SW_INCR)
>  		    && (enable & BIT(i))) {
> -			reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
> +			reg = __vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
>  			reg = lower_32_bits(reg);
> -			vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
> +			__vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
>  			if (!reg)
> -				vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
> +				__vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= BIT(i);
>  		}
>  	}
>  }
> @@ -348,7 +349,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
>  	mask = kvm_pmu_valid_counter_mask(vcpu);
>  	if (val & ARMV8_PMU_PMCR_E) {
>  		kvm_pmu_enable_counter(vcpu,
> -				vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask);
> +		       __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & mask);

This one looks pretty OK, and would be 90 anyway.

>  	} else {
>  		kvm_pmu_disable_counter(vcpu, mask);
>  	}
> @@ -369,8 +370,8 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
>  
>  static bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu, u64 select_idx)
>  {
> -	return (vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) &&
> -	       (vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
> +	return (__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) &&
> +	       (__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
>  }
>  
>  /**
> -- 
> 2.14.2
>

Thanks,
drew 

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

* Re: [PATCH v4 31/40] KVM: arm64: Move common VHE/non-VHE trap config in separate functions
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-22 15:34     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 15:34 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, kvmarm, Yury Norov, linux-arm-kernel,
	Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:23PM +0100, Christoffer Dall wrote:
> As we are about to be more lazy with some of the trap configuration
> register read/writes for VHE systems, move the logic that is currently
> shared between VHE and non-VHE into a separate function which can be
> called from either the world-switch path or from vcpu_load/vcpu_put.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Separate fpsimd32 trap configuration into a separate function
>        which is still called from __activate_traps, because we no longer
>        defer saving/restoring of VFP registers to load/put.
> 
>  arch/arm64/kvm/hyp/switch.c | 76 +++++++++++++++++++++++++++------------------
>  1 file changed, 45 insertions(+), 31 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 909aa3fe9196..17e3c6f26a34 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -56,7 +56,45 @@ static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
>  	vcpu->arch.ctxt.sys_regs[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
>  }
>  
> -static void __hyp_text __activate_traps_vhe(void)
> +static void __hyp_text __activate_traps_fpsimd32(struct kvm_vcpu *vcpu)
> +{
> +	/*
> +	 * We are about to set CPTR_EL2.TFP to trap all floating point
> +	 * register accesses to EL2, however, the ARM ARM clearly states that
> +	 * traps are only taken to EL2 if the operation would not otherwise
> +	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> +	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> +	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> +	 * it will cause an exception.
> +	 */
> +	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> +		write_sysreg(1 << 30, fpexc32_el2);
> +		isb();
> +	}
> +}
> +
> +static void __hyp_text __activate_traps_common(struct kvm_vcpu *vcpu)
> +{
> +	/* Trap on AArch32 cp15 c15 (impdef sysregs) accesses (EL1 or EL0) */
> +	write_sysreg(1 << 15, hstr_el2);

Could use a blank line here.

> +	/*
> +	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> +	 * PMSELR_EL0 to make sure it never contains the cycle
> +	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> +	 * EL1 instead of being trapped to EL2.
> +	 */
> +	write_sysreg(0, pmselr_el0);
> +	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> +	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> +}
> +
> +static void __hyp_text __deactivate_traps_common(void)
> +{
> +	write_sysreg(0, hstr_el2);
> +	write_sysreg(0, pmuserenr_el0);
> +}
> +
> +static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
>  {
>  	u64 val;
>  
> @@ -68,7 +106,7 @@ static void __hyp_text __activate_traps_vhe(void)
>  	write_sysreg(kvm_get_hyp_vector(), vbar_el1);
>  }
>  
> -static void __hyp_text __activate_traps_nvhe(void)
> +static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
>  {
>  	u64 val;
>  
> @@ -85,37 +123,14 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
>  {
>  	u64 hcr = vcpu->arch.hcr_el2;
>  
> -	/*
> -	 * We are about to set CPTR_EL2.TFP to trap all floating point
> -	 * register accesses to EL2, however, the ARM ARM clearly states that
> -	 * traps are only taken to EL2 if the operation would not otherwise
> -	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> -	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> -	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> -	 * it will cause an exception.
> -	 */
> -	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> -		write_sysreg(1 << 30, fpexc32_el2);
> -		isb();
> -	}
> +	write_sysreg(hcr, hcr_el2);
>  
>  	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
>  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
>  
> -	write_sysreg(hcr, hcr_el2);
> -
> -	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
> -	write_sysreg(1 << 15, hstr_el2);
> -	/*
> -	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> -	 * PMSELR_EL0 to make sure it never contains the cycle
> -	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> -	 * EL1 instead of being trapped to EL2.
> -	 */
> -	write_sysreg(0, pmselr_el0);
> -	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> -	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> -	__activate_traps_arch()();
> +	__activate_traps_fpsimd32(vcpu);
> +	__activate_traps_common(vcpu);
> +	__activate_traps_arch()(vcpu);
>  }
>  
>  static void __hyp_text __deactivate_traps_vhe(void)
> @@ -160,9 +175,8 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
>  	if (vcpu->arch.hcr_el2 & HCR_VSE)
>  		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
>  
> +	__deactivate_traps_common();
>  	__deactivate_traps_arch()();
> -	write_sysreg(0, hstr_el2);
> -	write_sysreg(0, pmuserenr_el0);
>  }
>  
>  static void __hyp_text __activate_vm(struct kvm *kvm)
> -- 
> 2.14.2
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 31/40] KVM: arm64: Move common VHE/non-VHE trap config in separate functions
@ 2018-02-22 15:34     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 15:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:23PM +0100, Christoffer Dall wrote:
> As we are about to be more lazy with some of the trap configuration
> register read/writes for VHE systems, move the logic that is currently
> shared between VHE and non-VHE into a separate function which can be
> called from either the world-switch path or from vcpu_load/vcpu_put.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - Separate fpsimd32 trap configuration into a separate function
>        which is still called from __activate_traps, because we no longer
>        defer saving/restoring of VFP registers to load/put.
> 
>  arch/arm64/kvm/hyp/switch.c | 76 +++++++++++++++++++++++++++------------------
>  1 file changed, 45 insertions(+), 31 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 909aa3fe9196..17e3c6f26a34 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -56,7 +56,45 @@ static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
>  	vcpu->arch.ctxt.sys_regs[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
>  }
>  
> -static void __hyp_text __activate_traps_vhe(void)
> +static void __hyp_text __activate_traps_fpsimd32(struct kvm_vcpu *vcpu)
> +{
> +	/*
> +	 * We are about to set CPTR_EL2.TFP to trap all floating point
> +	 * register accesses to EL2, however, the ARM ARM clearly states that
> +	 * traps are only taken to EL2 if the operation would not otherwise
> +	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> +	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> +	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> +	 * it will cause an exception.
> +	 */
> +	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> +		write_sysreg(1 << 30, fpexc32_el2);
> +		isb();
> +	}
> +}
> +
> +static void __hyp_text __activate_traps_common(struct kvm_vcpu *vcpu)
> +{
> +	/* Trap on AArch32 cp15 c15 (impdef sysregs) accesses (EL1 or EL0) */
> +	write_sysreg(1 << 15, hstr_el2);

Could use a blank line here.

> +	/*
> +	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> +	 * PMSELR_EL0 to make sure it never contains the cycle
> +	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> +	 * EL1 instead of being trapped to EL2.
> +	 */
> +	write_sysreg(0, pmselr_el0);
> +	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> +	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> +}
> +
> +static void __hyp_text __deactivate_traps_common(void)
> +{
> +	write_sysreg(0, hstr_el2);
> +	write_sysreg(0, pmuserenr_el0);
> +}
> +
> +static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
>  {
>  	u64 val;
>  
> @@ -68,7 +106,7 @@ static void __hyp_text __activate_traps_vhe(void)
>  	write_sysreg(kvm_get_hyp_vector(), vbar_el1);
>  }
>  
> -static void __hyp_text __activate_traps_nvhe(void)
> +static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
>  {
>  	u64 val;
>  
> @@ -85,37 +123,14 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
>  {
>  	u64 hcr = vcpu->arch.hcr_el2;
>  
> -	/*
> -	 * We are about to set CPTR_EL2.TFP to trap all floating point
> -	 * register accesses to EL2, however, the ARM ARM clearly states that
> -	 * traps are only taken to EL2 if the operation would not otherwise
> -	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> -	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> -	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> -	 * it will cause an exception.
> -	 */
> -	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> -		write_sysreg(1 << 30, fpexc32_el2);
> -		isb();
> -	}
> +	write_sysreg(hcr, hcr_el2);
>  
>  	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
>  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
>  
> -	write_sysreg(hcr, hcr_el2);
> -
> -	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
> -	write_sysreg(1 << 15, hstr_el2);
> -	/*
> -	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> -	 * PMSELR_EL0 to make sure it never contains the cycle
> -	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> -	 * EL1 instead of being trapped to EL2.
> -	 */
> -	write_sysreg(0, pmselr_el0);
> -	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> -	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> -	__activate_traps_arch()();
> +	__activate_traps_fpsimd32(vcpu);
> +	__activate_traps_common(vcpu);
> +	__activate_traps_arch()(vcpu);
>  }
>  
>  static void __hyp_text __deactivate_traps_vhe(void)
> @@ -160,9 +175,8 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
>  	if (vcpu->arch.hcr_el2 & HCR_VSE)
>  		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
>  
> +	__deactivate_traps_common();
>  	__deactivate_traps_arch()();
> -	write_sysreg(0, hstr_el2);
> -	write_sysreg(0, pmuserenr_el0);
>  }
>  
>  static void __hyp_text __activate_vm(struct kvm *kvm)
> -- 
> 2.14.2
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 32/40] KVM: arm64: Directly call VHE and non-VHE FPSIMD enabled functions
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-22 15:38     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 15:38 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, kvmarm, Yury Norov, linux-arm-kernel,
	Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:24PM +0100, Christoffer Dall wrote:
> There is no longer a need for an alternative to choose the right
> function to tell us whether or not FPSIMD was enabled for the VM,
> because we can simply cann the appropriate functions directly fromwithin

s/cann/call/
s/fromwithin/from within/

> the _vhe and _nvhe run functions.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - New patch since we no longer defer FPSIMD handling to load/put
> 
>  arch/arm64/kvm/hyp/switch.c | 15 +++------------
>  1 file changed, 3 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 17e3c6f26a34..9c40e203bd09 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -33,20 +33,11 @@ static bool __hyp_text __fpsimd_enabled_nvhe(void)
>  	return !(read_sysreg(cptr_el2) & CPTR_EL2_TFP);
>  }
>  
> -static bool __hyp_text __fpsimd_enabled_vhe(void)
> +static bool fpsimd_enabled_vhe(void)
>  {
>  	return !!(read_sysreg(cpacr_el1) & CPACR_EL1_FPEN);
>  }
>  
> -static hyp_alternate_select(__fpsimd_is_enabled,
> -			    __fpsimd_enabled_nvhe, __fpsimd_enabled_vhe,
> -			    ARM64_HAS_VIRT_HOST_EXTN);
> -
> -bool __hyp_text __fpsimd_enabled(void)
> -{
> -	return __fpsimd_is_enabled()();
> -}
> -
>  /* Save the 32-bit only FPSIMD system register state */
>  static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
>  {
> @@ -413,7 +404,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  		/* And we're baaack! */
>  	} while (fixup_guest_exit(vcpu, &exit_code));
>  
> -	fp_enabled = __fpsimd_enabled();
> +	fp_enabled = fpsimd_enabled_vhe();
>  
>  	sysreg_save_guest_state_vhe(guest_ctxt);
>  	__vgic_save_state(vcpu);
> @@ -478,7 +469,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
>  			__qcom_hyp_sanitize_btac_predictors();
>  	}
>  
> -	fp_enabled = __fpsimd_enabled();
> +	fp_enabled = __fpsimd_enabled_nvhe();
>  
>  	__sysreg_save_state_nvhe(guest_ctxt);
>  	__sysreg32_save_state(vcpu);
> -- 
> 2.14.2
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 32/40] KVM: arm64: Directly call VHE and non-VHE FPSIMD enabled functions
@ 2018-02-22 15:38     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 15:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:24PM +0100, Christoffer Dall wrote:
> There is no longer a need for an alternative to choose the right
> function to tell us whether or not FPSIMD was enabled for the VM,
> because we can simply cann the appropriate functions directly fromwithin

s/cann/call/
s/fromwithin/from within/

> the _vhe and _nvhe run functions.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>     Changes since v3:
>      - New patch since we no longer defer FPSIMD handling to load/put
> 
>  arch/arm64/kvm/hyp/switch.c | 15 +++------------
>  1 file changed, 3 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 17e3c6f26a34..9c40e203bd09 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -33,20 +33,11 @@ static bool __hyp_text __fpsimd_enabled_nvhe(void)
>  	return !(read_sysreg(cptr_el2) & CPTR_EL2_TFP);
>  }
>  
> -static bool __hyp_text __fpsimd_enabled_vhe(void)
> +static bool fpsimd_enabled_vhe(void)
>  {
>  	return !!(read_sysreg(cpacr_el1) & CPACR_EL1_FPEN);
>  }
>  
> -static hyp_alternate_select(__fpsimd_is_enabled,
> -			    __fpsimd_enabled_nvhe, __fpsimd_enabled_vhe,
> -			    ARM64_HAS_VIRT_HOST_EXTN);
> -
> -bool __hyp_text __fpsimd_enabled(void)
> -{
> -	return __fpsimd_is_enabled()();
> -}
> -
>  /* Save the 32-bit only FPSIMD system register state */
>  static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
>  {
> @@ -413,7 +404,7 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>  		/* And we're baaack! */
>  	} while (fixup_guest_exit(vcpu, &exit_code));
>  
> -	fp_enabled = __fpsimd_enabled();
> +	fp_enabled = fpsimd_enabled_vhe();
>  
>  	sysreg_save_guest_state_vhe(guest_ctxt);
>  	__vgic_save_state(vcpu);
> @@ -478,7 +469,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
>  			__qcom_hyp_sanitize_btac_predictors();
>  	}
>  
> -	fp_enabled = __fpsimd_enabled();
> +	fp_enabled = __fpsimd_enabled_nvhe();
>  
>  	__sysreg_save_state_nvhe(guest_ctxt);
>  	__sysreg32_save_state(vcpu);
> -- 
> 2.14.2
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 33/40] KVM: arm64: Configure c15, PMU, and debug register traps on cpu load/put for VHE
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-22 15:51     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 15:51 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, kvmarm, Yury Norov, linux-arm-kernel,
	Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:25PM +0100, Christoffer Dall wrote:
> We do not have to change the c15 trap setting on each switch to/from the
> guest on VHE systems, because this setting only affects EL0.
> 
> The PMU and debug trap configuration can also be done on vcpu load/put
> instead, because they don't affect how the host kernel can access the
> debug registers while executing KVM kernel code.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/include/asm/kvm_hyp.h |  3 +++
>  arch/arm64/kvm/hyp/switch.c      | 31 ++++++++++++++++++++++---------
>  arch/arm64/kvm/hyp/sysreg-sr.c   |  4 ++++
>  3 files changed, 29 insertions(+), 9 deletions(-)
>

The last patch 32/40 probably should have been closer to 13/40 in
this series. That would allow this patch to directly follow it's
preparatory patch 31/40, but I'm just whiny reviewer...

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 33/40] KVM: arm64: Configure c15, PMU, and debug register traps on cpu load/put for VHE
@ 2018-02-22 15:51     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 15:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:25PM +0100, Christoffer Dall wrote:
> We do not have to change the c15 trap setting on each switch to/from the
> guest on VHE systems, because this setting only affects EL0.
> 
> The PMU and debug trap configuration can also be done on vcpu load/put
> instead, because they don't affect how the host kernel can access the
> debug registers while executing KVM kernel code.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/include/asm/kvm_hyp.h |  3 +++
>  arch/arm64/kvm/hyp/switch.c      | 31 ++++++++++++++++++++++---------
>  arch/arm64/kvm/hyp/sysreg-sr.c   |  4 ++++
>  3 files changed, 29 insertions(+), 9 deletions(-)
>

The last patch 32/40 probably should have been closer to 13/40 in
this series. That would allow this patch to directly follow it's
preparatory patch 31/40, but I'm just whiny reviewer...

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 34/40] KVM: arm64: Cleanup __activate_traps and __deactive_traps for VHE and non-VHE
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-22 15:54     ` Andrew Jones
  -1 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 15:54 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, Marc Zyngier, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 15, 2018 at 10:03:26PM +0100, Christoffer Dall wrote:
> To make the code more readable and to avoid the overhead of a function
> call, let's get rid of a pair of the alternative function selectors and
> explicitly call the VHE and non-VHE functions using the has_vhe() static
> key based selector instead, telling the compiler to try to inline the
> static function if it can.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/kvm/hyp/switch.c | 30 ++++++++++++++----------------
>  1 file changed, 14 insertions(+), 16 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* [PATCH v4 34/40] KVM: arm64: Cleanup __activate_traps and __deactive_traps for VHE and non-VHE
@ 2018-02-22 15:54     ` Andrew Jones
  0 siblings, 0 replies; 276+ messages in thread
From: Andrew Jones @ 2018-02-22 15:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 15, 2018 at 10:03:26PM +0100, Christoffer Dall wrote:
> To make the code more readable and to avoid the overhead of a function
> call, let's get rid of a pair of the alternative function selectors and
> explicitly call the VHE and non-VHE functions using the has_vhe() static
> key based selector instead, telling the compiler to try to inline the
> static function if it can.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
>  arch/arm64/kvm/hyp/switch.c | 30 ++++++++++++++----------------
>  1 file changed, 14 insertions(+), 16 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
  2018-02-22 15:11     ` Andrew Jones
@ 2018-02-22 15:58       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 15:58 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Christoffer Dall, kvm, Marc Zyngier, Tomasz Nowicki, kvmarm,
	Julien Grall, Yury Norov, linux-arm-kernel, Dave Martin,
	Shih-Wei Li

On Thu, Feb 22, 2018 at 04:11:38PM +0100, Andrew Jones wrote:
> 
> Hi Christoffer,
> 
> I'm just pointing out some broken lines that we could maybe cheat the
> 80-char limit on. Naturally feel free to ignore.

Thanks.  I'll go over them as I respin.

-Christoffer

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

* [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions
@ 2018-02-22 15:58       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 15:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 22, 2018 at 04:11:38PM +0100, Andrew Jones wrote:
> 
> Hi Christoffer,
> 
> I'm just pointing out some broken lines that we could maybe cheat the
> 80-char limit on. Naturally feel free to ignore.

Thanks.  I'll go over them as I respin.

-Christoffer

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

* Re: [PATCH v4 38/40] KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on VHE
  2018-02-22 15:01         ` Marc Zyngier
@ 2018-02-22 16:02           ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 16:02 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 22, 2018 at 03:01:17PM +0000, Marc Zyngier wrote:
> On Thu, 22 Feb 2018 14:42:27 +0000,
> Christoffer Dall wrote:
> > 
> > On Thu, Feb 22, 2018 at 12:32:11PM +0000, Marc Zyngier wrote:
> > > On 15/02/18 21:03, Christoffer Dall wrote:
> > > > Just like we can program the GICv2 hypervisor control interface directly
> > > > from the core vgic code, we can do the same for the GICv3 hypervisor
> > > > control interface on VHE systems.
> > > > 
> > > > We do this by simply calling the save/restore functions when we have VHE
> > > > and we can then get rid of the save/restore function calls from the VHE
> > > > world switch function.
> > > > 
> > > > One caveat is that we now write GICv3 system register state before the
> > > > potential early exit path in the run loop, and because we sync back
> > > > state in the early exit path, we have to ensure that we read a
> > > > consistent GIC state from the sync path, even though we have never
> > > > actually run the guest with the newly written GIC state.  We solve this
> > > > by inserting an ISB in the early exit path.
> > > > 
> > > > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > > > ---
> > > > 
> > > > Notes:
> > > >     Changes since v2:
> > > >      - Added ISB in the early exit path in the run loop as explained
> > > >        in the commit message.
> > > > 
> > > >  arch/arm64/kvm/hyp/switch.c | 3 ---
> > > >  virt/kvm/arm/arm.c          | 1 +
> > > >  virt/kvm/arm/vgic/vgic.c    | 5 +++++
> > > >  3 files changed, 6 insertions(+), 3 deletions(-)
> > > > 
> > > > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > > > index cbafc27a617b..466cfcdbcaf3 100644
> > > > --- a/arch/arm64/kvm/hyp/switch.c
> > > > +++ b/arch/arm64/kvm/hyp/switch.c
> > > > @@ -399,8 +399,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> > > >  	__activate_traps(vcpu);
> > > >  	__activate_vm(vcpu->kvm);
> > > >  
> > > > -	__vgic_restore_state(vcpu);
> > > > -
> > > >  	sysreg_restore_guest_state_vhe(guest_ctxt);
> > > >  	__debug_switch_to_guest(vcpu);
> > > >  
> > > > @@ -414,7 +412,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> > > >  	fp_enabled = fpsimd_enabled_vhe();
> > > >  
> > > >  	sysreg_save_guest_state_vhe(guest_ctxt);
> > > > -	__vgic_save_state(vcpu);
> > > >  
> > > >  	__deactivate_traps(vcpu);
> > > >  
> > > > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > > > index 5bd879c78951..6de7641f3ff2 100644
> > > > --- a/virt/kvm/arm/arm.c
> > > > +++ b/virt/kvm/arm/arm.c
> > > > @@ -717,6 +717,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> > > >  		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
> > > >  		    kvm_request_pending(vcpu)) {
> > > >  			vcpu->mode = OUTSIDE_GUEST_MODE;
> > > > +			isb(); /* Ensure work in x_flush_hwstate is committed */
> > > >  			kvm_pmu_sync_hwstate(vcpu);
> > > >  			if (static_branch_unlikely(&userspace_irqchip_in_use))
> > > >  				kvm_timer_sync_hwstate(vcpu);
> > > > diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> > > > index 12e2a28f437e..d0a19a8c196a 100644
> > > > --- a/virt/kvm/arm/vgic/vgic.c
> > > > +++ b/virt/kvm/arm/vgic/vgic.c
> > > > @@ -19,6 +19,7 @@
> > > >  #include <linux/list_sort.h>
> > > >  #include <linux/interrupt.h>
> > > >  #include <linux/irq.h>
> > > > +#include <asm/kvm_hyp.h>
> > > >  
> > > >  #include "vgic.h"
> > > >  
> > > > @@ -753,6 +754,8 @@ static inline void vgic_save_state(struct kvm_vcpu *vcpu)
> > > >  {
> > > >  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> > > >  		vgic_v2_save_state(vcpu);
> > > > +	else if (has_vhe())
> > > > +		__vgic_v3_save_state(vcpu);
> > > >  }
> > > >  
> > > >  /* Sync back the hardware VGIC state into our emulation after a guest's run. */
> > > > @@ -777,6 +780,8 @@ static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
> > > >  {
> > > >  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> > > >  		vgic_v2_restore_state(vcpu);
> > > > +	else if (has_vhe())
> > > > +		__vgic_v3_restore_state(vcpu);
> > > >  }
> > > >  
> > > >  /* Flush our emulation state into the GIC hardware before entering the guest. */
> > > > 
> > > 
> > > I'm slowly wrapping my brain around this thing again. If I grasp the
> > > general idea, we end up with two cases:
> > > 
> > > (1) The GIC is accessible from the kernel, and we save/restore it
> > > outside of the HYP code.
> > > 
> > > (2) The GIC is only accessible from the HYP code, and we do it there.
> > > 
> > > Maybe we should bite the bullet and introduce that primitive instead?
> > > 
> > 
> > You mean something the following?
> > 
> > static inline bool can_access_vgic_from_kernel(void)
> > {
> > 	/*
> > 	 * GICv2 can always be accessed from the kernel because it is
> > 	 * memory-mapped, and VHE systems can access GICv3 EL2 system
> > 	 * registers.
> > 	 */
> > 	return !static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) || has_vhe();
> > }
> 
> Yes. I think this would go a long way in making this code easy to
> understand. 

I'll give it a go on the next respin.

> It also mean that we can have a unified save/restore
> function that picks the right GIC back-end, resulting in less
> code duplication.
> 
Not sure I understand hat you mean here?

Thanks,
-Christoffer

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

* [PATCH v4 38/40] KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on VHE
@ 2018-02-22 16:02           ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 16:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 22, 2018 at 03:01:17PM +0000, Marc Zyngier wrote:
> On Thu, 22 Feb 2018 14:42:27 +0000,
> Christoffer Dall wrote:
> > 
> > On Thu, Feb 22, 2018 at 12:32:11PM +0000, Marc Zyngier wrote:
> > > On 15/02/18 21:03, Christoffer Dall wrote:
> > > > Just like we can program the GICv2 hypervisor control interface directly
> > > > from the core vgic code, we can do the same for the GICv3 hypervisor
> > > > control interface on VHE systems.
> > > > 
> > > > We do this by simply calling the save/restore functions when we have VHE
> > > > and we can then get rid of the save/restore function calls from the VHE
> > > > world switch function.
> > > > 
> > > > One caveat is that we now write GICv3 system register state before the
> > > > potential early exit path in the run loop, and because we sync back
> > > > state in the early exit path, we have to ensure that we read a
> > > > consistent GIC state from the sync path, even though we have never
> > > > actually run the guest with the newly written GIC state.  We solve this
> > > > by inserting an ISB in the early exit path.
> > > > 
> > > > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > > > ---
> > > > 
> > > > Notes:
> > > >     Changes since v2:
> > > >      - Added ISB in the early exit path in the run loop as explained
> > > >        in the commit message.
> > > > 
> > > >  arch/arm64/kvm/hyp/switch.c | 3 ---
> > > >  virt/kvm/arm/arm.c          | 1 +
> > > >  virt/kvm/arm/vgic/vgic.c    | 5 +++++
> > > >  3 files changed, 6 insertions(+), 3 deletions(-)
> > > > 
> > > > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > > > index cbafc27a617b..466cfcdbcaf3 100644
> > > > --- a/arch/arm64/kvm/hyp/switch.c
> > > > +++ b/arch/arm64/kvm/hyp/switch.c
> > > > @@ -399,8 +399,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> > > >  	__activate_traps(vcpu);
> > > >  	__activate_vm(vcpu->kvm);
> > > >  
> > > > -	__vgic_restore_state(vcpu);
> > > > -
> > > >  	sysreg_restore_guest_state_vhe(guest_ctxt);
> > > >  	__debug_switch_to_guest(vcpu);
> > > >  
> > > > @@ -414,7 +412,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> > > >  	fp_enabled = fpsimd_enabled_vhe();
> > > >  
> > > >  	sysreg_save_guest_state_vhe(guest_ctxt);
> > > > -	__vgic_save_state(vcpu);
> > > >  
> > > >  	__deactivate_traps(vcpu);
> > > >  
> > > > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > > > index 5bd879c78951..6de7641f3ff2 100644
> > > > --- a/virt/kvm/arm/arm.c
> > > > +++ b/virt/kvm/arm/arm.c
> > > > @@ -717,6 +717,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> > > >  		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
> > > >  		    kvm_request_pending(vcpu)) {
> > > >  			vcpu->mode = OUTSIDE_GUEST_MODE;
> > > > +			isb(); /* Ensure work in x_flush_hwstate is committed */
> > > >  			kvm_pmu_sync_hwstate(vcpu);
> > > >  			if (static_branch_unlikely(&userspace_irqchip_in_use))
> > > >  				kvm_timer_sync_hwstate(vcpu);
> > > > diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> > > > index 12e2a28f437e..d0a19a8c196a 100644
> > > > --- a/virt/kvm/arm/vgic/vgic.c
> > > > +++ b/virt/kvm/arm/vgic/vgic.c
> > > > @@ -19,6 +19,7 @@
> > > >  #include <linux/list_sort.h>
> > > >  #include <linux/interrupt.h>
> > > >  #include <linux/irq.h>
> > > > +#include <asm/kvm_hyp.h>
> > > >  
> > > >  #include "vgic.h"
> > > >  
> > > > @@ -753,6 +754,8 @@ static inline void vgic_save_state(struct kvm_vcpu *vcpu)
> > > >  {
> > > >  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> > > >  		vgic_v2_save_state(vcpu);
> > > > +	else if (has_vhe())
> > > > +		__vgic_v3_save_state(vcpu);
> > > >  }
> > > >  
> > > >  /* Sync back the hardware VGIC state into our emulation after a guest's run. */
> > > > @@ -777,6 +780,8 @@ static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
> > > >  {
> > > >  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> > > >  		vgic_v2_restore_state(vcpu);
> > > > +	else if (has_vhe())
> > > > +		__vgic_v3_restore_state(vcpu);
> > > >  }
> > > >  
> > > >  /* Flush our emulation state into the GIC hardware before entering the guest. */
> > > > 
> > > 
> > > I'm slowly wrapping my brain around this thing again. If I grasp the
> > > general idea, we end up with two cases:
> > > 
> > > (1) The GIC is accessible from the kernel, and we save/restore it
> > > outside of the HYP code.
> > > 
> > > (2) The GIC is only accessible from the HYP code, and we do it there.
> > > 
> > > Maybe we should bite the bullet and introduce that primitive instead?
> > > 
> > 
> > You mean something the following?
> > 
> > static inline bool can_access_vgic_from_kernel(void)
> > {
> > 	/*
> > 	 * GICv2 can always be accessed from the kernel because it is
> > 	 * memory-mapped, and VHE systems can access GICv3 EL2 system
> > 	 * registers.
> > 	 */
> > 	return !static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) || has_vhe();
> > }
> 
> Yes. I think this would go a long way in making this code easy to
> understand. 

I'll give it a go on the next respin.

> It also mean that we can have a unified save/restore
> function that picks the right GIC back-end, resulting in less
> code duplication.
> 
Not sure I understand hat you mean here?

Thanks,
-Christoffer

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

* Re: [PATCH v4 38/40] KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on VHE
  2018-02-22 16:02           ` Christoffer Dall
@ 2018-02-22 17:21             ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-22 17:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, kvmarm, Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On 22/02/18 16:02, Christoffer Dall wrote:
> On Thu, Feb 22, 2018 at 03:01:17PM +0000, Marc Zyngier wrote:
>> On Thu, 22 Feb 2018 14:42:27 +0000,
>> Christoffer Dall wrote:
>>>
>>> On Thu, Feb 22, 2018 at 12:32:11PM +0000, Marc Zyngier wrote:
>>>> On 15/02/18 21:03, Christoffer Dall wrote:
>>>>> Just like we can program the GICv2 hypervisor control interface directly
>>>>> from the core vgic code, we can do the same for the GICv3 hypervisor
>>>>> control interface on VHE systems.
>>>>>
>>>>> We do this by simply calling the save/restore functions when we have VHE
>>>>> and we can then get rid of the save/restore function calls from the VHE
>>>>> world switch function.
>>>>>
>>>>> One caveat is that we now write GICv3 system register state before the
>>>>> potential early exit path in the run loop, and because we sync back
>>>>> state in the early exit path, we have to ensure that we read a
>>>>> consistent GIC state from the sync path, even though we have never
>>>>> actually run the guest with the newly written GIC state.  We solve this
>>>>> by inserting an ISB in the early exit path.
>>>>>
>>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>>>> ---
>>>>>
>>>>> Notes:
>>>>>     Changes since v2:
>>>>>      - Added ISB in the early exit path in the run loop as explained
>>>>>        in the commit message.
>>>>>
>>>>>  arch/arm64/kvm/hyp/switch.c | 3 ---
>>>>>  virt/kvm/arm/arm.c          | 1 +
>>>>>  virt/kvm/arm/vgic/vgic.c    | 5 +++++
>>>>>  3 files changed, 6 insertions(+), 3 deletions(-)
>>>>>
>>>>> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
>>>>> index cbafc27a617b..466cfcdbcaf3 100644
>>>>> --- a/arch/arm64/kvm/hyp/switch.c
>>>>> +++ b/arch/arm64/kvm/hyp/switch.c
>>>>> @@ -399,8 +399,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>>>>>  	__activate_traps(vcpu);
>>>>>  	__activate_vm(vcpu->kvm);
>>>>>  
>>>>> -	__vgic_restore_state(vcpu);
>>>>> -
>>>>>  	sysreg_restore_guest_state_vhe(guest_ctxt);
>>>>>  	__debug_switch_to_guest(vcpu);
>>>>>  
>>>>> @@ -414,7 +412,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>>>>>  	fp_enabled = fpsimd_enabled_vhe();
>>>>>  
>>>>>  	sysreg_save_guest_state_vhe(guest_ctxt);
>>>>> -	__vgic_save_state(vcpu);
>>>>>  
>>>>>  	__deactivate_traps(vcpu);
>>>>>  
>>>>> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
>>>>> index 5bd879c78951..6de7641f3ff2 100644
>>>>> --- a/virt/kvm/arm/arm.c
>>>>> +++ b/virt/kvm/arm/arm.c
>>>>> @@ -717,6 +717,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>>>>>  		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
>>>>>  		    kvm_request_pending(vcpu)) {
>>>>>  			vcpu->mode = OUTSIDE_GUEST_MODE;
>>>>> +			isb(); /* Ensure work in x_flush_hwstate is committed */
>>>>>  			kvm_pmu_sync_hwstate(vcpu);
>>>>>  			if (static_branch_unlikely(&userspace_irqchip_in_use))
>>>>>  				kvm_timer_sync_hwstate(vcpu);
>>>>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>>>>> index 12e2a28f437e..d0a19a8c196a 100644
>>>>> --- a/virt/kvm/arm/vgic/vgic.c
>>>>> +++ b/virt/kvm/arm/vgic/vgic.c
>>>>> @@ -19,6 +19,7 @@
>>>>>  #include <linux/list_sort.h>
>>>>>  #include <linux/interrupt.h>
>>>>>  #include <linux/irq.h>
>>>>> +#include <asm/kvm_hyp.h>
>>>>>  
>>>>>  #include "vgic.h"
>>>>>  
>>>>> @@ -753,6 +754,8 @@ static inline void vgic_save_state(struct kvm_vcpu *vcpu)
>>>>>  {
>>>>>  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
>>>>>  		vgic_v2_save_state(vcpu);
>>>>> +	else if (has_vhe())
>>>>> +		__vgic_v3_save_state(vcpu);
>>>>>  }
>>>>>  
>>>>>  /* Sync back the hardware VGIC state into our emulation after a guest's run. */
>>>>> @@ -777,6 +780,8 @@ static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
>>>>>  {
>>>>>  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
>>>>>  		vgic_v2_restore_state(vcpu);
>>>>> +	else if (has_vhe())
>>>>> +		__vgic_v3_restore_state(vcpu);
>>>>>  }
>>>>>  
>>>>>  /* Flush our emulation state into the GIC hardware before entering the guest. */
>>>>>
>>>>
>>>> I'm slowly wrapping my brain around this thing again. If I grasp the
>>>> general idea, we end up with two cases:
>>>>
>>>> (1) The GIC is accessible from the kernel, and we save/restore it
>>>> outside of the HYP code.
>>>>
>>>> (2) The GIC is only accessible from the HYP code, and we do it there.
>>>>
>>>> Maybe we should bite the bullet and introduce that primitive instead?
>>>>
>>>
>>> You mean something the following?
>>>
>>> static inline bool can_access_vgic_from_kernel(void)
>>> {
>>> 	/*
>>> 	 * GICv2 can always be accessed from the kernel because it is
>>> 	 * memory-mapped, and VHE systems can access GICv3 EL2 system
>>> 	 * registers.
>>> 	 */
>>> 	return !static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) || has_vhe();
>>> }
>>
>> Yes. I think this would go a long way in making this code easy to
>> understand. 
> 
> I'll give it a go on the next respin.
> 
>> It also mean that we can have a unified save/restore
>> function that picks the right GIC back-end, resulting in less
>> code duplication.
>>
> Not sure I understand hat you mean here?

We now have:

static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
{
        if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
                __vgic_v3_activate_traps(vcpu);
                __vgic_v3_restore_state(vcpu);
        }
}

and 

static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
{
        if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
                vgic_v2_restore_state(vcpu);
        else if (has_vhe())
                __vgic_v3_restore_state(vcpu);
}

I have the feeling that we could reconcile them in a nice way, but
I'm not completely sure now...

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v4 38/40] KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on VHE
@ 2018-02-22 17:21             ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-22 17:21 UTC (permalink / raw)
  To: linux-arm-kernel

On 22/02/18 16:02, Christoffer Dall wrote:
> On Thu, Feb 22, 2018 at 03:01:17PM +0000, Marc Zyngier wrote:
>> On Thu, 22 Feb 2018 14:42:27 +0000,
>> Christoffer Dall wrote:
>>>
>>> On Thu, Feb 22, 2018 at 12:32:11PM +0000, Marc Zyngier wrote:
>>>> On 15/02/18 21:03, Christoffer Dall wrote:
>>>>> Just like we can program the GICv2 hypervisor control interface directly
>>>>> from the core vgic code, we can do the same for the GICv3 hypervisor
>>>>> control interface on VHE systems.
>>>>>
>>>>> We do this by simply calling the save/restore functions when we have VHE
>>>>> and we can then get rid of the save/restore function calls from the VHE
>>>>> world switch function.
>>>>>
>>>>> One caveat is that we now write GICv3 system register state before the
>>>>> potential early exit path in the run loop, and because we sync back
>>>>> state in the early exit path, we have to ensure that we read a
>>>>> consistent GIC state from the sync path, even though we have never
>>>>> actually run the guest with the newly written GIC state.  We solve this
>>>>> by inserting an ISB in the early exit path.
>>>>>
>>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>>>> ---
>>>>>
>>>>> Notes:
>>>>>     Changes since v2:
>>>>>      - Added ISB in the early exit path in the run loop as explained
>>>>>        in the commit message.
>>>>>
>>>>>  arch/arm64/kvm/hyp/switch.c | 3 ---
>>>>>  virt/kvm/arm/arm.c          | 1 +
>>>>>  virt/kvm/arm/vgic/vgic.c    | 5 +++++
>>>>>  3 files changed, 6 insertions(+), 3 deletions(-)
>>>>>
>>>>> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
>>>>> index cbafc27a617b..466cfcdbcaf3 100644
>>>>> --- a/arch/arm64/kvm/hyp/switch.c
>>>>> +++ b/arch/arm64/kvm/hyp/switch.c
>>>>> @@ -399,8 +399,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>>>>>  	__activate_traps(vcpu);
>>>>>  	__activate_vm(vcpu->kvm);
>>>>>  
>>>>> -	__vgic_restore_state(vcpu);
>>>>> -
>>>>>  	sysreg_restore_guest_state_vhe(guest_ctxt);
>>>>>  	__debug_switch_to_guest(vcpu);
>>>>>  
>>>>> @@ -414,7 +412,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
>>>>>  	fp_enabled = fpsimd_enabled_vhe();
>>>>>  
>>>>>  	sysreg_save_guest_state_vhe(guest_ctxt);
>>>>> -	__vgic_save_state(vcpu);
>>>>>  
>>>>>  	__deactivate_traps(vcpu);
>>>>>  
>>>>> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
>>>>> index 5bd879c78951..6de7641f3ff2 100644
>>>>> --- a/virt/kvm/arm/arm.c
>>>>> +++ b/virt/kvm/arm/arm.c
>>>>> @@ -717,6 +717,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>>>>>  		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
>>>>>  		    kvm_request_pending(vcpu)) {
>>>>>  			vcpu->mode = OUTSIDE_GUEST_MODE;
>>>>> +			isb(); /* Ensure work in x_flush_hwstate is committed */
>>>>>  			kvm_pmu_sync_hwstate(vcpu);
>>>>>  			if (static_branch_unlikely(&userspace_irqchip_in_use))
>>>>>  				kvm_timer_sync_hwstate(vcpu);
>>>>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
>>>>> index 12e2a28f437e..d0a19a8c196a 100644
>>>>> --- a/virt/kvm/arm/vgic/vgic.c
>>>>> +++ b/virt/kvm/arm/vgic/vgic.c
>>>>> @@ -19,6 +19,7 @@
>>>>>  #include <linux/list_sort.h>
>>>>>  #include <linux/interrupt.h>
>>>>>  #include <linux/irq.h>
>>>>> +#include <asm/kvm_hyp.h>
>>>>>  
>>>>>  #include "vgic.h"
>>>>>  
>>>>> @@ -753,6 +754,8 @@ static inline void vgic_save_state(struct kvm_vcpu *vcpu)
>>>>>  {
>>>>>  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
>>>>>  		vgic_v2_save_state(vcpu);
>>>>> +	else if (has_vhe())
>>>>> +		__vgic_v3_save_state(vcpu);
>>>>>  }
>>>>>  
>>>>>  /* Sync back the hardware VGIC state into our emulation after a guest's run. */
>>>>> @@ -777,6 +780,8 @@ static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
>>>>>  {
>>>>>  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
>>>>>  		vgic_v2_restore_state(vcpu);
>>>>> +	else if (has_vhe())
>>>>> +		__vgic_v3_restore_state(vcpu);
>>>>>  }
>>>>>  
>>>>>  /* Flush our emulation state into the GIC hardware before entering the guest. */
>>>>>
>>>>
>>>> I'm slowly wrapping my brain around this thing again. If I grasp the
>>>> general idea, we end up with two cases:
>>>>
>>>> (1) The GIC is accessible from the kernel, and we save/restore it
>>>> outside of the HYP code.
>>>>
>>>> (2) The GIC is only accessible from the HYP code, and we do it there.
>>>>
>>>> Maybe we should bite the bullet and introduce that primitive instead?
>>>>
>>>
>>> You mean something the following?
>>>
>>> static inline bool can_access_vgic_from_kernel(void)
>>> {
>>> 	/*
>>> 	 * GICv2 can always be accessed from the kernel because it is
>>> 	 * memory-mapped, and VHE systems can access GICv3 EL2 system
>>> 	 * registers.
>>> 	 */
>>> 	return !static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) || has_vhe();
>>> }
>>
>> Yes. I think this would go a long way in making this code easy to
>> understand. 
> 
> I'll give it a go on the next respin.
> 
>> It also mean that we can have a unified save/restore
>> function that picks the right GIC back-end, resulting in less
>> code duplication.
>>
> Not sure I understand hat you mean here?

We now have:

static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
{
        if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
                __vgic_v3_activate_traps(vcpu);
                __vgic_v3_restore_state(vcpu);
        }
}

and 

static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
{
        if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
                vgic_v2_restore_state(vcpu);
        else if (has_vhe())
                __vgic_v3_restore_state(vcpu);
}

I have the feeling that we could reconcile them in a nice way, but
I'm not completely sure now...

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v4 25/40] KVM: arm64: Introduce framework for accessing deferred sysregs
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-22 17:40     ` Julien Grall
  -1 siblings, 0 replies; 276+ messages in thread
From: Julien Grall @ 2018-02-22 17:40 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: Andrew Jones, kvm, Marc Zyngier, Tomasz Nowicki, Yury Norov,
	Dave Martin, Shih-Wei Li

Hi Christoffer,

On 15/02/18 21:03, Christoffer Dall wrote:
> We are about to defer saving and restoring some groups of system
> registers to vcpu_put and vcpu_load on supported systems.  This means
> that we need some infrastructure to access system registes which

NIT: s/registes/registers/

> supports either accessing the memory backing of the register or directly
> accessing the system registers, depending on the state of the system
> when we access the register.
> 
> We do this by defining read/write accessor functions, which can handle
> both "immediate" and "deferrable" system registers.  Immediate registers
> are always saved/restored in the world-switch path, but deferrable
> registers are only saved/restored in vcpu_put/vcpu_load when supported
> and sysregs_loaded_on_cpu will be set in that case.
> 
> Note that we don't use the deferred mechanism yet in this patch, but only
> introduce infrastructure.  This is to improve convenience of review in

NIT: double space after the period.

> the subsequent patches where it is clear which registers become
> deferred.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>      Changes since v3:
>       - Changed to a switch-statement based approach to improve
>         readability.
>      
>      Changes since v2:
>       - New patch (deferred register handling has been reworked)
> 
>   arch/arm64/include/asm/kvm_host.h |  8 ++++++--
>   arch/arm64/kvm/sys_regs.c         | 33 +++++++++++++++++++++++++++++++++
>   2 files changed, 39 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 68398bf7882f..b463b5e28959 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -284,6 +284,10 @@ struct kvm_vcpu_arch {
>   
>   	/* Virtual SError ESR to restore when HCR_EL2.VSE is set */
>   	u64 vsesr_el2;
> +
> +	/* True when deferrable sysregs are loaded on the physical CPU,
> +	 * see kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs. */

NIT: I think the preferred style comment is
/*
  * Foo
  */

Cheers,

-- 
Julien Grall

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

* [PATCH v4 25/40] KVM: arm64: Introduce framework for accessing deferred sysregs
@ 2018-02-22 17:40     ` Julien Grall
  0 siblings, 0 replies; 276+ messages in thread
From: Julien Grall @ 2018-02-22 17:40 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoffer,

On 15/02/18 21:03, Christoffer Dall wrote:
> We are about to defer saving and restoring some groups of system
> registers to vcpu_put and vcpu_load on supported systems.  This means
> that we need some infrastructure to access system registes which

NIT: s/registes/registers/

> supports either accessing the memory backing of the register or directly
> accessing the system registers, depending on the state of the system
> when we access the register.
> 
> We do this by defining read/write accessor functions, which can handle
> both "immediate" and "deferrable" system registers.  Immediate registers
> are always saved/restored in the world-switch path, but deferrable
> registers are only saved/restored in vcpu_put/vcpu_load when supported
> and sysregs_loaded_on_cpu will be set in that case.
> 
> Note that we don't use the deferred mechanism yet in this patch, but only
> introduce infrastructure.  This is to improve convenience of review in

NIT: double space after the period.

> the subsequent patches where it is clear which registers become
> deferred.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>      Changes since v3:
>       - Changed to a switch-statement based approach to improve
>         readability.
>      
>      Changes since v2:
>       - New patch (deferred register handling has been reworked)
> 
>   arch/arm64/include/asm/kvm_host.h |  8 ++++++--
>   arch/arm64/kvm/sys_regs.c         | 33 +++++++++++++++++++++++++++++++++
>   2 files changed, 39 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 68398bf7882f..b463b5e28959 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -284,6 +284,10 @@ struct kvm_vcpu_arch {
>   
>   	/* Virtual SError ESR to restore when HCR_EL2.VSE is set */
>   	u64 vsesr_el2;
> +
> +	/* True when deferrable sysregs are loaded on the physical CPU,
> +	 * see kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs. */

NIT: I think the preferred style comment is
/*
  * Foo
  */

Cheers,

-- 
Julien Grall

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

* Re: [PATCH v4 30/40] KVM: arm64: Defer saving/restoring 32-bit sysregs to vcpu load/put
  2018-02-21 16:27     ` Marc Zyngier
@ 2018-02-22 18:15       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 18:15 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Wed, Feb 21, 2018 at 04:27:25PM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:03:22 +0000,
> Christoffer Dall wrote:
> > 
> > When running a 32-bit VM (EL1 in AArch32), the AArch32 system registers
> > can be deferred to vcpu load/put on VHE systems because neither
> > the host kernel nor host userspace uses these registers.
> > 
> > Note that we can not defer saving DBGVCR32_EL2 conditionally based
> > on the state of the debug dirty flag on VHE, but since we do the
> > load/put pretty rarely, this comes out as a win anyway.
> 
> I'm not sure I understand that comment. We don't have any deferring
> for this register, so the load/put reference seems out of place.
> 

Yeah, this is a patch description editing snafu.  I'll fix it.

Thanks,
-Christoffer

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

* [PATCH v4 30/40] KVM: arm64: Defer saving/restoring 32-bit sysregs to vcpu load/put
@ 2018-02-22 18:15       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 18:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 21, 2018 at 04:27:25PM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:03:22 +0000,
> Christoffer Dall wrote:
> > 
> > When running a 32-bit VM (EL1 in AArch32), the AArch32 system registers
> > can be deferred to vcpu load/put on VHE systems because neither
> > the host kernel nor host userspace uses these registers.
> > 
> > Note that we can not defer saving DBGVCR32_EL2 conditionally based
> > on the state of the debug dirty flag on VHE, but since we do the
> > load/put pretty rarely, this comes out as a win anyway.
> 
> I'm not sure I understand that comment. We don't have any deferring
> for this register, so the load/put reference seems out of place.
> 

Yeah, this is a patch description editing snafu.  I'll fix it.

Thanks,
-Christoffer

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

* Re: [PATCH v4 31/40] KVM: arm64: Move common VHE/non-VHE trap config in separate functions
  2018-02-21 17:59     ` Marc Zyngier
@ 2018-02-22 18:17       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 18:17 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Wed, Feb 21, 2018 at 05:59:37PM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:03:23 +0000,
> Christoffer Dall wrote:
> > 
> > As we are about to be more lazy with some of the trap configuration
> > register read/writes for VHE systems, move the logic that is currently
> > shared between VHE and non-VHE into a separate function which can be
> > called from either the world-switch path or from vcpu_load/vcpu_put.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v3:
> >      - Separate fpsimd32 trap configuration into a separate function
> >        which is still called from __activate_traps, because we no longer
> >        defer saving/restoring of VFP registers to load/put.
> > 
> >  arch/arm64/kvm/hyp/switch.c | 76 +++++++++++++++++++++++++++------------------
> >  1 file changed, 45 insertions(+), 31 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index 909aa3fe9196..17e3c6f26a34 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c
> > @@ -56,7 +56,45 @@ static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
> >  	vcpu->arch.ctxt.sys_regs[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
> >  }
> >  
> > -static void __hyp_text __activate_traps_vhe(void)
> > +static void __hyp_text __activate_traps_fpsimd32(struct kvm_vcpu *vcpu)
> > +{
> > +	/*
> > +	 * We are about to set CPTR_EL2.TFP to trap all floating point
> > +	 * register accesses to EL2, however, the ARM ARM clearly states that
> > +	 * traps are only taken to EL2 if the operation would not otherwise
> > +	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> > +	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> > +	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> > +	 * it will cause an exception.
> > +	 */
> > +	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> > +		write_sysreg(1 << 30, fpexc32_el2);
> > +		isb();
> > +	}
> > +}
> > +
> > +static void __hyp_text __activate_traps_common(struct kvm_vcpu *vcpu)
> > +{
> > +	/* Trap on AArch32 cp15 c15 (impdef sysregs) accesses (EL1 or EL0) */
> > +	write_sysreg(1 << 15, hstr_el2);
> > +	/*
> > +	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> > +	 * PMSELR_EL0 to make sure it never contains the cycle
> > +	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> > +	 * EL1 instead of being trapped to EL2.
> > +	 */
> > +	write_sysreg(0, pmselr_el0);
> > +	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> > +	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> > +}
> > +
> > +static void __hyp_text __deactivate_traps_common(void)
> > +{
> > +	write_sysreg(0, hstr_el2);
> > +	write_sysreg(0, pmuserenr_el0);
> > +}
> > +
> > +static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 val;
> >  
> > @@ -68,7 +106,7 @@ static void __hyp_text __activate_traps_vhe(void)
> >  	write_sysreg(kvm_get_hyp_vector(), vbar_el1);
> >  }
> >  
> > -static void __hyp_text __activate_traps_nvhe(void)
> > +static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
> 
> I have the ugly feeling that this hunk should not be in this
> patch. Have you tried bisecting the compilation of this series?
> 

I have, and I seem to remember catching this one during that exact
exercise, but I probably committed the change to the wrong patch.  Duh.

Thanks for spotting.
-Christoffer

> >  {
> >  	u64 val;
> >  
> > @@ -85,37 +123,14 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 hcr = vcpu->arch.hcr_el2;
> >  
> > -	/*
> > -	 * We are about to set CPTR_EL2.TFP to trap all floating point
> > -	 * register accesses to EL2, however, the ARM ARM clearly states that
> > -	 * traps are only taken to EL2 if the operation would not otherwise
> > -	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> > -	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> > -	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> > -	 * it will cause an exception.
> > -	 */
> > -	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> > -		write_sysreg(1 << 30, fpexc32_el2);
> > -		isb();
> > -	}
> > +	write_sysreg(hcr, hcr_el2);
> >  
> >  	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
> >  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
> >  
> > -	write_sysreg(hcr, hcr_el2);
> > -
> > -	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
> > -	write_sysreg(1 << 15, hstr_el2);
> > -	/*
> > -	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> > -	 * PMSELR_EL0 to make sure it never contains the cycle
> > -	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> > -	 * EL1 instead of being trapped to EL2.
> > -	 */
> > -	write_sysreg(0, pmselr_el0);
> > -	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> > -	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> > -	__activate_traps_arch()();
> > +	__activate_traps_fpsimd32(vcpu);
> > +	__activate_traps_common(vcpu);
> > +	__activate_traps_arch()(vcpu);
> >  }
> >  
> >  static void __hyp_text __deactivate_traps_vhe(void)
> > @@ -160,9 +175,8 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
> >  	if (vcpu->arch.hcr_el2 & HCR_VSE)
> >  		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
> >  
> > +	__deactivate_traps_common();
> >  	__deactivate_traps_arch()();
> > -	write_sysreg(0, hstr_el2);
> > -	write_sysreg(0, pmuserenr_el0);
> >  }
> >  
> >  static void __hyp_text __activate_vm(struct kvm *kvm)
> > -- 
> > 2.14.2
> > 
> 
> Otherwise:
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> 
> 	M.
> 
> -- 
> Jazz is not dead, it just smell funny.

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

* [PATCH v4 31/40] KVM: arm64: Move common VHE/non-VHE trap config in separate functions
@ 2018-02-22 18:17       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 18:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 21, 2018 at 05:59:37PM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:03:23 +0000,
> Christoffer Dall wrote:
> > 
> > As we are about to be more lazy with some of the trap configuration
> > register read/writes for VHE systems, move the logic that is currently
> > shared between VHE and non-VHE into a separate function which can be
> > called from either the world-switch path or from vcpu_load/vcpu_put.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v3:
> >      - Separate fpsimd32 trap configuration into a separate function
> >        which is still called from __activate_traps, because we no longer
> >        defer saving/restoring of VFP registers to load/put.
> > 
> >  arch/arm64/kvm/hyp/switch.c | 76 +++++++++++++++++++++++++++------------------
> >  1 file changed, 45 insertions(+), 31 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index 909aa3fe9196..17e3c6f26a34 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c
> > @@ -56,7 +56,45 @@ static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
> >  	vcpu->arch.ctxt.sys_regs[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
> >  }
> >  
> > -static void __hyp_text __activate_traps_vhe(void)
> > +static void __hyp_text __activate_traps_fpsimd32(struct kvm_vcpu *vcpu)
> > +{
> > +	/*
> > +	 * We are about to set CPTR_EL2.TFP to trap all floating point
> > +	 * register accesses to EL2, however, the ARM ARM clearly states that
> > +	 * traps are only taken to EL2 if the operation would not otherwise
> > +	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> > +	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> > +	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> > +	 * it will cause an exception.
> > +	 */
> > +	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> > +		write_sysreg(1 << 30, fpexc32_el2);
> > +		isb();
> > +	}
> > +}
> > +
> > +static void __hyp_text __activate_traps_common(struct kvm_vcpu *vcpu)
> > +{
> > +	/* Trap on AArch32 cp15 c15 (impdef sysregs) accesses (EL1 or EL0) */
> > +	write_sysreg(1 << 15, hstr_el2);
> > +	/*
> > +	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> > +	 * PMSELR_EL0 to make sure it never contains the cycle
> > +	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> > +	 * EL1 instead of being trapped to EL2.
> > +	 */
> > +	write_sysreg(0, pmselr_el0);
> > +	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> > +	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> > +}
> > +
> > +static void __hyp_text __deactivate_traps_common(void)
> > +{
> > +	write_sysreg(0, hstr_el2);
> > +	write_sysreg(0, pmuserenr_el0);
> > +}
> > +
> > +static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 val;
> >  
> > @@ -68,7 +106,7 @@ static void __hyp_text __activate_traps_vhe(void)
> >  	write_sysreg(kvm_get_hyp_vector(), vbar_el1);
> >  }
> >  
> > -static void __hyp_text __activate_traps_nvhe(void)
> > +static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
> 
> I have the ugly feeling that this hunk should not be in this
> patch. Have you tried bisecting the compilation of this series?
> 

I have, and I seem to remember catching this one during that exact
exercise, but I probably committed the change to the wrong patch.  Duh.

Thanks for spotting.
-Christoffer

> >  {
> >  	u64 val;
> >  
> > @@ -85,37 +123,14 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 hcr = vcpu->arch.hcr_el2;
> >  
> > -	/*
> > -	 * We are about to set CPTR_EL2.TFP to trap all floating point
> > -	 * register accesses to EL2, however, the ARM ARM clearly states that
> > -	 * traps are only taken to EL2 if the operation would not otherwise
> > -	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> > -	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> > -	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> > -	 * it will cause an exception.
> > -	 */
> > -	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> > -		write_sysreg(1 << 30, fpexc32_el2);
> > -		isb();
> > -	}
> > +	write_sysreg(hcr, hcr_el2);
> >  
> >  	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
> >  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
> >  
> > -	write_sysreg(hcr, hcr_el2);
> > -
> > -	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
> > -	write_sysreg(1 << 15, hstr_el2);
> > -	/*
> > -	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> > -	 * PMSELR_EL0 to make sure it never contains the cycle
> > -	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> > -	 * EL1 instead of being trapped to EL2.
> > -	 */
> > -	write_sysreg(0, pmselr_el0);
> > -	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> > -	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> > -	__activate_traps_arch()();
> > +	__activate_traps_fpsimd32(vcpu);
> > +	__activate_traps_common(vcpu);
> > +	__activate_traps_arch()(vcpu);
> >  }
> >  
> >  static void __hyp_text __deactivate_traps_vhe(void)
> > @@ -160,9 +175,8 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
> >  	if (vcpu->arch.hcr_el2 & HCR_VSE)
> >  		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
> >  
> > +	__deactivate_traps_common();
> >  	__deactivate_traps_arch()();
> > -	write_sysreg(0, hstr_el2);
> > -	write_sysreg(0, pmuserenr_el0);
> >  }
> >  
> >  static void __hyp_text __activate_vm(struct kvm *kvm)
> > -- 
> > 2.14.2
> > 
> 
> Otherwise:
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> 
> 	M.
> 
> -- 
> Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 28/40] KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on VHE
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-22 18:30     ` Julien Grall
  -1 siblings, 0 replies; 276+ messages in thread
From: Julien Grall @ 2018-02-22 18:30 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: Andrew Jones, kvm, Marc Zyngier, Tomasz Nowicki, Yury Norov,
	Dave Martin, Shih-Wei Li

Hi Christoffer,

On 15/02/18 21:03, Christoffer Dall wrote:
> Some system registers do not affect the host kernel's execution and can
> therefore be loaded when we are about to run a VCPU and we don't have to
> restore the host state to the hardware before the time when we are
> actually about to return to userspace or schedule out the VCPU thread.
> 
> The EL1 system registers and the userspace state registers only
> affecting EL0 execution do not need to be saved and restored on every
> switch between the VM and the host, because they don't affect the host
> kernel's execution.
> 
> We mark all registers which are now deffered as such in the

NIT: s/deffered/deferred/ I think.

> vcpu_{read,write}_sys_reg accessors in sys-regs.c to ensure the most
> up-to-date copy is always accessed.
> 
> Note MPIDR_EL1 (controlled via VMPIDR_EL2) is accessed from other vcpu
> threads, for example via the GIC emulation, and therefore must be
> declared as immediate, which is fine as the guest cannot modify this
> value.
> 
> The 32-bit sysregs can also be deferred but we do this in a separate
> patch as it requires a bit more infrastructure.


[...]

> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index b3c3f014aa61..f060309337aa 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -87,6 +87,26 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
>   	 * exit from the guest but are only saved on vcpu_put.
>   	 */
>   	switch (reg) {
> +	case CSSELR_EL1:	return read_sysreg_s(SYS_CSSELR_EL1);
> +	case SCTLR_EL1:		return read_sysreg_s(sctlr_EL12);
> +	case ACTLR_EL1:		return read_sysreg_s(SYS_ACTLR_EL1);
> +	case CPACR_EL1:		return read_sysreg_s(cpacr_EL12);
> +	case TTBR0_EL1:		return read_sysreg_s(ttbr0_EL12);
> +	case TTBR1_EL1:		return read_sysreg_s(ttbr1_EL12);
> +	case TCR_EL1:		return read_sysreg_s(tcr_EL12);
> +	case ESR_EL1:		return read_sysreg_s(esr_EL12);
> +	case AFSR0_EL1:		return read_sysreg_s(afsr0_EL12);
> +	case AFSR1_EL1:		return read_sysreg_s(afsr1_EL12);
> +	case FAR_EL1:		return read_sysreg_s(far_EL12);
> +	case MAIR_EL1:		return read_sysreg_s(mair_EL12);
> +	case VBAR_EL1:		return read_sysreg_s(vbar_EL12);
> +	case CONTEXTIDR_EL1:	return read_sysreg_s(contextidr_EL12);
> +	case TPIDR_EL0:		return read_sysreg_s(SYS_TPIDR_EL0);
> +	case TPIDRRO_EL0:	return read_sysreg_s(SYS_TPIDRRO_EL0);

I find a bit confusing to have some EL0 registers in the middle of EL1 
ones. Is it because they are listed by encoding?

> +	case TPIDR_EL1:		return read_sysreg_s(SYS_TPIDR_EL1);
> +	case AMAIR_EL1:		return read_sysreg_s(amair_EL12);
> +	case CNTKCTL_EL1:	return read_sysreg_s(cntkctl_EL12);
> +	case PAR_EL1:		return read_sysreg_s(SYS_PAR_EL1);
>   	}
>   
>   immediate_read:
> @@ -103,6 +123,26 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
>   	 * entry to the guest but are only restored on vcpu_load.
>   	 */
>   	switch (reg) {
> +	case CSSELR_EL1:	write_sysreg_s(val, SYS_CSSELR_EL1);	return;
> +	case SCTLR_EL1:		write_sysreg_s(val, sctlr_EL12);	return;
> +	case ACTLR_EL1:		write_sysreg_s(val, SYS_ACTLR_EL1);	return;
> +	case CPACR_EL1:		write_sysreg_s(val, cpacr_EL12);	return;
> +	case TTBR0_EL1:		write_sysreg_s(val, ttbr0_EL12);	return;
> +	case TTBR1_EL1:		write_sysreg_s(val, ttbr1_EL12);	return;
> +	case TCR_EL1:		write_sysreg_s(val, tcr_EL12);		return;
> +	case ESR_EL1:		write_sysreg_s(val, esr_EL12);		return;
> +	case AFSR0_EL1:		write_sysreg_s(val, afsr0_EL12);	return;
> +	case AFSR1_EL1:		write_sysreg_s(val, afsr1_EL12);	return;
> +	case FAR_EL1:		write_sysreg_s(val, far_EL12);		return;
> +	case MAIR_EL1:		write_sysreg_s(val, mair_EL12);		return;
> +	case VBAR_EL1:		write_sysreg_s(val, vbar_EL12);		return;
> +	case CONTEXTIDR_EL1:	write_sysreg_s(val, contextidr_EL12);	return;
> +	case TPIDR_EL0:		write_sysreg_s(val, SYS_TPIDR_EL0);	return;
> +	case TPIDRRO_EL0:	write_sysreg_s(val, SYS_TPIDRRO_EL0);	return;
> +	case TPIDR_EL1:		write_sysreg_s(val, SYS_TPIDR_EL1);	return;
> +	case AMAIR_EL1:		write_sysreg_s(val, amair_EL12);	return;
> +	case CNTKCTL_EL1:	write_sysreg_s(val, cntkctl_EL12);	return;
> +	case PAR_EL1:		write_sysreg_s(val, SYS_PAR_EL1);	return;
>   	}
>   
>   immediate_write:
> 

Cheers,

-- 
Julien Grall

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

* [PATCH v4 28/40] KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on VHE
@ 2018-02-22 18:30     ` Julien Grall
  0 siblings, 0 replies; 276+ messages in thread
From: Julien Grall @ 2018-02-22 18:30 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoffer,

On 15/02/18 21:03, Christoffer Dall wrote:
> Some system registers do not affect the host kernel's execution and can
> therefore be loaded when we are about to run a VCPU and we don't have to
> restore the host state to the hardware before the time when we are
> actually about to return to userspace or schedule out the VCPU thread.
> 
> The EL1 system registers and the userspace state registers only
> affecting EL0 execution do not need to be saved and restored on every
> switch between the VM and the host, because they don't affect the host
> kernel's execution.
> 
> We mark all registers which are now deffered as such in the

NIT: s/deffered/deferred/ I think.

> vcpu_{read,write}_sys_reg accessors in sys-regs.c to ensure the most
> up-to-date copy is always accessed.
> 
> Note MPIDR_EL1 (controlled via VMPIDR_EL2) is accessed from other vcpu
> threads, for example via the GIC emulation, and therefore must be
> declared as immediate, which is fine as the guest cannot modify this
> value.
> 
> The 32-bit sysregs can also be deferred but we do this in a separate
> patch as it requires a bit more infrastructure.


[...]

> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index b3c3f014aa61..f060309337aa 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -87,6 +87,26 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
>   	 * exit from the guest but are only saved on vcpu_put.
>   	 */
>   	switch (reg) {
> +	case CSSELR_EL1:	return read_sysreg_s(SYS_CSSELR_EL1);
> +	case SCTLR_EL1:		return read_sysreg_s(sctlr_EL12);
> +	case ACTLR_EL1:		return read_sysreg_s(SYS_ACTLR_EL1);
> +	case CPACR_EL1:		return read_sysreg_s(cpacr_EL12);
> +	case TTBR0_EL1:		return read_sysreg_s(ttbr0_EL12);
> +	case TTBR1_EL1:		return read_sysreg_s(ttbr1_EL12);
> +	case TCR_EL1:		return read_sysreg_s(tcr_EL12);
> +	case ESR_EL1:		return read_sysreg_s(esr_EL12);
> +	case AFSR0_EL1:		return read_sysreg_s(afsr0_EL12);
> +	case AFSR1_EL1:		return read_sysreg_s(afsr1_EL12);
> +	case FAR_EL1:		return read_sysreg_s(far_EL12);
> +	case MAIR_EL1:		return read_sysreg_s(mair_EL12);
> +	case VBAR_EL1:		return read_sysreg_s(vbar_EL12);
> +	case CONTEXTIDR_EL1:	return read_sysreg_s(contextidr_EL12);
> +	case TPIDR_EL0:		return read_sysreg_s(SYS_TPIDR_EL0);
> +	case TPIDRRO_EL0:	return read_sysreg_s(SYS_TPIDRRO_EL0);

I find a bit confusing to have some EL0 registers in the middle of EL1 
ones. Is it because they are listed by encoding?

> +	case TPIDR_EL1:		return read_sysreg_s(SYS_TPIDR_EL1);
> +	case AMAIR_EL1:		return read_sysreg_s(amair_EL12);
> +	case CNTKCTL_EL1:	return read_sysreg_s(cntkctl_EL12);
> +	case PAR_EL1:		return read_sysreg_s(SYS_PAR_EL1);
>   	}
>   
>   immediate_read:
> @@ -103,6 +123,26 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
>   	 * entry to the guest but are only restored on vcpu_load.
>   	 */
>   	switch (reg) {
> +	case CSSELR_EL1:	write_sysreg_s(val, SYS_CSSELR_EL1);	return;
> +	case SCTLR_EL1:		write_sysreg_s(val, sctlr_EL12);	return;
> +	case ACTLR_EL1:		write_sysreg_s(val, SYS_ACTLR_EL1);	return;
> +	case CPACR_EL1:		write_sysreg_s(val, cpacr_EL12);	return;
> +	case TTBR0_EL1:		write_sysreg_s(val, ttbr0_EL12);	return;
> +	case TTBR1_EL1:		write_sysreg_s(val, ttbr1_EL12);	return;
> +	case TCR_EL1:		write_sysreg_s(val, tcr_EL12);		return;
> +	case ESR_EL1:		write_sysreg_s(val, esr_EL12);		return;
> +	case AFSR0_EL1:		write_sysreg_s(val, afsr0_EL12);	return;
> +	case AFSR1_EL1:		write_sysreg_s(val, afsr1_EL12);	return;
> +	case FAR_EL1:		write_sysreg_s(val, far_EL12);		return;
> +	case MAIR_EL1:		write_sysreg_s(val, mair_EL12);		return;
> +	case VBAR_EL1:		write_sysreg_s(val, vbar_EL12);		return;
> +	case CONTEXTIDR_EL1:	write_sysreg_s(val, contextidr_EL12);	return;
> +	case TPIDR_EL0:		write_sysreg_s(val, SYS_TPIDR_EL0);	return;
> +	case TPIDRRO_EL0:	write_sysreg_s(val, SYS_TPIDRRO_EL0);	return;
> +	case TPIDR_EL1:		write_sysreg_s(val, SYS_TPIDR_EL1);	return;
> +	case AMAIR_EL1:		write_sysreg_s(val, amair_EL12);	return;
> +	case CNTKCTL_EL1:	write_sysreg_s(val, cntkctl_EL12);	return;
> +	case PAR_EL1:		write_sysreg_s(val, SYS_PAR_EL1);	return;
>   	}
>   
>   immediate_write:
> 

Cheers,

-- 
Julien Grall

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

* Re: [PATCH v4 28/40] KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on VHE
  2018-02-22 18:30     ` Julien Grall
@ 2018-02-22 18:31       ` Julien Grall
  -1 siblings, 0 replies; 276+ messages in thread
From: Julien Grall @ 2018-02-22 18:31 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: Andrew Jones, kvm, Marc Zyngier, Tomasz Nowicki, Yury Norov,
	Dave Martin, Shih-Wei Li



On 22/02/18 18:30, Julien Grall wrote:
> Hi Christoffer,
> 
> On 15/02/18 21:03, Christoffer Dall wrote:
>> Some system registers do not affect the host kernel's execution and can
>> therefore be loaded when we are about to run a VCPU and we don't have to
>> restore the host state to the hardware before the time when we are
>> actually about to return to userspace or schedule out the VCPU thread.
>>
>> The EL1 system registers and the userspace state registers only
>> affecting EL0 execution do not need to be saved and restored on every
>> switch between the VM and the host, because they don't affect the host
>> kernel's execution.
>>
>> We mark all registers which are now deffered as such in the
> 
> NIT: s/deffered/deferred/ I think.
> 
>> vcpu_{read,write}_sys_reg accessors in sys-regs.c to ensure the most
>> up-to-date copy is always accessed.
>>
>> Note MPIDR_EL1 (controlled via VMPIDR_EL2) is accessed from other vcpu
>> threads, for example via the GIC emulation, and therefore must be
>> declared as immediate, which is fine as the guest cannot modify this
>> value.

I forgot to comment on this. I missed this paragraph at the first read 
and was wondering why MPIDR_EL1 was not accessed using sysreg in 
vcpu_{read,write}_sys_reg. It might be worth considering a comment in 
those functions.

>>
>> The 32-bit sysregs can also be deferred but we do this in a separate
>> patch as it requires a bit more infrastructure.
> 
> 
> [...]
> 
>> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>> index b3c3f014aa61..f060309337aa 100644
>> --- a/arch/arm64/kvm/sys_regs.c
>> +++ b/arch/arm64/kvm/sys_regs.c
>> @@ -87,6 +87,26 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
>>        * exit from the guest but are only saved on vcpu_put.
>>        */
>>       switch (reg) {
>> +    case CSSELR_EL1:    return read_sysreg_s(SYS_CSSELR_EL1);
>> +    case SCTLR_EL1:        return read_sysreg_s(sctlr_EL12);
>> +    case ACTLR_EL1:        return read_sysreg_s(SYS_ACTLR_EL1);
>> +    case CPACR_EL1:        return read_sysreg_s(cpacr_EL12);
>> +    case TTBR0_EL1:        return read_sysreg_s(ttbr0_EL12);
>> +    case TTBR1_EL1:        return read_sysreg_s(ttbr1_EL12);
>> +    case TCR_EL1:        return read_sysreg_s(tcr_EL12);
>> +    case ESR_EL1:        return read_sysreg_s(esr_EL12);
>> +    case AFSR0_EL1:        return read_sysreg_s(afsr0_EL12);
>> +    case AFSR1_EL1:        return read_sysreg_s(afsr1_EL12);
>> +    case FAR_EL1:        return read_sysreg_s(far_EL12);
>> +    case MAIR_EL1:        return read_sysreg_s(mair_EL12);
>> +    case VBAR_EL1:        return read_sysreg_s(vbar_EL12);
>> +    case CONTEXTIDR_EL1:    return read_sysreg_s(contextidr_EL12);
>> +    case TPIDR_EL0:        return read_sysreg_s(SYS_TPIDR_EL0);
>> +    case TPIDRRO_EL0:    return read_sysreg_s(SYS_TPIDRRO_EL0);
> 
> I find a bit confusing to have some EL0 registers in the middle of EL1 
> ones. Is it because they are listed by encoding?
> 
>> +    case TPIDR_EL1:        return read_sysreg_s(SYS_TPIDR_EL1);
>> +    case AMAIR_EL1:        return read_sysreg_s(amair_EL12);
>> +    case CNTKCTL_EL1:    return read_sysreg_s(cntkctl_EL12);
>> +    case PAR_EL1:        return read_sysreg_s(SYS_PAR_EL1);
>>       }
>>   immediate_read:
>> @@ -103,6 +123,26 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, 
>> int reg, u64 val)
>>        * entry to the guest but are only restored on vcpu_load.
>>        */
>>       switch (reg) {
>> +    case CSSELR_EL1:    write_sysreg_s(val, SYS_CSSELR_EL1);    return;
>> +    case SCTLR_EL1:        write_sysreg_s(val, sctlr_EL12);    return;
>> +    case ACTLR_EL1:        write_sysreg_s(val, SYS_ACTLR_EL1);    
>> return;
>> +    case CPACR_EL1:        write_sysreg_s(val, cpacr_EL12);    return;
>> +    case TTBR0_EL1:        write_sysreg_s(val, ttbr0_EL12);    return;
>> +    case TTBR1_EL1:        write_sysreg_s(val, ttbr1_EL12);    return;
>> +    case TCR_EL1:        write_sysreg_s(val, tcr_EL12);        return;
>> +    case ESR_EL1:        write_sysreg_s(val, esr_EL12);        return;
>> +    case AFSR0_EL1:        write_sysreg_s(val, afsr0_EL12);    return;
>> +    case AFSR1_EL1:        write_sysreg_s(val, afsr1_EL12);    return;
>> +    case FAR_EL1:        write_sysreg_s(val, far_EL12);        return;
>> +    case MAIR_EL1:        write_sysreg_s(val, mair_EL12);        return;
>> +    case VBAR_EL1:        write_sysreg_s(val, vbar_EL12);        return;
>> +    case CONTEXTIDR_EL1:    write_sysreg_s(val, contextidr_EL12);    
>> return;
>> +    case TPIDR_EL0:        write_sysreg_s(val, SYS_TPIDR_EL0);    
>> return;
>> +    case TPIDRRO_EL0:    write_sysreg_s(val, SYS_TPIDRRO_EL0);    
>> return;
>> +    case TPIDR_EL1:        write_sysreg_s(val, SYS_TPIDR_EL1);    
>> return;
>> +    case AMAIR_EL1:        write_sysreg_s(val, amair_EL12);    return;
>> +    case CNTKCTL_EL1:    write_sysreg_s(val, cntkctl_EL12);    return;
>> +    case PAR_EL1:        write_sysreg_s(val, SYS_PAR_EL1);    return;
>>       }
>>   immediate_write:
>>
> 
> Cheers,
> 

-- 
Julien Grall

_______________________________________________
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] 276+ messages in thread

* [PATCH v4 28/40] KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on VHE
@ 2018-02-22 18:31       ` Julien Grall
  0 siblings, 0 replies; 276+ messages in thread
From: Julien Grall @ 2018-02-22 18:31 UTC (permalink / raw)
  To: linux-arm-kernel



On 22/02/18 18:30, Julien Grall wrote:
> Hi Christoffer,
> 
> On 15/02/18 21:03, Christoffer Dall wrote:
>> Some system registers do not affect the host kernel's execution and can
>> therefore be loaded when we are about to run a VCPU and we don't have to
>> restore the host state to the hardware before the time when we are
>> actually about to return to userspace or schedule out the VCPU thread.
>>
>> The EL1 system registers and the userspace state registers only
>> affecting EL0 execution do not need to be saved and restored on every
>> switch between the VM and the host, because they don't affect the host
>> kernel's execution.
>>
>> We mark all registers which are now deffered as such in the
> 
> NIT: s/deffered/deferred/ I think.
> 
>> vcpu_{read,write}_sys_reg accessors in sys-regs.c to ensure the most
>> up-to-date copy is always accessed.
>>
>> Note MPIDR_EL1 (controlled via VMPIDR_EL2) is accessed from other vcpu
>> threads, for example via the GIC emulation, and therefore must be
>> declared as immediate, which is fine as the guest cannot modify this
>> value.

I forgot to comment on this. I missed this paragraph at the first read 
and was wondering why MPIDR_EL1 was not accessed using sysreg in 
vcpu_{read,write}_sys_reg. It might be worth considering a comment in 
those functions.

>>
>> The 32-bit sysregs can also be deferred but we do this in a separate
>> patch as it requires a bit more infrastructure.
> 
> 
> [...]
> 
>> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>> index b3c3f014aa61..f060309337aa 100644
>> --- a/arch/arm64/kvm/sys_regs.c
>> +++ b/arch/arm64/kvm/sys_regs.c
>> @@ -87,6 +87,26 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
>> ?????? * exit from the guest but are only saved on vcpu_put.
>> ?????? */
>> ????? switch (reg) {
>> +??? case CSSELR_EL1:??? return read_sysreg_s(SYS_CSSELR_EL1);
>> +??? case SCTLR_EL1:??????? return read_sysreg_s(sctlr_EL12);
>> +??? case ACTLR_EL1:??????? return read_sysreg_s(SYS_ACTLR_EL1);
>> +??? case CPACR_EL1:??????? return read_sysreg_s(cpacr_EL12);
>> +??? case TTBR0_EL1:??????? return read_sysreg_s(ttbr0_EL12);
>> +??? case TTBR1_EL1:??????? return read_sysreg_s(ttbr1_EL12);
>> +??? case TCR_EL1:??????? return read_sysreg_s(tcr_EL12);
>> +??? case ESR_EL1:??????? return read_sysreg_s(esr_EL12);
>> +??? case AFSR0_EL1:??????? return read_sysreg_s(afsr0_EL12);
>> +??? case AFSR1_EL1:??????? return read_sysreg_s(afsr1_EL12);
>> +??? case FAR_EL1:??????? return read_sysreg_s(far_EL12);
>> +??? case MAIR_EL1:??????? return read_sysreg_s(mair_EL12);
>> +??? case VBAR_EL1:??????? return read_sysreg_s(vbar_EL12);
>> +??? case CONTEXTIDR_EL1:??? return read_sysreg_s(contextidr_EL12);
>> +??? case TPIDR_EL0:??????? return read_sysreg_s(SYS_TPIDR_EL0);
>> +??? case TPIDRRO_EL0:??? return read_sysreg_s(SYS_TPIDRRO_EL0);
> 
> I find a bit confusing to have some EL0 registers in the middle of EL1 
> ones. Is it because they are listed by encoding?
> 
>> +??? case TPIDR_EL1:??????? return read_sysreg_s(SYS_TPIDR_EL1);
>> +??? case AMAIR_EL1:??????? return read_sysreg_s(amair_EL12);
>> +??? case CNTKCTL_EL1:??? return read_sysreg_s(cntkctl_EL12);
>> +??? case PAR_EL1:??????? return read_sysreg_s(SYS_PAR_EL1);
>> ????? }
>> ? immediate_read:
>> @@ -103,6 +123,26 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, 
>> int reg, u64 val)
>> ?????? * entry to the guest but are only restored on vcpu_load.
>> ?????? */
>> ????? switch (reg) {
>> +??? case CSSELR_EL1:??? write_sysreg_s(val, SYS_CSSELR_EL1);??? return;
>> +??? case SCTLR_EL1:??????? write_sysreg_s(val, sctlr_EL12);??? return;
>> +??? case ACTLR_EL1:??????? write_sysreg_s(val, SYS_ACTLR_EL1);    
>> return;
>> +??? case CPACR_EL1:??????? write_sysreg_s(val, cpacr_EL12);??? return;
>> +??? case TTBR0_EL1:??????? write_sysreg_s(val, ttbr0_EL12);??? return;
>> +??? case TTBR1_EL1:??????? write_sysreg_s(val, ttbr1_EL12);??? return;
>> +??? case TCR_EL1:??????? write_sysreg_s(val, tcr_EL12);??????? return;
>> +??? case ESR_EL1:??????? write_sysreg_s(val, esr_EL12);??????? return;
>> +??? case AFSR0_EL1:??????? write_sysreg_s(val, afsr0_EL12);??? return;
>> +??? case AFSR1_EL1:??????? write_sysreg_s(val, afsr1_EL12);??? return;
>> +??? case FAR_EL1:??????? write_sysreg_s(val, far_EL12);??????? return;
>> +??? case MAIR_EL1:??????? write_sysreg_s(val, mair_EL12);??????? return;
>> +??? case VBAR_EL1:??????? write_sysreg_s(val, vbar_EL12);??????? return;
>> +??? case CONTEXTIDR_EL1:??? write_sysreg_s(val, contextidr_EL12);    
>> return;
>> +??? case TPIDR_EL0:??????? write_sysreg_s(val, SYS_TPIDR_EL0);    
>> return;
>> +??? case TPIDRRO_EL0:??? write_sysreg_s(val, SYS_TPIDRRO_EL0);    
>> return;
>> +??? case TPIDR_EL1:??????? write_sysreg_s(val, SYS_TPIDR_EL1);    
>> return;
>> +??? case AMAIR_EL1:??????? write_sysreg_s(val, amair_EL12);??? return;
>> +??? case CNTKCTL_EL1:??? write_sysreg_s(val, cntkctl_EL12);??? return;
>> +??? case PAR_EL1:??????? write_sysreg_s(val, SYS_PAR_EL1);??? return;
>> ????? }
>> ? immediate_write:
>>
> 
> Cheers,
> 

-- 
Julien Grall

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

* Re: [PATCH v4 33/40] KVM: arm64: Configure c15, PMU, and debug register traps on cpu load/put for VHE
  2018-02-21 18:20     ` Marc Zyngier
@ 2018-02-22 18:57       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 18:57 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Wed, Feb 21, 2018 at 06:20:54PM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:03:25 +0000,
> Christoffer Dall wrote:
> > 
> > We do not have to change the c15 trap setting on each switch to/from the
> > guest on VHE systems, because this setting only affects EL0.
> 
> Did you mean EL1 instead?
> 

Not sure what I meant, but HSTR_EL2 appears to affect EL1 and EL0, and
the PMU configuration we can do on vcpu_load on VHE systems is only
about EL0 as far as I can tell.

> > 
> > The PMU and debug trap configuration can also be done on vcpu load/put
> > instead, because they don't affect how the host kernel can access the
> > debug registers while executing KVM kernel code.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> >  arch/arm64/include/asm/kvm_hyp.h |  3 +++
> >  arch/arm64/kvm/hyp/switch.c      | 31 ++++++++++++++++++++++---------
> >  arch/arm64/kvm/hyp/sysreg-sr.c   |  4 ++++
> >  3 files changed, 29 insertions(+), 9 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
> > index 2b1fda90dde4..949f2e77ae58 100644
> > --- a/arch/arm64/include/asm/kvm_hyp.h
> > +++ b/arch/arm64/include/asm/kvm_hyp.h
> > @@ -147,6 +147,9 @@ void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
> >  void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
> >  bool __fpsimd_enabled(void);
> >  
> > +void activate_traps_vhe_load(struct kvm_vcpu *vcpu);
> > +void deactivate_traps_vhe_put(void);
> > +
> >  u64 __guest_enter(struct kvm_vcpu *vcpu, struct kvm_cpu_context *host_ctxt);
> >  void __noreturn __hyp_do_panic(unsigned long, ...);
> >  
> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index 9c40e203bd09..5e94955b89ea 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c
> > @@ -101,6 +101,8 @@ static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 val;
> >  
> > +	__activate_traps_common(vcpu);
> > +
> >  	val = CPTR_EL2_DEFAULT;
> >  	val |= CPTR_EL2_TTA | CPTR_EL2_TFP | CPTR_EL2_TZ;
> >  	write_sysreg(val, cptr_el2);
> > @@ -120,20 +122,12 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> >  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
> >  
> >  	__activate_traps_fpsimd32(vcpu);
> > -	__activate_traps_common(vcpu);
> >  	__activate_traps_arch()(vcpu);
> >  }
> >  
> >  static void __hyp_text __deactivate_traps_vhe(void)
> >  {
> >  	extern char vectors[];	/* kernel exception vectors */
> > -	u64 mdcr_el2 = read_sysreg(mdcr_el2);
> > -
> > -	mdcr_el2 &= MDCR_EL2_HPMN_MASK |
> > -		    MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT |
> > -		    MDCR_EL2_TPMS;
> > -
> > -	write_sysreg(mdcr_el2, mdcr_el2);
> >  	write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
> >  	write_sysreg(CPACR_EL1_DEFAULT, cpacr_el1);
> >  	write_sysreg(vectors, vbar_el1);
> > @@ -143,6 +137,8 @@ static void __hyp_text __deactivate_traps_nvhe(void)
> >  {
> >  	u64 mdcr_el2 = read_sysreg(mdcr_el2);
> >  
> > +	__deactivate_traps_common();
> > +
> >  	mdcr_el2 &= MDCR_EL2_HPMN_MASK;
> >  	mdcr_el2 |= MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT;
> >  
> > @@ -166,10 +162,27 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
> >  	if (vcpu->arch.hcr_el2 & HCR_VSE)
> >  		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
> >  
> > -	__deactivate_traps_common();
> >  	__deactivate_traps_arch()();
> >  }
> >  
> > +void activate_traps_vhe_load(struct kvm_vcpu *vcpu)
> > +{
> > +	__activate_traps_common(vcpu);
> > +}
> > +
> > +void deactivate_traps_vhe_put(void)
> > +{
> > +	u64 mdcr_el2 = read_sysreg(mdcr_el2);
> > +
> > +	mdcr_el2 &= MDCR_EL2_HPMN_MASK |
> > +		    MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT |
> > +		    MDCR_EL2_TPMS;
> > +
> > +	write_sysreg(mdcr_el2, mdcr_el2);
> > +
> > +	__deactivate_traps_common();
> > +}
> > +
> >  static void __hyp_text __activate_vm(struct kvm *kvm)
> >  {
> >  	write_sysreg(kvm->arch.vttbr, vttbr_el2);
> > diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> > index aacba4636871..b3894df6bf1a 100644
> > --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> > +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> > @@ -254,6 +254,8 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
> >  	__sysreg_restore_el1_state(guest_ctxt);
> >  
> >  	vcpu->arch.sysregs_loaded_on_cpu = true;
> > +
> > +	activate_traps_vhe_load(vcpu);
> >  }
> >  
> >  /**
> > @@ -275,6 +277,8 @@ void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
> >  	if (!has_vhe())
> >  		return;
> >  
> > +	deactivate_traps_vhe_put();
> > +
> >  	__sysreg_save_el1_state(guest_ctxt);
> >  	__sysreg_save_user_state(guest_ctxt);
> >  	__sysreg32_save_state(vcpu);
> > -- 
> > 2.14.2
> > 
> 
> I must admit that I find these two layers of trap configuration mildly
> confusing. I can see why it is done like this (there is hardly any
> other way), but still...

Perhaps the naming could be improved.

Right now we have:

_traps_common:        Same code for non-VHE/VHE.  Called:
                         non-VHE: on every switch.
		         VHE: on load/put.
_traps:               Same code for non-VHE/VHE.  Called:
                         VHE/non-VHE: On every switch.
_traps_nvhe:          Code specific to non-VHE system.  Called:
                         non-VHE: on every switch
_traps_vhe:           Code specific to VHE system.  Called:
                         VHE: on every switch
_traps_vhe_load/put:  Code  specific to VHE system.  Called:
                         VHE: on vcpu load/put

We could simplify this at the cost of code duplication to:

_traps_nvhe
_traps_vhe
_traps_vhe_load/put

Thoughts?

> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> 

Thanks,
-Christoffer

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

* [PATCH v4 33/40] KVM: arm64: Configure c15, PMU, and debug register traps on cpu load/put for VHE
@ 2018-02-22 18:57       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 18:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 21, 2018 at 06:20:54PM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:03:25 +0000,
> Christoffer Dall wrote:
> > 
> > We do not have to change the c15 trap setting on each switch to/from the
> > guest on VHE systems, because this setting only affects EL0.
> 
> Did you mean EL1 instead?
> 

Not sure what I meant, but HSTR_EL2 appears to affect EL1 and EL0, and
the PMU configuration we can do on vcpu_load on VHE systems is only
about EL0 as far as I can tell.

> > 
> > The PMU and debug trap configuration can also be done on vcpu load/put
> > instead, because they don't affect how the host kernel can access the
> > debug registers while executing KVM kernel code.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> >  arch/arm64/include/asm/kvm_hyp.h |  3 +++
> >  arch/arm64/kvm/hyp/switch.c      | 31 ++++++++++++++++++++++---------
> >  arch/arm64/kvm/hyp/sysreg-sr.c   |  4 ++++
> >  3 files changed, 29 insertions(+), 9 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
> > index 2b1fda90dde4..949f2e77ae58 100644
> > --- a/arch/arm64/include/asm/kvm_hyp.h
> > +++ b/arch/arm64/include/asm/kvm_hyp.h
> > @@ -147,6 +147,9 @@ void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
> >  void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
> >  bool __fpsimd_enabled(void);
> >  
> > +void activate_traps_vhe_load(struct kvm_vcpu *vcpu);
> > +void deactivate_traps_vhe_put(void);
> > +
> >  u64 __guest_enter(struct kvm_vcpu *vcpu, struct kvm_cpu_context *host_ctxt);
> >  void __noreturn __hyp_do_panic(unsigned long, ...);
> >  
> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index 9c40e203bd09..5e94955b89ea 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c
> > @@ -101,6 +101,8 @@ static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 val;
> >  
> > +	__activate_traps_common(vcpu);
> > +
> >  	val = CPTR_EL2_DEFAULT;
> >  	val |= CPTR_EL2_TTA | CPTR_EL2_TFP | CPTR_EL2_TZ;
> >  	write_sysreg(val, cptr_el2);
> > @@ -120,20 +122,12 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> >  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
> >  
> >  	__activate_traps_fpsimd32(vcpu);
> > -	__activate_traps_common(vcpu);
> >  	__activate_traps_arch()(vcpu);
> >  }
> >  
> >  static void __hyp_text __deactivate_traps_vhe(void)
> >  {
> >  	extern char vectors[];	/* kernel exception vectors */
> > -	u64 mdcr_el2 = read_sysreg(mdcr_el2);
> > -
> > -	mdcr_el2 &= MDCR_EL2_HPMN_MASK |
> > -		    MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT |
> > -		    MDCR_EL2_TPMS;
> > -
> > -	write_sysreg(mdcr_el2, mdcr_el2);
> >  	write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
> >  	write_sysreg(CPACR_EL1_DEFAULT, cpacr_el1);
> >  	write_sysreg(vectors, vbar_el1);
> > @@ -143,6 +137,8 @@ static void __hyp_text __deactivate_traps_nvhe(void)
> >  {
> >  	u64 mdcr_el2 = read_sysreg(mdcr_el2);
> >  
> > +	__deactivate_traps_common();
> > +
> >  	mdcr_el2 &= MDCR_EL2_HPMN_MASK;
> >  	mdcr_el2 |= MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT;
> >  
> > @@ -166,10 +162,27 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
> >  	if (vcpu->arch.hcr_el2 & HCR_VSE)
> >  		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
> >  
> > -	__deactivate_traps_common();
> >  	__deactivate_traps_arch()();
> >  }
> >  
> > +void activate_traps_vhe_load(struct kvm_vcpu *vcpu)
> > +{
> > +	__activate_traps_common(vcpu);
> > +}
> > +
> > +void deactivate_traps_vhe_put(void)
> > +{
> > +	u64 mdcr_el2 = read_sysreg(mdcr_el2);
> > +
> > +	mdcr_el2 &= MDCR_EL2_HPMN_MASK |
> > +		    MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT |
> > +		    MDCR_EL2_TPMS;
> > +
> > +	write_sysreg(mdcr_el2, mdcr_el2);
> > +
> > +	__deactivate_traps_common();
> > +}
> > +
> >  static void __hyp_text __activate_vm(struct kvm *kvm)
> >  {
> >  	write_sysreg(kvm->arch.vttbr, vttbr_el2);
> > diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> > index aacba4636871..b3894df6bf1a 100644
> > --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> > +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> > @@ -254,6 +254,8 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
> >  	__sysreg_restore_el1_state(guest_ctxt);
> >  
> >  	vcpu->arch.sysregs_loaded_on_cpu = true;
> > +
> > +	activate_traps_vhe_load(vcpu);
> >  }
> >  
> >  /**
> > @@ -275,6 +277,8 @@ void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
> >  	if (!has_vhe())
> >  		return;
> >  
> > +	deactivate_traps_vhe_put();
> > +
> >  	__sysreg_save_el1_state(guest_ctxt);
> >  	__sysreg_save_user_state(guest_ctxt);
> >  	__sysreg32_save_state(vcpu);
> > -- 
> > 2.14.2
> > 
> 
> I must admit that I find these two layers of trap configuration mildly
> confusing. I can see why it is done like this (there is hardly any
> other way), but still...

Perhaps the naming could be improved.

Right now we have:

_traps_common:        Same code for non-VHE/VHE.  Called:
                         non-VHE: on every switch.
		         VHE: on load/put.
_traps:               Same code for non-VHE/VHE.  Called:
                         VHE/non-VHE: On every switch.
_traps_nvhe:          Code specific to non-VHE system.  Called:
                         non-VHE: on every switch
_traps_vhe:           Code specific to VHE system.  Called:
                         VHE: on every switch
_traps_vhe_load/put:  Code  specific to VHE system.  Called:
                         VHE: on vcpu load/put

We could simplify this at the cost of code duplication to:

_traps_nvhe
_traps_vhe
_traps_vhe_load/put

Thoughts?

> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> 

Thanks,
-Christoffer

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

* Re: [PATCH v4 34/40] KVM: arm64: Cleanup __activate_traps and __deactive_traps for VHE and non-VHE
  2018-02-21 18:26     ` Marc Zyngier
@ 2018-02-22 19:04       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 19:04 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Wed, Feb 21, 2018 at 06:26:39PM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:03:26 +0000,
> Christoffer Dall wrote:
> > 
> > To make the code more readable and to avoid the overhead of a function
> > call, let's get rid of a pair of the alternative function selectors and
> > explicitly call the VHE and non-VHE functions using the has_vhe() static
> > key based selector instead, telling the compiler to try to inline the
> > static function if it can.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> >  arch/arm64/kvm/hyp/switch.c | 30 ++++++++++++++----------------
> >  1 file changed, 14 insertions(+), 16 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index 5e94955b89ea..0e54fe2aab1c 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c
> > @@ -85,7 +85,7 @@ static void __hyp_text __deactivate_traps_common(void)
> >  	write_sysreg(0, pmuserenr_el0);
> >  }
> >  
> > -static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
> > +static inline void activate_traps_vhe(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 val;
> >  
> > @@ -97,7 +97,7 @@ static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
> >  	write_sysreg(kvm_get_hyp_vector(), vbar_el1);
> >  }
> >  
> > -static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
> > +static inline void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
> 
> Having both inline and __hyp_text does not make much sense (the
> function will be emitted in the section defined by the caller).

Is that true even if the function is not inlined?

> I
> suggest you drop the inline and let the compiler do its magic.
> 

We were using an older compiler (I believe GCC 4.8) when doing some of
the initial experiements, and saw that some of these small functions
weren't inlined without the inline hint.  However, this doesn't seem to
be an issue on any of the compilers I'm using today.  So I'll remove
the inline.

Thanks,
-Christoffer

> >  {
> >  	u64 val;
> >  
> > @@ -108,11 +108,7 @@ static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
> >  	write_sysreg(val, cptr_el2);
> >  }
> >  
> > -static hyp_alternate_select(__activate_traps_arch,
> > -			    __activate_traps_nvhe, __activate_traps_vhe,
> > -			    ARM64_HAS_VIRT_HOST_EXTN);
> > -
> > -static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> > +static inline void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> 
> Same here, and in other spots in this file.
> 
> >  {
> >  	u64 hcr = vcpu->arch.hcr_el2;
> >  
> > @@ -122,10 +118,13 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> >  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
> >  
> >  	__activate_traps_fpsimd32(vcpu);
> > -	__activate_traps_arch()(vcpu);
> > +	if (has_vhe())
> > +		activate_traps_vhe(vcpu);
> > +	else
> > +		__activate_traps_nvhe(vcpu);
> >  }
> >  
> > -static void __hyp_text __deactivate_traps_vhe(void)
> > +static inline void deactivate_traps_vhe(void)
> >  {
> >  	extern char vectors[];	/* kernel exception vectors */
> >  	write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
> > @@ -133,7 +132,7 @@ static void __hyp_text __deactivate_traps_vhe(void)
> >  	write_sysreg(vectors, vbar_el1);
> >  }
> >  
> > -static void __hyp_text __deactivate_traps_nvhe(void)
> > +static inline void __hyp_text __deactivate_traps_nvhe(void)
> >  {
> >  	u64 mdcr_el2 = read_sysreg(mdcr_el2);
> >  
> > @@ -147,11 +146,7 @@ static void __hyp_text __deactivate_traps_nvhe(void)
> >  	write_sysreg(CPTR_EL2_DEFAULT, cptr_el2);
> >  }
> >  
> > -static hyp_alternate_select(__deactivate_traps_arch,
> > -			    __deactivate_traps_nvhe, __deactivate_traps_vhe,
> > -			    ARM64_HAS_VIRT_HOST_EXTN);
> > -
> > -static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
> > +static inline void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
> >  {
> >  	/*
> >  	 * If we pended a virtual abort, preserve it until it gets
> > @@ -162,7 +157,10 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
> >  	if (vcpu->arch.hcr_el2 & HCR_VSE)
> >  		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
> >  
> > -	__deactivate_traps_arch()();
> > +	if (has_vhe())
> > +		deactivate_traps_vhe();
> > +	else
> > +		__deactivate_traps_nvhe();
> >  }
> >  
> >  void activate_traps_vhe_load(struct kvm_vcpu *vcpu)
> > -- 
> > 2.14.2
> > 
> 
> Thanks,
> 
> 	M.
> 
> -- 
> Jazz is not dead, it just smell funny.

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

* [PATCH v4 34/40] KVM: arm64: Cleanup __activate_traps and __deactive_traps for VHE and non-VHE
@ 2018-02-22 19:04       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 19:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 21, 2018 at 06:26:39PM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:03:26 +0000,
> Christoffer Dall wrote:
> > 
> > To make the code more readable and to avoid the overhead of a function
> > call, let's get rid of a pair of the alternative function selectors and
> > explicitly call the VHE and non-VHE functions using the has_vhe() static
> > key based selector instead, telling the compiler to try to inline the
> > static function if it can.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> >  arch/arm64/kvm/hyp/switch.c | 30 ++++++++++++++----------------
> >  1 file changed, 14 insertions(+), 16 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index 5e94955b89ea..0e54fe2aab1c 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c
> > @@ -85,7 +85,7 @@ static void __hyp_text __deactivate_traps_common(void)
> >  	write_sysreg(0, pmuserenr_el0);
> >  }
> >  
> > -static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
> > +static inline void activate_traps_vhe(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 val;
> >  
> > @@ -97,7 +97,7 @@ static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
> >  	write_sysreg(kvm_get_hyp_vector(), vbar_el1);
> >  }
> >  
> > -static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
> > +static inline void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
> 
> Having both inline and __hyp_text does not make much sense (the
> function will be emitted in the section defined by the caller).

Is that true even if the function is not inlined?

> I
> suggest you drop the inline and let the compiler do its magic.
> 

We were using an older compiler (I believe GCC 4.8) when doing some of
the initial experiements, and saw that some of these small functions
weren't inlined without the inline hint.  However, this doesn't seem to
be an issue on any of the compilers I'm using today.  So I'll remove
the inline.

Thanks,
-Christoffer

> >  {
> >  	u64 val;
> >  
> > @@ -108,11 +108,7 @@ static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
> >  	write_sysreg(val, cptr_el2);
> >  }
> >  
> > -static hyp_alternate_select(__activate_traps_arch,
> > -			    __activate_traps_nvhe, __activate_traps_vhe,
> > -			    ARM64_HAS_VIRT_HOST_EXTN);
> > -
> > -static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> > +static inline void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> 
> Same here, and in other spots in this file.
> 
> >  {
> >  	u64 hcr = vcpu->arch.hcr_el2;
> >  
> > @@ -122,10 +118,13 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> >  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
> >  
> >  	__activate_traps_fpsimd32(vcpu);
> > -	__activate_traps_arch()(vcpu);
> > +	if (has_vhe())
> > +		activate_traps_vhe(vcpu);
> > +	else
> > +		__activate_traps_nvhe(vcpu);
> >  }
> >  
> > -static void __hyp_text __deactivate_traps_vhe(void)
> > +static inline void deactivate_traps_vhe(void)
> >  {
> >  	extern char vectors[];	/* kernel exception vectors */
> >  	write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
> > @@ -133,7 +132,7 @@ static void __hyp_text __deactivate_traps_vhe(void)
> >  	write_sysreg(vectors, vbar_el1);
> >  }
> >  
> > -static void __hyp_text __deactivate_traps_nvhe(void)
> > +static inline void __hyp_text __deactivate_traps_nvhe(void)
> >  {
> >  	u64 mdcr_el2 = read_sysreg(mdcr_el2);
> >  
> > @@ -147,11 +146,7 @@ static void __hyp_text __deactivate_traps_nvhe(void)
> >  	write_sysreg(CPTR_EL2_DEFAULT, cptr_el2);
> >  }
> >  
> > -static hyp_alternate_select(__deactivate_traps_arch,
> > -			    __deactivate_traps_nvhe, __deactivate_traps_vhe,
> > -			    ARM64_HAS_VIRT_HOST_EXTN);
> > -
> > -static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
> > +static inline void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
> >  {
> >  	/*
> >  	 * If we pended a virtual abort, preserve it until it gets
> > @@ -162,7 +157,10 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
> >  	if (vcpu->arch.hcr_el2 & HCR_VSE)
> >  		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
> >  
> > -	__deactivate_traps_arch()();
> > +	if (has_vhe())
> > +		deactivate_traps_vhe();
> > +	else
> > +		__deactivate_traps_nvhe();
> >  }
> >  
> >  void activate_traps_vhe_load(struct kvm_vcpu *vcpu)
> > -- 
> > 2.14.2
> > 
> 
> Thanks,
> 
> 	M.
> 
> -- 
> Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 38/40] KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on VHE
  2018-02-22 17:21             ` Marc Zyngier
@ 2018-02-22 19:28               ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 19:28 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Thu, Feb 22, 2018 at 05:21:20PM +0000, Marc Zyngier wrote:
> On 22/02/18 16:02, Christoffer Dall wrote:
> > On Thu, Feb 22, 2018 at 03:01:17PM +0000, Marc Zyngier wrote:
> >> On Thu, 22 Feb 2018 14:42:27 +0000,
> >> Christoffer Dall wrote:
> >>>
> >>> On Thu, Feb 22, 2018 at 12:32:11PM +0000, Marc Zyngier wrote:
> >>>> On 15/02/18 21:03, Christoffer Dall wrote:
> >>>>> Just like we can program the GICv2 hypervisor control interface directly
> >>>>> from the core vgic code, we can do the same for the GICv3 hypervisor
> >>>>> control interface on VHE systems.
> >>>>>
> >>>>> We do this by simply calling the save/restore functions when we have VHE
> >>>>> and we can then get rid of the save/restore function calls from the VHE
> >>>>> world switch function.
> >>>>>
> >>>>> One caveat is that we now write GICv3 system register state before the
> >>>>> potential early exit path in the run loop, and because we sync back
> >>>>> state in the early exit path, we have to ensure that we read a
> >>>>> consistent GIC state from the sync path, even though we have never
> >>>>> actually run the guest with the newly written GIC state.  We solve this
> >>>>> by inserting an ISB in the early exit path.
> >>>>>
> >>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >>>>> ---
> >>>>>
> >>>>> Notes:
> >>>>>     Changes since v2:
> >>>>>      - Added ISB in the early exit path in the run loop as explained
> >>>>>        in the commit message.
> >>>>>
> >>>>>  arch/arm64/kvm/hyp/switch.c | 3 ---
> >>>>>  virt/kvm/arm/arm.c          | 1 +
> >>>>>  virt/kvm/arm/vgic/vgic.c    | 5 +++++
> >>>>>  3 files changed, 6 insertions(+), 3 deletions(-)
> >>>>>
> >>>>> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> >>>>> index cbafc27a617b..466cfcdbcaf3 100644
> >>>>> --- a/arch/arm64/kvm/hyp/switch.c
> >>>>> +++ b/arch/arm64/kvm/hyp/switch.c
> >>>>> @@ -399,8 +399,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> >>>>>  	__activate_traps(vcpu);
> >>>>>  	__activate_vm(vcpu->kvm);
> >>>>>  
> >>>>> -	__vgic_restore_state(vcpu);
> >>>>> -
> >>>>>  	sysreg_restore_guest_state_vhe(guest_ctxt);
> >>>>>  	__debug_switch_to_guest(vcpu);
> >>>>>  
> >>>>> @@ -414,7 +412,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> >>>>>  	fp_enabled = fpsimd_enabled_vhe();
> >>>>>  
> >>>>>  	sysreg_save_guest_state_vhe(guest_ctxt);
> >>>>> -	__vgic_save_state(vcpu);
> >>>>>  
> >>>>>  	__deactivate_traps(vcpu);
> >>>>>  
> >>>>> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> >>>>> index 5bd879c78951..6de7641f3ff2 100644
> >>>>> --- a/virt/kvm/arm/arm.c
> >>>>> +++ b/virt/kvm/arm/arm.c
> >>>>> @@ -717,6 +717,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> >>>>>  		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
> >>>>>  		    kvm_request_pending(vcpu)) {
> >>>>>  			vcpu->mode = OUTSIDE_GUEST_MODE;
> >>>>> +			isb(); /* Ensure work in x_flush_hwstate is committed */
> >>>>>  			kvm_pmu_sync_hwstate(vcpu);
> >>>>>  			if (static_branch_unlikely(&userspace_irqchip_in_use))
> >>>>>  				kvm_timer_sync_hwstate(vcpu);
> >>>>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> >>>>> index 12e2a28f437e..d0a19a8c196a 100644
> >>>>> --- a/virt/kvm/arm/vgic/vgic.c
> >>>>> +++ b/virt/kvm/arm/vgic/vgic.c
> >>>>> @@ -19,6 +19,7 @@
> >>>>>  #include <linux/list_sort.h>
> >>>>>  #include <linux/interrupt.h>
> >>>>>  #include <linux/irq.h>
> >>>>> +#include <asm/kvm_hyp.h>
> >>>>>  
> >>>>>  #include "vgic.h"
> >>>>>  
> >>>>> @@ -753,6 +754,8 @@ static inline void vgic_save_state(struct kvm_vcpu *vcpu)
> >>>>>  {
> >>>>>  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> >>>>>  		vgic_v2_save_state(vcpu);
> >>>>> +	else if (has_vhe())
> >>>>> +		__vgic_v3_save_state(vcpu);
> >>>>>  }
> >>>>>  
> >>>>>  /* Sync back the hardware VGIC state into our emulation after a guest's run. */
> >>>>> @@ -777,6 +780,8 @@ static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
> >>>>>  {
> >>>>>  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> >>>>>  		vgic_v2_restore_state(vcpu);
> >>>>> +	else if (has_vhe())
> >>>>> +		__vgic_v3_restore_state(vcpu);
> >>>>>  }
> >>>>>  
> >>>>>  /* Flush our emulation state into the GIC hardware before entering the guest. */
> >>>>>
> >>>>
> >>>> I'm slowly wrapping my brain around this thing again. If I grasp the
> >>>> general idea, we end up with two cases:
> >>>>
> >>>> (1) The GIC is accessible from the kernel, and we save/restore it
> >>>> outside of the HYP code.
> >>>>
> >>>> (2) The GIC is only accessible from the HYP code, and we do it there.
> >>>>
> >>>> Maybe we should bite the bullet and introduce that primitive instead?
> >>>>
> >>>
> >>> You mean something the following?
> >>>
> >>> static inline bool can_access_vgic_from_kernel(void)
> >>> {
> >>> 	/*
> >>> 	 * GICv2 can always be accessed from the kernel because it is
> >>> 	 * memory-mapped, and VHE systems can access GICv3 EL2 system
> >>> 	 * registers.
> >>> 	 */
> >>> 	return !static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) || has_vhe();
> >>> }
> >>
> >> Yes. I think this would go a long way in making this code easy to
> >> understand. 
> > 
> > I'll give it a go on the next respin.
> > 
> >> It also mean that we can have a unified save/restore
> >> function that picks the right GIC back-end, resulting in less
> >> code duplication.
> >>
> > Not sure I understand hat you mean here?
> 
> We now have:
> 
> static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
> {
>         if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
>                 __vgic_v3_activate_traps(vcpu);
>                 __vgic_v3_restore_state(vcpu);
>         }
> }
> 
> and 
> 
> static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
> {
>         if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
>                 vgic_v2_restore_state(vcpu);
>         else if (has_vhe())
>                 __vgic_v3_restore_state(vcpu);
> }
> 
> I have the feeling that we could reconcile them in a nice way, but
> I'm not completely sure now...
> 
Hmm, yeah, so we have the VHE GICv3 flow:

vcpu_load -> vgic_v3_load -> __vgic_v3_activate_traps
   KVM_RUN -> kvm_vgic_flush_hwstate -> vgic_restore_state ->
              __vgic_v3_restore_state (if we have irqs)

Then we have the non-VHE GICv3 flow:
   KVM_RUN -> __kvm_vcpu_run_nvhe -> __vgic_restore_state ->
     __vgic_v3_activate_traps
     __vgic_v3_restore_state

Then we have the GICv2 flow:
   KVM_RUN -> kvm_vgic_flush_hwstate -> vgic_restore_state ->
              __vgic_v2_restore_state (if we have irqs)

We could at least rename __vgic_restore_state to
__vgic_hyp_restore_state.  Do you see further room for making this less
complicated?

Thanks,
-Christoffer

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

* [PATCH v4 38/40] KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on VHE
@ 2018-02-22 19:28               ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 19:28 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 22, 2018 at 05:21:20PM +0000, Marc Zyngier wrote:
> On 22/02/18 16:02, Christoffer Dall wrote:
> > On Thu, Feb 22, 2018 at 03:01:17PM +0000, Marc Zyngier wrote:
> >> On Thu, 22 Feb 2018 14:42:27 +0000,
> >> Christoffer Dall wrote:
> >>>
> >>> On Thu, Feb 22, 2018 at 12:32:11PM +0000, Marc Zyngier wrote:
> >>>> On 15/02/18 21:03, Christoffer Dall wrote:
> >>>>> Just like we can program the GICv2 hypervisor control interface directly
> >>>>> from the core vgic code, we can do the same for the GICv3 hypervisor
> >>>>> control interface on VHE systems.
> >>>>>
> >>>>> We do this by simply calling the save/restore functions when we have VHE
> >>>>> and we can then get rid of the save/restore function calls from the VHE
> >>>>> world switch function.
> >>>>>
> >>>>> One caveat is that we now write GICv3 system register state before the
> >>>>> potential early exit path in the run loop, and because we sync back
> >>>>> state in the early exit path, we have to ensure that we read a
> >>>>> consistent GIC state from the sync path, even though we have never
> >>>>> actually run the guest with the newly written GIC state.  We solve this
> >>>>> by inserting an ISB in the early exit path.
> >>>>>
> >>>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >>>>> ---
> >>>>>
> >>>>> Notes:
> >>>>>     Changes since v2:
> >>>>>      - Added ISB in the early exit path in the run loop as explained
> >>>>>        in the commit message.
> >>>>>
> >>>>>  arch/arm64/kvm/hyp/switch.c | 3 ---
> >>>>>  virt/kvm/arm/arm.c          | 1 +
> >>>>>  virt/kvm/arm/vgic/vgic.c    | 5 +++++
> >>>>>  3 files changed, 6 insertions(+), 3 deletions(-)
> >>>>>
> >>>>> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> >>>>> index cbafc27a617b..466cfcdbcaf3 100644
> >>>>> --- a/arch/arm64/kvm/hyp/switch.c
> >>>>> +++ b/arch/arm64/kvm/hyp/switch.c
> >>>>> @@ -399,8 +399,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> >>>>>  	__activate_traps(vcpu);
> >>>>>  	__activate_vm(vcpu->kvm);
> >>>>>  
> >>>>> -	__vgic_restore_state(vcpu);
> >>>>> -
> >>>>>  	sysreg_restore_guest_state_vhe(guest_ctxt);
> >>>>>  	__debug_switch_to_guest(vcpu);
> >>>>>  
> >>>>> @@ -414,7 +412,6 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
> >>>>>  	fp_enabled = fpsimd_enabled_vhe();
> >>>>>  
> >>>>>  	sysreg_save_guest_state_vhe(guest_ctxt);
> >>>>> -	__vgic_save_state(vcpu);
> >>>>>  
> >>>>>  	__deactivate_traps(vcpu);
> >>>>>  
> >>>>> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> >>>>> index 5bd879c78951..6de7641f3ff2 100644
> >>>>> --- a/virt/kvm/arm/arm.c
> >>>>> +++ b/virt/kvm/arm/arm.c
> >>>>> @@ -717,6 +717,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
> >>>>>  		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
> >>>>>  		    kvm_request_pending(vcpu)) {
> >>>>>  			vcpu->mode = OUTSIDE_GUEST_MODE;
> >>>>> +			isb(); /* Ensure work in x_flush_hwstate is committed */
> >>>>>  			kvm_pmu_sync_hwstate(vcpu);
> >>>>>  			if (static_branch_unlikely(&userspace_irqchip_in_use))
> >>>>>  				kvm_timer_sync_hwstate(vcpu);
> >>>>> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> >>>>> index 12e2a28f437e..d0a19a8c196a 100644
> >>>>> --- a/virt/kvm/arm/vgic/vgic.c
> >>>>> +++ b/virt/kvm/arm/vgic/vgic.c
> >>>>> @@ -19,6 +19,7 @@
> >>>>>  #include <linux/list_sort.h>
> >>>>>  #include <linux/interrupt.h>
> >>>>>  #include <linux/irq.h>
> >>>>> +#include <asm/kvm_hyp.h>
> >>>>>  
> >>>>>  #include "vgic.h"
> >>>>>  
> >>>>> @@ -753,6 +754,8 @@ static inline void vgic_save_state(struct kvm_vcpu *vcpu)
> >>>>>  {
> >>>>>  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> >>>>>  		vgic_v2_save_state(vcpu);
> >>>>> +	else if (has_vhe())
> >>>>> +		__vgic_v3_save_state(vcpu);
> >>>>>  }
> >>>>>  
> >>>>>  /* Sync back the hardware VGIC state into our emulation after a guest's run. */
> >>>>> @@ -777,6 +780,8 @@ static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
> >>>>>  {
> >>>>>  	if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> >>>>>  		vgic_v2_restore_state(vcpu);
> >>>>> +	else if (has_vhe())
> >>>>> +		__vgic_v3_restore_state(vcpu);
> >>>>>  }
> >>>>>  
> >>>>>  /* Flush our emulation state into the GIC hardware before entering the guest. */
> >>>>>
> >>>>
> >>>> I'm slowly wrapping my brain around this thing again. If I grasp the
> >>>> general idea, we end up with two cases:
> >>>>
> >>>> (1) The GIC is accessible from the kernel, and we save/restore it
> >>>> outside of the HYP code.
> >>>>
> >>>> (2) The GIC is only accessible from the HYP code, and we do it there.
> >>>>
> >>>> Maybe we should bite the bullet and introduce that primitive instead?
> >>>>
> >>>
> >>> You mean something the following?
> >>>
> >>> static inline bool can_access_vgic_from_kernel(void)
> >>> {
> >>> 	/*
> >>> 	 * GICv2 can always be accessed from the kernel because it is
> >>> 	 * memory-mapped, and VHE systems can access GICv3 EL2 system
> >>> 	 * registers.
> >>> 	 */
> >>> 	return !static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) || has_vhe();
> >>> }
> >>
> >> Yes. I think this would go a long way in making this code easy to
> >> understand. 
> > 
> > I'll give it a go on the next respin.
> > 
> >> It also mean that we can have a unified save/restore
> >> function that picks the right GIC back-end, resulting in less
> >> code duplication.
> >>
> > Not sure I understand hat you mean here?
> 
> We now have:
> 
> static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
> {
>         if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
>                 __vgic_v3_activate_traps(vcpu);
>                 __vgic_v3_restore_state(vcpu);
>         }
> }
> 
> and 
> 
> static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
> {
>         if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
>                 vgic_v2_restore_state(vcpu);
>         else if (has_vhe())
>                 __vgic_v3_restore_state(vcpu);
> }
> 
> I have the feeling that we could reconcile them in a nice way, but
> I'm not completely sure now...
> 
Hmm, yeah, so we have the VHE GICv3 flow:

vcpu_load -> vgic_v3_load -> __vgic_v3_activate_traps
   KVM_RUN -> kvm_vgic_flush_hwstate -> vgic_restore_state ->
              __vgic_v3_restore_state (if we have irqs)

Then we have the non-VHE GICv3 flow:
   KVM_RUN -> __kvm_vcpu_run_nvhe -> __vgic_restore_state ->
     __vgic_v3_activate_traps
     __vgic_v3_restore_state

Then we have the GICv2 flow:
   KVM_RUN -> kvm_vgic_flush_hwstate -> vgic_restore_state ->
              __vgic_v2_restore_state (if we have irqs)

We could at least rename __vgic_restore_state to
__vgic_hyp_restore_state.  Do you see further room for making this less
complicated?

Thanks,
-Christoffer

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

* Re: [PATCH v4 28/40] KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on VHE
  2018-02-22 18:30     ` Julien Grall
@ 2018-02-22 19:48       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 19:48 UTC (permalink / raw)
  To: Julien Grall
  Cc: Andrew Jones, kvm, Marc Zyngier, Tomasz Nowicki, Dave Martin,
	Yury Norov, linux-arm-kernel, kvmarm, Shih-Wei Li

On Thu, Feb 22, 2018 at 06:30:11PM +0000, Julien Grall wrote:
> Hi Christoffer,
> 
> On 15/02/18 21:03, Christoffer Dall wrote:
> >Some system registers do not affect the host kernel's execution and can
> >therefore be loaded when we are about to run a VCPU and we don't have to
> >restore the host state to the hardware before the time when we are
> >actually about to return to userspace or schedule out the VCPU thread.
> >
> >The EL1 system registers and the userspace state registers only
> >affecting EL0 execution do not need to be saved and restored on every
> >switch between the VM and the host, because they don't affect the host
> >kernel's execution.
> >
> >We mark all registers which are now deffered as such in the
> 
> NIT: s/deffered/deferred/ I think.
> 
> >vcpu_{read,write}_sys_reg accessors in sys-regs.c to ensure the most
> >up-to-date copy is always accessed.
> >
> >Note MPIDR_EL1 (controlled via VMPIDR_EL2) is accessed from other vcpu
> >threads, for example via the GIC emulation, and therefore must be
> >declared as immediate, which is fine as the guest cannot modify this
> >value.
> >
> >The 32-bit sysregs can also be deferred but we do this in a separate
> >patch as it requires a bit more infrastructure.
> 
> 
> [...]
> 
> >diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> >index b3c3f014aa61..f060309337aa 100644
> >--- a/arch/arm64/kvm/sys_regs.c
> >+++ b/arch/arm64/kvm/sys_regs.c
> >@@ -87,6 +87,26 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
> >  	 * exit from the guest but are only saved on vcpu_put.
> >  	 */
> >  	switch (reg) {
> >+	case CSSELR_EL1:	return read_sysreg_s(SYS_CSSELR_EL1);
> >+	case SCTLR_EL1:		return read_sysreg_s(sctlr_EL12);
> >+	case ACTLR_EL1:		return read_sysreg_s(SYS_ACTLR_EL1);
> >+	case CPACR_EL1:		return read_sysreg_s(cpacr_EL12);
> >+	case TTBR0_EL1:		return read_sysreg_s(ttbr0_EL12);
> >+	case TTBR1_EL1:		return read_sysreg_s(ttbr1_EL12);
> >+	case TCR_EL1:		return read_sysreg_s(tcr_EL12);
> >+	case ESR_EL1:		return read_sysreg_s(esr_EL12);
> >+	case AFSR0_EL1:		return read_sysreg_s(afsr0_EL12);
> >+	case AFSR1_EL1:		return read_sysreg_s(afsr1_EL12);
> >+	case FAR_EL1:		return read_sysreg_s(far_EL12);
> >+	case MAIR_EL1:		return read_sysreg_s(mair_EL12);
> >+	case VBAR_EL1:		return read_sysreg_s(vbar_EL12);
> >+	case CONTEXTIDR_EL1:	return read_sysreg_s(contextidr_EL12);
> >+	case TPIDR_EL0:		return read_sysreg_s(SYS_TPIDR_EL0);
> >+	case TPIDRRO_EL0:	return read_sysreg_s(SYS_TPIDRRO_EL0);
> 
> I find a bit confusing to have some EL0 registers in the middle of EL1 ones.
> Is it because they are listed by encoding?
> 

They are sorted in the same way as the sysreg array defines.  I can add
that to the commentary.

> >+	case TPIDR_EL1:		return read_sysreg_s(SYS_TPIDR_EL1);
> >+	case AMAIR_EL1:		return read_sysreg_s(amair_EL12);
> >+	case CNTKCTL_EL1:	return read_sysreg_s(cntkctl_EL12);
> >+	case PAR_EL1:		return read_sysreg_s(SYS_PAR_EL1);
> >  	}
> >  immediate_read:
> >@@ -103,6 +123,26 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
> >  	 * entry to the guest but are only restored on vcpu_load.
> >  	 */
> >  	switch (reg) {
> >+	case CSSELR_EL1:	write_sysreg_s(val, SYS_CSSELR_EL1);	return;
> >+	case SCTLR_EL1:		write_sysreg_s(val, sctlr_EL12);	return;
> >+	case ACTLR_EL1:		write_sysreg_s(val, SYS_ACTLR_EL1);	return;
> >+	case CPACR_EL1:		write_sysreg_s(val, cpacr_EL12);	return;
> >+	case TTBR0_EL1:		write_sysreg_s(val, ttbr0_EL12);	return;
> >+	case TTBR1_EL1:		write_sysreg_s(val, ttbr1_EL12);	return;
> >+	case TCR_EL1:		write_sysreg_s(val, tcr_EL12);		return;
> >+	case ESR_EL1:		write_sysreg_s(val, esr_EL12);		return;
> >+	case AFSR0_EL1:		write_sysreg_s(val, afsr0_EL12);	return;
> >+	case AFSR1_EL1:		write_sysreg_s(val, afsr1_EL12);	return;
> >+	case FAR_EL1:		write_sysreg_s(val, far_EL12);		return;
> >+	case MAIR_EL1:		write_sysreg_s(val, mair_EL12);		return;
> >+	case VBAR_EL1:		write_sysreg_s(val, vbar_EL12);		return;
> >+	case CONTEXTIDR_EL1:	write_sysreg_s(val, contextidr_EL12);	return;
> >+	case TPIDR_EL0:		write_sysreg_s(val, SYS_TPIDR_EL0);	return;
> >+	case TPIDRRO_EL0:	write_sysreg_s(val, SYS_TPIDRRO_EL0);	return;
> >+	case TPIDR_EL1:		write_sysreg_s(val, SYS_TPIDR_EL1);	return;
> >+	case AMAIR_EL1:		write_sysreg_s(val, amair_EL12);	return;
> >+	case CNTKCTL_EL1:	write_sysreg_s(val, cntkctl_EL12);	return;
> >+	case PAR_EL1:		write_sysreg_s(val, SYS_PAR_EL1);	return;
> >  	}
> >  immediate_write:
> >
> 

Thanks,
-Christoffer

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

* [PATCH v4 28/40] KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on VHE
@ 2018-02-22 19:48       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 19:48 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 22, 2018 at 06:30:11PM +0000, Julien Grall wrote:
> Hi Christoffer,
> 
> On 15/02/18 21:03, Christoffer Dall wrote:
> >Some system registers do not affect the host kernel's execution and can
> >therefore be loaded when we are about to run a VCPU and we don't have to
> >restore the host state to the hardware before the time when we are
> >actually about to return to userspace or schedule out the VCPU thread.
> >
> >The EL1 system registers and the userspace state registers only
> >affecting EL0 execution do not need to be saved and restored on every
> >switch between the VM and the host, because they don't affect the host
> >kernel's execution.
> >
> >We mark all registers which are now deffered as such in the
> 
> NIT: s/deffered/deferred/ I think.
> 
> >vcpu_{read,write}_sys_reg accessors in sys-regs.c to ensure the most
> >up-to-date copy is always accessed.
> >
> >Note MPIDR_EL1 (controlled via VMPIDR_EL2) is accessed from other vcpu
> >threads, for example via the GIC emulation, and therefore must be
> >declared as immediate, which is fine as the guest cannot modify this
> >value.
> >
> >The 32-bit sysregs can also be deferred but we do this in a separate
> >patch as it requires a bit more infrastructure.
> 
> 
> [...]
> 
> >diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> >index b3c3f014aa61..f060309337aa 100644
> >--- a/arch/arm64/kvm/sys_regs.c
> >+++ b/arch/arm64/kvm/sys_regs.c
> >@@ -87,6 +87,26 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
> >  	 * exit from the guest but are only saved on vcpu_put.
> >  	 */
> >  	switch (reg) {
> >+	case CSSELR_EL1:	return read_sysreg_s(SYS_CSSELR_EL1);
> >+	case SCTLR_EL1:		return read_sysreg_s(sctlr_EL12);
> >+	case ACTLR_EL1:		return read_sysreg_s(SYS_ACTLR_EL1);
> >+	case CPACR_EL1:		return read_sysreg_s(cpacr_EL12);
> >+	case TTBR0_EL1:		return read_sysreg_s(ttbr0_EL12);
> >+	case TTBR1_EL1:		return read_sysreg_s(ttbr1_EL12);
> >+	case TCR_EL1:		return read_sysreg_s(tcr_EL12);
> >+	case ESR_EL1:		return read_sysreg_s(esr_EL12);
> >+	case AFSR0_EL1:		return read_sysreg_s(afsr0_EL12);
> >+	case AFSR1_EL1:		return read_sysreg_s(afsr1_EL12);
> >+	case FAR_EL1:		return read_sysreg_s(far_EL12);
> >+	case MAIR_EL1:		return read_sysreg_s(mair_EL12);
> >+	case VBAR_EL1:		return read_sysreg_s(vbar_EL12);
> >+	case CONTEXTIDR_EL1:	return read_sysreg_s(contextidr_EL12);
> >+	case TPIDR_EL0:		return read_sysreg_s(SYS_TPIDR_EL0);
> >+	case TPIDRRO_EL0:	return read_sysreg_s(SYS_TPIDRRO_EL0);
> 
> I find a bit confusing to have some EL0 registers in the middle of EL1 ones.
> Is it because they are listed by encoding?
> 

They are sorted in the same way as the sysreg array defines.  I can add
that to the commentary.

> >+	case TPIDR_EL1:		return read_sysreg_s(SYS_TPIDR_EL1);
> >+	case AMAIR_EL1:		return read_sysreg_s(amair_EL12);
> >+	case CNTKCTL_EL1:	return read_sysreg_s(cntkctl_EL12);
> >+	case PAR_EL1:		return read_sysreg_s(SYS_PAR_EL1);
> >  	}
> >  immediate_read:
> >@@ -103,6 +123,26 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
> >  	 * entry to the guest but are only restored on vcpu_load.
> >  	 */
> >  	switch (reg) {
> >+	case CSSELR_EL1:	write_sysreg_s(val, SYS_CSSELR_EL1);	return;
> >+	case SCTLR_EL1:		write_sysreg_s(val, sctlr_EL12);	return;
> >+	case ACTLR_EL1:		write_sysreg_s(val, SYS_ACTLR_EL1);	return;
> >+	case CPACR_EL1:		write_sysreg_s(val, cpacr_EL12);	return;
> >+	case TTBR0_EL1:		write_sysreg_s(val, ttbr0_EL12);	return;
> >+	case TTBR1_EL1:		write_sysreg_s(val, ttbr1_EL12);	return;
> >+	case TCR_EL1:		write_sysreg_s(val, tcr_EL12);		return;
> >+	case ESR_EL1:		write_sysreg_s(val, esr_EL12);		return;
> >+	case AFSR0_EL1:		write_sysreg_s(val, afsr0_EL12);	return;
> >+	case AFSR1_EL1:		write_sysreg_s(val, afsr1_EL12);	return;
> >+	case FAR_EL1:		write_sysreg_s(val, far_EL12);		return;
> >+	case MAIR_EL1:		write_sysreg_s(val, mair_EL12);		return;
> >+	case VBAR_EL1:		write_sysreg_s(val, vbar_EL12);		return;
> >+	case CONTEXTIDR_EL1:	write_sysreg_s(val, contextidr_EL12);	return;
> >+	case TPIDR_EL0:		write_sysreg_s(val, SYS_TPIDR_EL0);	return;
> >+	case TPIDRRO_EL0:	write_sysreg_s(val, SYS_TPIDRRO_EL0);	return;
> >+	case TPIDR_EL1:		write_sysreg_s(val, SYS_TPIDR_EL1);	return;
> >+	case AMAIR_EL1:		write_sysreg_s(val, amair_EL12);	return;
> >+	case CNTKCTL_EL1:	write_sysreg_s(val, cntkctl_EL12);	return;
> >+	case PAR_EL1:		write_sysreg_s(val, SYS_PAR_EL1);	return;
> >  	}
> >  immediate_write:
> >
> 

Thanks,
-Christoffer

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

* Re: [PATCH v4 28/40] KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on VHE
  2018-02-22 18:31       ` Julien Grall
@ 2018-02-22 19:49         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 19:49 UTC (permalink / raw)
  To: Julien Grall
  Cc: Andrew Jones, kvm, Marc Zyngier, Tomasz Nowicki, Dave Martin,
	Yury Norov, linux-arm-kernel, kvmarm, Shih-Wei Li

On Thu, Feb 22, 2018 at 06:31:08PM +0000, Julien Grall wrote:
> 
> 
> On 22/02/18 18:30, Julien Grall wrote:
> >Hi Christoffer,
> >
> >On 15/02/18 21:03, Christoffer Dall wrote:
> >>Some system registers do not affect the host kernel's execution and can
> >>therefore be loaded when we are about to run a VCPU and we don't have to
> >>restore the host state to the hardware before the time when we are
> >>actually about to return to userspace or schedule out the VCPU thread.
> >>
> >>The EL1 system registers and the userspace state registers only
> >>affecting EL0 execution do not need to be saved and restored on every
> >>switch between the VM and the host, because they don't affect the host
> >>kernel's execution.
> >>
> >>We mark all registers which are now deffered as such in the
> >
> >NIT: s/deffered/deferred/ I think.
> >
> >>vcpu_{read,write}_sys_reg accessors in sys-regs.c to ensure the most
> >>up-to-date copy is always accessed.
> >>
> >>Note MPIDR_EL1 (controlled via VMPIDR_EL2) is accessed from other vcpu
> >>threads, for example via the GIC emulation, and therefore must be
> >>declared as immediate, which is fine as the guest cannot modify this
> >>value.
> 
> I forgot to comment on this. I missed this paragraph at the first read and
> was wondering why MPIDR_EL1 was not accessed using sysreg in
> vcpu_{read,write}_sys_reg. It might be worth considering a comment in those
> functions.
> 

Hmmm, yeah, probably.  I'll see if I can stick it somewhere suitable.

Thanks,
-Christoffer

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

* [PATCH v4 28/40] KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on VHE
@ 2018-02-22 19:49         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-22 19:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 22, 2018 at 06:31:08PM +0000, Julien Grall wrote:
> 
> 
> On 22/02/18 18:30, Julien Grall wrote:
> >Hi Christoffer,
> >
> >On 15/02/18 21:03, Christoffer Dall wrote:
> >>Some system registers do not affect the host kernel's execution and can
> >>therefore be loaded when we are about to run a VCPU and we don't have to
> >>restore the host state to the hardware before the time when we are
> >>actually about to return to userspace or schedule out the VCPU thread.
> >>
> >>The EL1 system registers and the userspace state registers only
> >>affecting EL0 execution do not need to be saved and restored on every
> >>switch between the VM and the host, because they don't affect the host
> >>kernel's execution.
> >>
> >>We mark all registers which are now deffered as such in the
> >
> >NIT: s/deffered/deferred/ I think.
> >
> >>vcpu_{read,write}_sys_reg accessors in sys-regs.c to ensure the most
> >>up-to-date copy is always accessed.
> >>
> >>Note MPIDR_EL1 (controlled via VMPIDR_EL2) is accessed from other vcpu
> >>threads, for example via the GIC emulation, and therefore must be
> >>declared as immediate, which is fine as the guest cannot modify this
> >>value.
> 
> I forgot to comment on this. I missed this paragraph at the first read and
> was wondering why MPIDR_EL1 was not accessed using sysreg in
> vcpu_{read,write}_sys_reg. It might be worth considering a comment in those
> functions.
> 

Hmmm, yeah, probably.  I'll see if I can stick it somewhere suitable.

Thanks,
-Christoffer

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

* Re: [PATCH v4 29/40] KVM: arm64: Prepare to handle deferred save/restore of 32-bit registers
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-23 11:35     ` Julien Grall
  -1 siblings, 0 replies; 276+ messages in thread
From: Julien Grall @ 2018-02-23 11:35 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: Andrew Jones, kvm, Marc Zyngier, Tomasz Nowicki, Yury Norov,
	Dave Martin, Shih-Wei Li

Hi Christoffer,

On 15/02/18 21:03, Christoffer Dall wrote:
> 32-bit registers are not used by a 64-bit host kernel and can be
> deferred, but we need to rework the accesses to this register to access
> the latest value depending on whether or not guest system registers are
> loaded on the CPU or only reside in memory.

I realize that you explain in the new patch why FPEXC32_EL2 is not 
directly accessed below. But I think it might be worth to explain it 
here as well because the commit message implies all 32-bit registers 
could be deferred.

> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>      Changes since v3:
>       - Don't also try to write hardware spsr when sysregs are not loaded
>       - Adapted patch to use switch-based sysreg save/restore approach
>       - (Kept additional BUG_ON() in vcpu_read_spsr32() to keep the compiler happy)
>      
>      Changes since v2:
>       - New patch (deferred register handling has been reworked)
> 
>   arch/arm64/include/asm/kvm_emulate.h | 32 +++++------------
>   arch/arm64/kvm/regmap.c              | 67 +++++++++++++++++++++++++++---------
>   arch/arm64/kvm/sys_regs.c            |  6 ++++
>   3 files changed, 65 insertions(+), 40 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 9cb13b23c7a1..23b33e8ea03a 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -33,7 +33,8 @@
>   #include <asm/virt.h>
>   
>   unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num);
> -unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu);
> +unsigned long vcpu_read_spsr32(const struct kvm_vcpu *vcpu);
> +void vcpu_write_spsr32(struct kvm_vcpu *vcpu, unsigned long v);
>   
>   bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
>   void kvm_skip_instr32(struct kvm_vcpu *vcpu, bool is_wide_instr);
> @@ -162,41 +163,26 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
>   
>   static inline unsigned long vcpu_read_spsr(const struct kvm_vcpu *vcpu)
>   {
> -	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> -
> -	if (vcpu_mode_is_32bit(vcpu)) {
> -		unsigned long *p_32bit = vcpu_spsr32(vcpu);
> -
> -		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> -		if (p_32bit != (unsigned long *)p)
> -			return *p_32bit;
> -	}
> +	if (vcpu_mode_is_32bit(vcpu))
> +		return vcpu_read_spsr32(vcpu);
>   
>   	if (vcpu->arch.sysregs_loaded_on_cpu)
>   		return read_sysreg_el1(spsr);
>   	else
> -		return *p;
> +		return vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
>   }
>   
> -static inline void vcpu_write_spsr(const struct kvm_vcpu *vcpu, unsigned long v)
> +static inline void vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long v)
>   {
> -	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> -
> -	/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
>   	if (vcpu_mode_is_32bit(vcpu)) {
> -		unsigned long *p_32bit = vcpu_spsr32(vcpu);
> -
> -		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> -		if (p_32bit != (unsigned long *)p) {
> -			*p_32bit = v;
> -			return;
> -		}
> +		vcpu_write_spsr32(vcpu, v);
> +		return;
>   	}
>   
>   	if (vcpu->arch.sysregs_loaded_on_cpu)
>   		write_sysreg_el1(v, spsr);
>   	else
> -		*p = v;
> +		vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1] = v;
>   }
>   
>   static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
> diff --git a/arch/arm64/kvm/regmap.c b/arch/arm64/kvm/regmap.c
> index bbc6ae32e4af..eefe403a2e63 100644
> --- a/arch/arm64/kvm/regmap.c
> +++ b/arch/arm64/kvm/regmap.c
> @@ -141,28 +141,61 @@ unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num)
>   /*
>    * Return the SPSR for the current mode of the virtual CPU.
>    */
> -unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu)
> +static int vcpu_spsr32_mode(const struct kvm_vcpu *vcpu)
>   {
>   	unsigned long mode = *vcpu_cpsr(vcpu) & COMPAT_PSR_MODE_MASK;
>   	switch (mode) {
> -	case COMPAT_PSR_MODE_SVC:
> -		mode = KVM_SPSR_SVC;
> -		break;
> -	case COMPAT_PSR_MODE_ABT:
> -		mode = KVM_SPSR_ABT;
> -		break;
> -	case COMPAT_PSR_MODE_UND:
> -		mode = KVM_SPSR_UND;
> -		break;
> -	case COMPAT_PSR_MODE_IRQ:
> -		mode = KVM_SPSR_IRQ;
> -		break;
> -	case COMPAT_PSR_MODE_FIQ:
> -		mode = KVM_SPSR_FIQ;
> -		break;
> +	case COMPAT_PSR_MODE_SVC: return KVM_SPSR_SVC;
> +	case COMPAT_PSR_MODE_ABT: return KVM_SPSR_ABT;
> +	case COMPAT_PSR_MODE_UND: return KVM_SPSR_UND;
> +	case COMPAT_PSR_MODE_IRQ: return KVM_SPSR_IRQ;
> +	case COMPAT_PSR_MODE_FIQ: return KVM_SPSR_FIQ;
> +	default: BUG();
> +	}
> +}
> +
> +unsigned long vcpu_read_spsr32(const struct kvm_vcpu *vcpu)
> +{
> +	int spsr_idx = vcpu_spsr32_mode(vcpu);
> +
> +	if (!vcpu->arch.sysregs_loaded_on_cpu)
> +		return vcpu_gp_regs(vcpu)->spsr[spsr_idx];
> +
> +	switch (spsr_idx) {
> +	case KVM_SPSR_SVC:
> +		return read_sysreg_el1(spsr);
> +	case KVM_SPSR_ABT:
> +		return read_sysreg(spsr_abt);
> +	case KVM_SPSR_UND:
> +		return read_sysreg(spsr_und);
> +	case KVM_SPSR_IRQ:
> +		return read_sysreg(spsr_irq);
> +	case KVM_SPSR_FIQ:
> +		return read_sysreg(spsr_fiq);
>   	default:
>   		BUG();
>   	}
> +}
> +
> +void vcpu_write_spsr32(struct kvm_vcpu *vcpu, unsigned long v)
> +{
> +	int spsr_idx = vcpu_spsr32_mode(vcpu);
> +
> +	if (!vcpu->arch.sysregs_loaded_on_cpu) {
> +		vcpu_gp_regs(vcpu)->spsr[spsr_idx] = v;
> +		return;
> +	}
>   
> -	return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[mode];
> +	switch (spsr_idx) {
> +	case KVM_SPSR_SVC:
> +		write_sysreg_el1(v, spsr);
> +	case KVM_SPSR_ABT:
> +		write_sysreg(v, spsr_abt);
> +	case KVM_SPSR_UND:
> +		write_sysreg(v, spsr_und);
> +	case KVM_SPSR_IRQ:
> +		write_sysreg(v, spsr_irq);
> +	case KVM_SPSR_FIQ:
> +		write_sysreg(v, spsr_fiq);
> +	}
>   }
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index f060309337aa..d2324560c9f5 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -107,6 +107,9 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
>   	case AMAIR_EL1:		return read_sysreg_s(amair_EL12);
>   	case CNTKCTL_EL1:	return read_sysreg_s(cntkctl_EL12);
>   	case PAR_EL1:		return read_sysreg_s(SYS_PAR_EL1);
> +	case DACR32_EL2:	return read_sysreg_s(SYS_DACR32_EL2);
> +	case IFSR32_EL2:	return read_sysreg_s(SYS_IFSR32_EL2);
> +	case DBGVCR32_EL2:	return read_sysreg_s(SYS_DBGVCR32_EL2);
>   	}
>   
>   immediate_read:
> @@ -143,6 +146,9 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
>   	case AMAIR_EL1:		write_sysreg_s(val, amair_EL12);	return;
>   	case CNTKCTL_EL1:	write_sysreg_s(val, cntkctl_EL12);	return;
>   	case PAR_EL1:		write_sysreg_s(val, SYS_PAR_EL1);	return;
> +	case DACR32_EL2:	write_sysreg_s(val, SYS_DACR32_EL2);	return;
> +	case IFSR32_EL2:	write_sysreg_s(val, SYS_IFSR32_EL2);	return;
> +	case DBGVCR32_EL2:	write_sysreg_s(val, SYS_DBGVCR32_EL2);	return;
>   	}
>   
>   immediate_write:
> 

Cheers,

-- 
Julien Grall

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

* [PATCH v4 29/40] KVM: arm64: Prepare to handle deferred save/restore of 32-bit registers
@ 2018-02-23 11:35     ` Julien Grall
  0 siblings, 0 replies; 276+ messages in thread
From: Julien Grall @ 2018-02-23 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoffer,

On 15/02/18 21:03, Christoffer Dall wrote:
> 32-bit registers are not used by a 64-bit host kernel and can be
> deferred, but we need to rework the accesses to this register to access
> the latest value depending on whether or not guest system registers are
> loaded on the CPU or only reside in memory.

I realize that you explain in the new patch why FPEXC32_EL2 is not 
directly accessed below. But I think it might be worth to explain it 
here as well because the commit message implies all 32-bit registers 
could be deferred.

> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> 
> Notes:
>      Changes since v3:
>       - Don't also try to write hardware spsr when sysregs are not loaded
>       - Adapted patch to use switch-based sysreg save/restore approach
>       - (Kept additional BUG_ON() in vcpu_read_spsr32() to keep the compiler happy)
>      
>      Changes since v2:
>       - New patch (deferred register handling has been reworked)
> 
>   arch/arm64/include/asm/kvm_emulate.h | 32 +++++------------
>   arch/arm64/kvm/regmap.c              | 67 +++++++++++++++++++++++++++---------
>   arch/arm64/kvm/sys_regs.c            |  6 ++++
>   3 files changed, 65 insertions(+), 40 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 9cb13b23c7a1..23b33e8ea03a 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -33,7 +33,8 @@
>   #include <asm/virt.h>
>   
>   unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num);
> -unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu);
> +unsigned long vcpu_read_spsr32(const struct kvm_vcpu *vcpu);
> +void vcpu_write_spsr32(struct kvm_vcpu *vcpu, unsigned long v);
>   
>   bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
>   void kvm_skip_instr32(struct kvm_vcpu *vcpu, bool is_wide_instr);
> @@ -162,41 +163,26 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
>   
>   static inline unsigned long vcpu_read_spsr(const struct kvm_vcpu *vcpu)
>   {
> -	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> -
> -	if (vcpu_mode_is_32bit(vcpu)) {
> -		unsigned long *p_32bit = vcpu_spsr32(vcpu);
> -
> -		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> -		if (p_32bit != (unsigned long *)p)
> -			return *p_32bit;
> -	}
> +	if (vcpu_mode_is_32bit(vcpu))
> +		return vcpu_read_spsr32(vcpu);
>   
>   	if (vcpu->arch.sysregs_loaded_on_cpu)
>   		return read_sysreg_el1(spsr);
>   	else
> -		return *p;
> +		return vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
>   }
>   
> -static inline void vcpu_write_spsr(const struct kvm_vcpu *vcpu, unsigned long v)
> +static inline void vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long v)
>   {
> -	unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> -
> -	/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
>   	if (vcpu_mode_is_32bit(vcpu)) {
> -		unsigned long *p_32bit = vcpu_spsr32(vcpu);
> -
> -		/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
> -		if (p_32bit != (unsigned long *)p) {
> -			*p_32bit = v;
> -			return;
> -		}
> +		vcpu_write_spsr32(vcpu, v);
> +		return;
>   	}
>   
>   	if (vcpu->arch.sysregs_loaded_on_cpu)
>   		write_sysreg_el1(v, spsr);
>   	else
> -		*p = v;
> +		vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1] = v;
>   }
>   
>   static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
> diff --git a/arch/arm64/kvm/regmap.c b/arch/arm64/kvm/regmap.c
> index bbc6ae32e4af..eefe403a2e63 100644
> --- a/arch/arm64/kvm/regmap.c
> +++ b/arch/arm64/kvm/regmap.c
> @@ -141,28 +141,61 @@ unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num)
>   /*
>    * Return the SPSR for the current mode of the virtual CPU.
>    */
> -unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu)
> +static int vcpu_spsr32_mode(const struct kvm_vcpu *vcpu)
>   {
>   	unsigned long mode = *vcpu_cpsr(vcpu) & COMPAT_PSR_MODE_MASK;
>   	switch (mode) {
> -	case COMPAT_PSR_MODE_SVC:
> -		mode = KVM_SPSR_SVC;
> -		break;
> -	case COMPAT_PSR_MODE_ABT:
> -		mode = KVM_SPSR_ABT;
> -		break;
> -	case COMPAT_PSR_MODE_UND:
> -		mode = KVM_SPSR_UND;
> -		break;
> -	case COMPAT_PSR_MODE_IRQ:
> -		mode = KVM_SPSR_IRQ;
> -		break;
> -	case COMPAT_PSR_MODE_FIQ:
> -		mode = KVM_SPSR_FIQ;
> -		break;
> +	case COMPAT_PSR_MODE_SVC: return KVM_SPSR_SVC;
> +	case COMPAT_PSR_MODE_ABT: return KVM_SPSR_ABT;
> +	case COMPAT_PSR_MODE_UND: return KVM_SPSR_UND;
> +	case COMPAT_PSR_MODE_IRQ: return KVM_SPSR_IRQ;
> +	case COMPAT_PSR_MODE_FIQ: return KVM_SPSR_FIQ;
> +	default: BUG();
> +	}
> +}
> +
> +unsigned long vcpu_read_spsr32(const struct kvm_vcpu *vcpu)
> +{
> +	int spsr_idx = vcpu_spsr32_mode(vcpu);
> +
> +	if (!vcpu->arch.sysregs_loaded_on_cpu)
> +		return vcpu_gp_regs(vcpu)->spsr[spsr_idx];
> +
> +	switch (spsr_idx) {
> +	case KVM_SPSR_SVC:
> +		return read_sysreg_el1(spsr);
> +	case KVM_SPSR_ABT:
> +		return read_sysreg(spsr_abt);
> +	case KVM_SPSR_UND:
> +		return read_sysreg(spsr_und);
> +	case KVM_SPSR_IRQ:
> +		return read_sysreg(spsr_irq);
> +	case KVM_SPSR_FIQ:
> +		return read_sysreg(spsr_fiq);
>   	default:
>   		BUG();
>   	}
> +}
> +
> +void vcpu_write_spsr32(struct kvm_vcpu *vcpu, unsigned long v)
> +{
> +	int spsr_idx = vcpu_spsr32_mode(vcpu);
> +
> +	if (!vcpu->arch.sysregs_loaded_on_cpu) {
> +		vcpu_gp_regs(vcpu)->spsr[spsr_idx] = v;
> +		return;
> +	}
>   
> -	return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[mode];
> +	switch (spsr_idx) {
> +	case KVM_SPSR_SVC:
> +		write_sysreg_el1(v, spsr);
> +	case KVM_SPSR_ABT:
> +		write_sysreg(v, spsr_abt);
> +	case KVM_SPSR_UND:
> +		write_sysreg(v, spsr_und);
> +	case KVM_SPSR_IRQ:
> +		write_sysreg(v, spsr_irq);
> +	case KVM_SPSR_FIQ:
> +		write_sysreg(v, spsr_fiq);
> +	}
>   }
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index f060309337aa..d2324560c9f5 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -107,6 +107,9 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
>   	case AMAIR_EL1:		return read_sysreg_s(amair_EL12);
>   	case CNTKCTL_EL1:	return read_sysreg_s(cntkctl_EL12);
>   	case PAR_EL1:		return read_sysreg_s(SYS_PAR_EL1);
> +	case DACR32_EL2:	return read_sysreg_s(SYS_DACR32_EL2);
> +	case IFSR32_EL2:	return read_sysreg_s(SYS_IFSR32_EL2);
> +	case DBGVCR32_EL2:	return read_sysreg_s(SYS_DBGVCR32_EL2);
>   	}
>   
>   immediate_read:
> @@ -143,6 +146,9 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
>   	case AMAIR_EL1:		write_sysreg_s(val, amair_EL12);	return;
>   	case CNTKCTL_EL1:	write_sysreg_s(val, cntkctl_EL12);	return;
>   	case PAR_EL1:		write_sysreg_s(val, SYS_PAR_EL1);	return;
> +	case DACR32_EL2:	write_sysreg_s(val, SYS_DACR32_EL2);	return;
> +	case IFSR32_EL2:	write_sysreg_s(val, SYS_IFSR32_EL2);	return;
> +	case DBGVCR32_EL2:	write_sysreg_s(val, SYS_DBGVCR32_EL2);	return;
>   	}
>   
>   immediate_write:
> 

Cheers,

-- 
Julien Grall

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

* Re: [PATCH v4 31/40] KVM: arm64: Move common VHE/non-VHE trap config in separate functions
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-23 14:30     ` Julien Grall
  -1 siblings, 0 replies; 276+ messages in thread
From: Julien Grall @ 2018-02-23 14:30 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: Andrew Jones, kvm, Marc Zyngier, Tomasz Nowicki, Yury Norov,
	Dave Martin, Shih-Wei Li

Hi Christoffer,

On 15/02/18 21:03, Christoffer Dall wrote:
> @@ -85,37 +123,14 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
>   {
>   	u64 hcr = vcpu->arch.hcr_el2;
>   
> -	/*
> -	 * We are about to set CPTR_EL2.TFP to trap all floating point
> -	 * register accesses to EL2, however, the ARM ARM clearly states that
> -	 * traps are only taken to EL2 if the operation would not otherwise
> -	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> -	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> -	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> -	 * it will cause an exception.
> -	 */
> -	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> -		write_sysreg(1 << 30, fpexc32_el2);
> -		isb();
> -	}
> +	write_sysreg(hcr, hcr_el2);
>   
>   	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
>   		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
>   
> -	write_sysreg(hcr, hcr_el2);

OOI, any reason to move the write to HCR_EL2 just before the if?

> -
> -	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
> -	write_sysreg(1 << 15, hstr_el2);
> -	/*
> -	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> -	 * PMSELR_EL0 to make sure it never contains the cycle
> -	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> -	 * EL1 instead of being trapped to EL2.
> -	 */
> -	write_sysreg(0, pmselr_el0);
> -	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> -	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> -	__activate_traps_arch()();
> +	__activate_traps_fpsimd32(vcpu);
> +	__activate_traps_common(vcpu);
> +	__activate_traps_arch()(vcpu);
>   }
>   
>   static void __hyp_text __deactivate_traps_vhe(void)
> @@ -160,9 +175,8 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
>   	if (vcpu->arch.hcr_el2 & HCR_VSE)
>   		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
>   
> +	__deactivate_traps_common();
>   	__deactivate_traps_arch()();
> -	write_sysreg(0, hstr_el2);
> -	write_sysreg(0, pmuserenr_el0);
>   }
>   
>   static void __hyp_text __activate_vm(struct kvm *kvm)
> 

Cheers,

-- 
Julien Grall

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

* [PATCH v4 31/40] KVM: arm64: Move common VHE/non-VHE trap config in separate functions
@ 2018-02-23 14:30     ` Julien Grall
  0 siblings, 0 replies; 276+ messages in thread
From: Julien Grall @ 2018-02-23 14:30 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoffer,

On 15/02/18 21:03, Christoffer Dall wrote:
> @@ -85,37 +123,14 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
>   {
>   	u64 hcr = vcpu->arch.hcr_el2;
>   
> -	/*
> -	 * We are about to set CPTR_EL2.TFP to trap all floating point
> -	 * register accesses to EL2, however, the ARM ARM clearly states that
> -	 * traps are only taken to EL2 if the operation would not otherwise
> -	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> -	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> -	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> -	 * it will cause an exception.
> -	 */
> -	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> -		write_sysreg(1 << 30, fpexc32_el2);
> -		isb();
> -	}
> +	write_sysreg(hcr, hcr_el2);
>   
>   	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
>   		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
>   
> -	write_sysreg(hcr, hcr_el2);

OOI, any reason to move the write to HCR_EL2 just before the if?

> -
> -	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
> -	write_sysreg(1 << 15, hstr_el2);
> -	/*
> -	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> -	 * PMSELR_EL0 to make sure it never contains the cycle
> -	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> -	 * EL1 instead of being trapped to EL2.
> -	 */
> -	write_sysreg(0, pmselr_el0);
> -	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> -	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> -	__activate_traps_arch()();
> +	__activate_traps_fpsimd32(vcpu);
> +	__activate_traps_common(vcpu);
> +	__activate_traps_arch()(vcpu);
>   }
>   
>   static void __hyp_text __deactivate_traps_vhe(void)
> @@ -160,9 +175,8 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
>   	if (vcpu->arch.hcr_el2 & HCR_VSE)
>   		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
>   
> +	__deactivate_traps_common();
>   	__deactivate_traps_arch()();
> -	write_sysreg(0, hstr_el2);
> -	write_sysreg(0, pmuserenr_el0);
>   }
>   
>   static void __hyp_text __activate_vm(struct kvm *kvm)
> 

Cheers,

-- 
Julien Grall

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

* Re: [PATCH v4 35/40] KVM: arm/arm64: Get rid of vgic_elrsr
  2018-02-15 21:03   ` Christoffer Dall
@ 2018-02-23 14:44     ` Julien Grall
  -1 siblings, 0 replies; 276+ messages in thread
From: Julien Grall @ 2018-02-23 14:44 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: kvm, Marc Zyngier, Yury Norov, Dave Martin, Shih-Wei Li

Hi Christoffer,

On 15/02/18 21:03, Christoffer Dall wrote:
> There is really no need to store the vgic_elrsr on the VGIC data
> structures as the only need we have for the elrsr is to figure out if an
> LR is inactive when we save the VGIC state upon returning from the
> guest.  We can might as well store this in a temporary local variable.
> 
> This also gets rid of the endianness conversion in the VGIC save
> function, which is completely unnecessary and would actually result in
> incorrect functionality on big-endian systems, because we are only using
> typed values here and not converting pointers and reading different
> types here.

I can't find any endianness code removed in this code. What did I miss?

Cheers,

-- 
Julien Grall

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

* [PATCH v4 35/40] KVM: arm/arm64: Get rid of vgic_elrsr
@ 2018-02-23 14:44     ` Julien Grall
  0 siblings, 0 replies; 276+ messages in thread
From: Julien Grall @ 2018-02-23 14:44 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Christoffer,

On 15/02/18 21:03, Christoffer Dall wrote:
> There is really no need to store the vgic_elrsr on the VGIC data
> structures as the only need we have for the elrsr is to figure out if an
> LR is inactive when we save the VGIC state upon returning from the
> guest.  We can might as well store this in a temporary local variable.
> 
> This also gets rid of the endianness conversion in the VGIC save
> function, which is completely unnecessary and would actually result in
> incorrect functionality on big-endian systems, because we are only using
> typed values here and not converting pointers and reading different
> types here.

I can't find any endianness code removed in this code. What did I miss?

Cheers,

-- 
Julien Grall

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

* Re: [PATCH v4 31/40] KVM: arm64: Move common VHE/non-VHE trap config in separate functions
  2018-02-23 14:30     ` Julien Grall
@ 2018-02-23 17:48       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-23 17:48 UTC (permalink / raw)
  To: Julien Grall
  Cc: Andrew Jones, kvm, Marc Zyngier, Tomasz Nowicki, Dave Martin,
	Yury Norov, linux-arm-kernel, kvmarm, Shih-Wei Li

On Fri, Feb 23, 2018 at 02:30:54PM +0000, Julien Grall wrote:
> Hi Christoffer,
> 
> On 15/02/18 21:03, Christoffer Dall wrote:
> >@@ -85,37 +123,14 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 hcr = vcpu->arch.hcr_el2;
> >-	/*
> >-	 * We are about to set CPTR_EL2.TFP to trap all floating point
> >-	 * register accesses to EL2, however, the ARM ARM clearly states that
> >-	 * traps are only taken to EL2 if the operation would not otherwise
> >-	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> >-	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> >-	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> >-	 * it will cause an exception.
> >-	 */
> >-	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> >-		write_sysreg(1 << 30, fpexc32_el2);
> >-		isb();
> >-	}
> >+	write_sysreg(hcr, hcr_el2);
> >  	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
> >  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
> >-	write_sysreg(hcr, hcr_el2);
> 
> OOI, any reason to move the write to HCR_EL2 just before the if?
> 

I suppose not, I think this is just a rebasing artifact.

> >-
> >-	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
> >-	write_sysreg(1 << 15, hstr_el2);
> >-	/*
> >-	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> >-	 * PMSELR_EL0 to make sure it never contains the cycle
> >-	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> >-	 * EL1 instead of being trapped to EL2.
> >-	 */
> >-	write_sysreg(0, pmselr_el0);
> >-	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> >-	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> >-	__activate_traps_arch()();
> >+	__activate_traps_fpsimd32(vcpu);
> >+	__activate_traps_common(vcpu);
> >+	__activate_traps_arch()(vcpu);
> >  }
> >  static void __hyp_text __deactivate_traps_vhe(void)
> >@@ -160,9 +175,8 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
> >  	if (vcpu->arch.hcr_el2 & HCR_VSE)
> >  		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
> >+	__deactivate_traps_common();
> >  	__deactivate_traps_arch()();
> >-	write_sysreg(0, hstr_el2);
> >-	write_sysreg(0, pmuserenr_el0);
> >  }
> >  static void __hyp_text __activate_vm(struct kvm *kvm)
> >
> 
Thanks,
-Christoffer

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

* [PATCH v4 31/40] KVM: arm64: Move common VHE/non-VHE trap config in separate functions
@ 2018-02-23 17:48       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-23 17:48 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Feb 23, 2018 at 02:30:54PM +0000, Julien Grall wrote:
> Hi Christoffer,
> 
> On 15/02/18 21:03, Christoffer Dall wrote:
> >@@ -85,37 +123,14 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 hcr = vcpu->arch.hcr_el2;
> >-	/*
> >-	 * We are about to set CPTR_EL2.TFP to trap all floating point
> >-	 * register accesses to EL2, however, the ARM ARM clearly states that
> >-	 * traps are only taken to EL2 if the operation would not otherwise
> >-	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> >-	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> >-	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> >-	 * it will cause an exception.
> >-	 */
> >-	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> >-		write_sysreg(1 << 30, fpexc32_el2);
> >-		isb();
> >-	}
> >+	write_sysreg(hcr, hcr_el2);
> >  	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
> >  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
> >-	write_sysreg(hcr, hcr_el2);
> 
> OOI, any reason to move the write to HCR_EL2 just before the if?
> 

I suppose not, I think this is just a rebasing artifact.

> >-
> >-	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
> >-	write_sysreg(1 << 15, hstr_el2);
> >-	/*
> >-	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> >-	 * PMSELR_EL0 to make sure it never contains the cycle
> >-	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> >-	 * EL1 instead of being trapped to EL2.
> >-	 */
> >-	write_sysreg(0, pmselr_el0);
> >-	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> >-	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> >-	__activate_traps_arch()();
> >+	__activate_traps_fpsimd32(vcpu);
> >+	__activate_traps_common(vcpu);
> >+	__activate_traps_arch()(vcpu);
> >  }
> >  static void __hyp_text __deactivate_traps_vhe(void)
> >@@ -160,9 +175,8 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
> >  	if (vcpu->arch.hcr_el2 & HCR_VSE)
> >  		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
> >+	__deactivate_traps_common();
> >  	__deactivate_traps_arch()();
> >-	write_sysreg(0, hstr_el2);
> >-	write_sysreg(0, pmuserenr_el0);
> >  }
> >  static void __hyp_text __activate_vm(struct kvm *kvm)
> >
> 
Thanks,
-Christoffer

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

* Re: [PATCH v4 35/40] KVM: arm/arm64: Get rid of vgic_elrsr
  2018-02-23 14:44     ` Julien Grall
@ 2018-02-23 17:50       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-23 17:50 UTC (permalink / raw)
  To: Julien Grall
  Cc: Andrew Jones, kvm, Marc Zyngier, Tomasz Nowicki, Dave Martin,
	Yury Norov, linux-arm-kernel, kvmarm, Shih-Wei Li

On Fri, Feb 23, 2018 at 02:44:30PM +0000, Julien Grall wrote:
> Hi Christoffer,
> 
> On 15/02/18 21:03, Christoffer Dall wrote:
> >There is really no need to store the vgic_elrsr on the VGIC data
> >structures as the only need we have for the elrsr is to figure out if an
> >LR is inactive when we save the VGIC state upon returning from the
> >guest.  We can might as well store this in a temporary local variable.
> >
> >This also gets rid of the endianness conversion in the VGIC save
> >function, which is completely unnecessary and would actually result in
> >incorrect functionality on big-endian systems, because we are only using
> >typed values here and not converting pointers and reading different
> >types here.
> 
> I can't find any endianness code removed in this code. What did I miss?
> 

Ah, good find, we ended up fixing this in a separate commit:

fc396e066318, "KVM: arm/arm64: Fix broken GICH_ELRSR big endian conversion", 2017-12-03

I'll adjust the commit message.

Thanks,
-Christoffer

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

* [PATCH v4 35/40] KVM: arm/arm64: Get rid of vgic_elrsr
@ 2018-02-23 17:50       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-23 17:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Feb 23, 2018 at 02:44:30PM +0000, Julien Grall wrote:
> Hi Christoffer,
> 
> On 15/02/18 21:03, Christoffer Dall wrote:
> >There is really no need to store the vgic_elrsr on the VGIC data
> >structures as the only need we have for the elrsr is to figure out if an
> >LR is inactive when we save the VGIC state upon returning from the
> >guest.  We can might as well store this in a temporary local variable.
> >
> >This also gets rid of the endianness conversion in the VGIC save
> >function, which is completely unnecessary and would actually result in
> >incorrect functionality on big-endian systems, because we are only using
> >typed values here and not converting pointers and reading different
> >types here.
> 
> I can't find any endianness code removed in this code. What did I miss?
> 

Ah, good find, we ended up fixing this in a separate commit:

fc396e066318, "KVM: arm/arm64: Fix broken GICH_ELRSR big endian conversion", 2017-12-03

I'll adjust the commit message.

Thanks,
-Christoffer

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

* Re: [PATCH v4 28/40] KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on VHE
  2018-02-21 15:33     ` Marc Zyngier
@ 2018-02-23 18:05       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-23 18:05 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Wed, Feb 21, 2018 at 03:33:47PM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:03:20 +0000,
> Christoffer Dall wrote:
> > 
> > Some system registers do not affect the host kernel's execution and can
> > therefore be loaded when we are about to run a VCPU and we don't have to
> > restore the host state to the hardware before the time when we are
> > actually about to return to userspace or schedule out the VCPU thread.
> > 
> > The EL1 system registers and the userspace state registers only
> > affecting EL0 execution do not need to be saved and restored on every
> > switch between the VM and the host, because they don't affect the host
> > kernel's execution.
> > 
> > We mark all registers which are now deffered as such in the
> > vcpu_{read,write}_sys_reg accessors in sys-regs.c to ensure the most
> > up-to-date copy is always accessed.
> > 
> > Note MPIDR_EL1 (controlled via VMPIDR_EL2) is accessed from other vcpu
> > threads, for example via the GIC emulation, and therefore must be
> > declared as immediate, which is fine as the guest cannot modify this
> > value.
> > 
> > The 32-bit sysregs can also be deferred but we do this in a separate
> > patch as it requires a bit more infrastructure.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v3:
> >      - Changed to switch-based sysreg approach
> > 
> >  arch/arm64/kvm/hyp/sysreg-sr.c | 39 +++++++++++++++++++++++++++++++--------
> >  arch/arm64/kvm/sys_regs.c      | 40 ++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 71 insertions(+), 8 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> > index 906606dc4e2c..9c60b8062724 100644
> > --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> > +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> > @@ -25,8 +25,12 @@
> >  /*
> >   * Non-VHE: Both host and guest must save everything.
> >   *
> > - * VHE: Host must save tpidr*_el0, mdscr_el1, sp_el0,
> > - * and guest must save everything.
> > + * VHE: Host and guest must save mdscr_el1 and sp_el0 (and the PC and pstate,
> > + * which are handled as part of the el2 return state) on every switch.
> > + * tpidr_el0 and tpidrro_el0 only need to be switched when going
> 
> How about suspend/resume, which saves/restores both of these EL0
> registers (see cpu_do_suspend)? We may not need to do anything (either
> because vcpu_put will have happened, or because we'll come back
> exactly where we were), but I'd like to make sure this hasn't been
> overlooked.
> 

Interesting question.

AFAICT, cpu_do_suspend preserves the values in these registers, which
means it will either preserve the guest's or user space's values,
depending on when cpu_do_suspend is called.  It will be the former if
cpu_do_suspend is called in between vcpu_load and vcpu_put (from
interrupt context, for example), and it will be the latter if called
after the thread goes to sleep for example.

I can't see how suspend can break this.  Am I missing something?

> > + * to host userspace or a different VCPU.  EL1 registers only need to be
> > + * switched when potentially going to run a different VCPU.  The latter two
> > + * classes are handled as part of kvm_arch_vcpu_load and kvm_arch_vcpu_put.
> >   */
> >  
> >  static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
> > @@ -93,14 +97,11 @@ void __hyp_text __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt)
> >  void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt)
> >  {
> >  	__sysreg_save_common_state(ctxt);
> > -	__sysreg_save_user_state(ctxt);
> >  }
> >  
> >  void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt)
> >  {
> > -	__sysreg_save_el1_state(ctxt);
> >  	__sysreg_save_common_state(ctxt);
> > -	__sysreg_save_user_state(ctxt);
> >  	__sysreg_save_el2_return_state(ctxt);
> >  }
> >  
> > @@ -169,14 +170,11 @@ void __hyp_text __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt)
> >  void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt)
> >  {
> >  	__sysreg_restore_common_state(ctxt);
> > -	__sysreg_restore_user_state(ctxt);
> >  }
> >  
> >  void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt)
> >  {
> > -	__sysreg_restore_el1_state(ctxt);
> >  	__sysreg_restore_common_state(ctxt);
> > -	__sysreg_restore_user_state(ctxt);
> >  	__sysreg_restore_el2_return_state(ctxt);
> >  }
> >  
> > @@ -240,6 +238,18 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
> >   */
> >  void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
> >  {
> > +	struct kvm_cpu_context *host_ctxt = vcpu->arch.host_cpu_context;
> > +	struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt;
> > +
> > +	if (!has_vhe())
> > +		return;
> > +
> > +	__sysreg_save_user_state(host_ctxt);
> > +
> > +	__sysreg_restore_user_state(guest_ctxt);
> > +	__sysreg_restore_el1_state(guest_ctxt);
> > +
> > +	vcpu->arch.sysregs_loaded_on_cpu = true;
> >  }
> >  
> >  /**
> > @@ -255,6 +265,19 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
> >   */
> >  void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
> >  {
> > +	struct kvm_cpu_context *host_ctxt = vcpu->arch.host_cpu_context;
> > +	struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt;
> > +
> > +	if (!has_vhe())
> > +		return;
> > +
> > +	__sysreg_save_el1_state(guest_ctxt);
> > +	__sysreg_save_user_state(guest_ctxt);
> > +
> > +	/* Restore host user state */
> > +	__sysreg_restore_user_state(host_ctxt);
> > +
> > +	vcpu->arch.sysregs_loaded_on_cpu = false;
> >  }
> >  
> >  void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2)
> > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> > index b3c3f014aa61..f060309337aa 100644
> > --- a/arch/arm64/kvm/sys_regs.c
> > +++ b/arch/arm64/kvm/sys_regs.c
> > @@ -87,6 +87,26 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
> >  	 * exit from the guest but are only saved on vcpu_put.
> >  	 */
> >  	switch (reg) {
> > +	case CSSELR_EL1:	return read_sysreg_s(SYS_CSSELR_EL1);
> > +	case SCTLR_EL1:		return read_sysreg_s(sctlr_EL12);
> > +	case ACTLR_EL1:		return read_sysreg_s(SYS_ACTLR_EL1);
> > +	case CPACR_EL1:		return read_sysreg_s(cpacr_EL12);
> > +	case TTBR0_EL1:		return read_sysreg_s(ttbr0_EL12);
> > +	case TTBR1_EL1:		return read_sysreg_s(ttbr1_EL12);
> > +	case TCR_EL1:		return read_sysreg_s(tcr_EL12);
> > +	case ESR_EL1:		return read_sysreg_s(esr_EL12);
> > +	case AFSR0_EL1:		return read_sysreg_s(afsr0_EL12);
> > +	case AFSR1_EL1:		return read_sysreg_s(afsr1_EL12);
> > +	case FAR_EL1:		return read_sysreg_s(far_EL12);
> > +	case MAIR_EL1:		return read_sysreg_s(mair_EL12);
> > +	case VBAR_EL1:		return read_sysreg_s(vbar_EL12);
> > +	case CONTEXTIDR_EL1:	return read_sysreg_s(contextidr_EL12);
> > +	case TPIDR_EL0:		return read_sysreg_s(SYS_TPIDR_EL0);
> > +	case TPIDRRO_EL0:	return read_sysreg_s(SYS_TPIDRRO_EL0);
> > +	case TPIDR_EL1:		return read_sysreg_s(SYS_TPIDR_EL1);
> > +	case AMAIR_EL1:		return read_sysreg_s(amair_EL12);
> > +	case CNTKCTL_EL1:	return read_sysreg_s(cntkctl_EL12);
> > +	case PAR_EL1:		return read_sysreg_s(SYS_PAR_EL1);
> >  	}
> >  
> >  immediate_read:
> > @@ -103,6 +123,26 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
> >  	 * entry to the guest but are only restored on vcpu_load.
> >  	 */
> >  	switch (reg) {
> > +	case CSSELR_EL1:	write_sysreg_s(val, SYS_CSSELR_EL1);	return;
> > +	case SCTLR_EL1:		write_sysreg_s(val, sctlr_EL12);	return;
> > +	case ACTLR_EL1:		write_sysreg_s(val, SYS_ACTLR_EL1);	return;
> > +	case CPACR_EL1:		write_sysreg_s(val, cpacr_EL12);	return;
> > +	case TTBR0_EL1:		write_sysreg_s(val, ttbr0_EL12);	return;
> > +	case TTBR1_EL1:		write_sysreg_s(val, ttbr1_EL12);	return;
> > +	case TCR_EL1:		write_sysreg_s(val, tcr_EL12);		return;
> > +	case ESR_EL1:		write_sysreg_s(val, esr_EL12);		return;
> > +	case AFSR0_EL1:		write_sysreg_s(val, afsr0_EL12);	return;
> > +	case AFSR1_EL1:		write_sysreg_s(val, afsr1_EL12);	return;
> > +	case FAR_EL1:		write_sysreg_s(val, far_EL12);		return;
> > +	case MAIR_EL1:		write_sysreg_s(val, mair_EL12);		return;
> > +	case VBAR_EL1:		write_sysreg_s(val, vbar_EL12);		return;
> > +	case CONTEXTIDR_EL1:	write_sysreg_s(val, contextidr_EL12);	return;
> > +	case TPIDR_EL0:		write_sysreg_s(val, SYS_TPIDR_EL0);	return;
> > +	case TPIDRRO_EL0:	write_sysreg_s(val, SYS_TPIDRRO_EL0);	return;
> > +	case TPIDR_EL1:		write_sysreg_s(val, SYS_TPIDR_EL1);	return;
> > +	case AMAIR_EL1:		write_sysreg_s(val, amair_EL12);	return;
> > +	case CNTKCTL_EL1:	write_sysreg_s(val, cntkctl_EL12);	return;
> > +	case PAR_EL1:		write_sysreg_s(val, SYS_PAR_EL1);	return;
> >  	}
> >  
> >  immediate_write:
> > -- 
> > 2.14.2
> > 
> 
> Looks good to me otherwise.
> 

Thanks,
-Christoffer

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

* [PATCH v4 28/40] KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on VHE
@ 2018-02-23 18:05       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-23 18:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 21, 2018 at 03:33:47PM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:03:20 +0000,
> Christoffer Dall wrote:
> > 
> > Some system registers do not affect the host kernel's execution and can
> > therefore be loaded when we are about to run a VCPU and we don't have to
> > restore the host state to the hardware before the time when we are
> > actually about to return to userspace or schedule out the VCPU thread.
> > 
> > The EL1 system registers and the userspace state registers only
> > affecting EL0 execution do not need to be saved and restored on every
> > switch between the VM and the host, because they don't affect the host
> > kernel's execution.
> > 
> > We mark all registers which are now deffered as such in the
> > vcpu_{read,write}_sys_reg accessors in sys-regs.c to ensure the most
> > up-to-date copy is always accessed.
> > 
> > Note MPIDR_EL1 (controlled via VMPIDR_EL2) is accessed from other vcpu
> > threads, for example via the GIC emulation, and therefore must be
> > declared as immediate, which is fine as the guest cannot modify this
> > value.
> > 
> > The 32-bit sysregs can also be deferred but we do this in a separate
> > patch as it requires a bit more infrastructure.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v3:
> >      - Changed to switch-based sysreg approach
> > 
> >  arch/arm64/kvm/hyp/sysreg-sr.c | 39 +++++++++++++++++++++++++++++++--------
> >  arch/arm64/kvm/sys_regs.c      | 40 ++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 71 insertions(+), 8 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
> > index 906606dc4e2c..9c60b8062724 100644
> > --- a/arch/arm64/kvm/hyp/sysreg-sr.c
> > +++ b/arch/arm64/kvm/hyp/sysreg-sr.c
> > @@ -25,8 +25,12 @@
> >  /*
> >   * Non-VHE: Both host and guest must save everything.
> >   *
> > - * VHE: Host must save tpidr*_el0, mdscr_el1, sp_el0,
> > - * and guest must save everything.
> > + * VHE: Host and guest must save mdscr_el1 and sp_el0 (and the PC and pstate,
> > + * which are handled as part of the el2 return state) on every switch.
> > + * tpidr_el0 and tpidrro_el0 only need to be switched when going
> 
> How about suspend/resume, which saves/restores both of these EL0
> registers (see cpu_do_suspend)? We may not need to do anything (either
> because vcpu_put will have happened, or because we'll come back
> exactly where we were), but I'd like to make sure this hasn't been
> overlooked.
> 

Interesting question.

AFAICT, cpu_do_suspend preserves the values in these registers, which
means it will either preserve the guest's or user space's values,
depending on when cpu_do_suspend is called.  It will be the former if
cpu_do_suspend is called in between vcpu_load and vcpu_put (from
interrupt context, for example), and it will be the latter if called
after the thread goes to sleep for example.

I can't see how suspend can break this.  Am I missing something?

> > + * to host userspace or a different VCPU.  EL1 registers only need to be
> > + * switched when potentially going to run a different VCPU.  The latter two
> > + * classes are handled as part of kvm_arch_vcpu_load and kvm_arch_vcpu_put.
> >   */
> >  
> >  static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
> > @@ -93,14 +97,11 @@ void __hyp_text __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt)
> >  void sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt)
> >  {
> >  	__sysreg_save_common_state(ctxt);
> > -	__sysreg_save_user_state(ctxt);
> >  }
> >  
> >  void sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt)
> >  {
> > -	__sysreg_save_el1_state(ctxt);
> >  	__sysreg_save_common_state(ctxt);
> > -	__sysreg_save_user_state(ctxt);
> >  	__sysreg_save_el2_return_state(ctxt);
> >  }
> >  
> > @@ -169,14 +170,11 @@ void __hyp_text __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt)
> >  void sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt)
> >  {
> >  	__sysreg_restore_common_state(ctxt);
> > -	__sysreg_restore_user_state(ctxt);
> >  }
> >  
> >  void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt)
> >  {
> > -	__sysreg_restore_el1_state(ctxt);
> >  	__sysreg_restore_common_state(ctxt);
> > -	__sysreg_restore_user_state(ctxt);
> >  	__sysreg_restore_el2_return_state(ctxt);
> >  }
> >  
> > @@ -240,6 +238,18 @@ void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
> >   */
> >  void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
> >  {
> > +	struct kvm_cpu_context *host_ctxt = vcpu->arch.host_cpu_context;
> > +	struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt;
> > +
> > +	if (!has_vhe())
> > +		return;
> > +
> > +	__sysreg_save_user_state(host_ctxt);
> > +
> > +	__sysreg_restore_user_state(guest_ctxt);
> > +	__sysreg_restore_el1_state(guest_ctxt);
> > +
> > +	vcpu->arch.sysregs_loaded_on_cpu = true;
> >  }
> >  
> >  /**
> > @@ -255,6 +265,19 @@ void kvm_vcpu_load_sysregs(struct kvm_vcpu *vcpu)
> >   */
> >  void kvm_vcpu_put_sysregs(struct kvm_vcpu *vcpu)
> >  {
> > +	struct kvm_cpu_context *host_ctxt = vcpu->arch.host_cpu_context;
> > +	struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt;
> > +
> > +	if (!has_vhe())
> > +		return;
> > +
> > +	__sysreg_save_el1_state(guest_ctxt);
> > +	__sysreg_save_user_state(guest_ctxt);
> > +
> > +	/* Restore host user state */
> > +	__sysreg_restore_user_state(host_ctxt);
> > +
> > +	vcpu->arch.sysregs_loaded_on_cpu = false;
> >  }
> >  
> >  void __hyp_text __kvm_set_tpidr_el2(u64 tpidr_el2)
> > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> > index b3c3f014aa61..f060309337aa 100644
> > --- a/arch/arm64/kvm/sys_regs.c
> > +++ b/arch/arm64/kvm/sys_regs.c
> > @@ -87,6 +87,26 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
> >  	 * exit from the guest but are only saved on vcpu_put.
> >  	 */
> >  	switch (reg) {
> > +	case CSSELR_EL1:	return read_sysreg_s(SYS_CSSELR_EL1);
> > +	case SCTLR_EL1:		return read_sysreg_s(sctlr_EL12);
> > +	case ACTLR_EL1:		return read_sysreg_s(SYS_ACTLR_EL1);
> > +	case CPACR_EL1:		return read_sysreg_s(cpacr_EL12);
> > +	case TTBR0_EL1:		return read_sysreg_s(ttbr0_EL12);
> > +	case TTBR1_EL1:		return read_sysreg_s(ttbr1_EL12);
> > +	case TCR_EL1:		return read_sysreg_s(tcr_EL12);
> > +	case ESR_EL1:		return read_sysreg_s(esr_EL12);
> > +	case AFSR0_EL1:		return read_sysreg_s(afsr0_EL12);
> > +	case AFSR1_EL1:		return read_sysreg_s(afsr1_EL12);
> > +	case FAR_EL1:		return read_sysreg_s(far_EL12);
> > +	case MAIR_EL1:		return read_sysreg_s(mair_EL12);
> > +	case VBAR_EL1:		return read_sysreg_s(vbar_EL12);
> > +	case CONTEXTIDR_EL1:	return read_sysreg_s(contextidr_EL12);
> > +	case TPIDR_EL0:		return read_sysreg_s(SYS_TPIDR_EL0);
> > +	case TPIDRRO_EL0:	return read_sysreg_s(SYS_TPIDRRO_EL0);
> > +	case TPIDR_EL1:		return read_sysreg_s(SYS_TPIDR_EL1);
> > +	case AMAIR_EL1:		return read_sysreg_s(amair_EL12);
> > +	case CNTKCTL_EL1:	return read_sysreg_s(cntkctl_EL12);
> > +	case PAR_EL1:		return read_sysreg_s(SYS_PAR_EL1);
> >  	}
> >  
> >  immediate_read:
> > @@ -103,6 +123,26 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
> >  	 * entry to the guest but are only restored on vcpu_load.
> >  	 */
> >  	switch (reg) {
> > +	case CSSELR_EL1:	write_sysreg_s(val, SYS_CSSELR_EL1);	return;
> > +	case SCTLR_EL1:		write_sysreg_s(val, sctlr_EL12);	return;
> > +	case ACTLR_EL1:		write_sysreg_s(val, SYS_ACTLR_EL1);	return;
> > +	case CPACR_EL1:		write_sysreg_s(val, cpacr_EL12);	return;
> > +	case TTBR0_EL1:		write_sysreg_s(val, ttbr0_EL12);	return;
> > +	case TTBR1_EL1:		write_sysreg_s(val, ttbr1_EL12);	return;
> > +	case TCR_EL1:		write_sysreg_s(val, tcr_EL12);		return;
> > +	case ESR_EL1:		write_sysreg_s(val, esr_EL12);		return;
> > +	case AFSR0_EL1:		write_sysreg_s(val, afsr0_EL12);	return;
> > +	case AFSR1_EL1:		write_sysreg_s(val, afsr1_EL12);	return;
> > +	case FAR_EL1:		write_sysreg_s(val, far_EL12);		return;
> > +	case MAIR_EL1:		write_sysreg_s(val, mair_EL12);		return;
> > +	case VBAR_EL1:		write_sysreg_s(val, vbar_EL12);		return;
> > +	case CONTEXTIDR_EL1:	write_sysreg_s(val, contextidr_EL12);	return;
> > +	case TPIDR_EL0:		write_sysreg_s(val, SYS_TPIDR_EL0);	return;
> > +	case TPIDRRO_EL0:	write_sysreg_s(val, SYS_TPIDRRO_EL0);	return;
> > +	case TPIDR_EL1:		write_sysreg_s(val, SYS_TPIDR_EL1);	return;
> > +	case AMAIR_EL1:		write_sysreg_s(val, amair_EL12);	return;
> > +	case CNTKCTL_EL1:	write_sysreg_s(val, cntkctl_EL12);	return;
> > +	case PAR_EL1:		write_sysreg_s(val, SYS_PAR_EL1);	return;
> >  	}
> >  
> >  immediate_write:
> > -- 
> > 2.14.2
> > 
> 
> Looks good to me otherwise.
> 

Thanks,
-Christoffer

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

* Re: [PATCH v4 10/40] KVM: arm64: Slightly improve debug save/restore functions
  2018-02-21 17:52       ` Marc Zyngier
@ 2018-02-24 18:32         ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-24 18:32 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Wed, Feb 21, 2018 at 05:52:41PM +0000, Marc Zyngier wrote:
> On 21/02/18 17:39, Andrew Jones wrote:
> > On Thu, Feb 15, 2018 at 10:03:02PM +0100, Christoffer Dall wrote:
> >> The debug save/restore functions can be improved by using the has_vhe()
> >> static key instead of the instruction alternative.  Using the static key
> >> uses the same paradigm as we're going to use elsewhere, it makes the
> >> code more readable, and it generates slightly better code (no
> >> stack setups and function calls unless necessary).
> >>
> >> We also use a static key on the restore path, because it will be
> >> marginally faster than loading a value from memory.
> >>
> >> Finally, we don't have to conditionally clear the debug dirty flag if
> >> it's set, we can just clear it.
> >>
> >> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> ---
> >>
> >> Notes:
> >>     Changes since v1:
> >>      - Change dot to comma in comment
> >>      - Rename __debug_restore_spe to __debug_restore_spe_nvhe
> >>
> >>  arch/arm64/kvm/hyp/debug-sr.c | 26 ++++++++++++--------------
> >>  1 file changed, 12 insertions(+), 14 deletions(-)
> >>
> > 
> > Maybe after this series is merged, if there are any hyp_alternate_select's
> > left, we can replace all the remaining ones with has_vhe() and then just
> > completely remove hyp_alternate_select.
> 
> Note that older compilers (such as GCC 4.8) will generate horrible code
> with static keys, as they do not support "asm goto". Not that I want to
> preserve the home brew hyp_alternate_select mechanism, but I just want
> to make it plain that some distros will definitely suffer from the
> transition.
> 
That's unfortunate.  I'd still like to use has_vhe() most places, but we
could change the implementation of has_vhe() to use the hyp alternative
until nobody cares about kernels compiled with GCC 4.8 ?

Thanks,
-Christoffer

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

* [PATCH v4 10/40] KVM: arm64: Slightly improve debug save/restore functions
@ 2018-02-24 18:32         ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-24 18:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 21, 2018 at 05:52:41PM +0000, Marc Zyngier wrote:
> On 21/02/18 17:39, Andrew Jones wrote:
> > On Thu, Feb 15, 2018 at 10:03:02PM +0100, Christoffer Dall wrote:
> >> The debug save/restore functions can be improved by using the has_vhe()
> >> static key instead of the instruction alternative.  Using the static key
> >> uses the same paradigm as we're going to use elsewhere, it makes the
> >> code more readable, and it generates slightly better code (no
> >> stack setups and function calls unless necessary).
> >>
> >> We also use a static key on the restore path, because it will be
> >> marginally faster than loading a value from memory.
> >>
> >> Finally, we don't have to conditionally clear the debug dirty flag if
> >> it's set, we can just clear it.
> >>
> >> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> >> ---
> >>
> >> Notes:
> >>     Changes since v1:
> >>      - Change dot to comma in comment
> >>      - Rename __debug_restore_spe to __debug_restore_spe_nvhe
> >>
> >>  arch/arm64/kvm/hyp/debug-sr.c | 26 ++++++++++++--------------
> >>  1 file changed, 12 insertions(+), 14 deletions(-)
> >>
> > 
> > Maybe after this series is merged, if there are any hyp_alternate_select's
> > left, we can replace all the remaining ones with has_vhe() and then just
> > completely remove hyp_alternate_select.
> 
> Note that older compilers (such as GCC 4.8) will generate horrible code
> with static keys, as they do not support "asm goto". Not that I want to
> preserve the home brew hyp_alternate_select mechanism, but I just want
> to make it plain that some distros will definitely suffer from the
> transition.
> 
That's unfortunate.  I'd still like to use has_vhe() most places, but we
could change the implementation of has_vhe() to use the hyp alternative
until nobody cares about kernels compiled with GCC 4.8 ?

Thanks,
-Christoffer

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

* Re: [PATCH v4 10/40] KVM: arm64: Slightly improve debug save/restore functions
  2018-02-24 18:32         ` Christoffer Dall
@ 2018-02-24 20:16           ` Marc Zyngier
  -1 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-24 20:16 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Sat, 24 Feb 2018 18:32:36 +0000,
Christoffer Dall wrote:
> 
> On Wed, Feb 21, 2018 at 05:52:41PM +0000, Marc Zyngier wrote:
> > On 21/02/18 17:39, Andrew Jones wrote:
> > > On Thu, Feb 15, 2018 at 10:03:02PM +0100, Christoffer Dall wrote:
> > >> The debug save/restore functions can be improved by using the has_vhe()
> > >> static key instead of the instruction alternative.  Using the static key
> > >> uses the same paradigm as we're going to use elsewhere, it makes the
> > >> code more readable, and it generates slightly better code (no
> > >> stack setups and function calls unless necessary).
> > >>
> > >> We also use a static key on the restore path, because it will be
> > >> marginally faster than loading a value from memory.
> > >>
> > >> Finally, we don't have to conditionally clear the debug dirty flag if
> > >> it's set, we can just clear it.
> > >>
> > >> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> > >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > >> ---
> > >>
> > >> Notes:
> > >>     Changes since v1:
> > >>      - Change dot to comma in comment
> > >>      - Rename __debug_restore_spe to __debug_restore_spe_nvhe
> > >>
> > >>  arch/arm64/kvm/hyp/debug-sr.c | 26 ++++++++++++--------------
> > >>  1 file changed, 12 insertions(+), 14 deletions(-)
> > >>
> > > 
> > > Maybe after this series is merged, if there are any hyp_alternate_select's
> > > left, we can replace all the remaining ones with has_vhe() and then just
> > > completely remove hyp_alternate_select.
> > 
> > Note that older compilers (such as GCC 4.8) will generate horrible code
> > with static keys, as they do not support "asm goto". Not that I want to
> > preserve the home brew hyp_alternate_select mechanism, but I just want
> > to make it plain that some distros will definitely suffer from the
> > transition.
> > 
> That's unfortunate.  I'd still like to use has_vhe() most places, but we
> could change the implementation of has_vhe() to use the hyp alternative
> until nobody cares about kernels compiled with GCC 4.8 ?

Honestly, if you're using something as outdated as GCC 4.8, you
deserve to have crap performance. You end up with mediocre code
generation, and the lack of "asm goto" is just icing on the cake.

Given the kernel reliance on static keys for most things, I'd be
perfectly happy to drop the hyp alternative. It was only there because
we couldn't use static keys at hyp at the time, and we've moved on
since the initial VHE patches.

I cast my vote in favour of has_vhe() in its current form, everywhere.

Thanks,

	M.

-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v4 10/40] KVM: arm64: Slightly improve debug save/restore functions
@ 2018-02-24 20:16           ` Marc Zyngier
  0 siblings, 0 replies; 276+ messages in thread
From: Marc Zyngier @ 2018-02-24 20:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, 24 Feb 2018 18:32:36 +0000,
Christoffer Dall wrote:
> 
> On Wed, Feb 21, 2018 at 05:52:41PM +0000, Marc Zyngier wrote:
> > On 21/02/18 17:39, Andrew Jones wrote:
> > > On Thu, Feb 15, 2018 at 10:03:02PM +0100, Christoffer Dall wrote:
> > >> The debug save/restore functions can be improved by using the has_vhe()
> > >> static key instead of the instruction alternative.  Using the static key
> > >> uses the same paradigm as we're going to use elsewhere, it makes the
> > >> code more readable, and it generates slightly better code (no
> > >> stack setups and function calls unless necessary).
> > >>
> > >> We also use a static key on the restore path, because it will be
> > >> marginally faster than loading a value from memory.
> > >>
> > >> Finally, we don't have to conditionally clear the debug dirty flag if
> > >> it's set, we can just clear it.
> > >>
> > >> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> > >> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > >> ---
> > >>
> > >> Notes:
> > >>     Changes since v1:
> > >>      - Change dot to comma in comment
> > >>      - Rename __debug_restore_spe to __debug_restore_spe_nvhe
> > >>
> > >>  arch/arm64/kvm/hyp/debug-sr.c | 26 ++++++++++++--------------
> > >>  1 file changed, 12 insertions(+), 14 deletions(-)
> > >>
> > > 
> > > Maybe after this series is merged, if there are any hyp_alternate_select's
> > > left, we can replace all the remaining ones with has_vhe() and then just
> > > completely remove hyp_alternate_select.
> > 
> > Note that older compilers (such as GCC 4.8) will generate horrible code
> > with static keys, as they do not support "asm goto". Not that I want to
> > preserve the home brew hyp_alternate_select mechanism, but I just want
> > to make it plain that some distros will definitely suffer from the
> > transition.
> > 
> That's unfortunate.  I'd still like to use has_vhe() most places, but we
> could change the implementation of has_vhe() to use the hyp alternative
> until nobody cares about kernels compiled with GCC 4.8 ?

Honestly, if you're using something as outdated as GCC 4.8, you
deserve to have crap performance. You end up with mediocre code
generation, and the lack of "asm goto" is just icing on the cake.

Given the kernel reliance on static keys for most things, I'd be
perfectly happy to drop the hyp alternative. It was only there because
we couldn't use static keys at hyp at the time, and we've moved on
since the initial VHE patches.

I cast my vote in favour of has_vhe() in its current form, everywhere.

Thanks,

	M.

-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v4 31/40] KVM: arm64: Move common VHE/non-VHE trap config in separate functions
  2018-02-21 17:59     ` Marc Zyngier
@ 2018-02-25 21:27       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-25 21:27 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Andrew Jones, kvm, Tomasz Nowicki, kvmarm, Julien Grall,
	Yury Norov, linux-arm-kernel, Dave Martin, Shih-Wei Li

On Wed, Feb 21, 2018 at 05:59:37PM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:03:23 +0000,
> Christoffer Dall wrote:
> > 
> > As we are about to be more lazy with some of the trap configuration
> > register read/writes for VHE systems, move the logic that is currently
> > shared between VHE and non-VHE into a separate function which can be
> > called from either the world-switch path or from vcpu_load/vcpu_put.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v3:
> >      - Separate fpsimd32 trap configuration into a separate function
> >        which is still called from __activate_traps, because we no longer
> >        defer saving/restoring of VFP registers to load/put.
> > 
> >  arch/arm64/kvm/hyp/switch.c | 76 +++++++++++++++++++++++++++------------------
> >  1 file changed, 45 insertions(+), 31 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index 909aa3fe9196..17e3c6f26a34 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c
> > @@ -56,7 +56,45 @@ static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
> >  	vcpu->arch.ctxt.sys_regs[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
> >  }
> >  
> > -static void __hyp_text __activate_traps_vhe(void)
> > +static void __hyp_text __activate_traps_fpsimd32(struct kvm_vcpu *vcpu)
> > +{
> > +	/*
> > +	 * We are about to set CPTR_EL2.TFP to trap all floating point
> > +	 * register accesses to EL2, however, the ARM ARM clearly states that
> > +	 * traps are only taken to EL2 if the operation would not otherwise
> > +	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> > +	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> > +	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> > +	 * it will cause an exception.
> > +	 */
> > +	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> > +		write_sysreg(1 << 30, fpexc32_el2);
> > +		isb();
> > +	}
> > +}
> > +
> > +static void __hyp_text __activate_traps_common(struct kvm_vcpu *vcpu)
> > +{
> > +	/* Trap on AArch32 cp15 c15 (impdef sysregs) accesses (EL1 or EL0) */
> > +	write_sysreg(1 << 15, hstr_el2);
> > +	/*
> > +	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> > +	 * PMSELR_EL0 to make sure it never contains the cycle
> > +	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> > +	 * EL1 instead of being trapped to EL2.
> > +	 */
> > +	write_sysreg(0, pmselr_el0);
> > +	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> > +	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> > +}
> > +
> > +static void __hyp_text __deactivate_traps_common(void)
> > +{
> > +	write_sysreg(0, hstr_el2);
> > +	write_sysreg(0, pmuserenr_el0);
> > +}
> > +
> > +static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 val;
> >  
> > @@ -68,7 +106,7 @@ static void __hyp_text __activate_traps_vhe(void)
> >  	write_sysreg(kvm_get_hyp_vector(), vbar_el1);
> >  }
> >  
> > -static void __hyp_text __activate_traps_nvhe(void)
> > +static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
> 
> I have the ugly feeling that this hunk should not be in this
> patch. Have you tried bisecting the compilation of this series?
> 

Actually, I don't see why this shouldn't be in this patch?  We change
both versions of the functions and we change the call to
__activate_traps_arch() below.  We just don't change the hyp
alternative, because it doesn't care about arguments and parameters, it
just cares the the types of the functions are the same.

Admittedly, this patch is really hard to read, it's easier to apply it
and just look at the code.

> >  {
> >  	u64 val;
> >  
> > @@ -85,37 +123,14 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 hcr = vcpu->arch.hcr_el2;
> >  
> > -	/*
> > -	 * We are about to set CPTR_EL2.TFP to trap all floating point
> > -	 * register accesses to EL2, however, the ARM ARM clearly states that
> > -	 * traps are only taken to EL2 if the operation would not otherwise
> > -	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> > -	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> > -	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> > -	 * it will cause an exception.
> > -	 */
> > -	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> > -		write_sysreg(1 << 30, fpexc32_el2);
> > -		isb();
> > -	}
> > +	write_sysreg(hcr, hcr_el2);
> >  
> >  	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
> >  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
> >  
> > -	write_sysreg(hcr, hcr_el2);
> > -
> > -	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
> > -	write_sysreg(1 << 15, hstr_el2);
> > -	/*
> > -	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> > -	 * PMSELR_EL0 to make sure it never contains the cycle
> > -	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> > -	 * EL1 instead of being trapped to EL2.
> > -	 */
> > -	write_sysreg(0, pmselr_el0);
> > -	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> > -	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> > -	__activate_traps_arch()();
> > +	__activate_traps_fpsimd32(vcpu);
> > +	__activate_traps_common(vcpu);
> > +	__activate_traps_arch()(vcpu);
> >  }
> >  
> >  static void __hyp_text __deactivate_traps_vhe(void)
> > @@ -160,9 +175,8 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
> >  	if (vcpu->arch.hcr_el2 & HCR_VSE)
> >  		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
> >  
> > +	__deactivate_traps_common();
> >  	__deactivate_traps_arch()();
> > -	write_sysreg(0, hstr_el2);
> > -	write_sysreg(0, pmuserenr_el0);
> >  }
> >  
> >  static void __hyp_text __activate_vm(struct kvm *kvm)
> > -- 
> > 2.14.2
> > 
> 
> Otherwise:
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> 
Thanks!
-Christoffer

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

* [PATCH v4 31/40] KVM: arm64: Move common VHE/non-VHE trap config in separate functions
@ 2018-02-25 21:27       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-25 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 21, 2018 at 05:59:37PM +0000, Marc Zyngier wrote:
> On Thu, 15 Feb 2018 21:03:23 +0000,
> Christoffer Dall wrote:
> > 
> > As we are about to be more lazy with some of the trap configuration
> > register read/writes for VHE systems, move the logic that is currently
> > shared between VHE and non-VHE into a separate function which can be
> > called from either the world-switch path or from vcpu_load/vcpu_put.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> > ---
> > 
> > Notes:
> >     Changes since v3:
> >      - Separate fpsimd32 trap configuration into a separate function
> >        which is still called from __activate_traps, because we no longer
> >        defer saving/restoring of VFP registers to load/put.
> > 
> >  arch/arm64/kvm/hyp/switch.c | 76 +++++++++++++++++++++++++++------------------
> >  1 file changed, 45 insertions(+), 31 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index 909aa3fe9196..17e3c6f26a34 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c
> > @@ -56,7 +56,45 @@ static inline void __hyp_text __fpsimd_save_fpexc32(struct kvm_vcpu *vcpu)
> >  	vcpu->arch.ctxt.sys_regs[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
> >  }
> >  
> > -static void __hyp_text __activate_traps_vhe(void)
> > +static void __hyp_text __activate_traps_fpsimd32(struct kvm_vcpu *vcpu)
> > +{
> > +	/*
> > +	 * We are about to set CPTR_EL2.TFP to trap all floating point
> > +	 * register accesses to EL2, however, the ARM ARM clearly states that
> > +	 * traps are only taken to EL2 if the operation would not otherwise
> > +	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> > +	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> > +	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> > +	 * it will cause an exception.
> > +	 */
> > +	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> > +		write_sysreg(1 << 30, fpexc32_el2);
> > +		isb();
> > +	}
> > +}
> > +
> > +static void __hyp_text __activate_traps_common(struct kvm_vcpu *vcpu)
> > +{
> > +	/* Trap on AArch32 cp15 c15 (impdef sysregs) accesses (EL1 or EL0) */
> > +	write_sysreg(1 << 15, hstr_el2);
> > +	/*
> > +	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> > +	 * PMSELR_EL0 to make sure it never contains the cycle
> > +	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> > +	 * EL1 instead of being trapped to EL2.
> > +	 */
> > +	write_sysreg(0, pmselr_el0);
> > +	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> > +	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> > +}
> > +
> > +static void __hyp_text __deactivate_traps_common(void)
> > +{
> > +	write_sysreg(0, hstr_el2);
> > +	write_sysreg(0, pmuserenr_el0);
> > +}
> > +
> > +static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 val;
> >  
> > @@ -68,7 +106,7 @@ static void __hyp_text __activate_traps_vhe(void)
> >  	write_sysreg(kvm_get_hyp_vector(), vbar_el1);
> >  }
> >  
> > -static void __hyp_text __activate_traps_nvhe(void)
> > +static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
> 
> I have the ugly feeling that this hunk should not be in this
> patch. Have you tried bisecting the compilation of this series?
> 

Actually, I don't see why this shouldn't be in this patch?  We change
both versions of the functions and we change the call to
__activate_traps_arch() below.  We just don't change the hyp
alternative, because it doesn't care about arguments and parameters, it
just cares the the types of the functions are the same.

Admittedly, this patch is really hard to read, it's easier to apply it
and just look at the code.

> >  {
> >  	u64 val;
> >  
> > @@ -85,37 +123,14 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 hcr = vcpu->arch.hcr_el2;
> >  
> > -	/*
> > -	 * We are about to set CPTR_EL2.TFP to trap all floating point
> > -	 * register accesses to EL2, however, the ARM ARM clearly states that
> > -	 * traps are only taken to EL2 if the operation would not otherwise
> > -	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> > -	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> > -	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> > -	 * it will cause an exception.
> > -	 */
> > -	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> > -		write_sysreg(1 << 30, fpexc32_el2);
> > -		isb();
> > -	}
> > +	write_sysreg(hcr, hcr_el2);
> >  
> >  	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
> >  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
> >  
> > -	write_sysreg(hcr, hcr_el2);
> > -
> > -	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
> > -	write_sysreg(1 << 15, hstr_el2);
> > -	/*
> > -	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
> > -	 * PMSELR_EL0 to make sure it never contains the cycle
> > -	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
> > -	 * EL1 instead of being trapped to EL2.
> > -	 */
> > -	write_sysreg(0, pmselr_el0);
> > -	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> > -	write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
> > -	__activate_traps_arch()();
> > +	__activate_traps_fpsimd32(vcpu);
> > +	__activate_traps_common(vcpu);
> > +	__activate_traps_arch()(vcpu);
> >  }
> >  
> >  static void __hyp_text __deactivate_traps_vhe(void)
> > @@ -160,9 +175,8 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
> >  	if (vcpu->arch.hcr_el2 & HCR_VSE)
> >  		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
> >  
> > +	__deactivate_traps_common();
> >  	__deactivate_traps_arch()();
> > -	write_sysreg(0, hstr_el2);
> > -	write_sysreg(0, pmuserenr_el0);
> >  }
> >  
> >  static void __hyp_text __activate_vm(struct kvm *kvm)
> > -- 
> > 2.14.2
> > 
> 
> Otherwise:
> 
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> 
Thanks!
-Christoffer

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

* Re: [PATCH v4 31/40] KVM: arm64: Move common VHE/non-VHE trap config in separate functions
  2018-02-23 14:30     ` Julien Grall
@ 2018-02-25 21:29       ` Christoffer Dall
  -1 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-25 21:29 UTC (permalink / raw)
  To: Julien Grall
  Cc: Andrew Jones, kvm, Marc Zyngier, Tomasz Nowicki, Dave Martin,
	Yury Norov, linux-arm-kernel, kvmarm, Shih-Wei Li

On Fri, Feb 23, 2018 at 02:30:54PM +0000, Julien Grall wrote:
> Hi Christoffer,
> 
> On 15/02/18 21:03, Christoffer Dall wrote:
> >@@ -85,37 +123,14 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 hcr = vcpu->arch.hcr_el2;
> >-	/*
> >-	 * We are about to set CPTR_EL2.TFP to trap all floating point
> >-	 * register accesses to EL2, however, the ARM ARM clearly states that
> >-	 * traps are only taken to EL2 if the operation would not otherwise
> >-	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> >-	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> >-	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> >-	 * it will cause an exception.
> >-	 */
> >-	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> >-		write_sysreg(1 << 30, fpexc32_el2);
> >-		isb();
> >-	}
> >+	write_sysreg(hcr, hcr_el2);
> >  	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
> >  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
> >-	write_sysreg(hcr, hcr_el2);
> 
> OOI, any reason to move the write to HCR_EL2 just before the if?
> 

Just to keep the two lines together where we read the value from the
vcpu structure and write it to hardware.  It's hard to tell from this
patch, but I think it looks nicer in the end.

Thanks,
-Christoffer

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

* [PATCH v4 31/40] KVM: arm64: Move common VHE/non-VHE trap config in separate functions
@ 2018-02-25 21:29       ` Christoffer Dall
  0 siblings, 0 replies; 276+ messages in thread
From: Christoffer Dall @ 2018-02-25 21:29 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Feb 23, 2018 at 02:30:54PM +0000, Julien Grall wrote:
> Hi Christoffer,
> 
> On 15/02/18 21:03, Christoffer Dall wrote:
> >@@ -85,37 +123,14 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
> >  {
> >  	u64 hcr = vcpu->arch.hcr_el2;
> >-	/*
> >-	 * We are about to set CPTR_EL2.TFP to trap all floating point
> >-	 * register accesses to EL2, however, the ARM ARM clearly states that
> >-	 * traps are only taken to EL2 if the operation would not otherwise
> >-	 * trap to EL1.  Therefore, always make sure that for 32-bit guests,
> >-	 * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
> >-	 * If FP/ASIMD is not implemented, FPEXC is UNDEFINED and any access to
> >-	 * it will cause an exception.
> >-	 */
> >-	if (vcpu_el1_is_32bit(vcpu) && system_supports_fpsimd()) {
> >-		write_sysreg(1 << 30, fpexc32_el2);
> >-		isb();
> >-	}
> >+	write_sysreg(hcr, hcr_el2);
> >  	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
> >  		write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
> >-	write_sysreg(hcr, hcr_el2);
> 
> OOI, any reason to move the write to HCR_EL2 just before the if?
> 

Just to keep the two lines together where we read the value from the
vcpu structure and write it to hardware.  It's hard to tell from this
patch, but I think it looks nicer in the end.

Thanks,
-Christoffer

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

end of thread, other threads:[~2018-02-25 21:29 UTC | newest]

Thread overview: 276+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-15 21:02 [PATCH v4 00/40] Optimize KVM/ARM for VHE systems Christoffer Dall
2018-02-15 21:02 ` Christoffer Dall
2018-02-15 21:02 ` [PATCH v4 01/40] KVM: arm/arm64: Avoid vcpu_load for other vcpu ioctls than KVM_RUN Christoffer Dall
2018-02-15 21:02   ` Christoffer Dall
2018-02-21  9:32   ` Marc Zyngier
2018-02-21  9:32     ` Marc Zyngier
2018-02-21 17:05   ` Andrew Jones
2018-02-21 17:05     ` Andrew Jones
2018-02-15 21:02 ` [PATCH v4 02/40] KVM: arm/arm64: Move vcpu_load call after kvm_vcpu_first_run_init Christoffer Dall
2018-02-15 21:02   ` Christoffer Dall
2018-02-21 11:05   ` Marc Zyngier
2018-02-21 11:05     ` Marc Zyngier
2018-02-15 21:02 ` [PATCH v4 03/40] KVM: arm64: Avoid storing the vcpu pointer on the stack Christoffer Dall
2018-02-15 21:02   ` Christoffer Dall
2018-02-19 15:50   ` Julien Grall
2018-02-19 15:50     ` Julien Grall
2018-02-22  8:43     ` Christoffer Dall
2018-02-22  8:43       ` Christoffer Dall
2018-02-21 11:34   ` Marc Zyngier
2018-02-21 11:34     ` Marc Zyngier
2018-02-22  9:02     ` Christoffer Dall
2018-02-22  9:02       ` Christoffer Dall
2018-02-22  9:35       ` Marc Zyngier
2018-02-22  9:35         ` Marc Zyngier
2018-02-22  9:49       ` Andrew Jones
2018-02-22  9:49         ` Andrew Jones
2018-02-21 17:32   ` Andrew Jones
2018-02-21 17:32     ` Andrew Jones
2018-02-22  9:10     ` Christoffer Dall
2018-02-22  9:10       ` Christoffer Dall
2018-02-22  9:56       ` Andrew Jones
2018-02-22  9:56         ` Andrew Jones
2018-02-22 10:24         ` Christoffer Dall
2018-02-22 10:24           ` Christoffer Dall
2018-02-15 21:02 ` [PATCH v4 04/40] KVM: arm64: Rework hyp_panic for VHE and non-VHE Christoffer Dall
2018-02-15 21:02   ` Christoffer Dall
2018-02-21 17:32   ` Andrew Jones
2018-02-21 17:32     ` Andrew Jones
2018-02-15 21:02 ` [PATCH v4 05/40] KVM: arm64: Move HCR_INT_OVERRIDE to default HCR_EL2 guest flag Christoffer Dall
2018-02-15 21:02   ` Christoffer Dall
2018-02-15 21:02 ` [PATCH v4 06/40] KVM: arm/arm64: Get rid of vcpu->arch.irq_lines Christoffer Dall
2018-02-15 21:02   ` Christoffer Dall
2018-02-15 21:02 ` [PATCH v4 07/40] KVM: arm/arm64: Add kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs Christoffer Dall
2018-02-15 21:02   ` Christoffer Dall
2018-02-15 21:03 ` [PATCH v4 08/40] KVM: arm/arm64: Introduce vcpu_el1_is_32bit Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 12:05   ` Marc Zyngier
2018-02-21 12:05     ` Marc Zyngier
2018-02-22  9:11     ` Christoffer Dall
2018-02-22  9:11       ` Christoffer Dall
2018-02-21 17:34   ` Andrew Jones
2018-02-21 17:34     ` Andrew Jones
2018-02-15 21:03 ` [PATCH v4 09/40] KVM: arm64: Move debug dirty flag calculation out of world switch Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 17:35   ` Andrew Jones
2018-02-21 17:35     ` Andrew Jones
2018-02-15 21:03 ` [PATCH v4 10/40] KVM: arm64: Slightly improve debug save/restore functions Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 17:39   ` Andrew Jones
2018-02-21 17:39     ` Andrew Jones
2018-02-21 17:52     ` Marc Zyngier
2018-02-21 17:52       ` Marc Zyngier
2018-02-22  8:05       ` Andrew Jones
2018-02-22  8:05         ` Andrew Jones
2018-02-24 18:32       ` Christoffer Dall
2018-02-24 18:32         ` Christoffer Dall
2018-02-24 20:16         ` Marc Zyngier
2018-02-24 20:16           ` Marc Zyngier
2018-02-15 21:03 ` [PATCH v4 11/40] KVM: arm64: Improve debug register save/restore flow Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 17:40   ` Andrew Jones
2018-02-21 17:40     ` Andrew Jones
2018-02-15 21:03 ` [PATCH v4 12/40] KVM: arm64: Factor out fault info population and gic workarounds Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 17:41   ` Andrew Jones
2018-02-21 17:41     ` Andrew Jones
2018-02-15 21:03 ` [PATCH v4 13/40] KVM: arm64: Introduce VHE-specific kvm_vcpu_run Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 17:43   ` Andrew Jones
2018-02-21 17:43     ` Andrew Jones
2018-02-21 18:18     ` Andrew Jones
2018-02-21 18:18       ` Andrew Jones
2018-02-22  9:16       ` Christoffer Dall
2018-02-22  9:16         ` Christoffer Dall
2018-02-15 21:03 ` [PATCH v4 14/40] KVM: arm64: Remove kern_hyp_va() use in VHE switch function Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-15 21:03 ` [PATCH v4 15/40] KVM: arm64: Don't deactivate VM on VHE systems Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-15 21:03 ` [PATCH v4 16/40] KVM: arm64: Remove noop calls to timer save/restore from VHE switch Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 17:43   ` Andrew Jones
2018-02-21 17:43     ` Andrew Jones
2018-02-15 21:03 ` [PATCH v4 17/40] KVM: arm64: Move userspace system registers into separate function Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-19 17:21   ` Julien Grall
2018-02-19 17:21     ` Julien Grall
2018-02-22  9:18     ` Christoffer Dall
2018-02-22  9:18       ` Christoffer Dall
2018-02-21 12:21   ` Marc Zyngier
2018-02-21 12:21     ` Marc Zyngier
2018-02-15 21:03 ` [PATCH v4 18/40] KVM: arm64: Rewrite sysreg alternatives to static keys Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 17:44   ` Andrew Jones
2018-02-21 17:44     ` Andrew Jones
2018-02-15 21:03 ` [PATCH v4 19/40] KVM: arm64: Introduce separate VHE/non-VHE sysreg save/restore functions Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-15 21:03 ` [PATCH v4 20/40] KVM: arm/arm64: Remove leftover comment from kvm_vcpu_run_vhe Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 17:47   ` Andrew Jones
2018-02-21 17:47     ` Andrew Jones
2018-02-15 21:03 ` [PATCH v4 21/40] KVM: arm64: Unify non-VHE host/guest sysreg save and restore functions Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-15 21:03 ` [PATCH v4 22/40] KVM: arm64: Don't save the host ELR_EL2 and SPSR_EL2 on VHE systems Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 17:49   ` Andrew Jones
2018-02-21 17:49     ` Andrew Jones
2018-02-15 21:03 ` [PATCH v4 23/40] KVM: arm64: Change 32-bit handling of VM system registers Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-15 21:03 ` [PATCH v4 24/40] KVM: arm64: Rewrite system register accessors to read/write functions Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-19 18:12   ` Julien Grall
2018-02-19 18:12     ` Julien Grall
2018-02-22  9:18     ` Christoffer Dall
2018-02-22  9:18       ` Christoffer Dall
2018-02-21 13:32   ` Marc Zyngier
2018-02-21 13:32     ` Marc Zyngier
2018-02-22  9:22     ` Christoffer Dall
2018-02-22  9:22       ` Christoffer Dall
2018-02-22 10:48       ` Marc Zyngier
2018-02-22 10:48         ` Marc Zyngier
2018-02-22 11:10         ` Christoffer Dall
2018-02-22 11:10           ` Christoffer Dall
2018-02-22 13:26           ` Marc Zyngier
2018-02-22 13:26             ` Marc Zyngier
2018-02-22 13:34   ` Andrew Jones
2018-02-22 13:34     ` Andrew Jones
2018-02-22 14:35     ` Christoffer Dall
2018-02-22 14:35       ` Christoffer Dall
2018-02-22 15:11   ` Andrew Jones
2018-02-22 15:11     ` Andrew Jones
2018-02-22 15:58     ` Christoffer Dall
2018-02-22 15:58       ` Christoffer Dall
2018-02-15 21:03 ` [PATCH v4 25/40] KVM: arm64: Introduce framework for accessing deferred sysregs Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 14:16   ` Marc Zyngier
2018-02-21 14:16     ` Marc Zyngier
2018-02-22 13:40   ` Andrew Jones
2018-02-22 13:40     ` Andrew Jones
2018-02-22 14:56     ` Christoffer Dall
2018-02-22 14:56       ` Christoffer Dall
2018-02-22 17:40   ` Julien Grall
2018-02-22 17:40     ` Julien Grall
2018-02-15 21:03 ` [PATCH v4 26/40] KVM: arm/arm64: Prepare to handle deferred save/restore of SPSR_EL1 Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 14:47   ` Marc Zyngier
2018-02-21 14:47     ` Marc Zyngier
2018-02-22  9:25     ` Christoffer Dall
2018-02-22  9:25       ` Christoffer Dall
2018-02-22 13:49   ` Andrew Jones
2018-02-22 13:49     ` Andrew Jones
2018-02-15 21:03 ` [PATCH v4 27/40] KVM: arm64: Prepare to handle deferred save/restore of ELR_EL1 Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 15:08   ` Marc Zyngier
2018-02-21 15:08     ` Marc Zyngier
2018-02-22 13:51   ` Andrew Jones
2018-02-22 13:51     ` Andrew Jones
2018-02-15 21:03 ` [PATCH v4 28/40] KVM: arm64: Defer saving/restoring 64-bit sysregs to vcpu load/put on VHE Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 15:33   ` Marc Zyngier
2018-02-21 15:33     ` Marc Zyngier
2018-02-23 18:05     ` Christoffer Dall
2018-02-23 18:05       ` Christoffer Dall
2018-02-22 14:04   ` Andrew Jones
2018-02-22 14:04     ` Andrew Jones
2018-02-22 18:30   ` Julien Grall
2018-02-22 18:30     ` Julien Grall
2018-02-22 18:31     ` Julien Grall
2018-02-22 18:31       ` Julien Grall
2018-02-22 19:49       ` Christoffer Dall
2018-02-22 19:49         ` Christoffer Dall
2018-02-22 19:48     ` Christoffer Dall
2018-02-22 19:48       ` Christoffer Dall
2018-02-15 21:03 ` [PATCH v4 29/40] KVM: arm64: Prepare to handle deferred save/restore of 32-bit registers Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 15:44   ` Marc Zyngier
2018-02-21 15:44     ` Marc Zyngier
2018-02-22 14:30   ` Andrew Jones
2018-02-22 14:30     ` Andrew Jones
2018-02-23 11:35   ` Julien Grall
2018-02-23 11:35     ` Julien Grall
2018-02-15 21:03 ` [PATCH v4 30/40] KVM: arm64: Defer saving/restoring 32-bit sysregs to vcpu load/put Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 16:27   ` Marc Zyngier
2018-02-21 16:27     ` Marc Zyngier
2018-02-22 18:15     ` Christoffer Dall
2018-02-22 18:15       ` Christoffer Dall
2018-02-22 14:35   ` Andrew Jones
2018-02-22 14:35     ` Andrew Jones
2018-02-22 14:58     ` Christoffer Dall
2018-02-22 14:58       ` Christoffer Dall
2018-02-15 21:03 ` [PATCH v4 31/40] KVM: arm64: Move common VHE/non-VHE trap config in separate functions Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 17:59   ` Marc Zyngier
2018-02-21 17:59     ` Marc Zyngier
2018-02-22 18:17     ` Christoffer Dall
2018-02-22 18:17       ` Christoffer Dall
2018-02-25 21:27     ` Christoffer Dall
2018-02-25 21:27       ` Christoffer Dall
2018-02-22 15:34   ` Andrew Jones
2018-02-22 15:34     ` Andrew Jones
2018-02-23 14:30   ` Julien Grall
2018-02-23 14:30     ` Julien Grall
2018-02-23 17:48     ` Christoffer Dall
2018-02-23 17:48       ` Christoffer Dall
2018-02-25 21:29     ` Christoffer Dall
2018-02-25 21:29       ` Christoffer Dall
2018-02-15 21:03 ` [PATCH v4 32/40] KVM: arm64: Directly call VHE and non-VHE FPSIMD enabled functions Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 18:11   ` Marc Zyngier
2018-02-21 18:11     ` Marc Zyngier
2018-02-22 15:38   ` Andrew Jones
2018-02-22 15:38     ` Andrew Jones
2018-02-15 21:03 ` [PATCH v4 33/40] KVM: arm64: Configure c15, PMU, and debug register traps on cpu load/put for VHE Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 18:20   ` Marc Zyngier
2018-02-21 18:20     ` Marc Zyngier
2018-02-22 18:57     ` Christoffer Dall
2018-02-22 18:57       ` Christoffer Dall
2018-02-22 15:51   ` Andrew Jones
2018-02-22 15:51     ` Andrew Jones
2018-02-15 21:03 ` [PATCH v4 34/40] KVM: arm64: Cleanup __activate_traps and __deactive_traps for VHE and non-VHE Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-21 18:26   ` Marc Zyngier
2018-02-21 18:26     ` Marc Zyngier
2018-02-22 19:04     ` Christoffer Dall
2018-02-22 19:04       ` Christoffer Dall
2018-02-22 15:54   ` Andrew Jones
2018-02-22 15:54     ` Andrew Jones
2018-02-15 21:03 ` [PATCH v4 35/40] KVM: arm/arm64: Get rid of vgic_elrsr Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-22  9:45   ` Marc Zyngier
2018-02-22  9:45     ` Marc Zyngier
2018-02-23 14:44   ` Julien Grall
2018-02-23 14:44     ` Julien Grall
2018-02-23 17:50     ` Christoffer Dall
2018-02-23 17:50       ` Christoffer Dall
2018-02-15 21:03 ` [PATCH v4 36/40] KVM: arm/arm64: Handle VGICv2 save/restore from the main VGIC code Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-15 21:03 ` [PATCH v4 37/40] KVM: arm/arm64: Move arm64-only vgic-v2-sr.c file to arm64 Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-22 12:33   ` Marc Zyngier
2018-02-22 12:33     ` Marc Zyngier
2018-02-22 14:37     ` Christoffer Dall
2018-02-22 14:37       ` Christoffer Dall
2018-02-15 21:03 ` [PATCH v4 38/40] KVM: arm/arm64: Handle VGICv3 save/restore from the main VGIC code on VHE Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-22 12:32   ` Marc Zyngier
2018-02-22 12:32     ` Marc Zyngier
2018-02-22 14:42     ` Christoffer Dall
2018-02-22 14:42       ` Christoffer Dall
2018-02-22 15:01       ` Marc Zyngier
2018-02-22 15:01         ` Marc Zyngier
2018-02-22 16:02         ` Christoffer Dall
2018-02-22 16:02           ` Christoffer Dall
2018-02-22 17:21           ` Marc Zyngier
2018-02-22 17:21             ` Marc Zyngier
2018-02-22 19:28             ` Christoffer Dall
2018-02-22 19:28               ` Christoffer Dall
2018-02-15 21:03 ` [PATCH v4 39/40] KVM: arm/arm64: Move VGIC APR save/restore to vgic put/load Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall
2018-02-22 13:11   ` Marc Zyngier
2018-02-22 13:11     ` Marc Zyngier
2018-02-22 14:44     ` Christoffer Dall
2018-02-22 14:44       ` Christoffer Dall
2018-02-15 21:03 ` [PATCH v4 40/40] KVM: arm/arm64: Avoid VGICv3 save/restore on VHE with no IRQs Christoffer Dall
2018-02-15 21:03   ` Christoffer Dall

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