All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 00/27] KVM: arm64: SVE guest support
@ 2019-03-29 13:00 ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

This series implements support for allowing KVM guests to use the Arm
Scalable Vector Extension (SVE), superseding the previous v6 series [1].

The patches are also available on a branch for reviewer convenience. [2]

The patches are based on v5.1-rc2.

This series addresses a couple of minor review comments received on v6
and otherwise applies reviewer tags only.  The code differences
between v6 and this series consist of minor cosmetic fixups only.

Draft kvmtool patches were posted separately [3], [4].

For a description of minor updates, see the individual patches.


Thanks go to Julien Thierry and Julian Grall for their review efforts,
and to Zhang Lei for testing the series -- many thanks for their help
in getting the series to this point!


Reviewers' attention is drawn to the following patches, which have no
Reviewed-by/Acked-by.  Please take a look if you have a moment.

 * Patch 11 (KVM: arm64: Support runtime sysreg visibility filtering)

   Previously Reviewed-by Julien Thierry, but this version of the
   patch contains some minor rework suggested by Mark Rutland during
   the v5 review [5].

 * Patch 15 (KVM: arm64: Add missing #include of <linux/string.h>
   in guest.c)

   (Trivial patch.)

 * Patch 26: (KVM: Document errors for KVM_GET_ONE_REG and
   KVM_SET_ONE_REG)

   (Documentation only.)

 * Patch 27: KVM: arm64/sve: Document KVM API extensions for SVE

   (Documentation only.)


Known issues: none


Testing status:

 * Lightweight testing on the Arm Fast Model, primarily to exercise the
   new vcpu finalization API.

   Ran sve-stress testing for several days on v6 on the Arm Fast Model,
   with no errors observed.

 * ThunderX2: basic testing of arm64 defconfig, including booting guests
   (no SVE support on this hardware).

   Some stress testing with fpsimd-stress (to be published separately)
   and paranoia, with no problems observed over several days.

   This testing was done on v6.

 * aarch32 host testing has only been done in v5 so far.  arch/arm
   changes between v5 and v7 are minimal.  I plan to redo sanity-check
   testing after this posting.

   
[1] Previous series:
[PATCH v5 00/26] KVM: arm64: SVE guest support
https://lists.cs.columbia.edu/pipermail/kvmarm/2019-March/thread.html

(Note, the subject line for this posting was incorrect.  It should have
read: [PATCH v6 00/27] KVM: arm64: SVE guest support)

[2] This series in git:
http://linux-arm.org/git?p=linux-dm.git;a=shortlog;h=refs/heads/sve-kvm/v7/head
git://linux-arm.org/linux-dm.git sve-kvm/v7/head

[3] [PATCH kvmtool v2 0/3] arm64: Basic SVE guest support
https://lists.cs.columbia.edu/pipermail/kvmarm/2019-March/035198.html

[4]
git://linux-arm.org/kvmtool-dm.git sve-linuxv6/v2/head
http://linux-arm.org/git?p=kvmtool-dm.git;a=shortlog;h=refs/heads/sve-linuxv6/v2/head

[5]
Mark Rutland Re: [PATCH v5 12/26] KVM: arm64: Support runtime sysreg
visibility filtering
https://lists.cs.columbia.edu/pipermail/kvmarm/2019-February/034718.html

Dave Martin (27):
  KVM: Documentation: Document arm64 core registers in detail
  arm64: fpsimd: Always set TIF_FOREIGN_FPSTATE on task state flush
  KVM: arm64: Delete orphaned declaration for __fpsimd_enabled()
  KVM: arm64: Refactor kvm_arm_num_regs() for easier maintenance
  KVM: arm64: Add missing #includes to kvm_host.h
  arm64/sve: Clarify role of the VQ map maintenance functions
  arm64/sve: Check SVE virtualisability
  arm64/sve: Enable SVE state tracking for non-task contexts
  KVM: arm64: Add a vcpu flag to control SVE visibility for the guest
  KVM: arm64: Propagate vcpu into read_id_reg()
  KVM: arm64: Support runtime sysreg visibility filtering
  KVM: arm64/sve: System register context switch and access support
  KVM: arm64/sve: Context switch the SVE registers
  KVM: Allow 2048-bit register access via ioctl interface
  KVM: arm64: Add missing #include of <linux/string.h> in guest.c
  KVM: arm64: Factor out core register ID enumeration
  KVM: arm64: Reject ioctl access to FPSIMD V-regs on SVE vcpus
  KVM: arm64/sve: Add SVE support to register access ioctl interface
  KVM: arm64: Enumerate SVE register indices for KVM_GET_REG_LIST
  arm64/sve: In-kernel vector length availability query interface
  KVM: arm/arm64: Add hook for arch-specific KVM initialisation
  KVM: arm/arm64: Add KVM_ARM_VCPU_FINALIZE ioctl
  KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
  KVM: arm64/sve: Allow userspace to enable SVE for vcpus
  KVM: arm64: Add a capability to advertise SVE support
  KVM: Document errors for KVM_GET_ONE_REG and KVM_SET_ONE_REG
  KVM: arm64/sve: Document KVM API extensions for SVE

 Documentation/virtual/kvm/api.txt | 156 +++++++++++++++
 arch/arm/include/asm/kvm_host.h   |   6 +
 arch/arm64/include/asm/fpsimd.h   |  33 +++-
 arch/arm64/include/asm/kvm_host.h |  43 ++++-
 arch/arm64/include/asm/kvm_hyp.h  |   1 -
 arch/arm64/include/asm/sysreg.h   |   3 +
 arch/arm64/include/uapi/asm/kvm.h |  22 +++
 arch/arm64/kernel/cpufeature.c    |   2 +-
 arch/arm64/kernel/fpsimd.c        | 172 ++++++++++++-----
 arch/arm64/kernel/signal.c        |   5 -
 arch/arm64/kvm/fpsimd.c           |  17 +-
 arch/arm64/kvm/guest.c            | 394 +++++++++++++++++++++++++++++++++++---
 arch/arm64/kvm/hyp/switch.c       |  74 +++++--
 arch/arm64/kvm/reset.c            | 135 ++++++++++++-
 arch/arm64/kvm/sys_regs.c         | 130 +++++++++++--
 arch/arm64/kvm/sys_regs.h         |  25 +++
 include/uapi/linux/kvm.h          |   5 +
 virt/kvm/arm/arm.c                |  22 +++
 18 files changed, 1115 insertions(+), 130 deletions(-)

-- 
2.1.4

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

* [PATCH v7 00/27] KVM: arm64: SVE guest support
@ 2019-03-29 13:00 ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

This series implements support for allowing KVM guests to use the Arm
Scalable Vector Extension (SVE), superseding the previous v6 series [1].

The patches are also available on a branch for reviewer convenience. [2]

The patches are based on v5.1-rc2.

This series addresses a couple of minor review comments received on v6
and otherwise applies reviewer tags only.  The code differences
between v6 and this series consist of minor cosmetic fixups only.

Draft kvmtool patches were posted separately [3], [4].

For a description of minor updates, see the individual patches.


Thanks go to Julien Thierry and Julian Grall for their review efforts,
and to Zhang Lei for testing the series -- many thanks for their help
in getting the series to this point!


Reviewers' attention is drawn to the following patches, which have no
Reviewed-by/Acked-by.  Please take a look if you have a moment.

 * Patch 11 (KVM: arm64: Support runtime sysreg visibility filtering)

   Previously Reviewed-by Julien Thierry, but this version of the
   patch contains some minor rework suggested by Mark Rutland during
   the v5 review [5].

 * Patch 15 (KVM: arm64: Add missing #include of <linux/string.h>
   in guest.c)

   (Trivial patch.)

 * Patch 26: (KVM: Document errors for KVM_GET_ONE_REG and
   KVM_SET_ONE_REG)

   (Documentation only.)

 * Patch 27: KVM: arm64/sve: Document KVM API extensions for SVE

   (Documentation only.)


Known issues: none


Testing status:

 * Lightweight testing on the Arm Fast Model, primarily to exercise the
   new vcpu finalization API.

   Ran sve-stress testing for several days on v6 on the Arm Fast Model,
   with no errors observed.

 * ThunderX2: basic testing of arm64 defconfig, including booting guests
   (no SVE support on this hardware).

   Some stress testing with fpsimd-stress (to be published separately)
   and paranoia, with no problems observed over several days.

   This testing was done on v6.

 * aarch32 host testing has only been done in v5 so far.  arch/arm
   changes between v5 and v7 are minimal.  I plan to redo sanity-check
   testing after this posting.

   
[1] Previous series:
[PATCH v5 00/26] KVM: arm64: SVE guest support
https://lists.cs.columbia.edu/pipermail/kvmarm/2019-March/thread.html

(Note, the subject line for this posting was incorrect.  It should have
read: [PATCH v6 00/27] KVM: arm64: SVE guest support)

[2] This series in git:
http://linux-arm.org/git?p=linux-dm.git;a=shortlog;h=refs/heads/sve-kvm/v7/head
git://linux-arm.org/linux-dm.git sve-kvm/v7/head

[3] [PATCH kvmtool v2 0/3] arm64: Basic SVE guest support
https://lists.cs.columbia.edu/pipermail/kvmarm/2019-March/035198.html

[4]
git://linux-arm.org/kvmtool-dm.git sve-linuxv6/v2/head
http://linux-arm.org/git?p=kvmtool-dm.git;a=shortlog;h=refs/heads/sve-linuxv6/v2/head

[5]
Mark Rutland Re: [PATCH v5 12/26] KVM: arm64: Support runtime sysreg
visibility filtering
https://lists.cs.columbia.edu/pipermail/kvmarm/2019-February/034718.html

Dave Martin (27):
  KVM: Documentation: Document arm64 core registers in detail
  arm64: fpsimd: Always set TIF_FOREIGN_FPSTATE on task state flush
  KVM: arm64: Delete orphaned declaration for __fpsimd_enabled()
  KVM: arm64: Refactor kvm_arm_num_regs() for easier maintenance
  KVM: arm64: Add missing #includes to kvm_host.h
  arm64/sve: Clarify role of the VQ map maintenance functions
  arm64/sve: Check SVE virtualisability
  arm64/sve: Enable SVE state tracking for non-task contexts
  KVM: arm64: Add a vcpu flag to control SVE visibility for the guest
  KVM: arm64: Propagate vcpu into read_id_reg()
  KVM: arm64: Support runtime sysreg visibility filtering
  KVM: arm64/sve: System register context switch and access support
  KVM: arm64/sve: Context switch the SVE registers
  KVM: Allow 2048-bit register access via ioctl interface
  KVM: arm64: Add missing #include of <linux/string.h> in guest.c
  KVM: arm64: Factor out core register ID enumeration
  KVM: arm64: Reject ioctl access to FPSIMD V-regs on SVE vcpus
  KVM: arm64/sve: Add SVE support to register access ioctl interface
  KVM: arm64: Enumerate SVE register indices for KVM_GET_REG_LIST
  arm64/sve: In-kernel vector length availability query interface
  KVM: arm/arm64: Add hook for arch-specific KVM initialisation
  KVM: arm/arm64: Add KVM_ARM_VCPU_FINALIZE ioctl
  KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
  KVM: arm64/sve: Allow userspace to enable SVE for vcpus
  KVM: arm64: Add a capability to advertise SVE support
  KVM: Document errors for KVM_GET_ONE_REG and KVM_SET_ONE_REG
  KVM: arm64/sve: Document KVM API extensions for SVE

 Documentation/virtual/kvm/api.txt | 156 +++++++++++++++
 arch/arm/include/asm/kvm_host.h   |   6 +
 arch/arm64/include/asm/fpsimd.h   |  33 +++-
 arch/arm64/include/asm/kvm_host.h |  43 ++++-
 arch/arm64/include/asm/kvm_hyp.h  |   1 -
 arch/arm64/include/asm/sysreg.h   |   3 +
 arch/arm64/include/uapi/asm/kvm.h |  22 +++
 arch/arm64/kernel/cpufeature.c    |   2 +-
 arch/arm64/kernel/fpsimd.c        | 172 ++++++++++++-----
 arch/arm64/kernel/signal.c        |   5 -
 arch/arm64/kvm/fpsimd.c           |  17 +-
 arch/arm64/kvm/guest.c            | 394 +++++++++++++++++++++++++++++++++++---
 arch/arm64/kvm/hyp/switch.c       |  74 +++++--
 arch/arm64/kvm/reset.c            | 135 ++++++++++++-
 arch/arm64/kvm/sys_regs.c         | 130 +++++++++++--
 arch/arm64/kvm/sys_regs.h         |  25 +++
 include/uapi/linux/kvm.h          |   5 +
 virt/kvm/arm/arm.c                |  22 +++
 18 files changed, 1115 insertions(+), 130 deletions(-)

-- 
2.1.4


_______________________________________________
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] 224+ messages in thread

* [PATCH v7 01/27] KVM: Documentation: Document arm64 core registers in detail
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

Since the the sizes of individual members of the core arm64
registers vary, the list of register encodings that make sense is
not a simple linear sequence.

To clarify which encodings to use, this patch adds a brief list
to the documentation.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Grall <julien.grall@arm.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
 Documentation/virtual/kvm/api.txt | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 7de9eee..2d4f7ce 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2107,6 +2107,30 @@ contains elements ranging from 32 to 128 bits. The index is a 32bit
 value in the kvm_regs structure seen as a 32bit array.
   0x60x0 0000 0010 <index into the kvm_regs struct:16>
 
+Specifically:
+    Encoding            Register  Bits  kvm_regs member
+----------------------------------------------------------------
+  0x6030 0000 0010 0000 X0          64  regs.regs[0]
+  0x6030 0000 0010 0002 X1          64  regs.regs[1]
+    ...
+  0x6030 0000 0010 003c X30         64  regs.regs[30]
+  0x6030 0000 0010 003e SP          64  regs.sp
+  0x6030 0000 0010 0040 PC          64  regs.pc
+  0x6030 0000 0010 0042 PSTATE      64  regs.pstate
+  0x6030 0000 0010 0044 SP_EL1      64  sp_el1
+  0x6030 0000 0010 0046 ELR_EL1     64  elr_el1
+  0x6030 0000 0010 0048 SPSR_EL1    64  spsr[KVM_SPSR_EL1] (alias SPSR_SVC)
+  0x6030 0000 0010 004a SPSR_ABT    64  spsr[KVM_SPSR_ABT]
+  0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
+  0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
+  0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
+  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]
+  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]
+    ...
+  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]
+  0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
+  0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
+
 arm64 CCSIDR registers are demultiplexed by CSSELR value:
   0x6020 0000 0011 00 <csselr:8>
 
-- 
2.1.4

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

* [PATCH v7 01/27] KVM: Documentation: Document arm64 core registers in detail
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

Since the the sizes of individual members of the core arm64
registers vary, the list of register encodings that make sense is
not a simple linear sequence.

To clarify which encodings to use, this patch adds a brief list
to the documentation.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Grall <julien.grall@arm.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
---
 Documentation/virtual/kvm/api.txt | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 7de9eee..2d4f7ce 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2107,6 +2107,30 @@ contains elements ranging from 32 to 128 bits. The index is a 32bit
 value in the kvm_regs structure seen as a 32bit array.
   0x60x0 0000 0010 <index into the kvm_regs struct:16>
 
+Specifically:
+    Encoding            Register  Bits  kvm_regs member
+----------------------------------------------------------------
+  0x6030 0000 0010 0000 X0          64  regs.regs[0]
+  0x6030 0000 0010 0002 X1          64  regs.regs[1]
+    ...
+  0x6030 0000 0010 003c X30         64  regs.regs[30]
+  0x6030 0000 0010 003e SP          64  regs.sp
+  0x6030 0000 0010 0040 PC          64  regs.pc
+  0x6030 0000 0010 0042 PSTATE      64  regs.pstate
+  0x6030 0000 0010 0044 SP_EL1      64  sp_el1
+  0x6030 0000 0010 0046 ELR_EL1     64  elr_el1
+  0x6030 0000 0010 0048 SPSR_EL1    64  spsr[KVM_SPSR_EL1] (alias SPSR_SVC)
+  0x6030 0000 0010 004a SPSR_ABT    64  spsr[KVM_SPSR_ABT]
+  0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
+  0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
+  0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
+  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]
+  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]
+    ...
+  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]
+  0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
+  0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
+
 arm64 CCSIDR registers are demultiplexed by CSSELR value:
   0x6020 0000 0011 00 <csselr:8>
 
-- 
2.1.4


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

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

* [PATCH v7 02/27] arm64: fpsimd: Always set TIF_FOREIGN_FPSTATE on task state flush
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

This patch updates fpsimd_flush_task_state() to mirror the new
semantics of fpsimd_flush_cpu_state() introduced by commit
d8ad71fa38a9 ("arm64: fpsimd: Fix TIF_FOREIGN_FPSTATE after
invalidating cpu regs").  Both functions now implicitly set
TIF_FOREIGN_FPSTATE to indicate that the task's FPSIMD state is not
loaded into the cpu.

As a side-effect, fpsimd_flush_task_state() now sets
TIF_FOREIGN_FPSTATE even for non-running tasks.  In the case of
non-running tasks this is not useful but also harmless, because the
flag is live only while the corresponding task is running.  This
function is not called from fast paths, so special-casing this for
the task == current case is not really worth it.

Compiler barriers previously present in restore_sve_fpsimd_context()
are pulled into fpsimd_flush_task_state() so that it can be safely
called with preemption enabled if necessary.

Explicit calls to set TIF_FOREIGN_FPSTATE that accompany
fpsimd_flush_task_state() calls and are now redundant are removed
as appropriate.

fpsimd_flush_task_state() is used to get exclusive access to the
representation of the task's state via task_struct, for the purpose
of replacing the state.  Thus, the call to this function should
happen before manipulating fpsimd_state or sve_state etc. in
task_struct.  Anomalous cases are reordered appropriately in order
to make the code more consistent, although there should be no
functional difference since these cases are protected by
local_bh_disable() anyway.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 arch/arm64/kernel/fpsimd.c | 25 +++++++++++++++++++------
 arch/arm64/kernel/signal.c |  5 -----
 2 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 5ebe73b..62c37f0 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -550,7 +550,6 @@ int sve_set_vector_length(struct task_struct *task,
 		local_bh_disable();
 
 		fpsimd_save();
-		set_thread_flag(TIF_FOREIGN_FPSTATE);
 	}
 
 	fpsimd_flush_task_state(task);
@@ -816,12 +815,11 @@ asmlinkage void do_sve_acc(unsigned int esr, struct pt_regs *regs)
 	local_bh_disable();
 
 	fpsimd_save();
-	fpsimd_to_sve(current);
 
 	/* Force ret_to_user to reload the registers: */
 	fpsimd_flush_task_state(current);
-	set_thread_flag(TIF_FOREIGN_FPSTATE);
 
+	fpsimd_to_sve(current);
 	if (test_and_set_thread_flag(TIF_SVE))
 		WARN_ON(1); /* SVE access shouldn't have trapped */
 
@@ -894,9 +892,9 @@ void fpsimd_flush_thread(void)
 
 	local_bh_disable();
 
+	fpsimd_flush_task_state(current);
 	memset(&current->thread.uw.fpsimd_state, 0,
 	       sizeof(current->thread.uw.fpsimd_state));
-	fpsimd_flush_task_state(current);
 
 	if (system_supports_sve()) {
 		clear_thread_flag(TIF_SVE);
@@ -933,8 +931,6 @@ void fpsimd_flush_thread(void)
 			current->thread.sve_vl_onexec = 0;
 	}
 
-	set_thread_flag(TIF_FOREIGN_FPSTATE);
-
 	local_bh_enable();
 }
 
@@ -1043,12 +1039,29 @@ void fpsimd_update_current_state(struct user_fpsimd_state const *state)
 
 /*
  * Invalidate live CPU copies of task t's FPSIMD state
+ *
+ * This function may be called with preemption enabled.  The barrier()
+ * ensures that the assignment to fpsimd_cpu is visible to any
+ * preemption/softirq that could race with set_tsk_thread_flag(), so
+ * that TIF_FOREIGN_FPSTATE cannot be spuriously re-cleared.
+ *
+ * The final barrier ensures that TIF_FOREIGN_FPSTATE is seen set by any
+ * subsequent code.
  */
 void fpsimd_flush_task_state(struct task_struct *t)
 {
 	t->thread.fpsimd_cpu = NR_CPUS;
+
+	barrier();
+	set_tsk_thread_flag(t, TIF_FOREIGN_FPSTATE);
+
+	barrier();
 }
 
+/*
+ * Invalidate any task's FPSIMD state that is present on this cpu.
+ * This function must be called with softirqs disabled.
+ */
 void fpsimd_flush_cpu_state(void)
 {
 	__this_cpu_write(fpsimd_last_state.st, NULL);
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 867a7ce..a9b0485 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -296,11 +296,6 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
 	 */
 
 	fpsimd_flush_task_state(current);
-	barrier();
-	/* From now, fpsimd_thread_switch() won't clear TIF_FOREIGN_FPSTATE */
-
-	set_thread_flag(TIF_FOREIGN_FPSTATE);
-	barrier();
 	/* From now, fpsimd_thread_switch() won't touch thread.sve_state */
 
 	sve_alloc(current);
-- 
2.1.4

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

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

* [PATCH v7 02/27] arm64: fpsimd: Always set TIF_FOREIGN_FPSTATE on task state flush
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

This patch updates fpsimd_flush_task_state() to mirror the new
semantics of fpsimd_flush_cpu_state() introduced by commit
d8ad71fa38a9 ("arm64: fpsimd: Fix TIF_FOREIGN_FPSTATE after
invalidating cpu regs").  Both functions now implicitly set
TIF_FOREIGN_FPSTATE to indicate that the task's FPSIMD state is not
loaded into the cpu.

As a side-effect, fpsimd_flush_task_state() now sets
TIF_FOREIGN_FPSTATE even for non-running tasks.  In the case of
non-running tasks this is not useful but also harmless, because the
flag is live only while the corresponding task is running.  This
function is not called from fast paths, so special-casing this for
the task == current case is not really worth it.

Compiler barriers previously present in restore_sve_fpsimd_context()
are pulled into fpsimd_flush_task_state() so that it can be safely
called with preemption enabled if necessary.

Explicit calls to set TIF_FOREIGN_FPSTATE that accompany
fpsimd_flush_task_state() calls and are now redundant are removed
as appropriate.

fpsimd_flush_task_state() is used to get exclusive access to the
representation of the task's state via task_struct, for the purpose
of replacing the state.  Thus, the call to this function should
happen before manipulating fpsimd_state or sve_state etc. in
task_struct.  Anomalous cases are reordered appropriately in order
to make the code more consistent, although there should be no
functional difference since these cases are protected by
local_bh_disable() anyway.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 arch/arm64/kernel/fpsimd.c | 25 +++++++++++++++++++------
 arch/arm64/kernel/signal.c |  5 -----
 2 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 5ebe73b..62c37f0 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -550,7 +550,6 @@ int sve_set_vector_length(struct task_struct *task,
 		local_bh_disable();
 
 		fpsimd_save();
-		set_thread_flag(TIF_FOREIGN_FPSTATE);
 	}
 
 	fpsimd_flush_task_state(task);
@@ -816,12 +815,11 @@ asmlinkage void do_sve_acc(unsigned int esr, struct pt_regs *regs)
 	local_bh_disable();
 
 	fpsimd_save();
-	fpsimd_to_sve(current);
 
 	/* Force ret_to_user to reload the registers: */
 	fpsimd_flush_task_state(current);
-	set_thread_flag(TIF_FOREIGN_FPSTATE);
 
+	fpsimd_to_sve(current);
 	if (test_and_set_thread_flag(TIF_SVE))
 		WARN_ON(1); /* SVE access shouldn't have trapped */
 
@@ -894,9 +892,9 @@ void fpsimd_flush_thread(void)
 
 	local_bh_disable();
 
+	fpsimd_flush_task_state(current);
 	memset(&current->thread.uw.fpsimd_state, 0,
 	       sizeof(current->thread.uw.fpsimd_state));
-	fpsimd_flush_task_state(current);
 
 	if (system_supports_sve()) {
 		clear_thread_flag(TIF_SVE);
@@ -933,8 +931,6 @@ void fpsimd_flush_thread(void)
 			current->thread.sve_vl_onexec = 0;
 	}
 
-	set_thread_flag(TIF_FOREIGN_FPSTATE);
-
 	local_bh_enable();
 }
 
@@ -1043,12 +1039,29 @@ void fpsimd_update_current_state(struct user_fpsimd_state const *state)
 
 /*
  * Invalidate live CPU copies of task t's FPSIMD state
+ *
+ * This function may be called with preemption enabled.  The barrier()
+ * ensures that the assignment to fpsimd_cpu is visible to any
+ * preemption/softirq that could race with set_tsk_thread_flag(), so
+ * that TIF_FOREIGN_FPSTATE cannot be spuriously re-cleared.
+ *
+ * The final barrier ensures that TIF_FOREIGN_FPSTATE is seen set by any
+ * subsequent code.
  */
 void fpsimd_flush_task_state(struct task_struct *t)
 {
 	t->thread.fpsimd_cpu = NR_CPUS;
+
+	barrier();
+	set_tsk_thread_flag(t, TIF_FOREIGN_FPSTATE);
+
+	barrier();
 }
 
+/*
+ * Invalidate any task's FPSIMD state that is present on this cpu.
+ * This function must be called with softirqs disabled.
+ */
 void fpsimd_flush_cpu_state(void)
 {
 	__this_cpu_write(fpsimd_last_state.st, NULL);
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 867a7ce..a9b0485 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -296,11 +296,6 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
 	 */
 
 	fpsimd_flush_task_state(current);
-	barrier();
-	/* From now, fpsimd_thread_switch() won't clear TIF_FOREIGN_FPSTATE */
-
-	set_thread_flag(TIF_FOREIGN_FPSTATE);
-	barrier();
 	/* From now, fpsimd_thread_switch() won't touch thread.sve_state */
 
 	sve_alloc(current);
-- 
2.1.4


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

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

* [PATCH v7 03/27] KVM: arm64: Delete orphaned declaration for __fpsimd_enabled()
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

__fpsimd_enabled() no longer exists, but a dangling declaration has
survived in kvm_hyp.h.

This patch gets rid of it.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 arch/arm64/include/asm/kvm_hyp.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 4da765f..ef8b839 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -149,7 +149,6 @@ 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);
-bool __fpsimd_enabled(void);
 
 void activate_traps_vhe_load(struct kvm_vcpu *vcpu);
 void deactivate_traps_vhe_put(void);
-- 
2.1.4

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

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

* [PATCH v7 03/27] KVM: arm64: Delete orphaned declaration for __fpsimd_enabled()
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

__fpsimd_enabled() no longer exists, but a dangling declaration has
survived in kvm_hyp.h.

This patch gets rid of it.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 arch/arm64/include/asm/kvm_hyp.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 4da765f..ef8b839 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -149,7 +149,6 @@ 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);
-bool __fpsimd_enabled(void);
 
 void activate_traps_vhe_load(struct kvm_vcpu *vcpu);
 void deactivate_traps_vhe_put(void);
-- 
2.1.4


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

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

* [PATCH v7 04/27] KVM: arm64: Refactor kvm_arm_num_regs() for easier maintenance
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

kvm_arm_num_regs() adds together various partial register counts in
a freeform sum expression, which makes it harder than necessary to
read diffs that add, modify or remove a single term in the sum
(which is expected to the common case under maintenance).

This patch refactors the code to add the term one per line, for
maximum readability.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 arch/arm64/kvm/guest.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index dd436a5..62514cb 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -258,8 +258,14 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
  */
 unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
 {
-	return num_core_regs() + kvm_arm_num_sys_reg_descs(vcpu)
-		+ kvm_arm_get_fw_num_regs(vcpu)	+ NUM_TIMER_REGS;
+	unsigned long res = 0;
+
+	res += num_core_regs();
+	res += kvm_arm_num_sys_reg_descs(vcpu);
+	res += kvm_arm_get_fw_num_regs(vcpu);
+	res += NUM_TIMER_REGS;
+
+	return res;
 }
 
 /**
-- 
2.1.4

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

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

* [PATCH v7 04/27] KVM: arm64: Refactor kvm_arm_num_regs() for easier maintenance
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

kvm_arm_num_regs() adds together various partial register counts in
a freeform sum expression, which makes it harder than necessary to
read diffs that add, modify or remove a single term in the sum
(which is expected to the common case under maintenance).

This patch refactors the code to add the term one per line, for
maximum readability.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 arch/arm64/kvm/guest.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index dd436a5..62514cb 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -258,8 +258,14 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
  */
 unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
 {
-	return num_core_regs() + kvm_arm_num_sys_reg_descs(vcpu)
-		+ kvm_arm_get_fw_num_regs(vcpu)	+ NUM_TIMER_REGS;
+	unsigned long res = 0;
+
+	res += num_core_regs();
+	res += kvm_arm_num_sys_reg_descs(vcpu);
+	res += kvm_arm_get_fw_num_regs(vcpu);
+	res += NUM_TIMER_REGS;
+
+	return res;
 }
 
 /**
-- 
2.1.4


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

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

* [PATCH v7 05/27] KVM: arm64: Add missing #includes to kvm_host.h
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

kvm_host.h uses some declarations from other headers that are
currently included by accident, without an explicit #include.

This patch adds a few #includes that are clearly missing.  Although
the header builds without them today, this should help to avoid
future surprises.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * [Mark Rutland] Add additional missing #includes <linux/jump_label.h>,
   <linux/percpu.h>, <asm/barrier.h>, while we're about it.

   Commit message reworded to match.
---
 arch/arm64/include/asm/kvm_host.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index a01fe087..6d10100 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -22,9 +22,13 @@
 #ifndef __ARM64_KVM_HOST_H__
 #define __ARM64_KVM_HOST_H__
 
+#include <linux/bitmap.h>
 #include <linux/types.h>
+#include <linux/jump_label.h>
 #include <linux/kvm_types.h>
+#include <linux/percpu.h>
 #include <asm/arch_gicv3.h>
+#include <asm/barrier.h>
 #include <asm/cpufeature.h>
 #include <asm/daifflags.h>
 #include <asm/fpsimd.h>
-- 
2.1.4

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

* [PATCH v7 05/27] KVM: arm64: Add missing #includes to kvm_host.h
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

kvm_host.h uses some declarations from other headers that are
currently included by accident, without an explicit #include.

This patch adds a few #includes that are clearly missing.  Although
the header builds without them today, this should help to avoid
future surprises.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * [Mark Rutland] Add additional missing #includes <linux/jump_label.h>,
   <linux/percpu.h>, <asm/barrier.h>, while we're about it.

   Commit message reworded to match.
---
 arch/arm64/include/asm/kvm_host.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index a01fe087..6d10100 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -22,9 +22,13 @@
 #ifndef __ARM64_KVM_HOST_H__
 #define __ARM64_KVM_HOST_H__
 
+#include <linux/bitmap.h>
 #include <linux/types.h>
+#include <linux/jump_label.h>
 #include <linux/kvm_types.h>
+#include <linux/percpu.h>
 #include <asm/arch_gicv3.h>
+#include <asm/barrier.h>
 #include <asm/cpufeature.h>
 #include <asm/daifflags.h>
 #include <asm/fpsimd.h>
-- 
2.1.4


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

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

* [PATCH v7 06/27] arm64/sve: Clarify role of the VQ map maintenance functions
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

The roles of sve_init_vq_map(), sve_update_vq_map() and
sve_verify_vq_map() are highly non-obvious to anyone who has not dug
through cpufeatures.c in detail.

Since the way these functions interact with each other is more
important here than a full understanding of the cpufeatures code, this
patch adds comments to make the functions' roles clearer.

No functional change.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Reviewed-by: Julien Grall <julien.grall@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * [Julien Thierry] This patch is useful for explaining the previous
   patch (as per the v5 ordering), and is anyway non-functional.
   Swapped it with the previous patch to provide a more logical reading
   order for the series.
---
 arch/arm64/kernel/fpsimd.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 62c37f0..f59ea67 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -647,6 +647,10 @@ static void sve_probe_vqs(DECLARE_BITMAP(map, SVE_VQ_MAX))
 	}
 }
 
+/*
+ * Initialise the set of known supported VQs for the boot CPU.
+ * This is called during kernel boot, before secondary CPUs are brought up.
+ */
 void __init sve_init_vq_map(void)
 {
 	sve_probe_vqs(sve_vq_map);
@@ -655,6 +659,7 @@ void __init sve_init_vq_map(void)
 /*
  * If we haven't committed to the set of supported VQs yet, filter out
  * those not supported by the current CPU.
+ * This function is called during the bring-up of early secondary CPUs only.
  */
 void sve_update_vq_map(void)
 {
@@ -662,7 +667,10 @@ void sve_update_vq_map(void)
 	bitmap_and(sve_vq_map, sve_vq_map, sve_secondary_vq_map, SVE_VQ_MAX);
 }
 
-/* Check whether the current CPU supports all VQs in the committed set */
+/*
+ * Check whether the current CPU supports all VQs in the committed set.
+ * This function is called during the bring-up of late secondary CPUs only.
+ */
 int sve_verify_vq_map(void)
 {
 	int ret = 0;
-- 
2.1.4

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

* [PATCH v7 06/27] arm64/sve: Clarify role of the VQ map maintenance functions
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

The roles of sve_init_vq_map(), sve_update_vq_map() and
sve_verify_vq_map() are highly non-obvious to anyone who has not dug
through cpufeatures.c in detail.

Since the way these functions interact with each other is more
important here than a full understanding of the cpufeatures code, this
patch adds comments to make the functions' roles clearer.

No functional change.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Reviewed-by: Julien Grall <julien.grall@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * [Julien Thierry] This patch is useful for explaining the previous
   patch (as per the v5 ordering), and is anyway non-functional.
   Swapped it with the previous patch to provide a more logical reading
   order for the series.
---
 arch/arm64/kernel/fpsimd.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 62c37f0..f59ea67 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -647,6 +647,10 @@ static void sve_probe_vqs(DECLARE_BITMAP(map, SVE_VQ_MAX))
 	}
 }
 
+/*
+ * Initialise the set of known supported VQs for the boot CPU.
+ * This is called during kernel boot, before secondary CPUs are brought up.
+ */
 void __init sve_init_vq_map(void)
 {
 	sve_probe_vqs(sve_vq_map);
@@ -655,6 +659,7 @@ void __init sve_init_vq_map(void)
 /*
  * If we haven't committed to the set of supported VQs yet, filter out
  * those not supported by the current CPU.
+ * This function is called during the bring-up of early secondary CPUs only.
  */
 void sve_update_vq_map(void)
 {
@@ -662,7 +667,10 @@ void sve_update_vq_map(void)
 	bitmap_and(sve_vq_map, sve_vq_map, sve_secondary_vq_map, SVE_VQ_MAX);
 }
 
-/* Check whether the current CPU supports all VQs in the committed set */
+/*
+ * Check whether the current CPU supports all VQs in the committed set.
+ * This function is called during the bring-up of late secondary CPUs only.
+ */
 int sve_verify_vq_map(void)
 {
 	int ret = 0;
-- 
2.1.4


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

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

* [PATCH v7 07/27] arm64/sve: Check SVE virtualisability
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

Due to the way the effective SVE vector length is controlled and
trapped at different exception levels, certain mismatches in the
sets of vector lengths supported by different physical CPUs in the
system may prevent straightforward virtualisation of SVE at parity
with the host.

This patch analyses the extent to which SVE can be virtualised
safely without interfering with migration of vcpus between physical
CPUs, and rejects late secondary CPUs that would erode the
situation further.

It is left up to KVM to decide what to do with this information.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

QUESTION: The final structure of this code makes it quite natural to
clamp the vector length for KVM guests to the maximum value supportable
across all CPUs; such a value is guaranteed to exist, but may be
surprisingly small on a given hardware platform.

Should we be stricter and actually refuse to support KVM at all on such
hardware?  This may help to force people to fix Linux (or the
architecture) if/when this issue comes up.

For now, I stick with pr_warn() and make do with a limited SVE vector
length for guests.

Changes since v5:

 * pr_info() about the presence of unvirtualisable vector lengths in
   sve_setup() upgrade to pr_warn(), for consistency with
   sve_verify_vq_map().
---
 arch/arm64/include/asm/fpsimd.h |  1 +
 arch/arm64/kernel/cpufeature.c  |  2 +-
 arch/arm64/kernel/fpsimd.c      | 86 ++++++++++++++++++++++++++++++++++-------
 3 files changed, 73 insertions(+), 16 deletions(-)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index dd1ad39..964adc9 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -87,6 +87,7 @@ extern void sve_kernel_enable(const struct arm64_cpu_capabilities *__unused);
 extern u64 read_zcr_features(void);
 
 extern int __ro_after_init sve_max_vl;
+extern int __ro_after_init sve_max_virtualisable_vl;
 
 #ifdef CONFIG_ARM64_SVE
 
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 4061de1..7f8cc51 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -1863,7 +1863,7 @@ static void verify_sve_features(void)
 	unsigned int len = zcr & ZCR_ELx_LEN_MASK;
 
 	if (len < safe_len || sve_verify_vq_map()) {
-		pr_crit("CPU%d: SVE: required vector length(s) missing\n",
+		pr_crit("CPU%d: SVE: vector length support mismatch\n",
 			smp_processor_id());
 		cpu_die_early();
 	}
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index f59ea67..b219796a 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -18,6 +18,7 @@
  */
 
 #include <linux/bitmap.h>
+#include <linux/bitops.h>
 #include <linux/bottom_half.h>
 #include <linux/bug.h>
 #include <linux/cache.h>
@@ -48,6 +49,7 @@
 #include <asm/sigcontext.h>
 #include <asm/sysreg.h>
 #include <asm/traps.h>
+#include <asm/virt.h>
 
 #define FPEXC_IOF	(1 << 0)
 #define FPEXC_DZF	(1 << 1)
@@ -130,14 +132,18 @@ static int sve_default_vl = -1;
 
 /* Maximum supported vector length across all CPUs (initially poisoned) */
 int __ro_after_init sve_max_vl = SVE_VL_MIN;
+int __ro_after_init sve_max_virtualisable_vl = SVE_VL_MIN;
 /* Set of available vector lengths, as vq_to_bit(vq): */
 static __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
+/* Set of vector lengths present on at least one cpu: */
+static __ro_after_init DECLARE_BITMAP(sve_vq_partial_map, SVE_VQ_MAX);
 static void __percpu *efi_sve_state;
 
 #else /* ! CONFIG_ARM64_SVE */
 
 /* Dummy declaration for code that will be optimised out: */
 extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
+extern __ro_after_init DECLARE_BITMAP(sve_vq_partial_map, SVE_VQ_MAX);
 extern void __percpu *efi_sve_state;
 
 #endif /* ! CONFIG_ARM64_SVE */
@@ -623,12 +629,6 @@ int sve_get_current_vl(void)
 	return sve_prctl_status(0);
 }
 
-/*
- * Bitmap for temporary storage of the per-CPU set of supported vector lengths
- * during secondary boot.
- */
-static DECLARE_BITMAP(sve_secondary_vq_map, SVE_VQ_MAX);
-
 static void sve_probe_vqs(DECLARE_BITMAP(map, SVE_VQ_MAX))
 {
 	unsigned int vq, vl;
@@ -654,6 +654,7 @@ static void sve_probe_vqs(DECLARE_BITMAP(map, SVE_VQ_MAX))
 void __init sve_init_vq_map(void)
 {
 	sve_probe_vqs(sve_vq_map);
+	bitmap_copy(sve_vq_partial_map, sve_vq_map, SVE_VQ_MAX);
 }
 
 /*
@@ -663,8 +664,11 @@ void __init sve_init_vq_map(void)
  */
 void sve_update_vq_map(void)
 {
-	sve_probe_vqs(sve_secondary_vq_map);
-	bitmap_and(sve_vq_map, sve_vq_map, sve_secondary_vq_map, SVE_VQ_MAX);
+	DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
+
+	sve_probe_vqs(tmp_map);
+	bitmap_and(sve_vq_map, sve_vq_map, tmp_map, SVE_VQ_MAX);
+	bitmap_or(sve_vq_partial_map, sve_vq_partial_map, tmp_map, SVE_VQ_MAX);
 }
 
 /*
@@ -673,18 +677,48 @@ void sve_update_vq_map(void)
  */
 int sve_verify_vq_map(void)
 {
-	int ret = 0;
+	DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
+	unsigned long b;
 
-	sve_probe_vqs(sve_secondary_vq_map);
-	bitmap_andnot(sve_secondary_vq_map, sve_vq_map, sve_secondary_vq_map,
-		      SVE_VQ_MAX);
-	if (!bitmap_empty(sve_secondary_vq_map, SVE_VQ_MAX)) {
+	sve_probe_vqs(tmp_map);
+
+	bitmap_complement(tmp_map, tmp_map, SVE_VQ_MAX);
+	if (bitmap_intersects(tmp_map, sve_vq_map, SVE_VQ_MAX)) {
 		pr_warn("SVE: cpu%d: Required vector length(s) missing\n",
 			smp_processor_id());
-		ret = -EINVAL;
+		return -EINVAL;
 	}
 
-	return ret;
+	if (!IS_ENABLED(CONFIG_KVM) || !is_hyp_mode_available())
+		return 0;
+
+	/*
+	 * For KVM, it is necessary to ensure that this CPU doesn't
+	 * support any vector length that guests may have probed as
+	 * unsupported.
+	 */
+
+	/* Recover the set of supported VQs: */
+	bitmap_complement(tmp_map, tmp_map, SVE_VQ_MAX);
+	/* Find VQs supported that are not globally supported: */
+	bitmap_andnot(tmp_map, tmp_map, sve_vq_map, SVE_VQ_MAX);
+
+	/* Find the lowest such VQ, if any: */
+	b = find_last_bit(tmp_map, SVE_VQ_MAX);
+	if (b >= SVE_VQ_MAX)
+		return 0; /* no mismatches */
+
+	/*
+	 * Mismatches above sve_max_virtualisable_vl are fine, since
+	 * no guest is allowed to configure ZCR_EL2.LEN to exceed this:
+	 */
+	if (sve_vl_from_vq(bit_to_vq(b)) <= sve_max_virtualisable_vl) {
+		pr_warn("SVE: cpu%d: Unsupported vector length(s) present\n",
+			smp_processor_id());
+		return -EINVAL;
+	}
+
+	return 0;
 }
 
 static void __init sve_efi_setup(void)
@@ -751,6 +785,8 @@ u64 read_zcr_features(void)
 void __init sve_setup(void)
 {
 	u64 zcr;
+	DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
+	unsigned long b;
 
 	if (!system_supports_sve())
 		return;
@@ -779,11 +815,31 @@ void __init sve_setup(void)
 	 */
 	sve_default_vl = find_supported_vector_length(64);
 
+	bitmap_andnot(tmp_map, sve_vq_partial_map, sve_vq_map,
+		      SVE_VQ_MAX);
+
+	b = find_last_bit(tmp_map, SVE_VQ_MAX);
+	if (b >= SVE_VQ_MAX)
+		/* No non-virtualisable VLs found */
+		sve_max_virtualisable_vl = SVE_VQ_MAX;
+	else if (WARN_ON(b == SVE_VQ_MAX - 1))
+		/* No virtualisable VLs?  This is architecturally forbidden. */
+		sve_max_virtualisable_vl = SVE_VQ_MIN;
+	else /* b + 1 < SVE_VQ_MAX */
+		sve_max_virtualisable_vl = sve_vl_from_vq(bit_to_vq(b + 1));
+
+	if (sve_max_virtualisable_vl > sve_max_vl)
+		sve_max_virtualisable_vl = sve_max_vl;
+
 	pr_info("SVE: maximum available vector length %u bytes per vector\n",
 		sve_max_vl);
 	pr_info("SVE: default vector length %u bytes per vector\n",
 		sve_default_vl);
 
+	/* KVM decides whether to support mismatched systems. Just warn here: */
+	if (sve_max_virtualisable_vl < sve_max_vl)
+		pr_warn("SVE: unvirtualisable vector lengths present\n");
+
 	sve_efi_setup();
 }
 
-- 
2.1.4

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

* [PATCH v7 07/27] arm64/sve: Check SVE virtualisability
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

Due to the way the effective SVE vector length is controlled and
trapped at different exception levels, certain mismatches in the
sets of vector lengths supported by different physical CPUs in the
system may prevent straightforward virtualisation of SVE at parity
with the host.

This patch analyses the extent to which SVE can be virtualised
safely without interfering with migration of vcpus between physical
CPUs, and rejects late secondary CPUs that would erode the
situation further.

It is left up to KVM to decide what to do with this information.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

QUESTION: The final structure of this code makes it quite natural to
clamp the vector length for KVM guests to the maximum value supportable
across all CPUs; such a value is guaranteed to exist, but may be
surprisingly small on a given hardware platform.

Should we be stricter and actually refuse to support KVM at all on such
hardware?  This may help to force people to fix Linux (or the
architecture) if/when this issue comes up.

For now, I stick with pr_warn() and make do with a limited SVE vector
length for guests.

Changes since v5:

 * pr_info() about the presence of unvirtualisable vector lengths in
   sve_setup() upgrade to pr_warn(), for consistency with
   sve_verify_vq_map().
---
 arch/arm64/include/asm/fpsimd.h |  1 +
 arch/arm64/kernel/cpufeature.c  |  2 +-
 arch/arm64/kernel/fpsimd.c      | 86 ++++++++++++++++++++++++++++++++++-------
 3 files changed, 73 insertions(+), 16 deletions(-)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index dd1ad39..964adc9 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -87,6 +87,7 @@ extern void sve_kernel_enable(const struct arm64_cpu_capabilities *__unused);
 extern u64 read_zcr_features(void);
 
 extern int __ro_after_init sve_max_vl;
+extern int __ro_after_init sve_max_virtualisable_vl;
 
 #ifdef CONFIG_ARM64_SVE
 
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 4061de1..7f8cc51 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -1863,7 +1863,7 @@ static void verify_sve_features(void)
 	unsigned int len = zcr & ZCR_ELx_LEN_MASK;
 
 	if (len < safe_len || sve_verify_vq_map()) {
-		pr_crit("CPU%d: SVE: required vector length(s) missing\n",
+		pr_crit("CPU%d: SVE: vector length support mismatch\n",
 			smp_processor_id());
 		cpu_die_early();
 	}
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index f59ea67..b219796a 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -18,6 +18,7 @@
  */
 
 #include <linux/bitmap.h>
+#include <linux/bitops.h>
 #include <linux/bottom_half.h>
 #include <linux/bug.h>
 #include <linux/cache.h>
@@ -48,6 +49,7 @@
 #include <asm/sigcontext.h>
 #include <asm/sysreg.h>
 #include <asm/traps.h>
+#include <asm/virt.h>
 
 #define FPEXC_IOF	(1 << 0)
 #define FPEXC_DZF	(1 << 1)
@@ -130,14 +132,18 @@ static int sve_default_vl = -1;
 
 /* Maximum supported vector length across all CPUs (initially poisoned) */
 int __ro_after_init sve_max_vl = SVE_VL_MIN;
+int __ro_after_init sve_max_virtualisable_vl = SVE_VL_MIN;
 /* Set of available vector lengths, as vq_to_bit(vq): */
 static __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
+/* Set of vector lengths present on at least one cpu: */
+static __ro_after_init DECLARE_BITMAP(sve_vq_partial_map, SVE_VQ_MAX);
 static void __percpu *efi_sve_state;
 
 #else /* ! CONFIG_ARM64_SVE */
 
 /* Dummy declaration for code that will be optimised out: */
 extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
+extern __ro_after_init DECLARE_BITMAP(sve_vq_partial_map, SVE_VQ_MAX);
 extern void __percpu *efi_sve_state;
 
 #endif /* ! CONFIG_ARM64_SVE */
@@ -623,12 +629,6 @@ int sve_get_current_vl(void)
 	return sve_prctl_status(0);
 }
 
-/*
- * Bitmap for temporary storage of the per-CPU set of supported vector lengths
- * during secondary boot.
- */
-static DECLARE_BITMAP(sve_secondary_vq_map, SVE_VQ_MAX);
-
 static void sve_probe_vqs(DECLARE_BITMAP(map, SVE_VQ_MAX))
 {
 	unsigned int vq, vl;
@@ -654,6 +654,7 @@ static void sve_probe_vqs(DECLARE_BITMAP(map, SVE_VQ_MAX))
 void __init sve_init_vq_map(void)
 {
 	sve_probe_vqs(sve_vq_map);
+	bitmap_copy(sve_vq_partial_map, sve_vq_map, SVE_VQ_MAX);
 }
 
 /*
@@ -663,8 +664,11 @@ void __init sve_init_vq_map(void)
  */
 void sve_update_vq_map(void)
 {
-	sve_probe_vqs(sve_secondary_vq_map);
-	bitmap_and(sve_vq_map, sve_vq_map, sve_secondary_vq_map, SVE_VQ_MAX);
+	DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
+
+	sve_probe_vqs(tmp_map);
+	bitmap_and(sve_vq_map, sve_vq_map, tmp_map, SVE_VQ_MAX);
+	bitmap_or(sve_vq_partial_map, sve_vq_partial_map, tmp_map, SVE_VQ_MAX);
 }
 
 /*
@@ -673,18 +677,48 @@ void sve_update_vq_map(void)
  */
 int sve_verify_vq_map(void)
 {
-	int ret = 0;
+	DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
+	unsigned long b;
 
-	sve_probe_vqs(sve_secondary_vq_map);
-	bitmap_andnot(sve_secondary_vq_map, sve_vq_map, sve_secondary_vq_map,
-		      SVE_VQ_MAX);
-	if (!bitmap_empty(sve_secondary_vq_map, SVE_VQ_MAX)) {
+	sve_probe_vqs(tmp_map);
+
+	bitmap_complement(tmp_map, tmp_map, SVE_VQ_MAX);
+	if (bitmap_intersects(tmp_map, sve_vq_map, SVE_VQ_MAX)) {
 		pr_warn("SVE: cpu%d: Required vector length(s) missing\n",
 			smp_processor_id());
-		ret = -EINVAL;
+		return -EINVAL;
 	}
 
-	return ret;
+	if (!IS_ENABLED(CONFIG_KVM) || !is_hyp_mode_available())
+		return 0;
+
+	/*
+	 * For KVM, it is necessary to ensure that this CPU doesn't
+	 * support any vector length that guests may have probed as
+	 * unsupported.
+	 */
+
+	/* Recover the set of supported VQs: */
+	bitmap_complement(tmp_map, tmp_map, SVE_VQ_MAX);
+	/* Find VQs supported that are not globally supported: */
+	bitmap_andnot(tmp_map, tmp_map, sve_vq_map, SVE_VQ_MAX);
+
+	/* Find the lowest such VQ, if any: */
+	b = find_last_bit(tmp_map, SVE_VQ_MAX);
+	if (b >= SVE_VQ_MAX)
+		return 0; /* no mismatches */
+
+	/*
+	 * Mismatches above sve_max_virtualisable_vl are fine, since
+	 * no guest is allowed to configure ZCR_EL2.LEN to exceed this:
+	 */
+	if (sve_vl_from_vq(bit_to_vq(b)) <= sve_max_virtualisable_vl) {
+		pr_warn("SVE: cpu%d: Unsupported vector length(s) present\n",
+			smp_processor_id());
+		return -EINVAL;
+	}
+
+	return 0;
 }
 
 static void __init sve_efi_setup(void)
@@ -751,6 +785,8 @@ u64 read_zcr_features(void)
 void __init sve_setup(void)
 {
 	u64 zcr;
+	DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
+	unsigned long b;
 
 	if (!system_supports_sve())
 		return;
@@ -779,11 +815,31 @@ void __init sve_setup(void)
 	 */
 	sve_default_vl = find_supported_vector_length(64);
 
+	bitmap_andnot(tmp_map, sve_vq_partial_map, sve_vq_map,
+		      SVE_VQ_MAX);
+
+	b = find_last_bit(tmp_map, SVE_VQ_MAX);
+	if (b >= SVE_VQ_MAX)
+		/* No non-virtualisable VLs found */
+		sve_max_virtualisable_vl = SVE_VQ_MAX;
+	else if (WARN_ON(b == SVE_VQ_MAX - 1))
+		/* No virtualisable VLs?  This is architecturally forbidden. */
+		sve_max_virtualisable_vl = SVE_VQ_MIN;
+	else /* b + 1 < SVE_VQ_MAX */
+		sve_max_virtualisable_vl = sve_vl_from_vq(bit_to_vq(b + 1));
+
+	if (sve_max_virtualisable_vl > sve_max_vl)
+		sve_max_virtualisable_vl = sve_max_vl;
+
 	pr_info("SVE: maximum available vector length %u bytes per vector\n",
 		sve_max_vl);
 	pr_info("SVE: default vector length %u bytes per vector\n",
 		sve_default_vl);
 
+	/* KVM decides whether to support mismatched systems. Just warn here: */
+	if (sve_max_virtualisable_vl < sve_max_vl)
+		pr_warn("SVE: unvirtualisable vector lengths present\n");
+
 	sve_efi_setup();
 }
 
-- 
2.1.4


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

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

* [PATCH v7 08/27] arm64/sve: Enable SVE state tracking for non-task contexts
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

The current FPSIMD/SVE context handling support for non-task (i.e.,
KVM vcpu) contexts does not take SVE into account.  This means that
only task contexts can safely use SVE at present.

In preparation for enabling KVM guests to use SVE, it is necessary
to keep track of SVE state for non-task contexts too.

This patch adds the necessary support, removing assumptions from
the context switch code about the location of the SVE context
storage.

When binding a vcpu context, its vector length is arbitrarily
specified as SVE_VL_MIN for now.  In any case, because TIF_SVE is
presently cleared at vcpu context bind time, the specified vector
length will not be used for anything yet.  In later patches TIF_SVE
will be set here as appropriate, and the appropriate maximum vector
length for the vcpu will be passed when binding.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 arch/arm64/include/asm/fpsimd.h |  3 ++-
 arch/arm64/kernel/fpsimd.c      | 20 +++++++++++++++-----
 arch/arm64/kvm/fpsimd.c         |  5 ++++-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 964adc9..df7a143 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -56,7 +56,8 @@ extern void fpsimd_restore_current_state(void);
 extern void fpsimd_update_current_state(struct user_fpsimd_state const *state);
 
 extern void fpsimd_bind_task_to_cpu(void);
-extern void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *state);
+extern void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *state,
+				     void *sve_state, unsigned int sve_vl);
 
 extern void fpsimd_flush_task_state(struct task_struct *target);
 extern void fpsimd_flush_cpu_state(void);
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index b219796a..8a93afa 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -121,6 +121,8 @@
  */
 struct fpsimd_last_state_struct {
 	struct user_fpsimd_state *st;
+	void *sve_state;
+	unsigned int sve_vl;
 };
 
 static DEFINE_PER_CPU(struct fpsimd_last_state_struct, fpsimd_last_state);
@@ -241,14 +243,15 @@ static void task_fpsimd_load(void)
  */
 void fpsimd_save(void)
 {
-	struct user_fpsimd_state *st = __this_cpu_read(fpsimd_last_state.st);
+	struct fpsimd_last_state_struct const *last =
+		this_cpu_ptr(&fpsimd_last_state);
 	/* set by fpsimd_bind_task_to_cpu() or fpsimd_bind_state_to_cpu() */
 
 	WARN_ON(!in_softirq() && !irqs_disabled());
 
 	if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) {
 		if (system_supports_sve() && test_thread_flag(TIF_SVE)) {
-			if (WARN_ON(sve_get_vl() != current->thread.sve_vl)) {
+			if (WARN_ON(sve_get_vl() != last->sve_vl)) {
 				/*
 				 * Can't save the user regs, so current would
 				 * re-enter user with corrupt state.
@@ -258,9 +261,11 @@ void fpsimd_save(void)
 				return;
 			}
 
-			sve_save_state(sve_pffr(&current->thread), &st->fpsr);
+			sve_save_state((char *)last->sve_state +
+						sve_ffr_offset(last->sve_vl),
+				       &last->st->fpsr);
 		} else
-			fpsimd_save_state(st);
+			fpsimd_save_state(last->st);
 	}
 }
 
@@ -1034,6 +1039,8 @@ void fpsimd_bind_task_to_cpu(void)
 		this_cpu_ptr(&fpsimd_last_state);
 
 	last->st = &current->thread.uw.fpsimd_state;
+	last->sve_state = current->thread.sve_state;
+	last->sve_vl = current->thread.sve_vl;
 	current->thread.fpsimd_cpu = smp_processor_id();
 
 	if (system_supports_sve()) {
@@ -1047,7 +1054,8 @@ void fpsimd_bind_task_to_cpu(void)
 	}
 }
 
-void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st)
+void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st, void *sve_state,
+			      unsigned int sve_vl)
 {
 	struct fpsimd_last_state_struct *last =
 		this_cpu_ptr(&fpsimd_last_state);
@@ -1055,6 +1063,8 @@ void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st)
 	WARN_ON(!in_softirq() && !irqs_disabled());
 
 	last->st = st;
+	last->sve_state = sve_state;
+	last->sve_vl = sve_vl;
 }
 
 /*
diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
index aac7808..1cf4f02 100644
--- a/arch/arm64/kvm/fpsimd.c
+++ b/arch/arm64/kvm/fpsimd.c
@@ -9,6 +9,7 @@
 #include <linux/sched.h>
 #include <linux/thread_info.h>
 #include <linux/kvm_host.h>
+#include <asm/fpsimd.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_host.h>
 #include <asm/kvm_mmu.h>
@@ -85,7 +86,9 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
 	WARN_ON_ONCE(!irqs_disabled());
 
 	if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
-		fpsimd_bind_state_to_cpu(&vcpu->arch.ctxt.gp_regs.fp_regs);
+		fpsimd_bind_state_to_cpu(&vcpu->arch.ctxt.gp_regs.fp_regs,
+					 NULL, SVE_VL_MIN);
+
 		clear_thread_flag(TIF_FOREIGN_FPSTATE);
 		clear_thread_flag(TIF_SVE);
 	}
-- 
2.1.4

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

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

* [PATCH v7 08/27] arm64/sve: Enable SVE state tracking for non-task contexts
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

The current FPSIMD/SVE context handling support for non-task (i.e.,
KVM vcpu) contexts does not take SVE into account.  This means that
only task contexts can safely use SVE at present.

In preparation for enabling KVM guests to use SVE, it is necessary
to keep track of SVE state for non-task contexts too.

This patch adds the necessary support, removing assumptions from
the context switch code about the location of the SVE context
storage.

When binding a vcpu context, its vector length is arbitrarily
specified as SVE_VL_MIN for now.  In any case, because TIF_SVE is
presently cleared at vcpu context bind time, the specified vector
length will not be used for anything yet.  In later patches TIF_SVE
will be set here as appropriate, and the appropriate maximum vector
length for the vcpu will be passed when binding.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 arch/arm64/include/asm/fpsimd.h |  3 ++-
 arch/arm64/kernel/fpsimd.c      | 20 +++++++++++++++-----
 arch/arm64/kvm/fpsimd.c         |  5 ++++-
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 964adc9..df7a143 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -56,7 +56,8 @@ extern void fpsimd_restore_current_state(void);
 extern void fpsimd_update_current_state(struct user_fpsimd_state const *state);
 
 extern void fpsimd_bind_task_to_cpu(void);
-extern void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *state);
+extern void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *state,
+				     void *sve_state, unsigned int sve_vl);
 
 extern void fpsimd_flush_task_state(struct task_struct *target);
 extern void fpsimd_flush_cpu_state(void);
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index b219796a..8a93afa 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -121,6 +121,8 @@
  */
 struct fpsimd_last_state_struct {
 	struct user_fpsimd_state *st;
+	void *sve_state;
+	unsigned int sve_vl;
 };
 
 static DEFINE_PER_CPU(struct fpsimd_last_state_struct, fpsimd_last_state);
@@ -241,14 +243,15 @@ static void task_fpsimd_load(void)
  */
 void fpsimd_save(void)
 {
-	struct user_fpsimd_state *st = __this_cpu_read(fpsimd_last_state.st);
+	struct fpsimd_last_state_struct const *last =
+		this_cpu_ptr(&fpsimd_last_state);
 	/* set by fpsimd_bind_task_to_cpu() or fpsimd_bind_state_to_cpu() */
 
 	WARN_ON(!in_softirq() && !irqs_disabled());
 
 	if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) {
 		if (system_supports_sve() && test_thread_flag(TIF_SVE)) {
-			if (WARN_ON(sve_get_vl() != current->thread.sve_vl)) {
+			if (WARN_ON(sve_get_vl() != last->sve_vl)) {
 				/*
 				 * Can't save the user regs, so current would
 				 * re-enter user with corrupt state.
@@ -258,9 +261,11 @@ void fpsimd_save(void)
 				return;
 			}
 
-			sve_save_state(sve_pffr(&current->thread), &st->fpsr);
+			sve_save_state((char *)last->sve_state +
+						sve_ffr_offset(last->sve_vl),
+				       &last->st->fpsr);
 		} else
-			fpsimd_save_state(st);
+			fpsimd_save_state(last->st);
 	}
 }
 
@@ -1034,6 +1039,8 @@ void fpsimd_bind_task_to_cpu(void)
 		this_cpu_ptr(&fpsimd_last_state);
 
 	last->st = &current->thread.uw.fpsimd_state;
+	last->sve_state = current->thread.sve_state;
+	last->sve_vl = current->thread.sve_vl;
 	current->thread.fpsimd_cpu = smp_processor_id();
 
 	if (system_supports_sve()) {
@@ -1047,7 +1054,8 @@ void fpsimd_bind_task_to_cpu(void)
 	}
 }
 
-void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st)
+void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st, void *sve_state,
+			      unsigned int sve_vl)
 {
 	struct fpsimd_last_state_struct *last =
 		this_cpu_ptr(&fpsimd_last_state);
@@ -1055,6 +1063,8 @@ void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st)
 	WARN_ON(!in_softirq() && !irqs_disabled());
 
 	last->st = st;
+	last->sve_state = sve_state;
+	last->sve_vl = sve_vl;
 }
 
 /*
diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
index aac7808..1cf4f02 100644
--- a/arch/arm64/kvm/fpsimd.c
+++ b/arch/arm64/kvm/fpsimd.c
@@ -9,6 +9,7 @@
 #include <linux/sched.h>
 #include <linux/thread_info.h>
 #include <linux/kvm_host.h>
+#include <asm/fpsimd.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_host.h>
 #include <asm/kvm_mmu.h>
@@ -85,7 +86,9 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
 	WARN_ON_ONCE(!irqs_disabled());
 
 	if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
-		fpsimd_bind_state_to_cpu(&vcpu->arch.ctxt.gp_regs.fp_regs);
+		fpsimd_bind_state_to_cpu(&vcpu->arch.ctxt.gp_regs.fp_regs,
+					 NULL, SVE_VL_MIN);
+
 		clear_thread_flag(TIF_FOREIGN_FPSTATE);
 		clear_thread_flag(TIF_SVE);
 	}
-- 
2.1.4


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

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

* [PATCH v7 09/27] KVM: arm64: Add a vcpu flag to control SVE visibility for the guest
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

Since SVE will be enabled or disabled on a per-vcpu basis, a flag
is needed in order to track which vcpus have it enabled.

This patch adds a suitable flag and a helper for checking it.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 arch/arm64/include/asm/kvm_host.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 6d10100..ad4f7f0 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -328,6 +328,10 @@ struct kvm_vcpu_arch {
 #define KVM_ARM64_FP_HOST		(1 << 2) /* host FP regs loaded */
 #define KVM_ARM64_HOST_SVE_IN_USE	(1 << 3) /* backup for host TIF_SVE */
 #define KVM_ARM64_HOST_SVE_ENABLED	(1 << 4) /* SVE enabled for EL0 */
+#define KVM_ARM64_GUEST_HAS_SVE		(1 << 5) /* SVE exposed to guest */
+
+#define vcpu_has_sve(vcpu) (system_supports_sve() && \
+			    ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))
 
 #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
 
-- 
2.1.4

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

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

* [PATCH v7 09/27] KVM: arm64: Add a vcpu flag to control SVE visibility for the guest
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

Since SVE will be enabled or disabled on a per-vcpu basis, a flag
is needed in order to track which vcpus have it enabled.

This patch adds a suitable flag and a helper for checking it.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 arch/arm64/include/asm/kvm_host.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 6d10100..ad4f7f0 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -328,6 +328,10 @@ struct kvm_vcpu_arch {
 #define KVM_ARM64_FP_HOST		(1 << 2) /* host FP regs loaded */
 #define KVM_ARM64_HOST_SVE_IN_USE	(1 << 3) /* backup for host TIF_SVE */
 #define KVM_ARM64_HOST_SVE_ENABLED	(1 << 4) /* SVE enabled for EL0 */
+#define KVM_ARM64_GUEST_HAS_SVE		(1 << 5) /* SVE exposed to guest */
+
+#define vcpu_has_sve(vcpu) (system_supports_sve() && \
+			    ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))
 
 #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
 
-- 
2.1.4


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

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

* [PATCH v7 10/27] KVM: arm64: Propagate vcpu into read_id_reg()
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

Architecture features that are conditionally visible to the guest
will require run-time checks in the ID register accessor functions.
In particular, read_id_reg() will need to perform checks in order
to generate the correct emulated value for certain ID register
fields such as ID_AA64PFR0_EL1.SVE for example.

This patch propagates vcpu into read_id_reg() so that future
patches can add run-time checks on the guest configuration here.

For now, there is no functional change.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 arch/arm64/kvm/sys_regs.c | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 539feec..a5d14b5 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1044,7 +1044,8 @@ static bool access_arch_timer(struct kvm_vcpu *vcpu,
 }
 
 /* Read a sanitised cpufeature ID register by sys_reg_desc */
-static u64 read_id_reg(struct sys_reg_desc const *r, bool raz)
+static u64 read_id_reg(const struct kvm_vcpu *vcpu,
+		struct sys_reg_desc const *r, bool raz)
 {
 	u32 id = sys_reg((u32)r->Op0, (u32)r->Op1,
 			 (u32)r->CRn, (u32)r->CRm, (u32)r->Op2);
@@ -1078,7 +1079,7 @@ static bool __access_id_reg(struct kvm_vcpu *vcpu,
 	if (p->is_write)
 		return write_to_read_only(vcpu, p, r);
 
-	p->regval = read_id_reg(r, raz);
+	p->regval = read_id_reg(vcpu, r, raz);
 	return true;
 }
 
@@ -1107,16 +1108,18 @@ static u64 sys_reg_to_index(const struct sys_reg_desc *reg);
  * are stored, and for set_id_reg() we don't allow the effective value
  * to be changed.
  */
-static int __get_id_reg(const struct sys_reg_desc *rd, void __user *uaddr,
+static int __get_id_reg(const struct kvm_vcpu *vcpu,
+			const struct sys_reg_desc *rd, void __user *uaddr,
 			bool raz)
 {
 	const u64 id = sys_reg_to_index(rd);
-	const u64 val = read_id_reg(rd, raz);
+	const u64 val = read_id_reg(vcpu, rd, raz);
 
 	return reg_to_user(uaddr, &val, id);
 }
 
-static int __set_id_reg(const struct sys_reg_desc *rd, void __user *uaddr,
+static int __set_id_reg(const struct kvm_vcpu *vcpu,
+			const struct sys_reg_desc *rd, void __user *uaddr,
 			bool raz)
 {
 	const u64 id = sys_reg_to_index(rd);
@@ -1128,7 +1131,7 @@ static int __set_id_reg(const struct sys_reg_desc *rd, void __user *uaddr,
 		return err;
 
 	/* This is what we mean by invariant: you can't change it. */
-	if (val != read_id_reg(rd, raz))
+	if (val != read_id_reg(vcpu, rd, raz))
 		return -EINVAL;
 
 	return 0;
@@ -1137,25 +1140,25 @@ static int __set_id_reg(const struct sys_reg_desc *rd, void __user *uaddr,
 static int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 		      const struct kvm_one_reg *reg, void __user *uaddr)
 {
-	return __get_id_reg(rd, uaddr, false);
+	return __get_id_reg(vcpu, rd, uaddr, false);
 }
 
 static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 		      const struct kvm_one_reg *reg, void __user *uaddr)
 {
-	return __set_id_reg(rd, uaddr, false);
+	return __set_id_reg(vcpu, rd, uaddr, false);
 }
 
 static int get_raz_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 			  const struct kvm_one_reg *reg, void __user *uaddr)
 {
-	return __get_id_reg(rd, uaddr, true);
+	return __get_id_reg(vcpu, rd, uaddr, true);
 }
 
 static int set_raz_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 			  const struct kvm_one_reg *reg, void __user *uaddr)
 {
-	return __set_id_reg(rd, uaddr, true);
+	return __set_id_reg(vcpu, rd, uaddr, true);
 }
 
 static bool access_ctr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
-- 
2.1.4

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

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

* [PATCH v7 10/27] KVM: arm64: Propagate vcpu into read_id_reg()
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

Architecture features that are conditionally visible to the guest
will require run-time checks in the ID register accessor functions.
In particular, read_id_reg() will need to perform checks in order
to generate the correct emulated value for certain ID register
fields such as ID_AA64PFR0_EL1.SVE for example.

This patch propagates vcpu into read_id_reg() so that future
patches can add run-time checks on the guest configuration here.

For now, there is no functional change.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 arch/arm64/kvm/sys_regs.c | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 539feec..a5d14b5 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1044,7 +1044,8 @@ static bool access_arch_timer(struct kvm_vcpu *vcpu,
 }
 
 /* Read a sanitised cpufeature ID register by sys_reg_desc */
-static u64 read_id_reg(struct sys_reg_desc const *r, bool raz)
+static u64 read_id_reg(const struct kvm_vcpu *vcpu,
+		struct sys_reg_desc const *r, bool raz)
 {
 	u32 id = sys_reg((u32)r->Op0, (u32)r->Op1,
 			 (u32)r->CRn, (u32)r->CRm, (u32)r->Op2);
@@ -1078,7 +1079,7 @@ static bool __access_id_reg(struct kvm_vcpu *vcpu,
 	if (p->is_write)
 		return write_to_read_only(vcpu, p, r);
 
-	p->regval = read_id_reg(r, raz);
+	p->regval = read_id_reg(vcpu, r, raz);
 	return true;
 }
 
@@ -1107,16 +1108,18 @@ static u64 sys_reg_to_index(const struct sys_reg_desc *reg);
  * are stored, and for set_id_reg() we don't allow the effective value
  * to be changed.
  */
-static int __get_id_reg(const struct sys_reg_desc *rd, void __user *uaddr,
+static int __get_id_reg(const struct kvm_vcpu *vcpu,
+			const struct sys_reg_desc *rd, void __user *uaddr,
 			bool raz)
 {
 	const u64 id = sys_reg_to_index(rd);
-	const u64 val = read_id_reg(rd, raz);
+	const u64 val = read_id_reg(vcpu, rd, raz);
 
 	return reg_to_user(uaddr, &val, id);
 }
 
-static int __set_id_reg(const struct sys_reg_desc *rd, void __user *uaddr,
+static int __set_id_reg(const struct kvm_vcpu *vcpu,
+			const struct sys_reg_desc *rd, void __user *uaddr,
 			bool raz)
 {
 	const u64 id = sys_reg_to_index(rd);
@@ -1128,7 +1131,7 @@ static int __set_id_reg(const struct sys_reg_desc *rd, void __user *uaddr,
 		return err;
 
 	/* This is what we mean by invariant: you can't change it. */
-	if (val != read_id_reg(rd, raz))
+	if (val != read_id_reg(vcpu, rd, raz))
 		return -EINVAL;
 
 	return 0;
@@ -1137,25 +1140,25 @@ static int __set_id_reg(const struct sys_reg_desc *rd, void __user *uaddr,
 static int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 		      const struct kvm_one_reg *reg, void __user *uaddr)
 {
-	return __get_id_reg(rd, uaddr, false);
+	return __get_id_reg(vcpu, rd, uaddr, false);
 }
 
 static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 		      const struct kvm_one_reg *reg, void __user *uaddr)
 {
-	return __set_id_reg(rd, uaddr, false);
+	return __set_id_reg(vcpu, rd, uaddr, false);
 }
 
 static int get_raz_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 			  const struct kvm_one_reg *reg, void __user *uaddr)
 {
-	return __get_id_reg(rd, uaddr, true);
+	return __get_id_reg(vcpu, rd, uaddr, true);
 }
 
 static int set_raz_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 			  const struct kvm_one_reg *reg, void __user *uaddr)
 {
-	return __set_id_reg(rd, uaddr, true);
+	return __set_id_reg(vcpu, rd, uaddr, true);
 }
 
 static bool access_ctr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
-- 
2.1.4


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

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

* [PATCH v7 11/27] KVM: arm64: Support runtime sysreg visibility filtering
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

Some optional features of the Arm architecture add new system
registers that are not present in the base architecture.

Where these features are optional for the guest, the visibility of
these registers may need to depend on some runtime configuration,
such as a flag passed to KVM_ARM_VCPU_INIT.

For example, ZCR_EL1 and ID_AA64ZFR0_EL1 need to be hidden if SVE
is not enabled for the guest, even though these registers may be
present in the hardware and visible to the host at EL2.

Adding special-case checks all over the place for individual
registers is going to get messy as the number of conditionally-
visible registers grows.

In order to help solve this problem, this patch adds a new sysreg
method visibility() that can be used to hook in any needed runtime
visibility checks.  This method can currently return
REG_HIDDEN_USER to inhibit enumeration and ioctl access to the
register for userspace, and REG_HIDDEN_GUEST to inhibit runtime
access by the guest using MSR/MRS.  Wrappers are added to allow
these flags to be conveniently queried.

This approach allows a conditionally modified view of individual
system registers such as the CPU ID registers, in addition to
completely hiding register where appropriate.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * Rename the visibility override flags, add some comments, and rename/
   introduce helpers to make the purpose of this code clearer.
---
 arch/arm64/kvm/sys_regs.c | 24 +++++++++++++++++++++---
 arch/arm64/kvm/sys_regs.h | 25 +++++++++++++++++++++++++
 2 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index a5d14b5..c86a7b0 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1927,6 +1927,12 @@ static void perform_access(struct kvm_vcpu *vcpu,
 {
 	trace_kvm_sys_access(*vcpu_pc(vcpu), params, r);
 
+	/* Check for regs disabled by runtime config */
+	if (sysreg_hidden_from_guest(vcpu, r)) {
+		kvm_inject_undefined(vcpu);
+		return;
+	}
+
 	/*
 	 * Not having an accessor means that we have configured a trap
 	 * that we don't know how to handle. This certainly qualifies
@@ -2438,6 +2444,10 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
 	if (!r)
 		return get_invariant_sys_reg(reg->id, uaddr);
 
+	/* Check for regs disabled by runtime config */
+	if (sysreg_hidden_from_user(vcpu, r))
+		return -ENOENT;
+
 	if (r->get_user)
 		return (r->get_user)(vcpu, r, reg, uaddr);
 
@@ -2459,6 +2469,10 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
 	if (!r)
 		return set_invariant_sys_reg(reg->id, uaddr);
 
+	/* Check for regs disabled by runtime config */
+	if (sysreg_hidden_from_user(vcpu, r))
+		return -ENOENT;
+
 	if (r->set_user)
 		return (r->set_user)(vcpu, r, reg, uaddr);
 
@@ -2515,7 +2529,8 @@ static bool copy_reg_to_user(const struct sys_reg_desc *reg, u64 __user **uind)
 	return true;
 }
 
-static int walk_one_sys_reg(const struct sys_reg_desc *rd,
+static int walk_one_sys_reg(const struct kvm_vcpu *vcpu,
+			    const struct sys_reg_desc *rd,
 			    u64 __user **uind,
 			    unsigned int *total)
 {
@@ -2526,6 +2541,9 @@ static int walk_one_sys_reg(const struct sys_reg_desc *rd,
 	if (!(rd->reg || rd->get_user))
 		return 0;
 
+	if (sysreg_hidden_from_user(vcpu, rd))
+		return 0;
+
 	if (!copy_reg_to_user(rd, uind))
 		return -EFAULT;
 
@@ -2554,9 +2572,9 @@ static int walk_sys_regs(struct kvm_vcpu *vcpu, u64 __user *uind)
 		int cmp = cmp_sys_reg(i1, i2);
 		/* target-specific overrides generic entry. */
 		if (cmp <= 0)
-			err = walk_one_sys_reg(i1, &uind, &total);
+			err = walk_one_sys_reg(vcpu, i1, &uind, &total);
 		else
-			err = walk_one_sys_reg(i2, &uind, &total);
+			err = walk_one_sys_reg(vcpu, i2, &uind, &total);
 
 		if (err)
 			return err;
diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
index 3b1bc7f..2be9950 100644
--- a/arch/arm64/kvm/sys_regs.h
+++ b/arch/arm64/kvm/sys_regs.h
@@ -64,8 +64,15 @@ struct sys_reg_desc {
 			const struct kvm_one_reg *reg, void __user *uaddr);
 	int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 			const struct kvm_one_reg *reg, void __user *uaddr);
+
+	/* Return mask of REG_* runtime visibility overrides */
+	unsigned int (*visibility)(const struct kvm_vcpu *vcpu,
+				   const struct sys_reg_desc *rd);
 };
 
+#define REG_HIDDEN_USER		(1 << 0) /* hidden from userspace ioctls */
+#define REG_HIDDEN_GUEST	(1 << 1) /* hidden from guest */
+
 static inline void print_sys_reg_instr(const struct sys_reg_params *p)
 {
 	/* Look, we even formatted it for you to paste into the table! */
@@ -102,6 +109,24 @@ static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r
 	__vcpu_sys_reg(vcpu, r->reg) = r->val;
 }
 
+static inline bool sysreg_hidden_from_guest(const struct kvm_vcpu *vcpu,
+					    const struct sys_reg_desc *r)
+{
+	if (likely(!r->visibility))
+		return false;
+
+	return r->visibility(vcpu, r) & REG_HIDDEN_GUEST;
+}
+
+static inline bool sysreg_hidden_from_user(const struct kvm_vcpu *vcpu,
+					   const struct sys_reg_desc *r)
+{
+	if (likely(!r->visibility))
+		return false;
+
+	return r->visibility(vcpu, r) & REG_HIDDEN_USER;
+}
+
 static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
 			      const struct sys_reg_desc *i2)
 {
-- 
2.1.4

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

* [PATCH v7 11/27] KVM: arm64: Support runtime sysreg visibility filtering
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

Some optional features of the Arm architecture add new system
registers that are not present in the base architecture.

Where these features are optional for the guest, the visibility of
these registers may need to depend on some runtime configuration,
such as a flag passed to KVM_ARM_VCPU_INIT.

For example, ZCR_EL1 and ID_AA64ZFR0_EL1 need to be hidden if SVE
is not enabled for the guest, even though these registers may be
present in the hardware and visible to the host at EL2.

Adding special-case checks all over the place for individual
registers is going to get messy as the number of conditionally-
visible registers grows.

In order to help solve this problem, this patch adds a new sysreg
method visibility() that can be used to hook in any needed runtime
visibility checks.  This method can currently return
REG_HIDDEN_USER to inhibit enumeration and ioctl access to the
register for userspace, and REG_HIDDEN_GUEST to inhibit runtime
access by the guest using MSR/MRS.  Wrappers are added to allow
these flags to be conveniently queried.

This approach allows a conditionally modified view of individual
system registers such as the CPU ID registers, in addition to
completely hiding register where appropriate.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * Rename the visibility override flags, add some comments, and rename/
   introduce helpers to make the purpose of this code clearer.
---
 arch/arm64/kvm/sys_regs.c | 24 +++++++++++++++++++++---
 arch/arm64/kvm/sys_regs.h | 25 +++++++++++++++++++++++++
 2 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index a5d14b5..c86a7b0 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1927,6 +1927,12 @@ static void perform_access(struct kvm_vcpu *vcpu,
 {
 	trace_kvm_sys_access(*vcpu_pc(vcpu), params, r);
 
+	/* Check for regs disabled by runtime config */
+	if (sysreg_hidden_from_guest(vcpu, r)) {
+		kvm_inject_undefined(vcpu);
+		return;
+	}
+
 	/*
 	 * Not having an accessor means that we have configured a trap
 	 * that we don't know how to handle. This certainly qualifies
@@ -2438,6 +2444,10 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
 	if (!r)
 		return get_invariant_sys_reg(reg->id, uaddr);
 
+	/* Check for regs disabled by runtime config */
+	if (sysreg_hidden_from_user(vcpu, r))
+		return -ENOENT;
+
 	if (r->get_user)
 		return (r->get_user)(vcpu, r, reg, uaddr);
 
@@ -2459,6 +2469,10 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
 	if (!r)
 		return set_invariant_sys_reg(reg->id, uaddr);
 
+	/* Check for regs disabled by runtime config */
+	if (sysreg_hidden_from_user(vcpu, r))
+		return -ENOENT;
+
 	if (r->set_user)
 		return (r->set_user)(vcpu, r, reg, uaddr);
 
@@ -2515,7 +2529,8 @@ static bool copy_reg_to_user(const struct sys_reg_desc *reg, u64 __user **uind)
 	return true;
 }
 
-static int walk_one_sys_reg(const struct sys_reg_desc *rd,
+static int walk_one_sys_reg(const struct kvm_vcpu *vcpu,
+			    const struct sys_reg_desc *rd,
 			    u64 __user **uind,
 			    unsigned int *total)
 {
@@ -2526,6 +2541,9 @@ static int walk_one_sys_reg(const struct sys_reg_desc *rd,
 	if (!(rd->reg || rd->get_user))
 		return 0;
 
+	if (sysreg_hidden_from_user(vcpu, rd))
+		return 0;
+
 	if (!copy_reg_to_user(rd, uind))
 		return -EFAULT;
 
@@ -2554,9 +2572,9 @@ static int walk_sys_regs(struct kvm_vcpu *vcpu, u64 __user *uind)
 		int cmp = cmp_sys_reg(i1, i2);
 		/* target-specific overrides generic entry. */
 		if (cmp <= 0)
-			err = walk_one_sys_reg(i1, &uind, &total);
+			err = walk_one_sys_reg(vcpu, i1, &uind, &total);
 		else
-			err = walk_one_sys_reg(i2, &uind, &total);
+			err = walk_one_sys_reg(vcpu, i2, &uind, &total);
 
 		if (err)
 			return err;
diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
index 3b1bc7f..2be9950 100644
--- a/arch/arm64/kvm/sys_regs.h
+++ b/arch/arm64/kvm/sys_regs.h
@@ -64,8 +64,15 @@ struct sys_reg_desc {
 			const struct kvm_one_reg *reg, void __user *uaddr);
 	int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 			const struct kvm_one_reg *reg, void __user *uaddr);
+
+	/* Return mask of REG_* runtime visibility overrides */
+	unsigned int (*visibility)(const struct kvm_vcpu *vcpu,
+				   const struct sys_reg_desc *rd);
 };
 
+#define REG_HIDDEN_USER		(1 << 0) /* hidden from userspace ioctls */
+#define REG_HIDDEN_GUEST	(1 << 1) /* hidden from guest */
+
 static inline void print_sys_reg_instr(const struct sys_reg_params *p)
 {
 	/* Look, we even formatted it for you to paste into the table! */
@@ -102,6 +109,24 @@ static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r
 	__vcpu_sys_reg(vcpu, r->reg) = r->val;
 }
 
+static inline bool sysreg_hidden_from_guest(const struct kvm_vcpu *vcpu,
+					    const struct sys_reg_desc *r)
+{
+	if (likely(!r->visibility))
+		return false;
+
+	return r->visibility(vcpu, r) & REG_HIDDEN_GUEST;
+}
+
+static inline bool sysreg_hidden_from_user(const struct kvm_vcpu *vcpu,
+					   const struct sys_reg_desc *r)
+{
+	if (likely(!r->visibility))
+		return false;
+
+	return r->visibility(vcpu, r) & REG_HIDDEN_USER;
+}
+
 static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
 			      const struct sys_reg_desc *i2)
 {
-- 
2.1.4


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

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

* [PATCH v7 12/27] KVM: arm64/sve: System register context switch and access support
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

This patch adds the necessary support for context switching ZCR_EL1
for each vcpu.

ZCR_EL1 is trapped alongside the FPSIMD/SVE registers, so it makes
sense for it to be handled as part of the guest FPSIMD/SVE context
for context switch purposes instead of handling it as a general
system register.  This means that it can be switched in lazily at
the appropriate time.  No effort is made to track host context for
this register, since SVE requires VHE: thus the hosts's value for
this register lives permanently in ZCR_EL2 and does not alias the
guest's value at any time.

The Hyp switch and fpsimd context handling code is extended
appropriately.

Accessors are added in sys_regs.c to expose the SVE system
registers and ID register fields.  Because these need to be
conditionally visible based on the guest configuration, they are
implemented separately for now rather than by use of the generic
system register helpers.  This may be abstracted better later on
when/if there are more features requiring this model.

ID_AA64ZFR0_EL1 is RO-RAZ for MRS/MSR when SVE is disabled for the
guest, but for compatibility with non-SVE aware KVM implementations
the register should not be enumerated at all for KVM_GET_REG_LIST
in this case.  For consistency we also reject ioctl access to the
register.  This ensures that a non-SVE-enabled guest looks the same
to userspace, irrespective of whether the kernel KVM implementation
supports SVE.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * Port to the renamed visibility() framework.

 * Swap visiblity() helpers so that they appear by the relevant accessor
   functions.

 * [Julien Grall] With the visibility() checks, {get,set}_zcr_el1()
   degenerate to doing exactly what the common code does, so drop them.

   The ID_AA64ZFR0_EL1 handlers are still needed to provide contitional
   RAZ behaviour.  This could be moved to the common code too, but since
   this is a one-off case I don't do this for now.  We can address this
   later if other regs need to follow the same pattern.

 * [Julien Thierry] Reset ZCR_EL1 to a fixed value using reset_val
   instead of using relying on reset_unknown() honouring set bits in val
   as RES0.

   Most of the bits in ZCR_EL1 are RES0 anyway, and many implementations
   of SVE will support larger vectors than 128 bits, so 0 seems as good
   a value as any to expose guests that forget to initialise this
   register properly.
---
 arch/arm64/include/asm/kvm_host.h |  1 +
 arch/arm64/include/asm/sysreg.h   |  3 ++
 arch/arm64/kvm/fpsimd.c           |  9 ++++-
 arch/arm64/kvm/hyp/switch.c       |  3 ++
 arch/arm64/kvm/sys_regs.c         | 83 ++++++++++++++++++++++++++++++++++++---
 5 files changed, 93 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index ad4f7f0..22cf484 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -121,6 +121,7 @@ enum vcpu_sysreg {
 	SCTLR_EL1,	/* System Control Register */
 	ACTLR_EL1,	/* Auxiliary Control Register */
 	CPACR_EL1,	/* Coprocessor Access Control */
+	ZCR_EL1,	/* SVE Control */
 	TTBR0_EL1,	/* Translation Table Base Register 0 */
 	TTBR1_EL1,	/* Translation Table Base Register 1 */
 	TCR_EL1,	/* Translation Control Register */
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 5b267de..4d6262d 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -454,6 +454,9 @@
 #define SYS_ICH_LR14_EL2		__SYS__LR8_EL2(6)
 #define SYS_ICH_LR15_EL2		__SYS__LR8_EL2(7)
 
+/* VHE encodings for architectural EL0/1 system registers */
+#define SYS_ZCR_EL12			sys_reg(3, 5, 1, 2, 0)
+
 /* Common SCTLR_ELx flags. */
 #define SCTLR_ELx_DSSBS	(_BITUL(44))
 #define SCTLR_ELx_ENIA	(_BITUL(31))
diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
index 1cf4f02..7053bf4 100644
--- a/arch/arm64/kvm/fpsimd.c
+++ b/arch/arm64/kvm/fpsimd.c
@@ -103,14 +103,21 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
 void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
 {
 	unsigned long flags;
+	bool host_has_sve = system_supports_sve();
+	bool guest_has_sve = vcpu_has_sve(vcpu);
 
 	local_irq_save(flags);
 
 	if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
+		u64 *guest_zcr = &vcpu->arch.ctxt.sys_regs[ZCR_EL1];
+
 		/* Clean guest FP state to memory and invalidate cpu view */
 		fpsimd_save();
 		fpsimd_flush_cpu_state();
-	} else if (system_supports_sve()) {
+
+		if (guest_has_sve)
+			*guest_zcr = read_sysreg_s(SYS_ZCR_EL12);
+	} else if (host_has_sve) {
 		/*
 		 * The FPSIMD/SVE state in the CPU has not been touched, and we
 		 * have SVE (and VHE): CPACR_EL1 (alias CPTR_EL2) has been
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 3563fe6..9d46066 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -351,6 +351,9 @@ static bool __hyp_text __hyp_switch_fpsimd(struct kvm_vcpu *vcpu)
 
 	__fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
 
+	if (vcpu_has_sve(vcpu))
+		write_sysreg_s(vcpu->arch.ctxt.sys_regs[ZCR_EL1], SYS_ZCR_EL12);
+
 	/* Skip restoring fpexc32 for AArch64 guests */
 	if (!(read_sysreg(hcr_el2) & HCR_RW))
 		write_sysreg(vcpu->arch.ctxt.sys_regs[FPEXC32_EL2],
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c86a7b0..09e9b06 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1051,10 +1051,7 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
 			 (u32)r->CRn, (u32)r->CRm, (u32)r->Op2);
 	u64 val = raz ? 0 : read_sanitised_ftr_reg(id);
 
-	if (id == SYS_ID_AA64PFR0_EL1) {
-		if (val & (0xfUL << ID_AA64PFR0_SVE_SHIFT))
-			kvm_debug("SVE unsupported for guests, suppressing\n");
-
+	if (id == SYS_ID_AA64PFR0_EL1 && !vcpu_has_sve(vcpu)) {
 		val &= ~(0xfUL << ID_AA64PFR0_SVE_SHIFT);
 	} else if (id == SYS_ID_AA64ISAR1_EL1) {
 		const u64 ptrauth_mask = (0xfUL << ID_AA64ISAR1_APA_SHIFT) |
@@ -1101,6 +1098,81 @@ static int reg_from_user(u64 *val, const void __user *uaddr, u64 id);
 static int reg_to_user(void __user *uaddr, const u64 *val, u64 id);
 static u64 sys_reg_to_index(const struct sys_reg_desc *reg);
 
+/* Visibility overrides for SVE-specific control registers */
+static unsigned int sve_visibility(const struct kvm_vcpu *vcpu,
+				   const struct sys_reg_desc *rd)
+{
+	if (vcpu_has_sve(vcpu))
+		return 0;
+
+	return REG_HIDDEN_USER | REG_HIDDEN_GUEST;
+}
+
+/* Visibility overrides for SVE-specific ID registers */
+static unsigned int sve_id_visibility(const struct kvm_vcpu *vcpu,
+				      const struct sys_reg_desc *rd)
+{
+	if (vcpu_has_sve(vcpu))
+		return 0;
+
+	return REG_HIDDEN_USER;
+}
+
+/* Generate the emulated ID_AA64ZFR0_EL1 value exposed to the guest */
+static u64 guest_id_aa64zfr0_el1(const struct kvm_vcpu *vcpu)
+{
+	if (!vcpu_has_sve(vcpu))
+		return 0;
+
+	return read_sanitised_ftr_reg(SYS_ID_AA64ZFR0_EL1);
+}
+
+static bool access_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
+				   struct sys_reg_params *p,
+				   const struct sys_reg_desc *rd)
+{
+	if (p->is_write)
+		return write_to_read_only(vcpu, p, rd);
+
+	p->regval = guest_id_aa64zfr0_el1(vcpu);
+	return true;
+}
+
+static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
+		const struct sys_reg_desc *rd,
+		const struct kvm_one_reg *reg, void __user *uaddr)
+{
+	u64 val;
+
+	if (!vcpu_has_sve(vcpu))
+		return -ENOENT;
+
+	val = guest_id_aa64zfr0_el1(vcpu);
+	return reg_to_user(uaddr, &val, reg->id);
+}
+
+static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
+		const struct sys_reg_desc *rd,
+		const struct kvm_one_reg *reg, void __user *uaddr)
+{
+	const u64 id = sys_reg_to_index(rd);
+	int err;
+	u64 val;
+
+	if (!vcpu_has_sve(vcpu))
+		return -ENOENT;
+
+	err = reg_from_user(&val, uaddr, id);
+	if (err)
+		return err;
+
+	/* This is what we mean by invariant: you can't change it. */
+	if (val != guest_id_aa64zfr0_el1(vcpu))
+		return -EINVAL;
+
+	return 0;
+}
+
 /*
  * cpufeature ID register user accessors
  *
@@ -1346,7 +1418,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	ID_SANITISED(ID_AA64PFR1_EL1),
 	ID_UNALLOCATED(4,2),
 	ID_UNALLOCATED(4,3),
-	ID_UNALLOCATED(4,4),
+	{ SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility },
 	ID_UNALLOCATED(4,5),
 	ID_UNALLOCATED(4,6),
 	ID_UNALLOCATED(4,7),
@@ -1383,6 +1455,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
 	{ SYS_DESC(SYS_SCTLR_EL1), access_vm_reg, reset_val, SCTLR_EL1, 0x00C50078 },
 	{ SYS_DESC(SYS_CPACR_EL1), NULL, reset_val, CPACR_EL1, 0 },
+	{ SYS_DESC(SYS_ZCR_EL1), NULL, reset_val, ZCR_EL1, 0, .visibility = sve_visibility },
 	{ SYS_DESC(SYS_TTBR0_EL1), access_vm_reg, reset_unknown, TTBR0_EL1 },
 	{ SYS_DESC(SYS_TTBR1_EL1), access_vm_reg, reset_unknown, TTBR1_EL1 },
 	{ SYS_DESC(SYS_TCR_EL1), access_vm_reg, reset_val, TCR_EL1, 0 },
-- 
2.1.4

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

* [PATCH v7 12/27] KVM: arm64/sve: System register context switch and access support
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

This patch adds the necessary support for context switching ZCR_EL1
for each vcpu.

ZCR_EL1 is trapped alongside the FPSIMD/SVE registers, so it makes
sense for it to be handled as part of the guest FPSIMD/SVE context
for context switch purposes instead of handling it as a general
system register.  This means that it can be switched in lazily at
the appropriate time.  No effort is made to track host context for
this register, since SVE requires VHE: thus the hosts's value for
this register lives permanently in ZCR_EL2 and does not alias the
guest's value at any time.

The Hyp switch and fpsimd context handling code is extended
appropriately.

Accessors are added in sys_regs.c to expose the SVE system
registers and ID register fields.  Because these need to be
conditionally visible based on the guest configuration, they are
implemented separately for now rather than by use of the generic
system register helpers.  This may be abstracted better later on
when/if there are more features requiring this model.

ID_AA64ZFR0_EL1 is RO-RAZ for MRS/MSR when SVE is disabled for the
guest, but for compatibility with non-SVE aware KVM implementations
the register should not be enumerated at all for KVM_GET_REG_LIST
in this case.  For consistency we also reject ioctl access to the
register.  This ensures that a non-SVE-enabled guest looks the same
to userspace, irrespective of whether the kernel KVM implementation
supports SVE.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * Port to the renamed visibility() framework.

 * Swap visiblity() helpers so that they appear by the relevant accessor
   functions.

 * [Julien Grall] With the visibility() checks, {get,set}_zcr_el1()
   degenerate to doing exactly what the common code does, so drop them.

   The ID_AA64ZFR0_EL1 handlers are still needed to provide contitional
   RAZ behaviour.  This could be moved to the common code too, but since
   this is a one-off case I don't do this for now.  We can address this
   later if other regs need to follow the same pattern.

 * [Julien Thierry] Reset ZCR_EL1 to a fixed value using reset_val
   instead of using relying on reset_unknown() honouring set bits in val
   as RES0.

   Most of the bits in ZCR_EL1 are RES0 anyway, and many implementations
   of SVE will support larger vectors than 128 bits, so 0 seems as good
   a value as any to expose guests that forget to initialise this
   register properly.
---
 arch/arm64/include/asm/kvm_host.h |  1 +
 arch/arm64/include/asm/sysreg.h   |  3 ++
 arch/arm64/kvm/fpsimd.c           |  9 ++++-
 arch/arm64/kvm/hyp/switch.c       |  3 ++
 arch/arm64/kvm/sys_regs.c         | 83 ++++++++++++++++++++++++++++++++++++---
 5 files changed, 93 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index ad4f7f0..22cf484 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -121,6 +121,7 @@ enum vcpu_sysreg {
 	SCTLR_EL1,	/* System Control Register */
 	ACTLR_EL1,	/* Auxiliary Control Register */
 	CPACR_EL1,	/* Coprocessor Access Control */
+	ZCR_EL1,	/* SVE Control */
 	TTBR0_EL1,	/* Translation Table Base Register 0 */
 	TTBR1_EL1,	/* Translation Table Base Register 1 */
 	TCR_EL1,	/* Translation Control Register */
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 5b267de..4d6262d 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -454,6 +454,9 @@
 #define SYS_ICH_LR14_EL2		__SYS__LR8_EL2(6)
 #define SYS_ICH_LR15_EL2		__SYS__LR8_EL2(7)
 
+/* VHE encodings for architectural EL0/1 system registers */
+#define SYS_ZCR_EL12			sys_reg(3, 5, 1, 2, 0)
+
 /* Common SCTLR_ELx flags. */
 #define SCTLR_ELx_DSSBS	(_BITUL(44))
 #define SCTLR_ELx_ENIA	(_BITUL(31))
diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
index 1cf4f02..7053bf4 100644
--- a/arch/arm64/kvm/fpsimd.c
+++ b/arch/arm64/kvm/fpsimd.c
@@ -103,14 +103,21 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
 void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
 {
 	unsigned long flags;
+	bool host_has_sve = system_supports_sve();
+	bool guest_has_sve = vcpu_has_sve(vcpu);
 
 	local_irq_save(flags);
 
 	if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
+		u64 *guest_zcr = &vcpu->arch.ctxt.sys_regs[ZCR_EL1];
+
 		/* Clean guest FP state to memory and invalidate cpu view */
 		fpsimd_save();
 		fpsimd_flush_cpu_state();
-	} else if (system_supports_sve()) {
+
+		if (guest_has_sve)
+			*guest_zcr = read_sysreg_s(SYS_ZCR_EL12);
+	} else if (host_has_sve) {
 		/*
 		 * The FPSIMD/SVE state in the CPU has not been touched, and we
 		 * have SVE (and VHE): CPACR_EL1 (alias CPTR_EL2) has been
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 3563fe6..9d46066 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -351,6 +351,9 @@ static bool __hyp_text __hyp_switch_fpsimd(struct kvm_vcpu *vcpu)
 
 	__fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
 
+	if (vcpu_has_sve(vcpu))
+		write_sysreg_s(vcpu->arch.ctxt.sys_regs[ZCR_EL1], SYS_ZCR_EL12);
+
 	/* Skip restoring fpexc32 for AArch64 guests */
 	if (!(read_sysreg(hcr_el2) & HCR_RW))
 		write_sysreg(vcpu->arch.ctxt.sys_regs[FPEXC32_EL2],
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c86a7b0..09e9b06 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1051,10 +1051,7 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
 			 (u32)r->CRn, (u32)r->CRm, (u32)r->Op2);
 	u64 val = raz ? 0 : read_sanitised_ftr_reg(id);
 
-	if (id == SYS_ID_AA64PFR0_EL1) {
-		if (val & (0xfUL << ID_AA64PFR0_SVE_SHIFT))
-			kvm_debug("SVE unsupported for guests, suppressing\n");
-
+	if (id == SYS_ID_AA64PFR0_EL1 && !vcpu_has_sve(vcpu)) {
 		val &= ~(0xfUL << ID_AA64PFR0_SVE_SHIFT);
 	} else if (id == SYS_ID_AA64ISAR1_EL1) {
 		const u64 ptrauth_mask = (0xfUL << ID_AA64ISAR1_APA_SHIFT) |
@@ -1101,6 +1098,81 @@ static int reg_from_user(u64 *val, const void __user *uaddr, u64 id);
 static int reg_to_user(void __user *uaddr, const u64 *val, u64 id);
 static u64 sys_reg_to_index(const struct sys_reg_desc *reg);
 
+/* Visibility overrides for SVE-specific control registers */
+static unsigned int sve_visibility(const struct kvm_vcpu *vcpu,
+				   const struct sys_reg_desc *rd)
+{
+	if (vcpu_has_sve(vcpu))
+		return 0;
+
+	return REG_HIDDEN_USER | REG_HIDDEN_GUEST;
+}
+
+/* Visibility overrides for SVE-specific ID registers */
+static unsigned int sve_id_visibility(const struct kvm_vcpu *vcpu,
+				      const struct sys_reg_desc *rd)
+{
+	if (vcpu_has_sve(vcpu))
+		return 0;
+
+	return REG_HIDDEN_USER;
+}
+
+/* Generate the emulated ID_AA64ZFR0_EL1 value exposed to the guest */
+static u64 guest_id_aa64zfr0_el1(const struct kvm_vcpu *vcpu)
+{
+	if (!vcpu_has_sve(vcpu))
+		return 0;
+
+	return read_sanitised_ftr_reg(SYS_ID_AA64ZFR0_EL1);
+}
+
+static bool access_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
+				   struct sys_reg_params *p,
+				   const struct sys_reg_desc *rd)
+{
+	if (p->is_write)
+		return write_to_read_only(vcpu, p, rd);
+
+	p->regval = guest_id_aa64zfr0_el1(vcpu);
+	return true;
+}
+
+static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
+		const struct sys_reg_desc *rd,
+		const struct kvm_one_reg *reg, void __user *uaddr)
+{
+	u64 val;
+
+	if (!vcpu_has_sve(vcpu))
+		return -ENOENT;
+
+	val = guest_id_aa64zfr0_el1(vcpu);
+	return reg_to_user(uaddr, &val, reg->id);
+}
+
+static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
+		const struct sys_reg_desc *rd,
+		const struct kvm_one_reg *reg, void __user *uaddr)
+{
+	const u64 id = sys_reg_to_index(rd);
+	int err;
+	u64 val;
+
+	if (!vcpu_has_sve(vcpu))
+		return -ENOENT;
+
+	err = reg_from_user(&val, uaddr, id);
+	if (err)
+		return err;
+
+	/* This is what we mean by invariant: you can't change it. */
+	if (val != guest_id_aa64zfr0_el1(vcpu))
+		return -EINVAL;
+
+	return 0;
+}
+
 /*
  * cpufeature ID register user accessors
  *
@@ -1346,7 +1418,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	ID_SANITISED(ID_AA64PFR1_EL1),
 	ID_UNALLOCATED(4,2),
 	ID_UNALLOCATED(4,3),
-	ID_UNALLOCATED(4,4),
+	{ SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility },
 	ID_UNALLOCATED(4,5),
 	ID_UNALLOCATED(4,6),
 	ID_UNALLOCATED(4,7),
@@ -1383,6 +1455,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
 	{ SYS_DESC(SYS_SCTLR_EL1), access_vm_reg, reset_val, SCTLR_EL1, 0x00C50078 },
 	{ SYS_DESC(SYS_CPACR_EL1), NULL, reset_val, CPACR_EL1, 0 },
+	{ SYS_DESC(SYS_ZCR_EL1), NULL, reset_val, ZCR_EL1, 0, .visibility = sve_visibility },
 	{ SYS_DESC(SYS_TTBR0_EL1), access_vm_reg, reset_unknown, TTBR0_EL1 },
 	{ SYS_DESC(SYS_TTBR1_EL1), access_vm_reg, reset_unknown, TTBR1_EL1 },
 	{ SYS_DESC(SYS_TCR_EL1), access_vm_reg, reset_val, TCR_EL1, 0 },
-- 
2.1.4


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

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

* [PATCH v7 13/27] KVM: arm64/sve: Context switch the SVE registers
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

In order to give each vcpu its own view of the SVE registers, this
patch adds context storage via a new sve_state pointer in struct
vcpu_arch.  An additional member sve_max_vl is also added for each
vcpu, to determine the maximum vector length visible to the guest
and thus the value to be configured in ZCR_EL2.LEN while the vcpu
is active.  This also determines the layout and size of the storage
in sve_state, which is read and written by the same backend
functions that are used for context-switching the SVE state for
host tasks.

On SVE-enabled vcpus, SVE access traps are now handled by switching
in the vcpu's SVE context and disabling the trap before returning
to the guest.  On other vcpus, the trap is not handled and an exit
back to the host occurs, where the handle_sve() fallback path
reflects an undefined instruction exception back to the guest,
consistently with the behaviour of non-SVE-capable hardware (as was
done unconditionally prior to this patch).

No SVE handling is added on non-VHE-only paths, since VHE is an
architectural and Kconfig prerequisite of SVE.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * [Julien Thierry, Julien Grall] Commit message typo fixes

 * [Mark Rutland] Rename trap_class to hsr_ec, for consistency with
   existing code.

 * [Mark Rutland] Simplify condition for refusing to handle an
   FPSIMD/SVE trap, using multiple if () statements for clarity.  The
   previous condition was a bit tortuous, and how that the static_key
   checks have been hoisted out, it makes little difference to the
   compiler how we express the condition here.
---
 arch/arm64/include/asm/kvm_host.h |  6 ++++
 arch/arm64/kvm/fpsimd.c           |  5 +--
 arch/arm64/kvm/hyp/switch.c       | 75 +++++++++++++++++++++++++++++----------
 3 files changed, 66 insertions(+), 20 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 22cf484..4fabfd2 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -228,6 +228,8 @@ struct vcpu_reset_state {
 
 struct kvm_vcpu_arch {
 	struct kvm_cpu_context ctxt;
+	void *sve_state;
+	unsigned int sve_max_vl;
 
 	/* HYP configuration */
 	u64 hcr_el2;
@@ -323,6 +325,10 @@ struct kvm_vcpu_arch {
 	bool sysregs_loaded_on_cpu;
 };
 
+/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
+#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
+				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
+
 /* vcpu_arch flags field values: */
 #define KVM_ARM64_DEBUG_DIRTY		(1 << 0)
 #define KVM_ARM64_FP_ENABLED		(1 << 1) /* guest FP regs loaded */
diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
index 7053bf4..6e3c9c8 100644
--- a/arch/arm64/kvm/fpsimd.c
+++ b/arch/arm64/kvm/fpsimd.c
@@ -87,10 +87,11 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
 
 	if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
 		fpsimd_bind_state_to_cpu(&vcpu->arch.ctxt.gp_regs.fp_regs,
-					 NULL, SVE_VL_MIN);
+					 vcpu->arch.sve_state,
+					 vcpu->arch.sve_max_vl);
 
 		clear_thread_flag(TIF_FOREIGN_FPSTATE);
-		clear_thread_flag(TIF_SVE);
+		update_thread_flag(TIF_SVE, vcpu_has_sve(vcpu));
 	}
 }
 
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 9d46066..5444b9c 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -100,7 +100,10 @@ static void activate_traps_vhe(struct kvm_vcpu *vcpu)
 	val = read_sysreg(cpacr_el1);
 	val |= CPACR_EL1_TTA;
 	val &= ~CPACR_EL1_ZEN;
-	if (!update_fp_enabled(vcpu)) {
+	if (update_fp_enabled(vcpu)) {
+		if (vcpu_has_sve(vcpu))
+			val |= CPACR_EL1_ZEN;
+	} else {
 		val &= ~CPACR_EL1_FPEN;
 		__activate_traps_fpsimd32(vcpu);
 	}
@@ -317,16 +320,48 @@ static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
 	return true;
 }
 
-static bool __hyp_text __hyp_switch_fpsimd(struct kvm_vcpu *vcpu)
+/* Check for an FPSIMD/SVE trap and handle as appropriate */
+static bool __hyp_text __hyp_handle_fpsimd(struct kvm_vcpu *vcpu)
 {
-	struct user_fpsimd_state *host_fpsimd = vcpu->arch.host_fpsimd_state;
+	bool vhe, sve_guest, sve_host;
+	u8 hsr_ec;
 
-	if (has_vhe())
-		write_sysreg(read_sysreg(cpacr_el1) | CPACR_EL1_FPEN,
-			     cpacr_el1);
-	else
+	if (!system_supports_fpsimd())
+		return false;
+
+	if (system_supports_sve()) {
+		sve_guest = vcpu_has_sve(vcpu);
+		sve_host = vcpu->arch.flags & KVM_ARM64_HOST_SVE_IN_USE;
+		vhe = true;
+	} else {
+		sve_guest = false;
+		sve_host = false;
+		vhe = has_vhe();
+	}
+
+	hsr_ec = kvm_vcpu_trap_get_class(vcpu);
+	if (hsr_ec != ESR_ELx_EC_FP_ASIMD &&
+	    hsr_ec != ESR_ELx_EC_SVE)
+		return false;
+
+	/* Don't handle SVE traps for non-SVE vcpus here: */
+	if (!sve_guest)
+		if (hsr_ec != ESR_ELx_EC_FP_ASIMD)
+			return false;
+
+	/* Valid trap.  Switch the context: */
+
+	if (vhe) {
+		u64 reg = read_sysreg(cpacr_el1) | CPACR_EL1_FPEN;
+
+		if (sve_guest)
+			reg |= CPACR_EL1_ZEN;
+
+		write_sysreg(reg, cpacr_el1);
+	} else {
 		write_sysreg(read_sysreg(cptr_el2) & ~(u64)CPTR_EL2_TFP,
 			     cptr_el2);
+	}
 
 	isb();
 
@@ -335,24 +370,28 @@ static bool __hyp_text __hyp_switch_fpsimd(struct kvm_vcpu *vcpu)
 		 * In the SVE case, VHE is assumed: it is enforced by
 		 * Kconfig and kvm_arch_init().
 		 */
-		if (system_supports_sve() &&
-		    (vcpu->arch.flags & KVM_ARM64_HOST_SVE_IN_USE)) {
+		if (sve_host) {
 			struct thread_struct *thread = container_of(
-				host_fpsimd,
+				vcpu->arch.host_fpsimd_state,
 				struct thread_struct, uw.fpsimd_state);
 
-			sve_save_state(sve_pffr(thread), &host_fpsimd->fpsr);
+			sve_save_state(sve_pffr(thread),
+				       &vcpu->arch.host_fpsimd_state->fpsr);
 		} else {
-			__fpsimd_save_state(host_fpsimd);
+			__fpsimd_save_state(vcpu->arch.host_fpsimd_state);
 		}
 
 		vcpu->arch.flags &= ~KVM_ARM64_FP_HOST;
 	}
 
-	__fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
-
-	if (vcpu_has_sve(vcpu))
+	if (sve_guest) {
+		sve_load_state(vcpu_sve_pffr(vcpu),
+			       &vcpu->arch.ctxt.gp_regs.fp_regs.fpsr,
+			       sve_vq_from_vl(vcpu->arch.sve_max_vl) - 1);
 		write_sysreg_s(vcpu->arch.ctxt.sys_regs[ZCR_EL1], SYS_ZCR_EL12);
+	} else {
+		__fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
+	}
 
 	/* Skip restoring fpexc32 for AArch64 guests */
 	if (!(read_sysreg(hcr_el2) & HCR_RW))
@@ -388,10 +427,10 @@ static bool __hyp_text fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
 	 * and restore the guest context lazily.
 	 * If FP/SIMD is not implemented, handle the trap and inject an
 	 * undefined instruction exception to the guest.
+	 * Similarly for trapped SVE accesses.
 	 */
-	if (system_supports_fpsimd() &&
-	    kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_FP_ASIMD)
-		return __hyp_switch_fpsimd(vcpu);
+	if (__hyp_handle_fpsimd(vcpu))
+		return true;
 
 	if (!__populate_fault_info(vcpu))
 		return true;
-- 
2.1.4

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

* [PATCH v7 13/27] KVM: arm64/sve: Context switch the SVE registers
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

In order to give each vcpu its own view of the SVE registers, this
patch adds context storage via a new sve_state pointer in struct
vcpu_arch.  An additional member sve_max_vl is also added for each
vcpu, to determine the maximum vector length visible to the guest
and thus the value to be configured in ZCR_EL2.LEN while the vcpu
is active.  This also determines the layout and size of the storage
in sve_state, which is read and written by the same backend
functions that are used for context-switching the SVE state for
host tasks.

On SVE-enabled vcpus, SVE access traps are now handled by switching
in the vcpu's SVE context and disabling the trap before returning
to the guest.  On other vcpus, the trap is not handled and an exit
back to the host occurs, where the handle_sve() fallback path
reflects an undefined instruction exception back to the guest,
consistently with the behaviour of non-SVE-capable hardware (as was
done unconditionally prior to this patch).

No SVE handling is added on non-VHE-only paths, since VHE is an
architectural and Kconfig prerequisite of SVE.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * [Julien Thierry, Julien Grall] Commit message typo fixes

 * [Mark Rutland] Rename trap_class to hsr_ec, for consistency with
   existing code.

 * [Mark Rutland] Simplify condition for refusing to handle an
   FPSIMD/SVE trap, using multiple if () statements for clarity.  The
   previous condition was a bit tortuous, and how that the static_key
   checks have been hoisted out, it makes little difference to the
   compiler how we express the condition here.
---
 arch/arm64/include/asm/kvm_host.h |  6 ++++
 arch/arm64/kvm/fpsimd.c           |  5 +--
 arch/arm64/kvm/hyp/switch.c       | 75 +++++++++++++++++++++++++++++----------
 3 files changed, 66 insertions(+), 20 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 22cf484..4fabfd2 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -228,6 +228,8 @@ struct vcpu_reset_state {
 
 struct kvm_vcpu_arch {
 	struct kvm_cpu_context ctxt;
+	void *sve_state;
+	unsigned int sve_max_vl;
 
 	/* HYP configuration */
 	u64 hcr_el2;
@@ -323,6 +325,10 @@ struct kvm_vcpu_arch {
 	bool sysregs_loaded_on_cpu;
 };
 
+/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
+#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
+				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
+
 /* vcpu_arch flags field values: */
 #define KVM_ARM64_DEBUG_DIRTY		(1 << 0)
 #define KVM_ARM64_FP_ENABLED		(1 << 1) /* guest FP regs loaded */
diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
index 7053bf4..6e3c9c8 100644
--- a/arch/arm64/kvm/fpsimd.c
+++ b/arch/arm64/kvm/fpsimd.c
@@ -87,10 +87,11 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
 
 	if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
 		fpsimd_bind_state_to_cpu(&vcpu->arch.ctxt.gp_regs.fp_regs,
-					 NULL, SVE_VL_MIN);
+					 vcpu->arch.sve_state,
+					 vcpu->arch.sve_max_vl);
 
 		clear_thread_flag(TIF_FOREIGN_FPSTATE);
-		clear_thread_flag(TIF_SVE);
+		update_thread_flag(TIF_SVE, vcpu_has_sve(vcpu));
 	}
 }
 
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 9d46066..5444b9c 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -100,7 +100,10 @@ static void activate_traps_vhe(struct kvm_vcpu *vcpu)
 	val = read_sysreg(cpacr_el1);
 	val |= CPACR_EL1_TTA;
 	val &= ~CPACR_EL1_ZEN;
-	if (!update_fp_enabled(vcpu)) {
+	if (update_fp_enabled(vcpu)) {
+		if (vcpu_has_sve(vcpu))
+			val |= CPACR_EL1_ZEN;
+	} else {
 		val &= ~CPACR_EL1_FPEN;
 		__activate_traps_fpsimd32(vcpu);
 	}
@@ -317,16 +320,48 @@ static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
 	return true;
 }
 
-static bool __hyp_text __hyp_switch_fpsimd(struct kvm_vcpu *vcpu)
+/* Check for an FPSIMD/SVE trap and handle as appropriate */
+static bool __hyp_text __hyp_handle_fpsimd(struct kvm_vcpu *vcpu)
 {
-	struct user_fpsimd_state *host_fpsimd = vcpu->arch.host_fpsimd_state;
+	bool vhe, sve_guest, sve_host;
+	u8 hsr_ec;
 
-	if (has_vhe())
-		write_sysreg(read_sysreg(cpacr_el1) | CPACR_EL1_FPEN,
-			     cpacr_el1);
-	else
+	if (!system_supports_fpsimd())
+		return false;
+
+	if (system_supports_sve()) {
+		sve_guest = vcpu_has_sve(vcpu);
+		sve_host = vcpu->arch.flags & KVM_ARM64_HOST_SVE_IN_USE;
+		vhe = true;
+	} else {
+		sve_guest = false;
+		sve_host = false;
+		vhe = has_vhe();
+	}
+
+	hsr_ec = kvm_vcpu_trap_get_class(vcpu);
+	if (hsr_ec != ESR_ELx_EC_FP_ASIMD &&
+	    hsr_ec != ESR_ELx_EC_SVE)
+		return false;
+
+	/* Don't handle SVE traps for non-SVE vcpus here: */
+	if (!sve_guest)
+		if (hsr_ec != ESR_ELx_EC_FP_ASIMD)
+			return false;
+
+	/* Valid trap.  Switch the context: */
+
+	if (vhe) {
+		u64 reg = read_sysreg(cpacr_el1) | CPACR_EL1_FPEN;
+
+		if (sve_guest)
+			reg |= CPACR_EL1_ZEN;
+
+		write_sysreg(reg, cpacr_el1);
+	} else {
 		write_sysreg(read_sysreg(cptr_el2) & ~(u64)CPTR_EL2_TFP,
 			     cptr_el2);
+	}
 
 	isb();
 
@@ -335,24 +370,28 @@ static bool __hyp_text __hyp_switch_fpsimd(struct kvm_vcpu *vcpu)
 		 * In the SVE case, VHE is assumed: it is enforced by
 		 * Kconfig and kvm_arch_init().
 		 */
-		if (system_supports_sve() &&
-		    (vcpu->arch.flags & KVM_ARM64_HOST_SVE_IN_USE)) {
+		if (sve_host) {
 			struct thread_struct *thread = container_of(
-				host_fpsimd,
+				vcpu->arch.host_fpsimd_state,
 				struct thread_struct, uw.fpsimd_state);
 
-			sve_save_state(sve_pffr(thread), &host_fpsimd->fpsr);
+			sve_save_state(sve_pffr(thread),
+				       &vcpu->arch.host_fpsimd_state->fpsr);
 		} else {
-			__fpsimd_save_state(host_fpsimd);
+			__fpsimd_save_state(vcpu->arch.host_fpsimd_state);
 		}
 
 		vcpu->arch.flags &= ~KVM_ARM64_FP_HOST;
 	}
 
-	__fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
-
-	if (vcpu_has_sve(vcpu))
+	if (sve_guest) {
+		sve_load_state(vcpu_sve_pffr(vcpu),
+			       &vcpu->arch.ctxt.gp_regs.fp_regs.fpsr,
+			       sve_vq_from_vl(vcpu->arch.sve_max_vl) - 1);
 		write_sysreg_s(vcpu->arch.ctxt.sys_regs[ZCR_EL1], SYS_ZCR_EL12);
+	} else {
+		__fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
+	}
 
 	/* Skip restoring fpexc32 for AArch64 guests */
 	if (!(read_sysreg(hcr_el2) & HCR_RW))
@@ -388,10 +427,10 @@ static bool __hyp_text fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
 	 * and restore the guest context lazily.
 	 * If FP/SIMD is not implemented, handle the trap and inject an
 	 * undefined instruction exception to the guest.
+	 * Similarly for trapped SVE accesses.
 	 */
-	if (system_supports_fpsimd() &&
-	    kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_FP_ASIMD)
-		return __hyp_switch_fpsimd(vcpu);
+	if (__hyp_handle_fpsimd(vcpu))
+		return true;
 
 	if (!__populate_fault_info(vcpu))
 		return true;
-- 
2.1.4


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

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

* [PATCH v7 14/27] KVM: Allow 2048-bit register access via ioctl interface
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

The Arm SVE architecture defines registers that are up to 2048 bits
in size (with some possibility of further future expansion).

In order to avoid the need for an excessively large number of
ioctls when saving and restoring a vcpu's registers, this patch
adds a #define to make support for individual 2048-bit registers
through the KVM_{GET,SET}_ONE_REG ioctl interface official.  This
will allow each SVE register to be accessed in a single call.

There are sufficient spare bits in the register id size field for
this change, so there is no ABI impact, providing that
KVM_GET_REG_LIST does not enumerate any 2048-bit register unless
userspace explicitly opts in to the relevant architecture-specific
features.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 include/uapi/linux/kvm.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 6d4ea4b..dc77a5a 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1145,6 +1145,7 @@ struct kvm_dirty_tlb {
 #define KVM_REG_SIZE_U256	0x0050000000000000ULL
 #define KVM_REG_SIZE_U512	0x0060000000000000ULL
 #define KVM_REG_SIZE_U1024	0x0070000000000000ULL
+#define KVM_REG_SIZE_U2048	0x0080000000000000ULL
 
 struct kvm_reg_list {
 	__u64 n; /* number of regs */
-- 
2.1.4

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

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

* [PATCH v7 14/27] KVM: Allow 2048-bit register access via ioctl interface
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

The Arm SVE architecture defines registers that are up to 2048 bits
in size (with some possibility of further future expansion).

In order to avoid the need for an excessively large number of
ioctls when saving and restoring a vcpu's registers, this patch
adds a #define to make support for individual 2048-bit registers
through the KVM_{GET,SET}_ONE_REG ioctl interface official.  This
will allow each SVE register to be accessed in a single call.

There are sufficient spare bits in the register id size field for
this change, so there is no ABI impact, providing that
KVM_GET_REG_LIST does not enumerate any 2048-bit register unless
userspace explicitly opts in to the relevant architecture-specific
features.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 include/uapi/linux/kvm.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 6d4ea4b..dc77a5a 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1145,6 +1145,7 @@ struct kvm_dirty_tlb {
 #define KVM_REG_SIZE_U256	0x0050000000000000ULL
 #define KVM_REG_SIZE_U512	0x0060000000000000ULL
 #define KVM_REG_SIZE_U1024	0x0070000000000000ULL
+#define KVM_REG_SIZE_U2048	0x0080000000000000ULL
 
 struct kvm_reg_list {
 	__u64 n; /* number of regs */
-- 
2.1.4


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

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

* [PATCH v7 15/27] KVM: arm64: Add missing #include of <linux/string.h> in guest.c
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

arch/arm64/kvm/guest.c uses the string functions, but the
corresponding header is not included.

We seem to get away with this for now, but for completeness this
patch adds the #include, in preparation for adding yet more
memset() calls.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 arch/arm64/kvm/guest.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 62514cb..3e38eb2 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -23,6 +23,7 @@
 #include <linux/err.h>
 #include <linux/kvm_host.h>
 #include <linux/module.h>
+#include <linux/string.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
 #include <kvm/arm_psci.h>
-- 
2.1.4

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

* [PATCH v7 15/27] KVM: arm64: Add missing #include of <linux/string.h> in guest.c
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

arch/arm64/kvm/guest.c uses the string functions, but the
corresponding header is not included.

We seem to get away with this for now, but for completeness this
patch adds the #include, in preparation for adding yet more
memset() calls.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 arch/arm64/kvm/guest.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 62514cb..3e38eb2 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -23,6 +23,7 @@
 #include <linux/err.h>
 #include <linux/kvm_host.h>
 #include <linux/module.h>
+#include <linux/string.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
 #include <kvm/arm_psci.h>
-- 
2.1.4


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

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

* [PATCH v7 16/27] KVM: arm64: Factor out core register ID enumeration
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

In preparation for adding logic to filter out some KVM_REG_ARM_CORE
registers from the KVM_GET_REG_LIST output, this patch factors out
the core register enumeration into a separate function and rebuilds
num_core_regs() on top of it.

This may be a little more expensive (depending on how good a job
the compiler does of specialising the code), but KVM_GET_REG_LIST
is not a hot path.

This will make it easier to consolidate ID filtering code in one
place.

No functional change.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * New patch.

   This reimplements part of the separately-posted patch "KVM: arm64:
   Factor out KVM_GET_REG_LIST core register enumeration", minus aspects
   that potentially break the ABI.

   As a result, the opportunity to truly consolidate all the ID reg
   filtering in one place is deliberately left on the floor, for now.
   This will be addressed in a separate series later on.
---
 arch/arm64/kvm/guest.c | 33 +++++++++++++++++++++++++--------
 1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 3e38eb2..a391a61 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -23,6 +23,7 @@
 #include <linux/err.h>
 #include <linux/kvm_host.h>
 #include <linux/module.h>
+#include <linux/stddef.h>
 #include <linux/string.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
@@ -194,9 +195,28 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 	return -EINVAL;
 }
 
+static int kvm_arm_copy_core_reg_indices(u64 __user *uindices)
+{
+	unsigned int i;
+	int n = 0;
+	const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
+
+	for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
+		if (uindices) {
+			if (put_user(core_reg | i, uindices))
+				return -EFAULT;
+			uindices++;
+		}
+
+		n++;
+	}
+
+	return n;
+}
+
 static unsigned long num_core_regs(void)
 {
-	return sizeof(struct kvm_regs) / sizeof(__u32);
+	return kvm_arm_copy_core_reg_indices(NULL);
 }
 
 /**
@@ -276,15 +296,12 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
  */
 int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 {
-	unsigned int i;
-	const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
 	int ret;
 
-	for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
-		if (put_user(core_reg | i, uindices))
-			return -EFAULT;
-		uindices++;
-	}
+	ret = kvm_arm_copy_core_reg_indices(uindices);
+	if (ret)
+		return ret;
+	uindices += ret;
 
 	ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
 	if (ret)
-- 
2.1.4

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

* [PATCH v7 16/27] KVM: arm64: Factor out core register ID enumeration
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

In preparation for adding logic to filter out some KVM_REG_ARM_CORE
registers from the KVM_GET_REG_LIST output, this patch factors out
the core register enumeration into a separate function and rebuilds
num_core_regs() on top of it.

This may be a little more expensive (depending on how good a job
the compiler does of specialising the code), but KVM_GET_REG_LIST
is not a hot path.

This will make it easier to consolidate ID filtering code in one
place.

No functional change.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * New patch.

   This reimplements part of the separately-posted patch "KVM: arm64:
   Factor out KVM_GET_REG_LIST core register enumeration", minus aspects
   that potentially break the ABI.

   As a result, the opportunity to truly consolidate all the ID reg
   filtering in one place is deliberately left on the floor, for now.
   This will be addressed in a separate series later on.
---
 arch/arm64/kvm/guest.c | 33 +++++++++++++++++++++++++--------
 1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 3e38eb2..a391a61 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -23,6 +23,7 @@
 #include <linux/err.h>
 #include <linux/kvm_host.h>
 #include <linux/module.h>
+#include <linux/stddef.h>
 #include <linux/string.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
@@ -194,9 +195,28 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 	return -EINVAL;
 }
 
+static int kvm_arm_copy_core_reg_indices(u64 __user *uindices)
+{
+	unsigned int i;
+	int n = 0;
+	const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
+
+	for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
+		if (uindices) {
+			if (put_user(core_reg | i, uindices))
+				return -EFAULT;
+			uindices++;
+		}
+
+		n++;
+	}
+
+	return n;
+}
+
 static unsigned long num_core_regs(void)
 {
-	return sizeof(struct kvm_regs) / sizeof(__u32);
+	return kvm_arm_copy_core_reg_indices(NULL);
 }
 
 /**
@@ -276,15 +296,12 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
  */
 int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 {
-	unsigned int i;
-	const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
 	int ret;
 
-	for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
-		if (put_user(core_reg | i, uindices))
-			return -EFAULT;
-		uindices++;
-	}
+	ret = kvm_arm_copy_core_reg_indices(uindices);
+	if (ret)
+		return ret;
+	uindices += ret;
 
 	ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
 	if (ret)
-- 
2.1.4


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

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

* [PATCH v7 17/27] KVM: arm64: Reject ioctl access to FPSIMD V-regs on SVE vcpus
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

In order to avoid the pointless complexity of maintaining two ioctl
register access views of the same data, this patch blocks ioctl
access to the FPSIMD V-registers on vcpus that support SVE.

This will make it more straightforward to add SVE register access
support.

Since SVE is an opt-in feature for userspace, this will not affect
existing users.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * Refactored to cope with the removal of core_reg_size_from_offset()
   (which was added by another series which will now be handled
   independently).

   This leaves some duplication in that we still filter the V-regs out
   in two places, but this no worse than other existing code in guest.c.
   I plan to tidy this up independently later on.
---
 arch/arm64/kvm/guest.c | 48 ++++++++++++++++++++++++++++++++++++------------
 1 file changed, 36 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index a391a61..756d0d6 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -54,12 +54,19 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
+static bool core_reg_offset_is_vreg(u64 off)
+{
+	return off >= KVM_REG_ARM_CORE_REG(fp_regs.vregs) &&
+		off < KVM_REG_ARM_CORE_REG(fp_regs.fpsr);
+}
+
 static u64 core_reg_offset_from_id(u64 id)
 {
 	return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
 }
 
-static int validate_core_offset(const struct kvm_one_reg *reg)
+static int validate_core_offset(const struct kvm_vcpu *vcpu,
+				const struct kvm_one_reg *reg)
 {
 	u64 off = core_reg_offset_from_id(reg->id);
 	int size;
@@ -91,11 +98,19 @@ static int validate_core_offset(const struct kvm_one_reg *reg)
 		return -EINVAL;
 	}
 
-	if (KVM_REG_SIZE(reg->id) == size &&
-	    IS_ALIGNED(off, size / sizeof(__u32)))
-		return 0;
+	if (KVM_REG_SIZE(reg->id) != size ||
+	    !IS_ALIGNED(off, size / sizeof(__u32)))
+		return -EINVAL;
 
-	return -EINVAL;
+	/*
+	 * The KVM_REG_ARM64_SVE regs must be used instead of
+	 * KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on
+	 * SVE-enabled vcpus:
+	 */
+	if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(off))
+		return -EINVAL;
+
+	return 0;
 }
 
 static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
@@ -117,7 +132,7 @@ static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	    (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
 		return -ENOENT;
 
-	if (validate_core_offset(reg))
+	if (validate_core_offset(vcpu, reg))
 		return -EINVAL;
 
 	if (copy_to_user(uaddr, ((u32 *)regs) + off, KVM_REG_SIZE(reg->id)))
@@ -142,7 +157,7 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	    (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
 		return -ENOENT;
 
-	if (validate_core_offset(reg))
+	if (validate_core_offset(vcpu, reg))
 		return -EINVAL;
 
 	if (KVM_REG_SIZE(reg->id) > sizeof(tmp))
@@ -195,13 +210,22 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 	return -EINVAL;
 }
 
-static int kvm_arm_copy_core_reg_indices(u64 __user *uindices)
+static int copy_core_reg_indices(const struct kvm_vcpu *vcpu,
+				 u64 __user *uindices)
 {
 	unsigned int i;
 	int n = 0;
 	const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
 
 	for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
+		/*
+		 * The KVM_REG_ARM64_SVE regs must be used instead of
+		 * KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on
+		 * SVE-enabled vcpus:
+		 */
+		if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(i))
+			continue;
+
 		if (uindices) {
 			if (put_user(core_reg | i, uindices))
 				return -EFAULT;
@@ -214,9 +238,9 @@ static int kvm_arm_copy_core_reg_indices(u64 __user *uindices)
 	return n;
 }
 
-static unsigned long num_core_regs(void)
+static unsigned long num_core_regs(const struct kvm_vcpu *vcpu)
 {
-	return kvm_arm_copy_core_reg_indices(NULL);
+	return copy_core_reg_indices(vcpu, NULL);
 }
 
 /**
@@ -281,7 +305,7 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
 {
 	unsigned long res = 0;
 
-	res += num_core_regs();
+	res += num_core_regs(vcpu);
 	res += kvm_arm_num_sys_reg_descs(vcpu);
 	res += kvm_arm_get_fw_num_regs(vcpu);
 	res += NUM_TIMER_REGS;
@@ -298,7 +322,7 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 {
 	int ret;
 
-	ret = kvm_arm_copy_core_reg_indices(uindices);
+	ret = copy_core_reg_indices(vcpu, uindices);
 	if (ret)
 		return ret;
 	uindices += ret;
-- 
2.1.4

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

* [PATCH v7 17/27] KVM: arm64: Reject ioctl access to FPSIMD V-regs on SVE vcpus
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

In order to avoid the pointless complexity of maintaining two ioctl
register access views of the same data, this patch blocks ioctl
access to the FPSIMD V-registers on vcpus that support SVE.

This will make it more straightforward to add SVE register access
support.

Since SVE is an opt-in feature for userspace, this will not affect
existing users.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * Refactored to cope with the removal of core_reg_size_from_offset()
   (which was added by another series which will now be handled
   independently).

   This leaves some duplication in that we still filter the V-regs out
   in two places, but this no worse than other existing code in guest.c.
   I plan to tidy this up independently later on.
---
 arch/arm64/kvm/guest.c | 48 ++++++++++++++++++++++++++++++++++++------------
 1 file changed, 36 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index a391a61..756d0d6 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -54,12 +54,19 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
+static bool core_reg_offset_is_vreg(u64 off)
+{
+	return off >= KVM_REG_ARM_CORE_REG(fp_regs.vregs) &&
+		off < KVM_REG_ARM_CORE_REG(fp_regs.fpsr);
+}
+
 static u64 core_reg_offset_from_id(u64 id)
 {
 	return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
 }
 
-static int validate_core_offset(const struct kvm_one_reg *reg)
+static int validate_core_offset(const struct kvm_vcpu *vcpu,
+				const struct kvm_one_reg *reg)
 {
 	u64 off = core_reg_offset_from_id(reg->id);
 	int size;
@@ -91,11 +98,19 @@ static int validate_core_offset(const struct kvm_one_reg *reg)
 		return -EINVAL;
 	}
 
-	if (KVM_REG_SIZE(reg->id) == size &&
-	    IS_ALIGNED(off, size / sizeof(__u32)))
-		return 0;
+	if (KVM_REG_SIZE(reg->id) != size ||
+	    !IS_ALIGNED(off, size / sizeof(__u32)))
+		return -EINVAL;
 
-	return -EINVAL;
+	/*
+	 * The KVM_REG_ARM64_SVE regs must be used instead of
+	 * KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on
+	 * SVE-enabled vcpus:
+	 */
+	if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(off))
+		return -EINVAL;
+
+	return 0;
 }
 
 static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
@@ -117,7 +132,7 @@ static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	    (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
 		return -ENOENT;
 
-	if (validate_core_offset(reg))
+	if (validate_core_offset(vcpu, reg))
 		return -EINVAL;
 
 	if (copy_to_user(uaddr, ((u32 *)regs) + off, KVM_REG_SIZE(reg->id)))
@@ -142,7 +157,7 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	    (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
 		return -ENOENT;
 
-	if (validate_core_offset(reg))
+	if (validate_core_offset(vcpu, reg))
 		return -EINVAL;
 
 	if (KVM_REG_SIZE(reg->id) > sizeof(tmp))
@@ -195,13 +210,22 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 	return -EINVAL;
 }
 
-static int kvm_arm_copy_core_reg_indices(u64 __user *uindices)
+static int copy_core_reg_indices(const struct kvm_vcpu *vcpu,
+				 u64 __user *uindices)
 {
 	unsigned int i;
 	int n = 0;
 	const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
 
 	for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
+		/*
+		 * The KVM_REG_ARM64_SVE regs must be used instead of
+		 * KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on
+		 * SVE-enabled vcpus:
+		 */
+		if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(i))
+			continue;
+
 		if (uindices) {
 			if (put_user(core_reg | i, uindices))
 				return -EFAULT;
@@ -214,9 +238,9 @@ static int kvm_arm_copy_core_reg_indices(u64 __user *uindices)
 	return n;
 }
 
-static unsigned long num_core_regs(void)
+static unsigned long num_core_regs(const struct kvm_vcpu *vcpu)
 {
-	return kvm_arm_copy_core_reg_indices(NULL);
+	return copy_core_reg_indices(vcpu, NULL);
 }
 
 /**
@@ -281,7 +305,7 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
 {
 	unsigned long res = 0;
 
-	res += num_core_regs();
+	res += num_core_regs(vcpu);
 	res += kvm_arm_num_sys_reg_descs(vcpu);
 	res += kvm_arm_get_fw_num_regs(vcpu);
 	res += NUM_TIMER_REGS;
@@ -298,7 +322,7 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 {
 	int ret;
 
-	ret = kvm_arm_copy_core_reg_indices(uindices);
+	ret = copy_core_reg_indices(vcpu, uindices);
 	if (ret)
 		return ret;
 	uindices += ret;
-- 
2.1.4


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

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

* [PATCH v7 18/27] KVM: arm64/sve: Add SVE support to register access ioctl interface
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

This patch adds the following registers for access via the
KVM_{GET,SET}_ONE_REG interface:

 * KVM_REG_ARM64_SVE_ZREG(n, i) (n = 0..31) (in 2048-bit slices)
 * KVM_REG_ARM64_SVE_PREG(n, i) (n = 0..15) (in 256-bit slices)
 * KVM_REG_ARM64_SVE_FFR(i) (in 256-bit slices)

In order to adapt gracefully to future architectural extensions,
the registers are logically divided up into slices as noted above:
the i parameter denotes the slice index.

This allows us to reserve space in the ABI for future expansion of
these registers.  However, as of today the architecture does not
permit registers to be larger than a single slice, so no code is
needed in the kernel to expose additional slices, for now.  The
code can be extended later as needed to expose them up to a maximum
of 32 slices (as carved out in the architecture itself) if they
really exist someday.

The registers are only visible for vcpus that have SVE enabled.
They are not enumerated by KVM_GET_REG_LIST on vcpus that do not
have SVE.

Accesses to the FPSIMD registers via KVM_REG_ARM_CORE is not
allowed for SVE-enabled vcpus: SVE-aware userspace can use the
KVM_REG_ARM64_SVE_ZREG() interface instead to access the same
register state.  This avoids some complex and pointless emulation
in the kernel to convert between the two views of these aliased
registers.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * [Julien Thierry] rename sve_reg_region() to sve_reg_to_region() to
   make its purpose a bit clearer.

 * [Julien Thierry] rename struct sve_state_region to
   sve_state_reg_region to make it clearer this this struct only
   describes the bounds of (part of) a single register within
   sve_state.

 * [Julien Thierry] Add a comment to clarify the purpose of struct
   sve_state_reg_region.
---
 arch/arm64/include/asm/kvm_host.h |  14 ++++
 arch/arm64/include/uapi/asm/kvm.h |  17 +++++
 arch/arm64/kvm/guest.c            | 139 ++++++++++++++++++++++++++++++++++----
 3 files changed, 158 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 4fabfd2..205438a 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -329,6 +329,20 @@ struct kvm_vcpu_arch {
 #define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
 				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
 
+#define vcpu_sve_state_size(vcpu) ({					\
+	size_t __size_ret;						\
+	unsigned int __vcpu_vq;						\
+									\
+	if (WARN_ON(!sve_vl_valid((vcpu)->arch.sve_max_vl))) {		\
+		__size_ret = 0;						\
+	} else {							\
+		__vcpu_vq = sve_vq_from_vl((vcpu)->arch.sve_max_vl);	\
+		__size_ret = SVE_SIG_REGS_SIZE(__vcpu_vq);		\
+	}								\
+									\
+	__size_ret;							\
+})
+
 /* vcpu_arch flags field values: */
 #define KVM_ARM64_DEBUG_DIRTY		(1 << 0)
 #define KVM_ARM64_FP_ENABLED		(1 << 1) /* guest FP regs loaded */
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 97c3478..ced760c 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -226,6 +226,23 @@ struct kvm_vcpu_events {
 					 KVM_REG_ARM_FW | ((r) & 0xffff))
 #define KVM_REG_ARM_PSCI_VERSION	KVM_REG_ARM_FW_REG(0)
 
+/* SVE registers */
+#define KVM_REG_ARM64_SVE		(0x15 << KVM_REG_ARM_COPROC_SHIFT)
+
+/* Z- and P-regs occupy blocks at the following offsets within this range: */
+#define KVM_REG_ARM64_SVE_ZREG_BASE	0
+#define KVM_REG_ARM64_SVE_PREG_BASE	0x400
+
+#define KVM_REG_ARM64_SVE_ZREG(n, i)	(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
+					 KVM_REG_ARM64_SVE_ZREG_BASE |	\
+					 KVM_REG_SIZE_U2048 |		\
+					 ((n) << 5) | (i))
+#define KVM_REG_ARM64_SVE_PREG(n, i)	(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
+					 KVM_REG_ARM64_SVE_PREG_BASE |	\
+					 KVM_REG_SIZE_U256 |		\
+					 ((n) << 5) | (i))
+#define KVM_REG_ARM64_SVE_FFR(i)	KVM_REG_ARM64_SVE_PREG(16, i)
+
 /* Device Control API: ARM VGIC */
 #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 756d0d6..736d8cb 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -19,8 +19,11 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/bits.h>
 #include <linux/errno.h>
 #include <linux/err.h>
+#include <linux/nospec.h>
+#include <linux/kernel.h>
 #include <linux/kvm_host.h>
 #include <linux/module.h>
 #include <linux/stddef.h>
@@ -30,9 +33,12 @@
 #include <kvm/arm_psci.h>
 #include <asm/cputype.h>
 #include <linux/uaccess.h>
+#include <asm/fpsimd.h>
 #include <asm/kvm.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_coproc.h>
+#include <asm/kvm_host.h>
+#include <asm/sigcontext.h>
 
 #include "trace.h"
 
@@ -200,6 +206,115 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	return err;
 }
 
+#define SVE_REG_SLICE_SHIFT	0
+#define SVE_REG_SLICE_BITS	5
+#define SVE_REG_ID_SHIFT	(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS)
+#define SVE_REG_ID_BITS		5
+
+#define SVE_REG_SLICE_MASK					\
+	GENMASK(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS - 1,	\
+		SVE_REG_SLICE_SHIFT)
+#define SVE_REG_ID_MASK							\
+	GENMASK(SVE_REG_ID_SHIFT + SVE_REG_ID_BITS - 1, SVE_REG_ID_SHIFT)
+
+#define SVE_NUM_SLICES (1 << SVE_REG_SLICE_BITS)
+
+#define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0))
+#define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0))
+
+/* Bounds of a single SVE register slice within vcpu->arch.sve_state */
+struct sve_state_reg_region {
+	unsigned int koffset;	/* offset into sve_state in kernel memory */
+	unsigned int klen;	/* length in kernel memory */
+	unsigned int upad;	/* extra trailing padding in user memory */
+};
+
+/* Get sanitised bounds for user/kernel SVE register copy */
+static int sve_reg_to_region(struct sve_state_reg_region *region,
+			     struct kvm_vcpu *vcpu,
+			     const struct kvm_one_reg *reg)
+{
+	/* reg ID ranges for Z- registers */
+	const u64 zreg_id_min = KVM_REG_ARM64_SVE_ZREG(0, 0);
+	const u64 zreg_id_max = KVM_REG_ARM64_SVE_ZREG(SVE_NUM_ZREGS - 1,
+						       SVE_NUM_SLICES - 1);
+
+	/* reg ID ranges for P- registers and FFR (which are contiguous) */
+	const u64 preg_id_min = KVM_REG_ARM64_SVE_PREG(0, 0);
+	const u64 preg_id_max = KVM_REG_ARM64_SVE_FFR(SVE_NUM_SLICES - 1);
+
+	unsigned int vq;
+	unsigned int reg_num;
+
+	unsigned int reqoffset, reqlen; /* User-requested offset and length */
+	unsigned int maxlen; /* Maxmimum permitted length */
+
+	size_t sve_state_size;
+
+	/* Only the first slice ever exists, for now: */
+	if ((reg->id & SVE_REG_SLICE_MASK) != 0)
+		return -ENOENT;
+
+	vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
+
+	reg_num = (reg->id & SVE_REG_ID_MASK) >> SVE_REG_ID_SHIFT;
+
+	if (reg->id >= zreg_id_min && reg->id <= zreg_id_max) {
+		reqoffset = SVE_SIG_ZREG_OFFSET(vq, reg_num) -
+				SVE_SIG_REGS_OFFSET;
+		reqlen = KVM_SVE_ZREG_SIZE;
+		maxlen = SVE_SIG_ZREG_SIZE(vq);
+	} else if (reg->id >= preg_id_min && reg->id <= preg_id_max) {
+		reqoffset = SVE_SIG_PREG_OFFSET(vq, reg_num) -
+				SVE_SIG_REGS_OFFSET;
+		reqlen = KVM_SVE_PREG_SIZE;
+		maxlen = SVE_SIG_PREG_SIZE(vq);
+	} else {
+		return -ENOENT;
+	}
+
+	sve_state_size = vcpu_sve_state_size(vcpu);
+	if (!sve_state_size)
+		return -EINVAL;
+
+	region->koffset = array_index_nospec(reqoffset, sve_state_size);
+	region->klen = min(maxlen, reqlen);
+	region->upad = reqlen - region->klen;
+
+	return 0;
+}
+
+static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	struct sve_state_reg_region region;
+	char __user *uptr = (char __user *)reg->addr;
+
+	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
+		return -ENOENT;
+
+	if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
+			 region.klen) ||
+	    clear_user(uptr + region.klen, region.upad))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	struct sve_state_reg_region region;
+	const char __user *uptr = (const char __user *)reg->addr;
+
+	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
+		return -ENOENT;
+
+	if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
+			   region.klen))
+		return -EFAULT;
+
+	return 0;
+}
+
 int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
 	return -EINVAL;
@@ -346,12 +461,12 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
 		return -EINVAL;
 
-	/* Register group 16 means we want a core register. */
-	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
-		return get_core_reg(vcpu, reg);
-
-	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
-		return kvm_arm_get_fw_reg(vcpu, reg);
+	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
+	case KVM_REG_ARM_CORE:	return get_core_reg(vcpu, reg);
+	case KVM_REG_ARM_FW:	return kvm_arm_get_fw_reg(vcpu, reg);
+	case KVM_REG_ARM64_SVE:	return get_sve_reg(vcpu, reg);
+	default: break; /* fall through */
+	}
 
 	if (is_timer_reg(reg->id))
 		return get_timer_reg(vcpu, reg);
@@ -365,12 +480,12 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
 		return -EINVAL;
 
-	/* Register group 16 means we set a core register. */
-	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
-		return set_core_reg(vcpu, reg);
-
-	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
-		return kvm_arm_set_fw_reg(vcpu, reg);
+	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
+	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
+	case KVM_REG_ARM_FW:	return kvm_arm_set_fw_reg(vcpu, reg);
+	case KVM_REG_ARM64_SVE:	return set_sve_reg(vcpu, reg);
+	default: break; /* fall through */
+	}
 
 	if (is_timer_reg(reg->id))
 		return set_timer_reg(vcpu, reg);
-- 
2.1.4

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

* [PATCH v7 18/27] KVM: arm64/sve: Add SVE support to register access ioctl interface
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

This patch adds the following registers for access via the
KVM_{GET,SET}_ONE_REG interface:

 * KVM_REG_ARM64_SVE_ZREG(n, i) (n = 0..31) (in 2048-bit slices)
 * KVM_REG_ARM64_SVE_PREG(n, i) (n = 0..15) (in 256-bit slices)
 * KVM_REG_ARM64_SVE_FFR(i) (in 256-bit slices)

In order to adapt gracefully to future architectural extensions,
the registers are logically divided up into slices as noted above:
the i parameter denotes the slice index.

This allows us to reserve space in the ABI for future expansion of
these registers.  However, as of today the architecture does not
permit registers to be larger than a single slice, so no code is
needed in the kernel to expose additional slices, for now.  The
code can be extended later as needed to expose them up to a maximum
of 32 slices (as carved out in the architecture itself) if they
really exist someday.

The registers are only visible for vcpus that have SVE enabled.
They are not enumerated by KVM_GET_REG_LIST on vcpus that do not
have SVE.

Accesses to the FPSIMD registers via KVM_REG_ARM_CORE is not
allowed for SVE-enabled vcpus: SVE-aware userspace can use the
KVM_REG_ARM64_SVE_ZREG() interface instead to access the same
register state.  This avoids some complex and pointless emulation
in the kernel to convert between the two views of these aliased
registers.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * [Julien Thierry] rename sve_reg_region() to sve_reg_to_region() to
   make its purpose a bit clearer.

 * [Julien Thierry] rename struct sve_state_region to
   sve_state_reg_region to make it clearer this this struct only
   describes the bounds of (part of) a single register within
   sve_state.

 * [Julien Thierry] Add a comment to clarify the purpose of struct
   sve_state_reg_region.
---
 arch/arm64/include/asm/kvm_host.h |  14 ++++
 arch/arm64/include/uapi/asm/kvm.h |  17 +++++
 arch/arm64/kvm/guest.c            | 139 ++++++++++++++++++++++++++++++++++----
 3 files changed, 158 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 4fabfd2..205438a 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -329,6 +329,20 @@ struct kvm_vcpu_arch {
 #define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
 				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
 
+#define vcpu_sve_state_size(vcpu) ({					\
+	size_t __size_ret;						\
+	unsigned int __vcpu_vq;						\
+									\
+	if (WARN_ON(!sve_vl_valid((vcpu)->arch.sve_max_vl))) {		\
+		__size_ret = 0;						\
+	} else {							\
+		__vcpu_vq = sve_vq_from_vl((vcpu)->arch.sve_max_vl);	\
+		__size_ret = SVE_SIG_REGS_SIZE(__vcpu_vq);		\
+	}								\
+									\
+	__size_ret;							\
+})
+
 /* vcpu_arch flags field values: */
 #define KVM_ARM64_DEBUG_DIRTY		(1 << 0)
 #define KVM_ARM64_FP_ENABLED		(1 << 1) /* guest FP regs loaded */
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 97c3478..ced760c 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -226,6 +226,23 @@ struct kvm_vcpu_events {
 					 KVM_REG_ARM_FW | ((r) & 0xffff))
 #define KVM_REG_ARM_PSCI_VERSION	KVM_REG_ARM_FW_REG(0)
 
+/* SVE registers */
+#define KVM_REG_ARM64_SVE		(0x15 << KVM_REG_ARM_COPROC_SHIFT)
+
+/* Z- and P-regs occupy blocks at the following offsets within this range: */
+#define KVM_REG_ARM64_SVE_ZREG_BASE	0
+#define KVM_REG_ARM64_SVE_PREG_BASE	0x400
+
+#define KVM_REG_ARM64_SVE_ZREG(n, i)	(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
+					 KVM_REG_ARM64_SVE_ZREG_BASE |	\
+					 KVM_REG_SIZE_U2048 |		\
+					 ((n) << 5) | (i))
+#define KVM_REG_ARM64_SVE_PREG(n, i)	(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
+					 KVM_REG_ARM64_SVE_PREG_BASE |	\
+					 KVM_REG_SIZE_U256 |		\
+					 ((n) << 5) | (i))
+#define KVM_REG_ARM64_SVE_FFR(i)	KVM_REG_ARM64_SVE_PREG(16, i)
+
 /* Device Control API: ARM VGIC */
 #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 756d0d6..736d8cb 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -19,8 +19,11 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/bits.h>
 #include <linux/errno.h>
 #include <linux/err.h>
+#include <linux/nospec.h>
+#include <linux/kernel.h>
 #include <linux/kvm_host.h>
 #include <linux/module.h>
 #include <linux/stddef.h>
@@ -30,9 +33,12 @@
 #include <kvm/arm_psci.h>
 #include <asm/cputype.h>
 #include <linux/uaccess.h>
+#include <asm/fpsimd.h>
 #include <asm/kvm.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_coproc.h>
+#include <asm/kvm_host.h>
+#include <asm/sigcontext.h>
 
 #include "trace.h"
 
@@ -200,6 +206,115 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	return err;
 }
 
+#define SVE_REG_SLICE_SHIFT	0
+#define SVE_REG_SLICE_BITS	5
+#define SVE_REG_ID_SHIFT	(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS)
+#define SVE_REG_ID_BITS		5
+
+#define SVE_REG_SLICE_MASK					\
+	GENMASK(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS - 1,	\
+		SVE_REG_SLICE_SHIFT)
+#define SVE_REG_ID_MASK							\
+	GENMASK(SVE_REG_ID_SHIFT + SVE_REG_ID_BITS - 1, SVE_REG_ID_SHIFT)
+
+#define SVE_NUM_SLICES (1 << SVE_REG_SLICE_BITS)
+
+#define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0))
+#define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0))
+
+/* Bounds of a single SVE register slice within vcpu->arch.sve_state */
+struct sve_state_reg_region {
+	unsigned int koffset;	/* offset into sve_state in kernel memory */
+	unsigned int klen;	/* length in kernel memory */
+	unsigned int upad;	/* extra trailing padding in user memory */
+};
+
+/* Get sanitised bounds for user/kernel SVE register copy */
+static int sve_reg_to_region(struct sve_state_reg_region *region,
+			     struct kvm_vcpu *vcpu,
+			     const struct kvm_one_reg *reg)
+{
+	/* reg ID ranges for Z- registers */
+	const u64 zreg_id_min = KVM_REG_ARM64_SVE_ZREG(0, 0);
+	const u64 zreg_id_max = KVM_REG_ARM64_SVE_ZREG(SVE_NUM_ZREGS - 1,
+						       SVE_NUM_SLICES - 1);
+
+	/* reg ID ranges for P- registers and FFR (which are contiguous) */
+	const u64 preg_id_min = KVM_REG_ARM64_SVE_PREG(0, 0);
+	const u64 preg_id_max = KVM_REG_ARM64_SVE_FFR(SVE_NUM_SLICES - 1);
+
+	unsigned int vq;
+	unsigned int reg_num;
+
+	unsigned int reqoffset, reqlen; /* User-requested offset and length */
+	unsigned int maxlen; /* Maxmimum permitted length */
+
+	size_t sve_state_size;
+
+	/* Only the first slice ever exists, for now: */
+	if ((reg->id & SVE_REG_SLICE_MASK) != 0)
+		return -ENOENT;
+
+	vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
+
+	reg_num = (reg->id & SVE_REG_ID_MASK) >> SVE_REG_ID_SHIFT;
+
+	if (reg->id >= zreg_id_min && reg->id <= zreg_id_max) {
+		reqoffset = SVE_SIG_ZREG_OFFSET(vq, reg_num) -
+				SVE_SIG_REGS_OFFSET;
+		reqlen = KVM_SVE_ZREG_SIZE;
+		maxlen = SVE_SIG_ZREG_SIZE(vq);
+	} else if (reg->id >= preg_id_min && reg->id <= preg_id_max) {
+		reqoffset = SVE_SIG_PREG_OFFSET(vq, reg_num) -
+				SVE_SIG_REGS_OFFSET;
+		reqlen = KVM_SVE_PREG_SIZE;
+		maxlen = SVE_SIG_PREG_SIZE(vq);
+	} else {
+		return -ENOENT;
+	}
+
+	sve_state_size = vcpu_sve_state_size(vcpu);
+	if (!sve_state_size)
+		return -EINVAL;
+
+	region->koffset = array_index_nospec(reqoffset, sve_state_size);
+	region->klen = min(maxlen, reqlen);
+	region->upad = reqlen - region->klen;
+
+	return 0;
+}
+
+static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	struct sve_state_reg_region region;
+	char __user *uptr = (char __user *)reg->addr;
+
+	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
+		return -ENOENT;
+
+	if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
+			 region.klen) ||
+	    clear_user(uptr + region.klen, region.upad))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	struct sve_state_reg_region region;
+	const char __user *uptr = (const char __user *)reg->addr;
+
+	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
+		return -ENOENT;
+
+	if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
+			   region.klen))
+		return -EFAULT;
+
+	return 0;
+}
+
 int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
 	return -EINVAL;
@@ -346,12 +461,12 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
 		return -EINVAL;
 
-	/* Register group 16 means we want a core register. */
-	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
-		return get_core_reg(vcpu, reg);
-
-	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
-		return kvm_arm_get_fw_reg(vcpu, reg);
+	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
+	case KVM_REG_ARM_CORE:	return get_core_reg(vcpu, reg);
+	case KVM_REG_ARM_FW:	return kvm_arm_get_fw_reg(vcpu, reg);
+	case KVM_REG_ARM64_SVE:	return get_sve_reg(vcpu, reg);
+	default: break; /* fall through */
+	}
 
 	if (is_timer_reg(reg->id))
 		return get_timer_reg(vcpu, reg);
@@ -365,12 +480,12 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
 		return -EINVAL;
 
-	/* Register group 16 means we set a core register. */
-	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
-		return set_core_reg(vcpu, reg);
-
-	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
-		return kvm_arm_set_fw_reg(vcpu, reg);
+	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
+	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
+	case KVM_REG_ARM_FW:	return kvm_arm_set_fw_reg(vcpu, reg);
+	case KVM_REG_ARM64_SVE:	return set_sve_reg(vcpu, reg);
+	default: break; /* fall through */
+	}
 
 	if (is_timer_reg(reg->id))
 		return set_timer_reg(vcpu, reg);
-- 
2.1.4


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

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

* [PATCH v7 19/27] KVM: arm64: Enumerate SVE register indices for KVM_GET_REG_LIST
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

This patch includes the SVE register IDs in the list returned by
KVM_GET_REG_LIST, as appropriate.

On a non-SVE-enabled vcpu, no new IDs are added.

On an SVE-enabled vcpu, IDs for the FPSIMD V-registers are removed
from the list, since userspace is required to access the Z-
registers instead in order to access the V-register content.  For
the variably-sized SVE registers, the appropriate set of slice IDs
are enumerated, depending on the maximum vector length for the
vcpu.

As it currently stands, the SVE architecture never requires more
than one slice to exist per register, so this patch adds no
explicit support for enumerating multiple slices.  The code can be
extended straightforwardly to support this in the future, if
needed.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v6:

 * [Julien Thierry] Add a #define to replace the magic "slices = 1",
   and add a comment explaining to maintainers what needs to happen if
   this is updated in the future.

Changes since v5:

(Dropped Julien Thierry's Reviewed-by due to non-trivial rebasing)

 * Move mis-split reword to prevent put_user()s being accidentally the
   correct size from KVM: arm64/sve: Add pseudo-register for the guest's
   vector lengths.
---
 arch/arm64/kvm/guest.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 736d8cb..2aa80a5 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -222,6 +222,13 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 #define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0))
 #define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0))
 
+/*
+ * number of register slices required to cover each whole SVE register on vcpu
+ * NOTE: If you are tempted to modify this, you must also to rework
+ * sve_reg_to_region() to match:
+ */
+#define vcpu_sve_slices(vcpu) 1
+
 /* Bounds of a single SVE register slice within vcpu->arch.sve_state */
 struct sve_state_reg_region {
 	unsigned int koffset;	/* offset into sve_state in kernel memory */
@@ -411,6 +418,56 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0;
 }
 
+static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
+{
+	/* Only the first slice ever exists, for now */
+	const unsigned int slices = vcpu_sve_slices(vcpu);
+
+	if (!vcpu_has_sve(vcpu))
+		return 0;
+
+	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */);
+}
+
+static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
+				u64 __user *uindices)
+{
+	/* Only the first slice ever exists, for now */
+	const unsigned int slices = vcpu_sve_slices(vcpu);
+	u64 reg;
+	unsigned int i, n;
+	int num_regs = 0;
+
+	if (!vcpu_has_sve(vcpu))
+		return 0;
+
+	for (i = 0; i < slices; i++) {
+		for (n = 0; n < SVE_NUM_ZREGS; n++) {
+			reg = KVM_REG_ARM64_SVE_ZREG(n, i);
+			if (put_user(reg, uindices++))
+				return -EFAULT;
+
+			num_regs++;
+		}
+
+		for (n = 0; n < SVE_NUM_PREGS; n++) {
+			reg = KVM_REG_ARM64_SVE_PREG(n, i);
+			if (put_user(reg, uindices++))
+				return -EFAULT;
+
+			num_regs++;
+		}
+
+		reg = KVM_REG_ARM64_SVE_FFR(i);
+		if (put_user(reg, uindices++))
+			return -EFAULT;
+
+		num_regs++;
+	}
+
+	return num_regs;
+}
+
 /**
  * kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG
  *
@@ -421,6 +478,7 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
 	unsigned long res = 0;
 
 	res += num_core_regs(vcpu);
+	res += num_sve_regs(vcpu);
 	res += kvm_arm_num_sys_reg_descs(vcpu);
 	res += kvm_arm_get_fw_num_regs(vcpu);
 	res += NUM_TIMER_REGS;
@@ -442,6 +500,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 		return ret;
 	uindices += ret;
 
+	ret = copy_sve_reg_indices(vcpu, uindices);
+	if (ret)
+		return ret;
+	uindices += ret;
+
 	ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
 	if (ret)
 		return ret;
-- 
2.1.4

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

* [PATCH v7 19/27] KVM: arm64: Enumerate SVE register indices for KVM_GET_REG_LIST
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

This patch includes the SVE register IDs in the list returned by
KVM_GET_REG_LIST, as appropriate.

On a non-SVE-enabled vcpu, no new IDs are added.

On an SVE-enabled vcpu, IDs for the FPSIMD V-registers are removed
from the list, since userspace is required to access the Z-
registers instead in order to access the V-register content.  For
the variably-sized SVE registers, the appropriate set of slice IDs
are enumerated, depending on the maximum vector length for the
vcpu.

As it currently stands, the SVE architecture never requires more
than one slice to exist per register, so this patch adds no
explicit support for enumerating multiple slices.  The code can be
extended straightforwardly to support this in the future, if
needed.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v6:

 * [Julien Thierry] Add a #define to replace the magic "slices = 1",
   and add a comment explaining to maintainers what needs to happen if
   this is updated in the future.

Changes since v5:

(Dropped Julien Thierry's Reviewed-by due to non-trivial rebasing)

 * Move mis-split reword to prevent put_user()s being accidentally the
   correct size from KVM: arm64/sve: Add pseudo-register for the guest's
   vector lengths.
---
 arch/arm64/kvm/guest.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 736d8cb..2aa80a5 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -222,6 +222,13 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 #define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0))
 #define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0))
 
+/*
+ * number of register slices required to cover each whole SVE register on vcpu
+ * NOTE: If you are tempted to modify this, you must also to rework
+ * sve_reg_to_region() to match:
+ */
+#define vcpu_sve_slices(vcpu) 1
+
 /* Bounds of a single SVE register slice within vcpu->arch.sve_state */
 struct sve_state_reg_region {
 	unsigned int koffset;	/* offset into sve_state in kernel memory */
@@ -411,6 +418,56 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0;
 }
 
+static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
+{
+	/* Only the first slice ever exists, for now */
+	const unsigned int slices = vcpu_sve_slices(vcpu);
+
+	if (!vcpu_has_sve(vcpu))
+		return 0;
+
+	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */);
+}
+
+static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
+				u64 __user *uindices)
+{
+	/* Only the first slice ever exists, for now */
+	const unsigned int slices = vcpu_sve_slices(vcpu);
+	u64 reg;
+	unsigned int i, n;
+	int num_regs = 0;
+
+	if (!vcpu_has_sve(vcpu))
+		return 0;
+
+	for (i = 0; i < slices; i++) {
+		for (n = 0; n < SVE_NUM_ZREGS; n++) {
+			reg = KVM_REG_ARM64_SVE_ZREG(n, i);
+			if (put_user(reg, uindices++))
+				return -EFAULT;
+
+			num_regs++;
+		}
+
+		for (n = 0; n < SVE_NUM_PREGS; n++) {
+			reg = KVM_REG_ARM64_SVE_PREG(n, i);
+			if (put_user(reg, uindices++))
+				return -EFAULT;
+
+			num_regs++;
+		}
+
+		reg = KVM_REG_ARM64_SVE_FFR(i);
+		if (put_user(reg, uindices++))
+			return -EFAULT;
+
+		num_regs++;
+	}
+
+	return num_regs;
+}
+
 /**
  * kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG
  *
@@ -421,6 +478,7 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
 	unsigned long res = 0;
 
 	res += num_core_regs(vcpu);
+	res += num_sve_regs(vcpu);
 	res += kvm_arm_num_sys_reg_descs(vcpu);
 	res += kvm_arm_get_fw_num_regs(vcpu);
 	res += NUM_TIMER_REGS;
@@ -442,6 +500,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 		return ret;
 	uindices += ret;
 
+	ret = copy_sve_reg_indices(vcpu, uindices);
+	if (ret)
+		return ret;
+	uindices += ret;
+
 	ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
 	if (ret)
 		return ret;
-- 
2.1.4


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

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

* [PATCH v7 20/27] arm64/sve: In-kernel vector length availability query interface
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

KVM will need to interrogate the set of SVE vector lengths
available on the system.

This patch exposes the relevant bits to the kernel, along with a
sve_vq_available() helper to check whether a particular vector
length is supported.

__vq_to_bit() and __bit_to_vq() are not intended for use outside
these functions: now that these are exposed outside fpsimd.c, they
are prefixed with __ in order to provide an extra hint that they
are not intended for general-purpose use.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 arch/arm64/include/asm/fpsimd.h | 29 +++++++++++++++++++++++++++++
 arch/arm64/kernel/fpsimd.c      | 35 ++++++++---------------------------
 2 files changed, 37 insertions(+), 27 deletions(-)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index df7a143..ad6d2e4 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -24,10 +24,13 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/bitmap.h>
 #include <linux/build_bug.h>
+#include <linux/bug.h>
 #include <linux/cache.h>
 #include <linux/init.h>
 #include <linux/stddef.h>
+#include <linux/types.h>
 
 #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
 /* Masks for extracting the FPSR and FPCR from the FPSCR */
@@ -89,6 +92,32 @@ extern u64 read_zcr_features(void);
 
 extern int __ro_after_init sve_max_vl;
 extern int __ro_after_init sve_max_virtualisable_vl;
+/* Set of available vector lengths, as vq_to_bit(vq): */
+extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
+
+/*
+ * Helpers to translate bit indices in sve_vq_map to VQ values (and
+ * vice versa).  This allows find_next_bit() to be used to find the
+ * _maximum_ VQ not exceeding a certain value.
+ */
+static inline unsigned int __vq_to_bit(unsigned int vq)
+{
+	return SVE_VQ_MAX - vq;
+}
+
+static inline unsigned int __bit_to_vq(unsigned int bit)
+{
+	if (WARN_ON(bit >= SVE_VQ_MAX))
+		bit = SVE_VQ_MAX - 1;
+
+	return SVE_VQ_MAX - bit;
+}
+
+/* Ensure vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX before calling this function */
+static inline bool sve_vq_available(unsigned int vq)
+{
+	return test_bit(__vq_to_bit(vq), sve_vq_map);
+}
 
 #ifdef CONFIG_ARM64_SVE
 
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 8a93afa..577296b 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -136,7 +136,7 @@ static int sve_default_vl = -1;
 int __ro_after_init sve_max_vl = SVE_VL_MIN;
 int __ro_after_init sve_max_virtualisable_vl = SVE_VL_MIN;
 /* Set of available vector lengths, as vq_to_bit(vq): */
-static __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
+__ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
 /* Set of vector lengths present on at least one cpu: */
 static __ro_after_init DECLARE_BITMAP(sve_vq_partial_map, SVE_VQ_MAX);
 static void __percpu *efi_sve_state;
@@ -270,25 +270,6 @@ void fpsimd_save(void)
 }
 
 /*
- * Helpers to translate bit indices in sve_vq_map to VQ values (and
- * vice versa).  This allows find_next_bit() to be used to find the
- * _maximum_ VQ not exceeding a certain value.
- */
-
-static unsigned int vq_to_bit(unsigned int vq)
-{
-	return SVE_VQ_MAX - vq;
-}
-
-static unsigned int bit_to_vq(unsigned int bit)
-{
-	if (WARN_ON(bit >= SVE_VQ_MAX))
-		bit = SVE_VQ_MAX - 1;
-
-	return SVE_VQ_MAX - bit;
-}
-
-/*
  * All vector length selection from userspace comes through here.
  * We're on a slow path, so some sanity-checks are included.
  * If things go wrong there's a bug somewhere, but try to fall back to a
@@ -309,8 +290,8 @@ static unsigned int find_supported_vector_length(unsigned int vl)
 		vl = max_vl;
 
 	bit = find_next_bit(sve_vq_map, SVE_VQ_MAX,
-			    vq_to_bit(sve_vq_from_vl(vl)));
-	return sve_vl_from_vq(bit_to_vq(bit));
+			    __vq_to_bit(sve_vq_from_vl(vl)));
+	return sve_vl_from_vq(__bit_to_vq(bit));
 }
 
 #ifdef CONFIG_SYSCTL
@@ -648,7 +629,7 @@ static void sve_probe_vqs(DECLARE_BITMAP(map, SVE_VQ_MAX))
 		write_sysreg_s(zcr | (vq - 1), SYS_ZCR_EL1); /* self-syncing */
 		vl = sve_get_vl();
 		vq = sve_vq_from_vl(vl); /* skip intervening lengths */
-		set_bit(vq_to_bit(vq), map);
+		set_bit(__vq_to_bit(vq), map);
 	}
 }
 
@@ -717,7 +698,7 @@ int sve_verify_vq_map(void)
 	 * Mismatches above sve_max_virtualisable_vl are fine, since
 	 * no guest is allowed to configure ZCR_EL2.LEN to exceed this:
 	 */
-	if (sve_vl_from_vq(bit_to_vq(b)) <= sve_max_virtualisable_vl) {
+	if (sve_vl_from_vq(__bit_to_vq(b)) <= sve_max_virtualisable_vl) {
 		pr_warn("SVE: cpu%d: Unsupported vector length(s) present\n",
 			smp_processor_id());
 		return -EINVAL;
@@ -801,8 +782,8 @@ void __init sve_setup(void)
 	 * so sve_vq_map must have at least SVE_VQ_MIN set.
 	 * If something went wrong, at least try to patch it up:
 	 */
-	if (WARN_ON(!test_bit(vq_to_bit(SVE_VQ_MIN), sve_vq_map)))
-		set_bit(vq_to_bit(SVE_VQ_MIN), sve_vq_map);
+	if (WARN_ON(!test_bit(__vq_to_bit(SVE_VQ_MIN), sve_vq_map)))
+		set_bit(__vq_to_bit(SVE_VQ_MIN), sve_vq_map);
 
 	zcr = read_sanitised_ftr_reg(SYS_ZCR_EL1);
 	sve_max_vl = sve_vl_from_vq((zcr & ZCR_ELx_LEN_MASK) + 1);
@@ -831,7 +812,7 @@ void __init sve_setup(void)
 		/* No virtualisable VLs?  This is architecturally forbidden. */
 		sve_max_virtualisable_vl = SVE_VQ_MIN;
 	else /* b + 1 < SVE_VQ_MAX */
-		sve_max_virtualisable_vl = sve_vl_from_vq(bit_to_vq(b + 1));
+		sve_max_virtualisable_vl = sve_vl_from_vq(__bit_to_vq(b + 1));
 
 	if (sve_max_virtualisable_vl > sve_max_vl)
 		sve_max_virtualisable_vl = sve_max_vl;
-- 
2.1.4

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

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

* [PATCH v7 20/27] arm64/sve: In-kernel vector length availability query interface
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

KVM will need to interrogate the set of SVE vector lengths
available on the system.

This patch exposes the relevant bits to the kernel, along with a
sve_vq_available() helper to check whether a particular vector
length is supported.

__vq_to_bit() and __bit_to_vq() are not intended for use outside
these functions: now that these are exposed outside fpsimd.c, they
are prefixed with __ in order to provide an extra hint that they
are not intended for general-purpose use.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 arch/arm64/include/asm/fpsimd.h | 29 +++++++++++++++++++++++++++++
 arch/arm64/kernel/fpsimd.c      | 35 ++++++++---------------------------
 2 files changed, 37 insertions(+), 27 deletions(-)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index df7a143..ad6d2e4 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -24,10 +24,13 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/bitmap.h>
 #include <linux/build_bug.h>
+#include <linux/bug.h>
 #include <linux/cache.h>
 #include <linux/init.h>
 #include <linux/stddef.h>
+#include <linux/types.h>
 
 #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
 /* Masks for extracting the FPSR and FPCR from the FPSCR */
@@ -89,6 +92,32 @@ extern u64 read_zcr_features(void);
 
 extern int __ro_after_init sve_max_vl;
 extern int __ro_after_init sve_max_virtualisable_vl;
+/* Set of available vector lengths, as vq_to_bit(vq): */
+extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
+
+/*
+ * Helpers to translate bit indices in sve_vq_map to VQ values (and
+ * vice versa).  This allows find_next_bit() to be used to find the
+ * _maximum_ VQ not exceeding a certain value.
+ */
+static inline unsigned int __vq_to_bit(unsigned int vq)
+{
+	return SVE_VQ_MAX - vq;
+}
+
+static inline unsigned int __bit_to_vq(unsigned int bit)
+{
+	if (WARN_ON(bit >= SVE_VQ_MAX))
+		bit = SVE_VQ_MAX - 1;
+
+	return SVE_VQ_MAX - bit;
+}
+
+/* Ensure vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX before calling this function */
+static inline bool sve_vq_available(unsigned int vq)
+{
+	return test_bit(__vq_to_bit(vq), sve_vq_map);
+}
 
 #ifdef CONFIG_ARM64_SVE
 
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 8a93afa..577296b 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -136,7 +136,7 @@ static int sve_default_vl = -1;
 int __ro_after_init sve_max_vl = SVE_VL_MIN;
 int __ro_after_init sve_max_virtualisable_vl = SVE_VL_MIN;
 /* Set of available vector lengths, as vq_to_bit(vq): */
-static __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
+__ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
 /* Set of vector lengths present on at least one cpu: */
 static __ro_after_init DECLARE_BITMAP(sve_vq_partial_map, SVE_VQ_MAX);
 static void __percpu *efi_sve_state;
@@ -270,25 +270,6 @@ void fpsimd_save(void)
 }
 
 /*
- * Helpers to translate bit indices in sve_vq_map to VQ values (and
- * vice versa).  This allows find_next_bit() to be used to find the
- * _maximum_ VQ not exceeding a certain value.
- */
-
-static unsigned int vq_to_bit(unsigned int vq)
-{
-	return SVE_VQ_MAX - vq;
-}
-
-static unsigned int bit_to_vq(unsigned int bit)
-{
-	if (WARN_ON(bit >= SVE_VQ_MAX))
-		bit = SVE_VQ_MAX - 1;
-
-	return SVE_VQ_MAX - bit;
-}
-
-/*
  * All vector length selection from userspace comes through here.
  * We're on a slow path, so some sanity-checks are included.
  * If things go wrong there's a bug somewhere, but try to fall back to a
@@ -309,8 +290,8 @@ static unsigned int find_supported_vector_length(unsigned int vl)
 		vl = max_vl;
 
 	bit = find_next_bit(sve_vq_map, SVE_VQ_MAX,
-			    vq_to_bit(sve_vq_from_vl(vl)));
-	return sve_vl_from_vq(bit_to_vq(bit));
+			    __vq_to_bit(sve_vq_from_vl(vl)));
+	return sve_vl_from_vq(__bit_to_vq(bit));
 }
 
 #ifdef CONFIG_SYSCTL
@@ -648,7 +629,7 @@ static void sve_probe_vqs(DECLARE_BITMAP(map, SVE_VQ_MAX))
 		write_sysreg_s(zcr | (vq - 1), SYS_ZCR_EL1); /* self-syncing */
 		vl = sve_get_vl();
 		vq = sve_vq_from_vl(vl); /* skip intervening lengths */
-		set_bit(vq_to_bit(vq), map);
+		set_bit(__vq_to_bit(vq), map);
 	}
 }
 
@@ -717,7 +698,7 @@ int sve_verify_vq_map(void)
 	 * Mismatches above sve_max_virtualisable_vl are fine, since
 	 * no guest is allowed to configure ZCR_EL2.LEN to exceed this:
 	 */
-	if (sve_vl_from_vq(bit_to_vq(b)) <= sve_max_virtualisable_vl) {
+	if (sve_vl_from_vq(__bit_to_vq(b)) <= sve_max_virtualisable_vl) {
 		pr_warn("SVE: cpu%d: Unsupported vector length(s) present\n",
 			smp_processor_id());
 		return -EINVAL;
@@ -801,8 +782,8 @@ void __init sve_setup(void)
 	 * so sve_vq_map must have at least SVE_VQ_MIN set.
 	 * If something went wrong, at least try to patch it up:
 	 */
-	if (WARN_ON(!test_bit(vq_to_bit(SVE_VQ_MIN), sve_vq_map)))
-		set_bit(vq_to_bit(SVE_VQ_MIN), sve_vq_map);
+	if (WARN_ON(!test_bit(__vq_to_bit(SVE_VQ_MIN), sve_vq_map)))
+		set_bit(__vq_to_bit(SVE_VQ_MIN), sve_vq_map);
 
 	zcr = read_sanitised_ftr_reg(SYS_ZCR_EL1);
 	sve_max_vl = sve_vl_from_vq((zcr & ZCR_ELx_LEN_MASK) + 1);
@@ -831,7 +812,7 @@ void __init sve_setup(void)
 		/* No virtualisable VLs?  This is architecturally forbidden. */
 		sve_max_virtualisable_vl = SVE_VQ_MIN;
 	else /* b + 1 < SVE_VQ_MAX */
-		sve_max_virtualisable_vl = sve_vl_from_vq(bit_to_vq(b + 1));
+		sve_max_virtualisable_vl = sve_vl_from_vq(__bit_to_vq(b + 1));
 
 	if (sve_max_virtualisable_vl > sve_max_vl)
 		sve_max_virtualisable_vl = sve_max_vl;
-- 
2.1.4


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

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

* [PATCH v7 21/27] KVM: arm/arm64: Add hook for arch-specific KVM initialisation
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

This patch adds a kvm_arm_init_arch_resources() hook to perform
subarch-specific initialisation when starting up KVM.

This will be used in a subsequent patch for global SVE-related
setup on arm64.

No functional change.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 arch/arm/include/asm/kvm_host.h   | 2 ++
 arch/arm64/include/asm/kvm_host.h | 2 ++
 virt/kvm/arm/arm.c                | 4 ++++
 3 files changed, 8 insertions(+)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 770d732..a49ee01 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -53,6 +53,8 @@
 
 DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
 
+static inline int kvm_arm_init_arch_resources(void) { return 0; }
+
 u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
 int __attribute_const__ kvm_target_cpu(void);
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 205438a..3e89509 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -58,6 +58,8 @@
 
 DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
 
+static inline int kvm_arm_init_arch_resources(void) { return 0; }
+
 int __attribute_const__ kvm_target_cpu(void);
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
 int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext);
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 99c3738..c69e137 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -1664,6 +1664,10 @@ int kvm_arch_init(void *opaque)
 	if (err)
 		return err;
 
+	err = kvm_arm_init_arch_resources();
+	if (err)
+		return err;
+
 	if (!in_hyp_mode) {
 		err = init_hyp_mode();
 		if (err)
-- 
2.1.4

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

* [PATCH v7 21/27] KVM: arm/arm64: Add hook for arch-specific KVM initialisation
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

This patch adds a kvm_arm_init_arch_resources() hook to perform
subarch-specific initialisation when starting up KVM.

This will be used in a subsequent patch for global SVE-related
setup on arm64.

No functional change.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
---
 arch/arm/include/asm/kvm_host.h   | 2 ++
 arch/arm64/include/asm/kvm_host.h | 2 ++
 virt/kvm/arm/arm.c                | 4 ++++
 3 files changed, 8 insertions(+)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 770d732..a49ee01 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -53,6 +53,8 @@
 
 DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
 
+static inline int kvm_arm_init_arch_resources(void) { return 0; }
+
 u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
 int __attribute_const__ kvm_target_cpu(void);
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 205438a..3e89509 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -58,6 +58,8 @@
 
 DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
 
+static inline int kvm_arm_init_arch_resources(void) { return 0; }
+
 int __attribute_const__ kvm_target_cpu(void);
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
 int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext);
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 99c3738..c69e137 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -1664,6 +1664,10 @@ int kvm_arch_init(void *opaque)
 	if (err)
 		return err;
 
+	err = kvm_arm_init_arch_resources();
+	if (err)
+		return err;
+
 	if (!in_hyp_mode) {
 		err = init_hyp_mode();
 		if (err)
-- 
2.1.4


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

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

* [PATCH v7 22/27] KVM: arm/arm64: Add KVM_ARM_VCPU_FINALIZE ioctl
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

Some aspects of vcpu configuration may be too complex to be
completed inside KVM_ARM_VCPU_INIT.  Thus, there may be a
requirement for userspace to do some additional configuration
before various other ioctls will work in a consistent way.

In particular this will be the case for SVE, where userspace will
need to negotiate the set of vector lengths to be made available to
the guest before the vcpu becomes fully usable.

In order to provide an explicit way for userspace to confirm that
it has finished setting up a particular vcpu feature, this patch
adds a new ioctl KVM_ARM_VCPU_FINALIZE.

When userspace has opted into a feature that requires finalization,
typically by means of a feature flag passed to KVM_ARM_VCPU_INIT, a
matching call to KVM_ARM_VCPU_FINALIZE is now required before
KVM_RUN or KVM_GET_REG_LIST is allowed.  Individual features may
impose additional restrictions where appropriate.

No existing vcpu features are affected by this, so current
userspace implementations will continue to work exactly as before,
with no need to issue KVM_ARM_VCPU_FINALIZE.

As implemented in this patch, KVM_ARM_VCPU_FINALIZE is currently a
placeholder: no finalizable features exist yet, so ioctl is not
required and will always yield EINVAL.  Subsequent patches will add
the finalization logic to make use of this ioctl for SVE.

No functional change for existing userspace.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * Commit message, including subject line, rewritten.

   This patch is a rework of "KVM: arm/arm64: Add hook to finalize the
   vcpu configuration".  The old subject line and commit message no
   longer accurately described what the patch does.  However, the code
   is an evolution of the previous patch rather than a wholesale
   rewrite.

 * Added an explicit KVM_ARM_VCPU_FINALIZE ioctl, rather than just
   providing internal hooks in the kernel to finalize the vcpu
   configuration implicitly.  This allows userspace to confirm exactly
   when it has finished configuring the vcpu and is ready to use it.

   This results in simpler (and hopefully more maintainable) ioctl
   ordering rules.
---
 arch/arm/include/asm/kvm_host.h   |  4 ++++
 arch/arm64/include/asm/kvm_host.h |  4 ++++
 include/uapi/linux/kvm.h          |  3 +++
 virt/kvm/arm/arm.c                | 18 ++++++++++++++++++
 4 files changed, 29 insertions(+)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index a49ee01..e80cfc1 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -19,6 +19,7 @@
 #ifndef __ARM_KVM_HOST_H__
 #define __ARM_KVM_HOST_H__
 
+#include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/kvm_types.h>
 #include <asm/cputype.h>
@@ -411,4 +412,7 @@ static inline int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type)
 	return 0;
 }
 
+#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
+#define kvm_arm_vcpu_is_finalized(vcpu) true
+
 #endif /* __ARM_KVM_HOST_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 3e89509..98658f7 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -23,6 +23,7 @@
 #define __ARM64_KVM_HOST_H__
 
 #include <linux/bitmap.h>
+#include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/jump_label.h>
 #include <linux/kvm_types.h>
@@ -625,4 +626,7 @@ void kvm_arch_free_vm(struct kvm *kvm);
 
 int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type);
 
+#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
+#define kvm_arm_vcpu_is_finalized(vcpu) true
+
 #endif /* __ARM64_KVM_HOST_H__ */
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index dc77a5a..c3b8e7a 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1441,6 +1441,9 @@ struct kvm_enc_region {
 /* Available with KVM_CAP_HYPERV_CPUID */
 #define KVM_GET_SUPPORTED_HV_CPUID _IOWR(KVMIO, 0xc1, struct kvm_cpuid2)
 
+/* Available with KVM_CAP_ARM_SVE */
+#define KVM_ARM_VCPU_FINALIZE	  _IOW(KVMIO,  0xc2, int)
+
 /* Secure Encrypted Virtualization command */
 enum sev_cmd_id {
 	/* Guest initialization commands */
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index c69e137..9edbf0f 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -545,6 +545,9 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
 	if (likely(vcpu->arch.has_run_once))
 		return 0;
 
+	if (!kvm_arm_vcpu_is_finalized(vcpu))
+		return -EPERM;
+
 	vcpu->arch.has_run_once = true;
 
 	if (likely(irqchip_in_kernel(kvm))) {
@@ -1116,6 +1119,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 		if (unlikely(!kvm_vcpu_initialized(vcpu)))
 			break;
 
+		r = -EPERM;
+		if (!kvm_arm_vcpu_is_finalized(vcpu))
+			break;
+
 		r = -EFAULT;
 		if (copy_from_user(&reg_list, user_list, sizeof(reg_list)))
 			break;
@@ -1169,6 +1176,17 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 
 		return kvm_arm_vcpu_set_events(vcpu, &events);
 	}
+	case KVM_ARM_VCPU_FINALIZE: {
+		int what;
+
+		if (!kvm_vcpu_initialized(vcpu))
+			return -ENOEXEC;
+
+		if (get_user(what, (const int __user *)argp))
+			return -EFAULT;
+
+		return kvm_arm_vcpu_finalize(vcpu, what);
+	}
 	default:
 		r = -EINVAL;
 	}
-- 
2.1.4

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

* [PATCH v7 22/27] KVM: arm/arm64: Add KVM_ARM_VCPU_FINALIZE ioctl
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

Some aspects of vcpu configuration may be too complex to be
completed inside KVM_ARM_VCPU_INIT.  Thus, there may be a
requirement for userspace to do some additional configuration
before various other ioctls will work in a consistent way.

In particular this will be the case for SVE, where userspace will
need to negotiate the set of vector lengths to be made available to
the guest before the vcpu becomes fully usable.

In order to provide an explicit way for userspace to confirm that
it has finished setting up a particular vcpu feature, this patch
adds a new ioctl KVM_ARM_VCPU_FINALIZE.

When userspace has opted into a feature that requires finalization,
typically by means of a feature flag passed to KVM_ARM_VCPU_INIT, a
matching call to KVM_ARM_VCPU_FINALIZE is now required before
KVM_RUN or KVM_GET_REG_LIST is allowed.  Individual features may
impose additional restrictions where appropriate.

No existing vcpu features are affected by this, so current
userspace implementations will continue to work exactly as before,
with no need to issue KVM_ARM_VCPU_FINALIZE.

As implemented in this patch, KVM_ARM_VCPU_FINALIZE is currently a
placeholder: no finalizable features exist yet, so ioctl is not
required and will always yield EINVAL.  Subsequent patches will add
the finalization logic to make use of this ioctl for SVE.

No functional change for existing userspace.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * Commit message, including subject line, rewritten.

   This patch is a rework of "KVM: arm/arm64: Add hook to finalize the
   vcpu configuration".  The old subject line and commit message no
   longer accurately described what the patch does.  However, the code
   is an evolution of the previous patch rather than a wholesale
   rewrite.

 * Added an explicit KVM_ARM_VCPU_FINALIZE ioctl, rather than just
   providing internal hooks in the kernel to finalize the vcpu
   configuration implicitly.  This allows userspace to confirm exactly
   when it has finished configuring the vcpu and is ready to use it.

   This results in simpler (and hopefully more maintainable) ioctl
   ordering rules.
---
 arch/arm/include/asm/kvm_host.h   |  4 ++++
 arch/arm64/include/asm/kvm_host.h |  4 ++++
 include/uapi/linux/kvm.h          |  3 +++
 virt/kvm/arm/arm.c                | 18 ++++++++++++++++++
 4 files changed, 29 insertions(+)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index a49ee01..e80cfc1 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -19,6 +19,7 @@
 #ifndef __ARM_KVM_HOST_H__
 #define __ARM_KVM_HOST_H__
 
+#include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/kvm_types.h>
 #include <asm/cputype.h>
@@ -411,4 +412,7 @@ static inline int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type)
 	return 0;
 }
 
+#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
+#define kvm_arm_vcpu_is_finalized(vcpu) true
+
 #endif /* __ARM_KVM_HOST_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 3e89509..98658f7 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -23,6 +23,7 @@
 #define __ARM64_KVM_HOST_H__
 
 #include <linux/bitmap.h>
+#include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/jump_label.h>
 #include <linux/kvm_types.h>
@@ -625,4 +626,7 @@ void kvm_arch_free_vm(struct kvm *kvm);
 
 int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type);
 
+#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
+#define kvm_arm_vcpu_is_finalized(vcpu) true
+
 #endif /* __ARM64_KVM_HOST_H__ */
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index dc77a5a..c3b8e7a 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1441,6 +1441,9 @@ struct kvm_enc_region {
 /* Available with KVM_CAP_HYPERV_CPUID */
 #define KVM_GET_SUPPORTED_HV_CPUID _IOWR(KVMIO, 0xc1, struct kvm_cpuid2)
 
+/* Available with KVM_CAP_ARM_SVE */
+#define KVM_ARM_VCPU_FINALIZE	  _IOW(KVMIO,  0xc2, int)
+
 /* Secure Encrypted Virtualization command */
 enum sev_cmd_id {
 	/* Guest initialization commands */
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index c69e137..9edbf0f 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -545,6 +545,9 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
 	if (likely(vcpu->arch.has_run_once))
 		return 0;
 
+	if (!kvm_arm_vcpu_is_finalized(vcpu))
+		return -EPERM;
+
 	vcpu->arch.has_run_once = true;
 
 	if (likely(irqchip_in_kernel(kvm))) {
@@ -1116,6 +1119,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 		if (unlikely(!kvm_vcpu_initialized(vcpu)))
 			break;
 
+		r = -EPERM;
+		if (!kvm_arm_vcpu_is_finalized(vcpu))
+			break;
+
 		r = -EFAULT;
 		if (copy_from_user(&reg_list, user_list, sizeof(reg_list)))
 			break;
@@ -1169,6 +1176,17 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 
 		return kvm_arm_vcpu_set_events(vcpu, &events);
 	}
+	case KVM_ARM_VCPU_FINALIZE: {
+		int what;
+
+		if (!kvm_vcpu_initialized(vcpu))
+			return -ENOEXEC;
+
+		if (get_user(what, (const int __user *)argp))
+			return -EFAULT;
+
+		return kvm_arm_vcpu_finalize(vcpu, what);
+	}
 	default:
 		r = -EINVAL;
 	}
-- 
2.1.4


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

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

* [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
allow userspace to set and query the set of vector lengths visible
to the guest.

In the future, multiple register slices per SVE register may be
visible through the ioctl interface.  Once the set of slices has
been determined we would not be able to allow the vector length set
to be changed any more, in order to avoid userspace seeing
inconsistent sets of registers.  For this reason, this patch adds
support for explicit finalization of the SVE configuration via the
KVM_ARM_VCPU_FINALIZE ioctl.

Finalization is the proper place to allocate the SVE register state
storage in vcpu->arch.sve_state, so this patch adds that as
appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
was previously a no-op on arm64.

To simplify the logic for determining what vector lengths can be
supported, some code is added to KVM init to work this out, in the
kvm_arm_init_arch_resources() hook.

The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
Subsequent patches will allow SVE to be turned on for guest vcpus,
making it visible.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * [Julien Thierry] Delete overzealous BUILD_BUG_ON() checks.
   It also turns out that these could cause kernel build failures in
   some configurations, even though the checked condition is compile-
   time constant.

   Because of the way the affected functions are called, the checks
   are superfluous, so the simplest option is simply to get rid of
   them.

 * [Julien Thierry] Free vcpu->arch.sve_state (if any) in
   kvm_arch_vcpu_uninit() (which is currently a no-op).

   This was accidentally lost during a previous rebase.

 * Add kvm_arm_init_arch_resources() hook, and use it to probe SVE
   configuration for KVM, to avoid duplicating the logic elsewhere.
   We only need to do this once.

 * Move sve_state buffer allocation to kvm_arm_vcpu_finalize().

   As well as making the code more straightforward, this avoids the
   need to allocate memory in kvm_reset_vcpu(), the meat of which is
   non-preemptible since commit 358b28f09f0a ("arm/arm64: KVM: Allow a
   VCPU to fully reset itself").

   The refactoring means that if this has not been done by the time
   we hit KVM_RUN, then this allocation will happen on the
   kvm_arm_first_run_init() path, where preemption remains enabled.

 * Add a couple of comments in {get,set}_sve_reg() to make the handling
   of the KVM_REG_ARM64_SVE_VLS special case a little clearer.

 * Move mis-split rework to avoid put_user() being the correct size
   by accident in KVM_GET_REG_LIST to KVM: arm64: Enumerate SVE register
   indices for KVM_GET_REG_LIST.

 * Fix wrong WARN_ON() check sense when checking whether the
   implementation may needs move SVE register slices than KVM can
   support.

 * Fix erroneous setting of vcpu->arch.sve_max_vl based on stale loop
   control veriable vq.

 * Move definition of KVM_ARM_VCPU_SVE from KVM: arm64/sve: Allow
   userspace to enable SVE for vcpus.

 * Migrate to explicit finalization of the SVE configuration, using
   KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
---
 arch/arm64/include/asm/kvm_host.h |  15 +++--
 arch/arm64/include/uapi/asm/kvm.h |   5 ++
 arch/arm64/kvm/guest.c            | 114 +++++++++++++++++++++++++++++++++++++-
 arch/arm64/kvm/reset.c            |  89 +++++++++++++++++++++++++++++
 4 files changed, 215 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 98658f7..5475cc4 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -23,7 +23,6 @@
 #define __ARM64_KVM_HOST_H__
 
 #include <linux/bitmap.h>
-#include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/jump_label.h>
 #include <linux/kvm_types.h>
@@ -50,6 +49,7 @@
 
 #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
 
+/* Will be incremented when KVM_ARM_VCPU_SVE is fully implemented: */
 #define KVM_VCPU_MAX_FEATURES 4
 
 #define KVM_REQ_SLEEP \
@@ -59,10 +59,12 @@
 
 DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
 
-static inline int kvm_arm_init_arch_resources(void) { return 0; }
+extern unsigned int kvm_sve_max_vl;
+int kvm_arm_init_arch_resources(void);
 
 int __attribute_const__ kvm_target_cpu(void);
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
+void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu);
 int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext);
 void __extended_idmap_trampoline(phys_addr_t boot_pgd, phys_addr_t idmap_start);
 
@@ -353,6 +355,7 @@ struct kvm_vcpu_arch {
 #define KVM_ARM64_HOST_SVE_IN_USE	(1 << 3) /* backup for host TIF_SVE */
 #define KVM_ARM64_HOST_SVE_ENABLED	(1 << 4) /* SVE enabled for EL0 */
 #define KVM_ARM64_GUEST_HAS_SVE		(1 << 5) /* SVE exposed to guest */
+#define KVM_ARM64_VCPU_SVE_FINALIZED	(1 << 6) /* SVE config completed */
 
 #define vcpu_has_sve(vcpu) (system_supports_sve() && \
 			    ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))
@@ -525,7 +528,6 @@ static inline bool kvm_arch_requires_vhe(void)
 
 static inline void kvm_arch_hardware_unsetup(void) {}
 static inline void kvm_arch_sync_events(struct kvm *kvm) {}
-static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {}
 static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
 static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {}
 
@@ -626,7 +628,10 @@ void kvm_arch_free_vm(struct kvm *kvm);
 
 int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type);
 
-#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
-#define kvm_arm_vcpu_is_finalized(vcpu) true
+int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what);
+bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
+
+#define kvm_arm_vcpu_sve_finalized(vcpu) \
+	((vcpu)->arch.flags & KVM_ARM64_VCPU_SVE_FINALIZED)
 
 #endif /* __ARM64_KVM_HOST_H__ */
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index ced760c..6963b7e 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -102,6 +102,7 @@ struct kvm_regs {
 #define KVM_ARM_VCPU_EL1_32BIT		1 /* CPU running a 32bit VM */
 #define KVM_ARM_VCPU_PSCI_0_2		2 /* CPU uses PSCI v0.2 */
 #define KVM_ARM_VCPU_PMU_V3		3 /* Support guest PMUv3 */
+#define KVM_ARM_VCPU_SVE		4 /* enable SVE for this CPU */
 
 struct kvm_vcpu_init {
 	__u32 target;
@@ -243,6 +244,10 @@ struct kvm_vcpu_events {
 					 ((n) << 5) | (i))
 #define KVM_REG_ARM64_SVE_FFR(i)	KVM_REG_ARM64_SVE_PREG(16, i)
 
+/* Vector lengths pseudo-register: */
+#define KVM_REG_ARM64_SVE_VLS		(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
+					 KVM_REG_SIZE_U512 | 0xffff)
+
 /* Device Control API: ARM VGIC */
 #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 2aa80a5..086ab05 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -206,6 +206,73 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	return err;
 }
 
+#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64)
+#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64)
+
+static bool vq_present(
+	const u64 (*const vqs)[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)],
+	unsigned int vq)
+{
+	return (*vqs)[vq_word(vq)] & vq_mask(vq);
+}
+
+static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	unsigned int max_vq, vq;
+	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
+
+	if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl)))
+		return -EINVAL;
+
+	memset(vqs, 0, sizeof(vqs));
+
+	max_vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
+	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
+		if (sve_vq_available(vq))
+			vqs[vq_word(vq)] |= vq_mask(vq);
+
+	if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	unsigned int max_vq, vq;
+	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
+
+	if (kvm_arm_vcpu_sve_finalized(vcpu))
+		return -EPERM; /* too late! */
+
+	if (WARN_ON(vcpu->arch.sve_state))
+		return -EINVAL;
+
+	if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs)))
+		return -EFAULT;
+
+	max_vq = 0;
+	for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq)
+		if (vq_present(&vqs, vq))
+			max_vq = vq;
+
+	if (max_vq > sve_vq_from_vl(kvm_sve_max_vl))
+		return -EINVAL;
+
+	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
+		if (vq_present(&vqs, vq) != sve_vq_available(vq))
+			return -EINVAL;
+
+	/* Can't run with no vector lengths at all: */
+	if (max_vq < SVE_VQ_MIN)
+		return -EINVAL;
+
+	/* vcpu->arch.sve_state will be alloc'd by kvm_vcpu_finalize_sve() */
+	vcpu->arch.sve_max_vl = sve_vl_from_vq(max_vq);
+
+	return 0;
+}
+
 #define SVE_REG_SLICE_SHIFT	0
 #define SVE_REG_SLICE_BITS	5
 #define SVE_REG_ID_SHIFT	(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS)
@@ -296,7 +363,19 @@ static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	struct sve_state_reg_region region;
 	char __user *uptr = (char __user *)reg->addr;
 
-	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
+	if (!vcpu_has_sve(vcpu))
+		return -ENOENT;
+
+	/* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */
+	if (reg->id == KVM_REG_ARM64_SVE_VLS)
+		return get_sve_vls(vcpu, reg);
+
+	/* Otherwise, reg is an architectural SVE register... */
+
+	if (!kvm_arm_vcpu_sve_finalized(vcpu))
+		return -EPERM;
+
+	if (sve_reg_to_region(&region, vcpu, reg))
 		return -ENOENT;
 
 	if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
@@ -312,7 +391,19 @@ static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	struct sve_state_reg_region region;
 	const char __user *uptr = (const char __user *)reg->addr;
 
-	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
+	if (!vcpu_has_sve(vcpu))
+		return -ENOENT;
+
+	/* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */
+	if (reg->id == KVM_REG_ARM64_SVE_VLS)
+		return set_sve_vls(vcpu, reg);
+
+	/* Otherwise, reg is an architectural SVE register... */
+
+	if (!kvm_arm_vcpu_sve_finalized(vcpu))
+		return -EPERM;
+
+	if (sve_reg_to_region(&region, vcpu, reg))
 		return -ENOENT;
 
 	if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
@@ -426,7 +517,11 @@ static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
 	if (!vcpu_has_sve(vcpu))
 		return 0;
 
-	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */);
+	/* Policed by KVM_GET_REG_LIST: */
+	WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
+
+	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */)
+		+ 1; /* KVM_REG_ARM64_SVE_VLS */
 }
 
 static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
@@ -441,6 +536,19 @@ static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
 	if (!vcpu_has_sve(vcpu))
 		return 0;
 
+	/* Policed by KVM_GET_REG_LIST: */
+	WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
+
+	/*
+	 * Enumerate this first, so that userspace can save/restore in
+	 * the order reported by KVM_GET_REG_LIST:
+	 */
+	reg = KVM_REG_ARM64_SVE_VLS;
+	if (put_user(reg, uindices++))
+		return -EFAULT;
+
+	++num_regs;
+
 	for (i = 0; i < slices; i++) {
 		for (n = 0; n < SVE_NUM_ZREGS; n++) {
 			reg = KVM_REG_ARM64_SVE_ZREG(n, i);
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index f16a5f8..e7f9c06 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -23,11 +23,14 @@
 #include <linux/kvm_host.h>
 #include <linux/kvm.h>
 #include <linux/hw_breakpoint.h>
+#include <linux/slab.h>
+#include <linux/types.h>
 
 #include <kvm/arm_arch_timer.h>
 
 #include <asm/cpufeature.h>
 #include <asm/cputype.h>
+#include <asm/fpsimd.h>
 #include <asm/ptrace.h>
 #include <asm/kvm_arm.h>
 #include <asm/kvm_asm.h>
@@ -99,6 +102,92 @@ int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 	return r;
 }
 
+unsigned int kvm_sve_max_vl;
+
+int kvm_arm_init_arch_resources(void)
+{
+	if (system_supports_sve()) {
+		kvm_sve_max_vl = sve_max_virtualisable_vl;
+
+		/*
+		 * The get_sve_reg()/set_sve_reg() ioctl interface will need
+		 * to be extended with multiple register slice support in
+		 * order to support vector lengths greater than
+		 * SVE_VL_ARCH_MAX:
+		 */
+		if (WARN_ON(kvm_sve_max_vl > SVE_VL_ARCH_MAX))
+			kvm_sve_max_vl = SVE_VL_ARCH_MAX;
+
+		/*
+		 * Don't even try to make use of vector lengths that
+		 * aren't available on all CPUs, for now:
+		 */
+		if (kvm_sve_max_vl < sve_max_vl)
+			pr_warn("KVM: SVE vector length for guests limited to %u bytes\n",
+				kvm_sve_max_vl);
+	}
+
+	return 0;
+}
+
+/*
+ * Finalize vcpu's maximum SVE vector length, allocating
+ * vcpu->arch.sve_state as necessary.
+ */
+static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
+{
+	void *buf;
+	unsigned int vl;
+
+	vl = vcpu->arch.sve_max_vl;
+
+	/*
+	 * Resposibility for these properties is shared between
+	 * kvm_arm_init_arch_resources(), kvm_vcpu_enable_sve() and
+	 * set_sve_vls().  Double-check here just to be sure:
+	 */
+	if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl ||
+		    vl > SVE_VL_ARCH_MAX))
+		return -EIO;
+
+	buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	vcpu->arch.sve_state = buf;
+	vcpu->arch.flags |= KVM_ARM64_VCPU_SVE_FINALIZED;
+	return 0;
+}
+
+int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what)
+{
+	switch (what) {
+	case KVM_ARM_VCPU_SVE:
+		if (!vcpu_has_sve(vcpu))
+			return -EINVAL;
+
+		if (kvm_arm_vcpu_sve_finalized(vcpu))
+			return -EPERM;
+
+		return kvm_vcpu_finalize_sve(vcpu);
+	}
+
+	return -EINVAL;
+}
+
+bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu)
+{
+	if (vcpu_has_sve(vcpu) && !kvm_arm_vcpu_sve_finalized(vcpu))
+		return false;
+
+	return true;
+}
+
+void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+	kfree(vcpu->arch.sve_state);
+}
+
 /**
  * kvm_reset_vcpu - sets core registers and sys_regs to reset value
  * @vcpu: The VCPU pointer
-- 
2.1.4

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

* [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
allow userspace to set and query the set of vector lengths visible
to the guest.

In the future, multiple register slices per SVE register may be
visible through the ioctl interface.  Once the set of slices has
been determined we would not be able to allow the vector length set
to be changed any more, in order to avoid userspace seeing
inconsistent sets of registers.  For this reason, this patch adds
support for explicit finalization of the SVE configuration via the
KVM_ARM_VCPU_FINALIZE ioctl.

Finalization is the proper place to allocate the SVE register state
storage in vcpu->arch.sve_state, so this patch adds that as
appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
was previously a no-op on arm64.

To simplify the logic for determining what vector lengths can be
supported, some code is added to KVM init to work this out, in the
kvm_arm_init_arch_resources() hook.

The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
Subsequent patches will allow SVE to be turned on for guest vcpus,
making it visible.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * [Julien Thierry] Delete overzealous BUILD_BUG_ON() checks.
   It also turns out that these could cause kernel build failures in
   some configurations, even though the checked condition is compile-
   time constant.

   Because of the way the affected functions are called, the checks
   are superfluous, so the simplest option is simply to get rid of
   them.

 * [Julien Thierry] Free vcpu->arch.sve_state (if any) in
   kvm_arch_vcpu_uninit() (which is currently a no-op).

   This was accidentally lost during a previous rebase.

 * Add kvm_arm_init_arch_resources() hook, and use it to probe SVE
   configuration for KVM, to avoid duplicating the logic elsewhere.
   We only need to do this once.

 * Move sve_state buffer allocation to kvm_arm_vcpu_finalize().

   As well as making the code more straightforward, this avoids the
   need to allocate memory in kvm_reset_vcpu(), the meat of which is
   non-preemptible since commit 358b28f09f0a ("arm/arm64: KVM: Allow a
   VCPU to fully reset itself").

   The refactoring means that if this has not been done by the time
   we hit KVM_RUN, then this allocation will happen on the
   kvm_arm_first_run_init() path, where preemption remains enabled.

 * Add a couple of comments in {get,set}_sve_reg() to make the handling
   of the KVM_REG_ARM64_SVE_VLS special case a little clearer.

 * Move mis-split rework to avoid put_user() being the correct size
   by accident in KVM_GET_REG_LIST to KVM: arm64: Enumerate SVE register
   indices for KVM_GET_REG_LIST.

 * Fix wrong WARN_ON() check sense when checking whether the
   implementation may needs move SVE register slices than KVM can
   support.

 * Fix erroneous setting of vcpu->arch.sve_max_vl based on stale loop
   control veriable vq.

 * Move definition of KVM_ARM_VCPU_SVE from KVM: arm64/sve: Allow
   userspace to enable SVE for vcpus.

 * Migrate to explicit finalization of the SVE configuration, using
   KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
---
 arch/arm64/include/asm/kvm_host.h |  15 +++--
 arch/arm64/include/uapi/asm/kvm.h |   5 ++
 arch/arm64/kvm/guest.c            | 114 +++++++++++++++++++++++++++++++++++++-
 arch/arm64/kvm/reset.c            |  89 +++++++++++++++++++++++++++++
 4 files changed, 215 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 98658f7..5475cc4 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -23,7 +23,6 @@
 #define __ARM64_KVM_HOST_H__
 
 #include <linux/bitmap.h>
-#include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/jump_label.h>
 #include <linux/kvm_types.h>
@@ -50,6 +49,7 @@
 
 #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
 
+/* Will be incremented when KVM_ARM_VCPU_SVE is fully implemented: */
 #define KVM_VCPU_MAX_FEATURES 4
 
 #define KVM_REQ_SLEEP \
@@ -59,10 +59,12 @@
 
 DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
 
-static inline int kvm_arm_init_arch_resources(void) { return 0; }
+extern unsigned int kvm_sve_max_vl;
+int kvm_arm_init_arch_resources(void);
 
 int __attribute_const__ kvm_target_cpu(void);
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
+void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu);
 int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext);
 void __extended_idmap_trampoline(phys_addr_t boot_pgd, phys_addr_t idmap_start);
 
@@ -353,6 +355,7 @@ struct kvm_vcpu_arch {
 #define KVM_ARM64_HOST_SVE_IN_USE	(1 << 3) /* backup for host TIF_SVE */
 #define KVM_ARM64_HOST_SVE_ENABLED	(1 << 4) /* SVE enabled for EL0 */
 #define KVM_ARM64_GUEST_HAS_SVE		(1 << 5) /* SVE exposed to guest */
+#define KVM_ARM64_VCPU_SVE_FINALIZED	(1 << 6) /* SVE config completed */
 
 #define vcpu_has_sve(vcpu) (system_supports_sve() && \
 			    ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))
@@ -525,7 +528,6 @@ static inline bool kvm_arch_requires_vhe(void)
 
 static inline void kvm_arch_hardware_unsetup(void) {}
 static inline void kvm_arch_sync_events(struct kvm *kvm) {}
-static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {}
 static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
 static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {}
 
@@ -626,7 +628,10 @@ void kvm_arch_free_vm(struct kvm *kvm);
 
 int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type);
 
-#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
-#define kvm_arm_vcpu_is_finalized(vcpu) true
+int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what);
+bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
+
+#define kvm_arm_vcpu_sve_finalized(vcpu) \
+	((vcpu)->arch.flags & KVM_ARM64_VCPU_SVE_FINALIZED)
 
 #endif /* __ARM64_KVM_HOST_H__ */
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index ced760c..6963b7e 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -102,6 +102,7 @@ struct kvm_regs {
 #define KVM_ARM_VCPU_EL1_32BIT		1 /* CPU running a 32bit VM */
 #define KVM_ARM_VCPU_PSCI_0_2		2 /* CPU uses PSCI v0.2 */
 #define KVM_ARM_VCPU_PMU_V3		3 /* Support guest PMUv3 */
+#define KVM_ARM_VCPU_SVE		4 /* enable SVE for this CPU */
 
 struct kvm_vcpu_init {
 	__u32 target;
@@ -243,6 +244,10 @@ struct kvm_vcpu_events {
 					 ((n) << 5) | (i))
 #define KVM_REG_ARM64_SVE_FFR(i)	KVM_REG_ARM64_SVE_PREG(16, i)
 
+/* Vector lengths pseudo-register: */
+#define KVM_REG_ARM64_SVE_VLS		(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
+					 KVM_REG_SIZE_U512 | 0xffff)
+
 /* Device Control API: ARM VGIC */
 #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 2aa80a5..086ab05 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -206,6 +206,73 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	return err;
 }
 
+#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64)
+#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64)
+
+static bool vq_present(
+	const u64 (*const vqs)[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)],
+	unsigned int vq)
+{
+	return (*vqs)[vq_word(vq)] & vq_mask(vq);
+}
+
+static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	unsigned int max_vq, vq;
+	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
+
+	if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl)))
+		return -EINVAL;
+
+	memset(vqs, 0, sizeof(vqs));
+
+	max_vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
+	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
+		if (sve_vq_available(vq))
+			vqs[vq_word(vq)] |= vq_mask(vq);
+
+	if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+	unsigned int max_vq, vq;
+	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
+
+	if (kvm_arm_vcpu_sve_finalized(vcpu))
+		return -EPERM; /* too late! */
+
+	if (WARN_ON(vcpu->arch.sve_state))
+		return -EINVAL;
+
+	if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs)))
+		return -EFAULT;
+
+	max_vq = 0;
+	for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq)
+		if (vq_present(&vqs, vq))
+			max_vq = vq;
+
+	if (max_vq > sve_vq_from_vl(kvm_sve_max_vl))
+		return -EINVAL;
+
+	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
+		if (vq_present(&vqs, vq) != sve_vq_available(vq))
+			return -EINVAL;
+
+	/* Can't run with no vector lengths at all: */
+	if (max_vq < SVE_VQ_MIN)
+		return -EINVAL;
+
+	/* vcpu->arch.sve_state will be alloc'd by kvm_vcpu_finalize_sve() */
+	vcpu->arch.sve_max_vl = sve_vl_from_vq(max_vq);
+
+	return 0;
+}
+
 #define SVE_REG_SLICE_SHIFT	0
 #define SVE_REG_SLICE_BITS	5
 #define SVE_REG_ID_SHIFT	(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS)
@@ -296,7 +363,19 @@ static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	struct sve_state_reg_region region;
 	char __user *uptr = (char __user *)reg->addr;
 
-	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
+	if (!vcpu_has_sve(vcpu))
+		return -ENOENT;
+
+	/* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */
+	if (reg->id == KVM_REG_ARM64_SVE_VLS)
+		return get_sve_vls(vcpu, reg);
+
+	/* Otherwise, reg is an architectural SVE register... */
+
+	if (!kvm_arm_vcpu_sve_finalized(vcpu))
+		return -EPERM;
+
+	if (sve_reg_to_region(&region, vcpu, reg))
 		return -ENOENT;
 
 	if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
@@ -312,7 +391,19 @@ static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
 	struct sve_state_reg_region region;
 	const char __user *uptr = (const char __user *)reg->addr;
 
-	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
+	if (!vcpu_has_sve(vcpu))
+		return -ENOENT;
+
+	/* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */
+	if (reg->id == KVM_REG_ARM64_SVE_VLS)
+		return set_sve_vls(vcpu, reg);
+
+	/* Otherwise, reg is an architectural SVE register... */
+
+	if (!kvm_arm_vcpu_sve_finalized(vcpu))
+		return -EPERM;
+
+	if (sve_reg_to_region(&region, vcpu, reg))
 		return -ENOENT;
 
 	if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
@@ -426,7 +517,11 @@ static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
 	if (!vcpu_has_sve(vcpu))
 		return 0;
 
-	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */);
+	/* Policed by KVM_GET_REG_LIST: */
+	WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
+
+	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */)
+		+ 1; /* KVM_REG_ARM64_SVE_VLS */
 }
 
 static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
@@ -441,6 +536,19 @@ static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
 	if (!vcpu_has_sve(vcpu))
 		return 0;
 
+	/* Policed by KVM_GET_REG_LIST: */
+	WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
+
+	/*
+	 * Enumerate this first, so that userspace can save/restore in
+	 * the order reported by KVM_GET_REG_LIST:
+	 */
+	reg = KVM_REG_ARM64_SVE_VLS;
+	if (put_user(reg, uindices++))
+		return -EFAULT;
+
+	++num_regs;
+
 	for (i = 0; i < slices; i++) {
 		for (n = 0; n < SVE_NUM_ZREGS; n++) {
 			reg = KVM_REG_ARM64_SVE_ZREG(n, i);
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index f16a5f8..e7f9c06 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -23,11 +23,14 @@
 #include <linux/kvm_host.h>
 #include <linux/kvm.h>
 #include <linux/hw_breakpoint.h>
+#include <linux/slab.h>
+#include <linux/types.h>
 
 #include <kvm/arm_arch_timer.h>
 
 #include <asm/cpufeature.h>
 #include <asm/cputype.h>
+#include <asm/fpsimd.h>
 #include <asm/ptrace.h>
 #include <asm/kvm_arm.h>
 #include <asm/kvm_asm.h>
@@ -99,6 +102,92 @@ int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 	return r;
 }
 
+unsigned int kvm_sve_max_vl;
+
+int kvm_arm_init_arch_resources(void)
+{
+	if (system_supports_sve()) {
+		kvm_sve_max_vl = sve_max_virtualisable_vl;
+
+		/*
+		 * The get_sve_reg()/set_sve_reg() ioctl interface will need
+		 * to be extended with multiple register slice support in
+		 * order to support vector lengths greater than
+		 * SVE_VL_ARCH_MAX:
+		 */
+		if (WARN_ON(kvm_sve_max_vl > SVE_VL_ARCH_MAX))
+			kvm_sve_max_vl = SVE_VL_ARCH_MAX;
+
+		/*
+		 * Don't even try to make use of vector lengths that
+		 * aren't available on all CPUs, for now:
+		 */
+		if (kvm_sve_max_vl < sve_max_vl)
+			pr_warn("KVM: SVE vector length for guests limited to %u bytes\n",
+				kvm_sve_max_vl);
+	}
+
+	return 0;
+}
+
+/*
+ * Finalize vcpu's maximum SVE vector length, allocating
+ * vcpu->arch.sve_state as necessary.
+ */
+static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
+{
+	void *buf;
+	unsigned int vl;
+
+	vl = vcpu->arch.sve_max_vl;
+
+	/*
+	 * Resposibility for these properties is shared between
+	 * kvm_arm_init_arch_resources(), kvm_vcpu_enable_sve() and
+	 * set_sve_vls().  Double-check here just to be sure:
+	 */
+	if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl ||
+		    vl > SVE_VL_ARCH_MAX))
+		return -EIO;
+
+	buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	vcpu->arch.sve_state = buf;
+	vcpu->arch.flags |= KVM_ARM64_VCPU_SVE_FINALIZED;
+	return 0;
+}
+
+int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what)
+{
+	switch (what) {
+	case KVM_ARM_VCPU_SVE:
+		if (!vcpu_has_sve(vcpu))
+			return -EINVAL;
+
+		if (kvm_arm_vcpu_sve_finalized(vcpu))
+			return -EPERM;
+
+		return kvm_vcpu_finalize_sve(vcpu);
+	}
+
+	return -EINVAL;
+}
+
+bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu)
+{
+	if (vcpu_has_sve(vcpu) && !kvm_arm_vcpu_sve_finalized(vcpu))
+		return false;
+
+	return true;
+}
+
+void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+	kfree(vcpu->arch.sve_state);
+}
+
 /**
  * kvm_reset_vcpu - sets core registers and sys_regs to reset value
  * @vcpu: The VCPU pointer
-- 
2.1.4


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

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

* [PATCH v7 24/27] KVM: arm64/sve: Allow userspace to enable SVE for vcpus
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

Now that all the pieces are in place, this patch offers a new flag
KVM_ARM_VCPU_SVE that userspace can pass to KVM_ARM_VCPU_INIT to
turn on SVE for the guest, on a per-vcpu basis.

As part of this, support for initialisation and reset of the SVE
vector length set and registers is added in the appropriate places,
as well as finally setting the KVM_ARM64_GUEST_HAS_SVE vcpu flag,
to turn on the SVE support code.

Allocation of the SVE register storage in vcpu->arch.sve_state is
deferred until the SVE configuration is finalized, by which time
the size of the registers is known.

Setting the vector lengths supported by the vcpu is considered
configuration of the emulated hardware rather than runtime
configuration, so no support is offered for changing the vector
lengths available to an existing vcpu across reset.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v6:

 * [Kristina Martšenko] Amend comments explaining the
   kvm_arm_vcpu_sve_finalized() versus !kvm_arm_vcpu_sve_finalized()
   cases in kvm_reset_vcpu().

   Actually, I've just deleted the comments, since if anything they're
   more confusing than the code they're supposed to describe.

Changes since v5:

 * Refactored to make the code flow clearer and clarify responsiblity
   for the various initialisation phases/checks.

   In place of the previous, confusingly dual-purpose kvm_reset_sve(),
   enabling and resetting of SVE are split into separate functions and
   called as appropriate from kvm_reset_vcpu().

   To avoid interactions with preempt_disable(), memory allocation is
   done in the kvm_vcpu_first_fun_init() path instead.  To achieve
   this, the SVE memory allocation is moved to kvm_arm_vcpu_finalize(),
   which now takes on the role of actually doing deferred setup instead
   of just setting a flag to indicate that the setup was done.

 * Add has_vhe() sanity-check into kvm_vcpu_enable_sve(), since it
   makes more sense here than when resetting the vcpu.

 * When checking for SVE finalization in kvm_reset_vcpu(), call the new
   SVE-specific function kvm_arm_vcpu_sve_finalized().  The new generic
   check kvm_arm_vcpu_is_finalized() is unnecessarily broad here: using
   the appropriate specific check makes the code more self-describing.

 * Definition of KVM_ARM_VCPU_SVE moved to KVM: arm64/sve: Add pseudo-
   register for the guest's vector lengths (which needs it for the
   KVM_ARM_VCPU_FINALIZE ioctl).
---
 arch/arm64/include/asm/kvm_host.h |  3 +--
 arch/arm64/kvm/reset.c            | 43 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 5475cc4..9d57cf8 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -49,8 +49,7 @@
 
 #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
 
-/* Will be incremented when KVM_ARM_VCPU_SVE is fully implemented: */
-#define KVM_VCPU_MAX_FEATURES 4
+#define KVM_VCPU_MAX_FEATURES 5
 
 #define KVM_REQ_SLEEP \
 	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index e7f9c06..32c5ac0 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -20,10 +20,12 @@
  */
 
 #include <linux/errno.h>
+#include <linux/kernel.h>
 #include <linux/kvm_host.h>
 #include <linux/kvm.h>
 #include <linux/hw_breakpoint.h>
 #include <linux/slab.h>
+#include <linux/string.h>
 #include <linux/types.h>
 
 #include <kvm/arm_arch_timer.h>
@@ -37,6 +39,7 @@
 #include <asm/kvm_coproc.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_mmu.h>
+#include <asm/virt.h>
 
 /* Maximum phys_shift supported for any VM on this host */
 static u32 kvm_ipa_limit;
@@ -130,6 +133,27 @@ int kvm_arm_init_arch_resources(void)
 	return 0;
 }
 
+static int kvm_vcpu_enable_sve(struct kvm_vcpu *vcpu)
+{
+	if (!system_supports_sve())
+		return -EINVAL;
+
+	/* Verify that KVM startup enforced this when SVE was detected: */
+	if (WARN_ON(!has_vhe()))
+		return -EINVAL;
+
+	vcpu->arch.sve_max_vl = kvm_sve_max_vl;
+
+	/*
+	 * Userspace can still customize the vector lengths by writing
+	 * KVM_REG_ARM64_SVE_VLS.  Allocation is deferred until
+	 * kvm_arm_vcpu_finalize(), which freezes the configuration.
+	 */
+	vcpu->arch.flags |= KVM_ARM64_GUEST_HAS_SVE;
+
+	return 0;
+}
+
 /*
  * Finalize vcpu's maximum SVE vector length, allocating
  * vcpu->arch.sve_state as necessary.
@@ -188,13 +212,20 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
 	kfree(vcpu->arch.sve_state);
 }
 
+static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
+{
+	if (vcpu_has_sve(vcpu))
+		memset(vcpu->arch.sve_state, 0, vcpu_sve_state_size(vcpu));
+}
+
 /**
  * kvm_reset_vcpu - sets core registers and sys_regs to reset value
  * @vcpu: The VCPU pointer
  *
  * This function finds the right table above and sets the registers on
  * the virtual CPU struct to their architecturally defined reset
- * values.
+ * values, except for registers whose reset is deferred until
+ * kvm_arm_vcpu_finalize().
  *
  * Note: This function can be called from two paths: The KVM_ARM_VCPU_INIT
  * ioctl or as part of handling a request issued by another VCPU in the PSCI
@@ -217,6 +248,16 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
 	if (loaded)
 		kvm_arch_vcpu_put(vcpu);
 
+	if (!kvm_arm_vcpu_sve_finalized(vcpu)) {
+		if (test_bit(KVM_ARM_VCPU_SVE, vcpu->arch.features)) {
+			ret = kvm_vcpu_enable_sve(vcpu);
+			if (ret)
+				goto out;
+		}
+	} else {
+		kvm_vcpu_reset_sve(vcpu);
+	}
+
 	switch (vcpu->arch.target) {
 	default:
 		if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) {
-- 
2.1.4

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

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

* [PATCH v7 24/27] KVM: arm64/sve: Allow userspace to enable SVE for vcpus
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

Now that all the pieces are in place, this patch offers a new flag
KVM_ARM_VCPU_SVE that userspace can pass to KVM_ARM_VCPU_INIT to
turn on SVE for the guest, on a per-vcpu basis.

As part of this, support for initialisation and reset of the SVE
vector length set and registers is added in the appropriate places,
as well as finally setting the KVM_ARM64_GUEST_HAS_SVE vcpu flag,
to turn on the SVE support code.

Allocation of the SVE register storage in vcpu->arch.sve_state is
deferred until the SVE configuration is finalized, by which time
the size of the registers is known.

Setting the vector lengths supported by the vcpu is considered
configuration of the emulated hardware rather than runtime
configuration, so no support is offered for changing the vector
lengths available to an existing vcpu across reset.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v6:

 * [Kristina Martšenko] Amend comments explaining the
   kvm_arm_vcpu_sve_finalized() versus !kvm_arm_vcpu_sve_finalized()
   cases in kvm_reset_vcpu().

   Actually, I've just deleted the comments, since if anything they're
   more confusing than the code they're supposed to describe.

Changes since v5:

 * Refactored to make the code flow clearer and clarify responsiblity
   for the various initialisation phases/checks.

   In place of the previous, confusingly dual-purpose kvm_reset_sve(),
   enabling and resetting of SVE are split into separate functions and
   called as appropriate from kvm_reset_vcpu().

   To avoid interactions with preempt_disable(), memory allocation is
   done in the kvm_vcpu_first_fun_init() path instead.  To achieve
   this, the SVE memory allocation is moved to kvm_arm_vcpu_finalize(),
   which now takes on the role of actually doing deferred setup instead
   of just setting a flag to indicate that the setup was done.

 * Add has_vhe() sanity-check into kvm_vcpu_enable_sve(), since it
   makes more sense here than when resetting the vcpu.

 * When checking for SVE finalization in kvm_reset_vcpu(), call the new
   SVE-specific function kvm_arm_vcpu_sve_finalized().  The new generic
   check kvm_arm_vcpu_is_finalized() is unnecessarily broad here: using
   the appropriate specific check makes the code more self-describing.

 * Definition of KVM_ARM_VCPU_SVE moved to KVM: arm64/sve: Add pseudo-
   register for the guest's vector lengths (which needs it for the
   KVM_ARM_VCPU_FINALIZE ioctl).
---
 arch/arm64/include/asm/kvm_host.h |  3 +--
 arch/arm64/kvm/reset.c            | 43 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 5475cc4..9d57cf8 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -49,8 +49,7 @@
 
 #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
 
-/* Will be incremented when KVM_ARM_VCPU_SVE is fully implemented: */
-#define KVM_VCPU_MAX_FEATURES 4
+#define KVM_VCPU_MAX_FEATURES 5
 
 #define KVM_REQ_SLEEP \
 	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index e7f9c06..32c5ac0 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -20,10 +20,12 @@
  */
 
 #include <linux/errno.h>
+#include <linux/kernel.h>
 #include <linux/kvm_host.h>
 #include <linux/kvm.h>
 #include <linux/hw_breakpoint.h>
 #include <linux/slab.h>
+#include <linux/string.h>
 #include <linux/types.h>
 
 #include <kvm/arm_arch_timer.h>
@@ -37,6 +39,7 @@
 #include <asm/kvm_coproc.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_mmu.h>
+#include <asm/virt.h>
 
 /* Maximum phys_shift supported for any VM on this host */
 static u32 kvm_ipa_limit;
@@ -130,6 +133,27 @@ int kvm_arm_init_arch_resources(void)
 	return 0;
 }
 
+static int kvm_vcpu_enable_sve(struct kvm_vcpu *vcpu)
+{
+	if (!system_supports_sve())
+		return -EINVAL;
+
+	/* Verify that KVM startup enforced this when SVE was detected: */
+	if (WARN_ON(!has_vhe()))
+		return -EINVAL;
+
+	vcpu->arch.sve_max_vl = kvm_sve_max_vl;
+
+	/*
+	 * Userspace can still customize the vector lengths by writing
+	 * KVM_REG_ARM64_SVE_VLS.  Allocation is deferred until
+	 * kvm_arm_vcpu_finalize(), which freezes the configuration.
+	 */
+	vcpu->arch.flags |= KVM_ARM64_GUEST_HAS_SVE;
+
+	return 0;
+}
+
 /*
  * Finalize vcpu's maximum SVE vector length, allocating
  * vcpu->arch.sve_state as necessary.
@@ -188,13 +212,20 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
 	kfree(vcpu->arch.sve_state);
 }
 
+static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
+{
+	if (vcpu_has_sve(vcpu))
+		memset(vcpu->arch.sve_state, 0, vcpu_sve_state_size(vcpu));
+}
+
 /**
  * kvm_reset_vcpu - sets core registers and sys_regs to reset value
  * @vcpu: The VCPU pointer
  *
  * This function finds the right table above and sets the registers on
  * the virtual CPU struct to their architecturally defined reset
- * values.
+ * values, except for registers whose reset is deferred until
+ * kvm_arm_vcpu_finalize().
  *
  * Note: This function can be called from two paths: The KVM_ARM_VCPU_INIT
  * ioctl or as part of handling a request issued by another VCPU in the PSCI
@@ -217,6 +248,16 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
 	if (loaded)
 		kvm_arch_vcpu_put(vcpu);
 
+	if (!kvm_arm_vcpu_sve_finalized(vcpu)) {
+		if (test_bit(KVM_ARM_VCPU_SVE, vcpu->arch.features)) {
+			ret = kvm_vcpu_enable_sve(vcpu);
+			if (ret)
+				goto out;
+		}
+	} else {
+		kvm_vcpu_reset_sve(vcpu);
+	}
+
 	switch (vcpu->arch.target) {
 	default:
 		if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) {
-- 
2.1.4


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

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

* [PATCH v7 25/27] KVM: arm64: Add a capability to advertise SVE support
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

To provide a uniform way to check for KVM SVE support amongst other
features, this patch adds a suitable capability KVM_CAP_ARM_SVE,
and reports it as present when SVE is available.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * [Julien Thierry] Strip out has_vhe() sanity-check, which wasn't in
   the most logical place, and anyway doesn't really belong in this
   patch.

   Moved to KVM: arm64/sve: Allow userspace to enable SVE for vcpus
   instead.
---
 arch/arm64/kvm/reset.c   | 3 +++
 include/uapi/linux/kvm.h | 1 +
 2 files changed, 4 insertions(+)

diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 32c5ac0..f13378d 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -98,6 +98,9 @@ int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 	case KVM_CAP_ARM_VM_IPA_SIZE:
 		r = kvm_ipa_limit;
 		break;
+	case KVM_CAP_ARM_SVE:
+		r = system_supports_sve();
+		break;
 	default:
 		r = 0;
 	}
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index c3b8e7a..1d56444 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -988,6 +988,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_ARM_VM_IPA_SIZE 165
 #define KVM_CAP_MANUAL_DIRTY_LOG_PROTECT 166
 #define KVM_CAP_HYPERV_CPUID 167
+#define KVM_CAP_ARM_SVE 168
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
-- 
2.1.4

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

* [PATCH v7 25/27] KVM: arm64: Add a capability to advertise SVE support
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

To provide a uniform way to check for KVM SVE support amongst other
features, this patch adds a suitable capability KVM_CAP_ARM_SVE,
and reports it as present when SVE is available.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

---

Changes since v5:

 * [Julien Thierry] Strip out has_vhe() sanity-check, which wasn't in
   the most logical place, and anyway doesn't really belong in this
   patch.

   Moved to KVM: arm64/sve: Allow userspace to enable SVE for vcpus
   instead.
---
 arch/arm64/kvm/reset.c   | 3 +++
 include/uapi/linux/kvm.h | 1 +
 2 files changed, 4 insertions(+)

diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 32c5ac0..f13378d 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -98,6 +98,9 @@ int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 	case KVM_CAP_ARM_VM_IPA_SIZE:
 		r = kvm_ipa_limit;
 		break;
+	case KVM_CAP_ARM_SVE:
+		r = system_supports_sve();
+		break;
 	default:
 		r = 0;
 	}
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index c3b8e7a..1d56444 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -988,6 +988,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_ARM_VM_IPA_SIZE 165
 #define KVM_CAP_MANUAL_DIRTY_LOG_PROTECT 166
 #define KVM_CAP_HYPERV_CPUID 167
+#define KVM_CAP_ARM_SVE 168
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
-- 
2.1.4


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

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

* [PATCH v7 26/27] KVM: Document errors for KVM_GET_ONE_REG and KVM_SET_ONE_REG
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

KVM_GET_ONE_REG and KVM_SET_ONE_REG return some error codes that
are not documented (but hopefully not surprising either).  To give
an indication of what these may mean, this patch adds brief
documentation.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 Documentation/virtual/kvm/api.txt | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 2d4f7ce..cd920dd 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -1871,6 +1871,9 @@ Architectures: all
 Type: vcpu ioctl
 Parameters: struct kvm_one_reg (in)
 Returns: 0 on success, negative value on failure
+Errors:
+  ENOENT:   no such register
+  EINVAL:   other errors, such as bad size encoding for a known register
 
 struct kvm_one_reg {
        __u64 id;
@@ -2192,6 +2195,9 @@ Architectures: all
 Type: vcpu ioctl
 Parameters: struct kvm_one_reg (in and out)
 Returns: 0 on success, negative value on failure
+Errors:
+  ENOENT:   no such register
+  EINVAL:   other errors, such as bad size encoding for a known register
 
 This ioctl allows to receive the value of a single register implemented
 in a vcpu. The register to read is indicated by the "id" field of the
-- 
2.1.4

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

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

* [PATCH v7 26/27] KVM: Document errors for KVM_GET_ONE_REG and KVM_SET_ONE_REG
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

KVM_GET_ONE_REG and KVM_SET_ONE_REG return some error codes that
are not documented (but hopefully not surprising either).  To give
an indication of what these may mean, this patch adds brief
documentation.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 Documentation/virtual/kvm/api.txt | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 2d4f7ce..cd920dd 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -1871,6 +1871,9 @@ Architectures: all
 Type: vcpu ioctl
 Parameters: struct kvm_one_reg (in)
 Returns: 0 on success, negative value on failure
+Errors:
+  ENOENT:   no such register
+  EINVAL:   other errors, such as bad size encoding for a known register
 
 struct kvm_one_reg {
        __u64 id;
@@ -2192,6 +2195,9 @@ Architectures: all
 Type: vcpu ioctl
 Parameters: struct kvm_one_reg (in and out)
 Returns: 0 on success, negative value on failure
+Errors:
+  ENOENT:   no such register
+  EINVAL:   other errors, such as bad size encoding for a known register
 
 This ioctl allows to receive the value of a single register implemented
 in a vcpu. The register to read is indicated by the "id" field of the
-- 
2.1.4


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

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

* [PATCH v7 27/27] KVM: arm64/sve: Document KVM API extensions for SVE
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 13:00   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

This patch adds sections to the KVM API documentation describing
the extensions for supporting the Scalable Vector Extension (SVE)
in guests.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>

---

Changes since v5:

 * Document KVM_ARM_VCPU_FINALIZE and its interactions with SVE.
---
 Documentation/virtual/kvm/api.txt | 132 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 129 insertions(+), 3 deletions(-)

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index cd920dd..68509de 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -1873,6 +1873,7 @@ Parameters: struct kvm_one_reg (in)
 Returns: 0 on success, negative value on failure
 Errors:
   ENOENT:   no such register
+  EPERM:    register access forbidden for architecture-dependent reasons
   EINVAL:   other errors, such as bad size encoding for a known register
 
 struct kvm_one_reg {
@@ -2127,13 +2128,20 @@ Specifically:
   0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
   0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
   0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
-  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]
-  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]
+  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]    (*)
+  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]    (*)
     ...
-  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]
+  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]   (*)
   0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
   0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
 
+(*) These encodings are not accepted for SVE-enabled vcpus.  See
+    KVM_ARM_VCPU_INIT.
+
+    The equivalent register content can be accessed via bits [127:0] of
+    the corresponding SVE Zn registers instead for vcpus that have SVE
+    enabled (see below).
+
 arm64 CCSIDR registers are demultiplexed by CSSELR value:
   0x6020 0000 0011 00 <csselr:8>
 
@@ -2143,6 +2151,61 @@ arm64 system registers have the following id bit patterns:
 arm64 firmware pseudo-registers have the following bit pattern:
   0x6030 0000 0014 <regno:16>
 
+arm64 SVE registers have the following bit patterns:
+  0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
+  0x6050 0000 0015 04 <n:4> <slice:5>   Pn bits[256*slice + 255 : 256*slice]
+  0x6050 0000 0015 060 <slice:5>        FFR bits[256*slice + 255 : 256*slice]
+  0x6060 0000 0015 ffff                 KVM_REG_ARM64_SVE_VLS pseudo-register
+
+Access to slices beyond the maximum vector length configured for the
+vcpu (i.e., where 16 * slice >= max_vq (**)) will fail with ENOENT.
+
+These registers are only accessible on vcpus for which SVE is enabled.
+See KVM_ARM_VCPU_INIT for details.
+
+In addition, except for KVM_REG_ARM64_SVE_VLS, these registers are not
+accessible until the vcpu's SVE configuration has been finalized
+using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).  See KVM_ARM_VCPU_INIT
+and KVM_ARM_VCPU_FINALIZE for more information about this procedure.
+
+KVM_REG_ARM64_SVE_VLS is a pseudo-register that allows the set of vector
+lengths supported by the vcpu to be discovered and configured by
+userspace.  When transferred to or from user memory via KVM_GET_ONE_REG
+or KVM_SET_ONE_REG, the value of this register is of type __u64[8], and
+encodes the set of vector lengths as follows:
+
+__u64 vector_lengths[8];
+
+if (vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX &&
+    ((vector_lengths[(vq - 1) / 64] >> ((vq - 1) % 64)) & 1))
+	/* Vector length vq * 16 bytes supported */
+else
+	/* Vector length vq * 16 bytes not supported */
+
+(**) The maximum value vq for which the above condition is true is
+max_vq.  This is the maximum vector length available to the guest on
+this vcpu, and determines which register slices are visible through
+this ioctl interface.
+
+(See Documentation/arm64/sve.txt for an explanation of the "vq"
+nomenclature.)
+
+KVM_REG_ARM64_SVE_VLS is only accessible after KVM_ARM_VCPU_INIT.
+KVM_ARM_VCPU_INIT initialises it to the best set of vector lengths that
+the host supports.
+
+Userspace may subsequently modify it if desired until the vcpu's SVE
+configuration is finalized using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
+
+Apart from simply removing all vector lengths from the host set that
+exceed some value, support for arbitrarily chosen sets of vector lengths
+is hardware-dependent and may not be available.  Attempting to configure
+an invalid set of vector lengths via KVM_SET_ONE_REG will fail with
+EINVAL.
+
+After the vcpu's SVE configuration is finalized, further attempts to
+write this register will fail with EPERM.
+
 
 MIPS registers are mapped using the lower 32 bits.  The upper 16 of that is
 the register group type:
@@ -2197,6 +2260,7 @@ Parameters: struct kvm_one_reg (in and out)
 Returns: 0 on success, negative value on failure
 Errors:
   ENOENT:   no such register
+  EPERM:    register access forbidden for architecture-dependent reasons
   EINVAL:   other errors, such as bad size encoding for a known register
 
 This ioctl allows to receive the value of a single register implemented
@@ -2690,6 +2754,33 @@ Possible features:
 	- KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
 	  Depends on KVM_CAP_ARM_PMU_V3.
 
+	- KVM_ARM_VCPU_SVE: Enables SVE for the CPU (arm64 only).
+	  Depends on KVM_CAP_ARM_SVE.
+	  Requires KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
+
+	   * After KVM_ARM_VCPU_INIT:
+
+	      - KVM_REG_ARM64_SVE_VLS may be read using KVM_GET_ONE_REG: the
+	        initial value of this pseudo-register indicates the best set of
+	        vector lengths possible for a vcpu on this host.
+
+	   * Before KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
+
+	      - KVM_RUN and KVM_GET_REG_LIST are not available;
+
+	      - KVM_GET_ONE_REG and KVM_SET_ONE_REG cannot be used to access
+	        the scalable archietctural SVE registers
+	        KVM_REG_ARM64_SVE_ZREG(), KVM_REG_ARM64_SVE_PREG() or
+	        KVM_REG_ARM64_SVE_FFR;
+
+	      - KVM_REG_ARM64_SVE_VLS may optionally be written using
+	        KVM_SET_ONE_REG, to modify the set of vector lengths available
+	        for the vcpu.
+
+	   * After KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
+
+	      - the KVM_REG_ARM64_SVE_VLS pseudo-register is immutable, and can
+	        no longer be written using KVM_SET_ONE_REG.
 
 4.83 KVM_ARM_PREFERRED_TARGET
 
@@ -3904,6 +3995,41 @@ number of valid entries in the 'entries' array, which is then filled.
 'index' and 'flags' fields in 'struct kvm_cpuid_entry2' are currently reserved,
 userspace should not expect to get any particular value there.
 
+4.119 KVM_ARM_VCPU_FINALIZE
+
+Capability: KVM_CAP_ARM_SVE
+Architectures: arm, arm64
+Type: vcpu ioctl
+Parameters: int feature (in)
+Returns: 0 on success, -1 on error
+Errors:
+  EPERM:     feature not enabled, needs configuration, or already finalized
+  EINVAL:    unknown feature
+
+Recognised values for feature:
+  arm64      KVM_ARM_VCPU_SVE
+
+Finalizes the configuration of the specified vcpu feature.
+
+The vcpu must already have been initialised, enabling the affected feature, by
+means of a successful KVM_ARM_VCPU_INIT call with the appropriate flag set in
+features[].
+
+For affected vcpu features, this is a mandatory step that must be performed
+before the vcpu is fully usable.
+
+Between KVM_ARM_VCPU_INIT and KVM_ARM_VCPU_FINALIZE, the feature may be
+configured by use of ioctls such as KVM_SET_ONE_REG.  The exact configuration
+that should be performaned and how to do it are feature-dependent.
+
+Other calls that depend on a particular feature being finalized, such as
+KVM_RUN, KVM_GET_REG_LIST, KVM_GET_ONE_REG and KVM_SET_ONE_REG, will fail with
+-EPERM unless the feature has already been finalized by means of a
+KVM_ARM_VCPU_FINALIZE call.
+
+See KVM_ARM_VCPU_INIT for details of vcpu features that require finalization
+using this ioctl.
+
 5. The kvm_run structure
 ------------------------
 
-- 
2.1.4

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

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

* [PATCH v7 27/27] KVM: arm64/sve: Document KVM API extensions for SVE
@ 2019-03-29 13:00   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 13:00 UTC (permalink / raw)
  To: kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, Alex Bennée, linux-arm-kernel

This patch adds sections to the KVM API documentation describing
the extensions for supporting the Scalable Vector Extension (SVE)
in guests.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>

---

Changes since v5:

 * Document KVM_ARM_VCPU_FINALIZE and its interactions with SVE.
---
 Documentation/virtual/kvm/api.txt | 132 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 129 insertions(+), 3 deletions(-)

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index cd920dd..68509de 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -1873,6 +1873,7 @@ Parameters: struct kvm_one_reg (in)
 Returns: 0 on success, negative value on failure
 Errors:
   ENOENT:   no such register
+  EPERM:    register access forbidden for architecture-dependent reasons
   EINVAL:   other errors, such as bad size encoding for a known register
 
 struct kvm_one_reg {
@@ -2127,13 +2128,20 @@ Specifically:
   0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
   0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
   0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
-  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]
-  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]
+  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]    (*)
+  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]    (*)
     ...
-  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]
+  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]   (*)
   0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
   0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
 
+(*) These encodings are not accepted for SVE-enabled vcpus.  See
+    KVM_ARM_VCPU_INIT.
+
+    The equivalent register content can be accessed via bits [127:0] of
+    the corresponding SVE Zn registers instead for vcpus that have SVE
+    enabled (see below).
+
 arm64 CCSIDR registers are demultiplexed by CSSELR value:
   0x6020 0000 0011 00 <csselr:8>
 
@@ -2143,6 +2151,61 @@ arm64 system registers have the following id bit patterns:
 arm64 firmware pseudo-registers have the following bit pattern:
   0x6030 0000 0014 <regno:16>
 
+arm64 SVE registers have the following bit patterns:
+  0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
+  0x6050 0000 0015 04 <n:4> <slice:5>   Pn bits[256*slice + 255 : 256*slice]
+  0x6050 0000 0015 060 <slice:5>        FFR bits[256*slice + 255 : 256*slice]
+  0x6060 0000 0015 ffff                 KVM_REG_ARM64_SVE_VLS pseudo-register
+
+Access to slices beyond the maximum vector length configured for the
+vcpu (i.e., where 16 * slice >= max_vq (**)) will fail with ENOENT.
+
+These registers are only accessible on vcpus for which SVE is enabled.
+See KVM_ARM_VCPU_INIT for details.
+
+In addition, except for KVM_REG_ARM64_SVE_VLS, these registers are not
+accessible until the vcpu's SVE configuration has been finalized
+using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).  See KVM_ARM_VCPU_INIT
+and KVM_ARM_VCPU_FINALIZE for more information about this procedure.
+
+KVM_REG_ARM64_SVE_VLS is a pseudo-register that allows the set of vector
+lengths supported by the vcpu to be discovered and configured by
+userspace.  When transferred to or from user memory via KVM_GET_ONE_REG
+or KVM_SET_ONE_REG, the value of this register is of type __u64[8], and
+encodes the set of vector lengths as follows:
+
+__u64 vector_lengths[8];
+
+if (vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX &&
+    ((vector_lengths[(vq - 1) / 64] >> ((vq - 1) % 64)) & 1))
+	/* Vector length vq * 16 bytes supported */
+else
+	/* Vector length vq * 16 bytes not supported */
+
+(**) The maximum value vq for which the above condition is true is
+max_vq.  This is the maximum vector length available to the guest on
+this vcpu, and determines which register slices are visible through
+this ioctl interface.
+
+(See Documentation/arm64/sve.txt for an explanation of the "vq"
+nomenclature.)
+
+KVM_REG_ARM64_SVE_VLS is only accessible after KVM_ARM_VCPU_INIT.
+KVM_ARM_VCPU_INIT initialises it to the best set of vector lengths that
+the host supports.
+
+Userspace may subsequently modify it if desired until the vcpu's SVE
+configuration is finalized using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
+
+Apart from simply removing all vector lengths from the host set that
+exceed some value, support for arbitrarily chosen sets of vector lengths
+is hardware-dependent and may not be available.  Attempting to configure
+an invalid set of vector lengths via KVM_SET_ONE_REG will fail with
+EINVAL.
+
+After the vcpu's SVE configuration is finalized, further attempts to
+write this register will fail with EPERM.
+
 
 MIPS registers are mapped using the lower 32 bits.  The upper 16 of that is
 the register group type:
@@ -2197,6 +2260,7 @@ Parameters: struct kvm_one_reg (in and out)
 Returns: 0 on success, negative value on failure
 Errors:
   ENOENT:   no such register
+  EPERM:    register access forbidden for architecture-dependent reasons
   EINVAL:   other errors, such as bad size encoding for a known register
 
 This ioctl allows to receive the value of a single register implemented
@@ -2690,6 +2754,33 @@ Possible features:
 	- KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
 	  Depends on KVM_CAP_ARM_PMU_V3.
 
+	- KVM_ARM_VCPU_SVE: Enables SVE for the CPU (arm64 only).
+	  Depends on KVM_CAP_ARM_SVE.
+	  Requires KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
+
+	   * After KVM_ARM_VCPU_INIT:
+
+	      - KVM_REG_ARM64_SVE_VLS may be read using KVM_GET_ONE_REG: the
+	        initial value of this pseudo-register indicates the best set of
+	        vector lengths possible for a vcpu on this host.
+
+	   * Before KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
+
+	      - KVM_RUN and KVM_GET_REG_LIST are not available;
+
+	      - KVM_GET_ONE_REG and KVM_SET_ONE_REG cannot be used to access
+	        the scalable archietctural SVE registers
+	        KVM_REG_ARM64_SVE_ZREG(), KVM_REG_ARM64_SVE_PREG() or
+	        KVM_REG_ARM64_SVE_FFR;
+
+	      - KVM_REG_ARM64_SVE_VLS may optionally be written using
+	        KVM_SET_ONE_REG, to modify the set of vector lengths available
+	        for the vcpu.
+
+	   * After KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
+
+	      - the KVM_REG_ARM64_SVE_VLS pseudo-register is immutable, and can
+	        no longer be written using KVM_SET_ONE_REG.
 
 4.83 KVM_ARM_PREFERRED_TARGET
 
@@ -3904,6 +3995,41 @@ number of valid entries in the 'entries' array, which is then filled.
 'index' and 'flags' fields in 'struct kvm_cpuid_entry2' are currently reserved,
 userspace should not expect to get any particular value there.
 
+4.119 KVM_ARM_VCPU_FINALIZE
+
+Capability: KVM_CAP_ARM_SVE
+Architectures: arm, arm64
+Type: vcpu ioctl
+Parameters: int feature (in)
+Returns: 0 on success, -1 on error
+Errors:
+  EPERM:     feature not enabled, needs configuration, or already finalized
+  EINVAL:    unknown feature
+
+Recognised values for feature:
+  arm64      KVM_ARM_VCPU_SVE
+
+Finalizes the configuration of the specified vcpu feature.
+
+The vcpu must already have been initialised, enabling the affected feature, by
+means of a successful KVM_ARM_VCPU_INIT call with the appropriate flag set in
+features[].
+
+For affected vcpu features, this is a mandatory step that must be performed
+before the vcpu is fully usable.
+
+Between KVM_ARM_VCPU_INIT and KVM_ARM_VCPU_FINALIZE, the feature may be
+configured by use of ioctls such as KVM_SET_ONE_REG.  The exact configuration
+that should be performaned and how to do it are feature-dependent.
+
+Other calls that depend on a particular feature being finalized, such as
+KVM_RUN, KVM_GET_REG_LIST, KVM_GET_ONE_REG and KVM_SET_ONE_REG, will fail with
+-EPERM unless the feature has already been finalized by means of a
+KVM_ARM_VCPU_FINALIZE call.
+
+See KVM_ARM_VCPU_INIT for details of vcpu features that require finalization
+using this ioctl.
+
 5. The kvm_run structure
 ------------------------
 
-- 
2.1.4


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

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

* Re: [PATCH v7 00/27] KVM: arm64: SVE guest support
  2019-03-29 13:00 ` Dave Martin
@ 2019-03-29 14:56   ` Marc Zyngier
  -1 siblings, 0 replies; 224+ messages in thread
From: Marc Zyngier @ 2019-03-29 14:56 UTC (permalink / raw)
  To: Dave Martin, kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

Hi Dave,

On 29/03/2019 13:00, Dave Martin wrote:
> This series implements support for allowing KVM guests to use the Arm
> Scalable Vector Extension (SVE), superseding the previous v6 series [1].
> 
> The patches are also available on a branch for reviewer convenience. [2]
> 
> The patches are based on v5.1-rc2.
> 
> This series addresses a couple of minor review comments received on v6
> and otherwise applies reviewer tags only.  The code differences
> between v6 and this series consist of minor cosmetic fixups only.
> 
> Draft kvmtool patches were posted separately [3], [4].
> 
> For a description of minor updates, see the individual patches.
> 
> 
> Thanks go to Julien Thierry and Julian Grall for their review efforts,
> and to Zhang Lei for testing the series -- many thanks for their help
> in getting the series to this point!
> 
> 
> Reviewers' attention is drawn to the following patches, which have no
> Reviewed-by/Acked-by.  Please take a look if you have a moment.
> 
>  * Patch 11 (KVM: arm64: Support runtime sysreg visibility filtering)
> 
>    Previously Reviewed-by Julien Thierry, but this version of the
>    patch contains some minor rework suggested by Mark Rutland during
>    the v5 review [5].
> 
>  * Patch 15 (KVM: arm64: Add missing #include of <linux/string.h>
>    in guest.c)
> 
>    (Trivial patch.)
> 
>  * Patch 26: (KVM: Document errors for KVM_GET_ONE_REG and
>    KVM_SET_ONE_REG)
> 
>    (Documentation only.)
> 
>  * Patch 27: KVM: arm64/sve: Document KVM API extensions for SVE
> 
>    (Documentation only.)

In order to get people to test this a bit more, I've now pushed this
series into -next. I'm pretty confident that it won't break a thing, but
better safe than sorry. I also expect any fix to be pushed on top of
this series.

This doesn't mean that the review is over, quite the opposite. I intend
to go over it once more, and I'd like other people to do the same
(specially anyone looking at implementing the required support in QEMU).

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v7 00/27] KVM: arm64: SVE guest support
@ 2019-03-29 14:56   ` Marc Zyngier
  0 siblings, 0 replies; 224+ messages in thread
From: Marc Zyngier @ 2019-03-29 14:56 UTC (permalink / raw)
  To: Dave Martin, kvmarm
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Catalin Marinas, Will Deacon, Zhang Lei,
	Julien Grall, Alex Bennée, linux-arm-kernel

Hi Dave,

On 29/03/2019 13:00, Dave Martin wrote:
> This series implements support for allowing KVM guests to use the Arm
> Scalable Vector Extension (SVE), superseding the previous v6 series [1].
> 
> The patches are also available on a branch for reviewer convenience. [2]
> 
> The patches are based on v5.1-rc2.
> 
> This series addresses a couple of minor review comments received on v6
> and otherwise applies reviewer tags only.  The code differences
> between v6 and this series consist of minor cosmetic fixups only.
> 
> Draft kvmtool patches were posted separately [3], [4].
> 
> For a description of minor updates, see the individual patches.
> 
> 
> Thanks go to Julien Thierry and Julian Grall for their review efforts,
> and to Zhang Lei for testing the series -- many thanks for their help
> in getting the series to this point!
> 
> 
> Reviewers' attention is drawn to the following patches, which have no
> Reviewed-by/Acked-by.  Please take a look if you have a moment.
> 
>  * Patch 11 (KVM: arm64: Support runtime sysreg visibility filtering)
> 
>    Previously Reviewed-by Julien Thierry, but this version of the
>    patch contains some minor rework suggested by Mark Rutland during
>    the v5 review [5].
> 
>  * Patch 15 (KVM: arm64: Add missing #include of <linux/string.h>
>    in guest.c)
> 
>    (Trivial patch.)
> 
>  * Patch 26: (KVM: Document errors for KVM_GET_ONE_REG and
>    KVM_SET_ONE_REG)
> 
>    (Documentation only.)
> 
>  * Patch 27: KVM: arm64/sve: Document KVM API extensions for SVE
> 
>    (Documentation only.)

In order to get people to test this a bit more, I've now pushed this
series into -next. I'm pretty confident that it won't break a thing, but
better safe than sorry. I also expect any fix to be pushed on top of
this series.

This doesn't mean that the review is over, quite the opposite. I intend
to go over it once more, and I'd like other people to do the same
(specially anyone looking at implementing the required support in QEMU).

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 00/27] KVM: arm64: SVE guest support
  2019-03-29 14:56   ` Marc Zyngier
@ 2019-03-29 15:06     ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 15:06 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 02:56:36PM +0000, Marc Zyngier wrote:
> Hi Dave,
> 
> On 29/03/2019 13:00, Dave Martin wrote:
> > This series implements support for allowing KVM guests to use the Arm
> > Scalable Vector Extension (SVE), superseding the previous v6 series [1].
> > 
> > The patches are also available on a branch for reviewer convenience. [2]
> > 
> > The patches are based on v5.1-rc2.
> > 
> > This series addresses a couple of minor review comments received on v6
> > and otherwise applies reviewer tags only.  The code differences
> > between v6 and this series consist of minor cosmetic fixups only.
> > 
> > Draft kvmtool patches were posted separately [3], [4].
> > 
> > For a description of minor updates, see the individual patches.
> > 
> > 
> > Thanks go to Julien Thierry and Julian Grall for their review efforts,
> > and to Zhang Lei for testing the series -- many thanks for their help
> > in getting the series to this point!
> > 
> > 
> > Reviewers' attention is drawn to the following patches, which have no
> > Reviewed-by/Acked-by.  Please take a look if you have a moment.
> > 
> >  * Patch 11 (KVM: arm64: Support runtime sysreg visibility filtering)
> > 
> >    Previously Reviewed-by Julien Thierry, but this version of the
> >    patch contains some minor rework suggested by Mark Rutland during
> >    the v5 review [5].
> > 
> >  * Patch 15 (KVM: arm64: Add missing #include of <linux/string.h>
> >    in guest.c)
> > 
> >    (Trivial patch.)
> > 
> >  * Patch 26: (KVM: Document errors for KVM_GET_ONE_REG and
> >    KVM_SET_ONE_REG)
> > 
> >    (Documentation only.)
> > 
> >  * Patch 27: KVM: arm64/sve: Document KVM API extensions for SVE
> > 
> >    (Documentation only.)
> 
> In order to get people to test this a bit more, I've now pushed this
> series into -next. I'm pretty confident that it won't break a thing, but
> better safe than sorry. I also expect any fix to be pushed on top of
> this series.
> 
> This doesn't mean that the review is over, quite the opposite. I intend
> to go over it once more, and I'd like other people to do the same
> (specially anyone looking at implementing the required support in QEMU).

Agreed, thanks for pushing it to next.

I'll continue testing and await further review from people.

Cheers
---Dave

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

* Re: [PATCH v7 00/27] KVM: arm64: SVE guest support
@ 2019-03-29 15:06     ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-03-29 15:06 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Catalin Marinas, Will Deacon, Zhang Lei,
	Julien Grall, Alex Bennée, kvmarm, linux-arm-kernel

On Fri, Mar 29, 2019 at 02:56:36PM +0000, Marc Zyngier wrote:
> Hi Dave,
> 
> On 29/03/2019 13:00, Dave Martin wrote:
> > This series implements support for allowing KVM guests to use the Arm
> > Scalable Vector Extension (SVE), superseding the previous v6 series [1].
> > 
> > The patches are also available on a branch for reviewer convenience. [2]
> > 
> > The patches are based on v5.1-rc2.
> > 
> > This series addresses a couple of minor review comments received on v6
> > and otherwise applies reviewer tags only.  The code differences
> > between v6 and this series consist of minor cosmetic fixups only.
> > 
> > Draft kvmtool patches were posted separately [3], [4].
> > 
> > For a description of minor updates, see the individual patches.
> > 
> > 
> > Thanks go to Julien Thierry and Julian Grall for their review efforts,
> > and to Zhang Lei for testing the series -- many thanks for their help
> > in getting the series to this point!
> > 
> > 
> > Reviewers' attention is drawn to the following patches, which have no
> > Reviewed-by/Acked-by.  Please take a look if you have a moment.
> > 
> >  * Patch 11 (KVM: arm64: Support runtime sysreg visibility filtering)
> > 
> >    Previously Reviewed-by Julien Thierry, but this version of the
> >    patch contains some minor rework suggested by Mark Rutland during
> >    the v5 review [5].
> > 
> >  * Patch 15 (KVM: arm64: Add missing #include of <linux/string.h>
> >    in guest.c)
> > 
> >    (Trivial patch.)
> > 
> >  * Patch 26: (KVM: Document errors for KVM_GET_ONE_REG and
> >    KVM_SET_ONE_REG)
> > 
> >    (Documentation only.)
> > 
> >  * Patch 27: KVM: arm64/sve: Document KVM API extensions for SVE
> > 
> >    (Documentation only.)
> 
> In order to get people to test this a bit more, I've now pushed this
> series into -next. I'm pretty confident that it won't break a thing, but
> better safe than sorry. I also expect any fix to be pushed on top of
> this series.
> 
> This doesn't mean that the review is over, quite the opposite. I intend
> to go over it once more, and I'd like other people to do the same
> (specially anyone looking at implementing the required support in QEMU).

Agreed, thanks for pushing it to next.

I'll continue testing and await further review from people.

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 16/27] KVM: arm64: Factor out core register ID enumeration
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-02  2:41     ` Marc Zyngier
  -1 siblings, 0 replies; 224+ messages in thread
From: Marc Zyngier @ 2019-04-02  2:41 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, 29 Mar 2019 13:00:41 +0000,
Dave Martin <Dave.Martin@arm.com> wrote:
> 
> In preparation for adding logic to filter out some KVM_REG_ARM_CORE
> registers from the KVM_GET_REG_LIST output, this patch factors out
> the core register enumeration into a separate function and rebuilds
> num_core_regs() on top of it.
> 
> This may be a little more expensive (depending on how good a job
> the compiler does of specialising the code), but KVM_GET_REG_LIST
> is not a hot path.
> 
> This will make it easier to consolidate ID filtering code in one
> place.
> 
> No functional change.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * New patch.
> 
>    This reimplements part of the separately-posted patch "KVM: arm64:
>    Factor out KVM_GET_REG_LIST core register enumeration", minus aspects
>    that potentially break the ABI.
> 
>    As a result, the opportunity to truly consolidate all the ID reg
>    filtering in one place is deliberately left on the floor, for now.
>    This will be addressed in a separate series later on.
> ---
>  arch/arm64/kvm/guest.c | 33 +++++++++++++++++++++++++--------
>  1 file changed, 25 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 3e38eb2..a391a61 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -23,6 +23,7 @@
>  #include <linux/err.h>
>  #include <linux/kvm_host.h>
>  #include <linux/module.h>
> +#include <linux/stddef.h>
>  #include <linux/string.h>
>  #include <linux/vmalloc.h>
>  #include <linux/fs.h>
> @@ -194,9 +195,28 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
>  	return -EINVAL;
>  }
>  
> +static int kvm_arm_copy_core_reg_indices(u64 __user *uindices)
> +{
> +	unsigned int i;
> +	int n = 0;
> +	const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
> +
> +	for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
> +		if (uindices) {
> +			if (put_user(core_reg | i, uindices))
> +				return -EFAULT;
> +			uindices++;
> +		}
> +
> +		n++;
> +	}
> +
> +	return n;
> +}
> +
>  static unsigned long num_core_regs(void)
>  {
> -	return sizeof(struct kvm_regs) / sizeof(__u32);
> +	return kvm_arm_copy_core_reg_indices(NULL);
>  }
>  
>  /**
> @@ -276,15 +296,12 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
>   */
>  int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
>  {
> -	unsigned int i;
> -	const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
>  	int ret;
>  
> -	for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
> -		if (put_user(core_reg | i, uindices))
> -			return -EFAULT;
> -		uindices++;
> -	}
> +	ret = kvm_arm_copy_core_reg_indices(uindices);
> +	if (ret)
> +		return ret;
> +	uindices += ret;

Interesting snippet. Given that most implementations have at least one
register, this can hardly work. Please do test things with QEMU, and
not only kvmtool which obviously doesn't exercise this path.

For the sake of getting -next back to a vaguely usable state, I've now
queued the following patch on top.

	M.

>From 832401c8912680ee56dc5cb6ab101266b3db416a Mon Sep 17 00:00:00 2001
From: Marc Zyngier <marc.zyngier@arm.com>
Date: Tue, 2 Apr 2019 03:28:39 +0100
Subject: [PATCH] arm64: KVM: Fix system register enumeration

The introduction of the SVE registers to userspace started with a
refactoring of the way we expose any register via the ONE_REG
interface.

Unfortunately, this change doesn't exactly behave as expected
if the number of registers is non-zero and consider everything
to be an error. The visible result is that QEMU barfs very early
when creating vcpus.

Make sure we only exit early in case there is an actual error, rather
than a positive number of registers...

be25bbb392fa ("KVM: arm64: Factor out core register ID enumeration")
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kvm/guest.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 086ab0508d69..4f7b26bbf671 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -604,22 +604,22 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 	int ret;
 
 	ret = copy_core_reg_indices(vcpu, uindices);
-	if (ret)
+	if (ret < 0)
 		return ret;
 	uindices += ret;
 
 	ret = copy_sve_reg_indices(vcpu, uindices);
-	if (ret)
+	if (ret < 0)
 		return ret;
 	uindices += ret;
 
 	ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
-	if (ret)
+	if (ret < 0)
 		return ret;
 	uindices += kvm_arm_get_fw_num_regs(vcpu);
 
 	ret = copy_timer_indices(vcpu, uindices);
-	if (ret)
+	if (ret < 0)
 		return ret;
 	uindices += NUM_TIMER_REGS;
 
-- 
2.20.1


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

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

* Re: [PATCH v7 16/27] KVM: arm64: Factor out core register ID enumeration
@ 2019-04-02  2:41     ` Marc Zyngier
  0 siblings, 0 replies; 224+ messages in thread
From: Marc Zyngier @ 2019-04-02  2:41 UTC (permalink / raw)
  To: Dave Martin
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Catalin Marinas, Will Deacon, Zhang Lei,
	Julien Grall, Alex Bennée, kvmarm, linux-arm-kernel

On Fri, 29 Mar 2019 13:00:41 +0000,
Dave Martin <Dave.Martin@arm.com> wrote:
> 
> In preparation for adding logic to filter out some KVM_REG_ARM_CORE
> registers from the KVM_GET_REG_LIST output, this patch factors out
> the core register enumeration into a separate function and rebuilds
> num_core_regs() on top of it.
> 
> This may be a little more expensive (depending on how good a job
> the compiler does of specialising the code), but KVM_GET_REG_LIST
> is not a hot path.
> 
> This will make it easier to consolidate ID filtering code in one
> place.
> 
> No functional change.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * New patch.
> 
>    This reimplements part of the separately-posted patch "KVM: arm64:
>    Factor out KVM_GET_REG_LIST core register enumeration", minus aspects
>    that potentially break the ABI.
> 
>    As a result, the opportunity to truly consolidate all the ID reg
>    filtering in one place is deliberately left on the floor, for now.
>    This will be addressed in a separate series later on.
> ---
>  arch/arm64/kvm/guest.c | 33 +++++++++++++++++++++++++--------
>  1 file changed, 25 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 3e38eb2..a391a61 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -23,6 +23,7 @@
>  #include <linux/err.h>
>  #include <linux/kvm_host.h>
>  #include <linux/module.h>
> +#include <linux/stddef.h>
>  #include <linux/string.h>
>  #include <linux/vmalloc.h>
>  #include <linux/fs.h>
> @@ -194,9 +195,28 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
>  	return -EINVAL;
>  }
>  
> +static int kvm_arm_copy_core_reg_indices(u64 __user *uindices)
> +{
> +	unsigned int i;
> +	int n = 0;
> +	const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
> +
> +	for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
> +		if (uindices) {
> +			if (put_user(core_reg | i, uindices))
> +				return -EFAULT;
> +			uindices++;
> +		}
> +
> +		n++;
> +	}
> +
> +	return n;
> +}
> +
>  static unsigned long num_core_regs(void)
>  {
> -	return sizeof(struct kvm_regs) / sizeof(__u32);
> +	return kvm_arm_copy_core_reg_indices(NULL);
>  }
>  
>  /**
> @@ -276,15 +296,12 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
>   */
>  int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
>  {
> -	unsigned int i;
> -	const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
>  	int ret;
>  
> -	for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
> -		if (put_user(core_reg | i, uindices))
> -			return -EFAULT;
> -		uindices++;
> -	}
> +	ret = kvm_arm_copy_core_reg_indices(uindices);
> +	if (ret)
> +		return ret;
> +	uindices += ret;

Interesting snippet. Given that most implementations have at least one
register, this can hardly work. Please do test things with QEMU, and
not only kvmtool which obviously doesn't exercise this path.

For the sake of getting -next back to a vaguely usable state, I've now
queued the following patch on top.

	M.

From 832401c8912680ee56dc5cb6ab101266b3db416a Mon Sep 17 00:00:00 2001
From: Marc Zyngier <marc.zyngier@arm.com>
Date: Tue, 2 Apr 2019 03:28:39 +0100
Subject: [PATCH] arm64: KVM: Fix system register enumeration

The introduction of the SVE registers to userspace started with a
refactoring of the way we expose any register via the ONE_REG
interface.

Unfortunately, this change doesn't exactly behave as expected
if the number of registers is non-zero and consider everything
to be an error. The visible result is that QEMU barfs very early
when creating vcpus.

Make sure we only exit early in case there is an actual error, rather
than a positive number of registers...

be25bbb392fa ("KVM: arm64: Factor out core register ID enumeration")
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kvm/guest.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 086ab0508d69..4f7b26bbf671 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -604,22 +604,22 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
 	int ret;
 
 	ret = copy_core_reg_indices(vcpu, uindices);
-	if (ret)
+	if (ret < 0)
 		return ret;
 	uindices += ret;
 
 	ret = copy_sve_reg_indices(vcpu, uindices);
-	if (ret)
+	if (ret < 0)
 		return ret;
 	uindices += ret;
 
 	ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
-	if (ret)
+	if (ret < 0)
 		return ret;
 	uindices += kvm_arm_get_fw_num_regs(vcpu);
 
 	ret = copy_timer_indices(vcpu, uindices);
-	if (ret)
+	if (ret < 0)
 		return ret;
 	uindices += NUM_TIMER_REGS;
 
-- 
2.20.1


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

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

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

* Re: [PATCH v7 16/27] KVM: arm64: Factor out core register ID enumeration
  2019-04-02  2:41     ` Marc Zyngier
@ 2019-04-02  8:59       ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-02  8:59 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Tue, Apr 02, 2019 at 03:41:56AM +0100, Marc Zyngier wrote:
> On Fri, 29 Mar 2019 13:00:41 +0000,
> Dave Martin <Dave.Martin@arm.com> wrote:
> > 
> > In preparation for adding logic to filter out some KVM_REG_ARM_CORE
> > registers from the KVM_GET_REG_LIST output, this patch factors out
> > the core register enumeration into a separate function and rebuilds
> > num_core_regs() on top of it.
> > 
> > This may be a little more expensive (depending on how good a job
> > the compiler does of specialising the code), but KVM_GET_REG_LIST
> > is not a hot path.
> > 
> > This will make it easier to consolidate ID filtering code in one
> > place.
> > 
> > No functional change.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > 
> > ---
> > 
> > Changes since v5:
> > 
> >  * New patch.
> > 
> >    This reimplements part of the separately-posted patch "KVM: arm64:
> >    Factor out KVM_GET_REG_LIST core register enumeration", minus aspects
> >    that potentially break the ABI.
> > 
> >    As a result, the opportunity to truly consolidate all the ID reg
> >    filtering in one place is deliberately left on the floor, for now.
> >    This will be addressed in a separate series later on.
> > ---
> >  arch/arm64/kvm/guest.c | 33 +++++++++++++++++++++++++--------
> >  1 file changed, 25 insertions(+), 8 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > index 3e38eb2..a391a61 100644
> > --- a/arch/arm64/kvm/guest.c
> > +++ b/arch/arm64/kvm/guest.c

[...]

> > @@ -276,15 +296,12 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
> >   */
> >  int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
> >  {
> > -	unsigned int i;
> > -	const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
> >  	int ret;
> >  
> > -	for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
> > -		if (put_user(core_reg | i, uindices))
> > -			return -EFAULT;
> > -		uindices++;
> > -	}
> > +	ret = kvm_arm_copy_core_reg_indices(uindices);
> > +	if (ret)
> > +		return ret;
> > +	uindices += ret;
> 
> Interesting snippet. Given that most implementations have at least one
> register, this can hardly work. Please do test things with QEMU, and
> not only kvmtool which obviously doesn't exercise this path.

My bad: this used to work to do the right thing, but I broke it when
splitting up [1] for v6 to avoid the dependency.

kvm_arm_copy_core_reg_indices() used to take &uindices and update it
directly, returning 0 on success instead of the number of registers.
But this seemed less consistent with the way the other functions are
called.

> For the sake of getting -next back to a vaguely usable state, I've now
> queued the following patch on top.
> 
> 	M.
> 
> From 832401c8912680ee56dc5cb6ab101266b3db416a Mon Sep 17 00:00:00 2001
> From: Marc Zyngier <marc.zyngier@arm.com>
> Date: Tue, 2 Apr 2019 03:28:39 +0100
> Subject: [PATCH] arm64: KVM: Fix system register enumeration
> 
> The introduction of the SVE registers to userspace started with a
> refactoring of the way we expose any register via the ONE_REG
> interface.
> 
> Unfortunately, this change doesn't exactly behave as expected
> if the number of registers is non-zero and consider everything
> to be an error. The visible result is that QEMU barfs very early
> when creating vcpus.
> 
> Make sure we only exit early in case there is an actual error, rather
> than a positive number of registers...
> 
> be25bbb392fa ("KVM: arm64: Factor out core register ID enumeration")
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm64/kvm/guest.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 086ab0508d69..4f7b26bbf671 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -604,22 +604,22 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
>  	int ret;
>  
>  	ret = copy_core_reg_indices(vcpu, uindices);
> -	if (ret)
> +	if (ret < 0)
>  		return ret;
>  	uindices += ret;
>  
>  	ret = copy_sve_reg_indices(vcpu, uindices);
> -	if (ret)
> +	if (ret < 0)
>  		return ret;
>  	uindices += ret;

^ Ack

>  	ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
> -	if (ret)
> +	if (ret < 0)
>  		return ret;
>  	uindices += kvm_arm_get_fw_num_regs(vcpu);
>  
>  	ret = copy_timer_indices(vcpu, uindices);
> -	if (ret)
> +	if (ret < 0)
>  		return ret;
>  	uindices += NUM_TIMER_REGS;

For these two, the interface is not really the same.  These don't
return the number of registers, so return 0 on success.  "< 0" here
could be a trap for the future, though the risk looks low.

I can have a go at some rework on top to make this more consistent,
but I'd rather not muddy the water further for the moment.

Any view on that?

Cheers
---Dave

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

* Re: [PATCH v7 16/27] KVM: arm64: Factor out core register ID enumeration
@ 2019-04-02  8:59       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-02  8:59 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Tue, Apr 02, 2019 at 03:41:56AM +0100, Marc Zyngier wrote:
> On Fri, 29 Mar 2019 13:00:41 +0000,
> Dave Martin <Dave.Martin@arm.com> wrote:
> > 
> > In preparation for adding logic to filter out some KVM_REG_ARM_CORE
> > registers from the KVM_GET_REG_LIST output, this patch factors out
> > the core register enumeration into a separate function and rebuilds
> > num_core_regs() on top of it.
> > 
> > This may be a little more expensive (depending on how good a job
> > the compiler does of specialising the code), but KVM_GET_REG_LIST
> > is not a hot path.
> > 
> > This will make it easier to consolidate ID filtering code in one
> > place.
> > 
> > No functional change.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > 
> > ---
> > 
> > Changes since v5:
> > 
> >  * New patch.
> > 
> >    This reimplements part of the separately-posted patch "KVM: arm64:
> >    Factor out KVM_GET_REG_LIST core register enumeration", minus aspects
> >    that potentially break the ABI.
> > 
> >    As a result, the opportunity to truly consolidate all the ID reg
> >    filtering in one place is deliberately left on the floor, for now.
> >    This will be addressed in a separate series later on.
> > ---
> >  arch/arm64/kvm/guest.c | 33 +++++++++++++++++++++++++--------
> >  1 file changed, 25 insertions(+), 8 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > index 3e38eb2..a391a61 100644
> > --- a/arch/arm64/kvm/guest.c
> > +++ b/arch/arm64/kvm/guest.c

[...]

> > @@ -276,15 +296,12 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
> >   */
> >  int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
> >  {
> > -	unsigned int i;
> > -	const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
> >  	int ret;
> >  
> > -	for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
> > -		if (put_user(core_reg | i, uindices))
> > -			return -EFAULT;
> > -		uindices++;
> > -	}
> > +	ret = kvm_arm_copy_core_reg_indices(uindices);
> > +	if (ret)
> > +		return ret;
> > +	uindices += ret;
> 
> Interesting snippet. Given that most implementations have at least one
> register, this can hardly work. Please do test things with QEMU, and
> not only kvmtool which obviously doesn't exercise this path.

My bad: this used to work to do the right thing, but I broke it when
splitting up [1] for v6 to avoid the dependency.

kvm_arm_copy_core_reg_indices() used to take &uindices and update it
directly, returning 0 on success instead of the number of registers.
But this seemed less consistent with the way the other functions are
called.

> For the sake of getting -next back to a vaguely usable state, I've now
> queued the following patch on top.
> 
> 	M.
> 
> From 832401c8912680ee56dc5cb6ab101266b3db416a Mon Sep 17 00:00:00 2001
> From: Marc Zyngier <marc.zyngier@arm.com>
> Date: Tue, 2 Apr 2019 03:28:39 +0100
> Subject: [PATCH] arm64: KVM: Fix system register enumeration
> 
> The introduction of the SVE registers to userspace started with a
> refactoring of the way we expose any register via the ONE_REG
> interface.
> 
> Unfortunately, this change doesn't exactly behave as expected
> if the number of registers is non-zero and consider everything
> to be an error. The visible result is that QEMU barfs very early
> when creating vcpus.
> 
> Make sure we only exit early in case there is an actual error, rather
> than a positive number of registers...
> 
> be25bbb392fa ("KVM: arm64: Factor out core register ID enumeration")
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm64/kvm/guest.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 086ab0508d69..4f7b26bbf671 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -604,22 +604,22 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
>  	int ret;
>  
>  	ret = copy_core_reg_indices(vcpu, uindices);
> -	if (ret)
> +	if (ret < 0)
>  		return ret;
>  	uindices += ret;
>  
>  	ret = copy_sve_reg_indices(vcpu, uindices);
> -	if (ret)
> +	if (ret < 0)
>  		return ret;
>  	uindices += ret;

^ Ack

>  	ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
> -	if (ret)
> +	if (ret < 0)
>  		return ret;
>  	uindices += kvm_arm_get_fw_num_regs(vcpu);
>  
>  	ret = copy_timer_indices(vcpu, uindices);
> -	if (ret)
> +	if (ret < 0)
>  		return ret;
>  	uindices += NUM_TIMER_REGS;

For these two, the interface is not really the same.  These don't
return the number of registers, so return 0 on success.  "< 0" here
could be a trap for the future, though the risk looks low.

I can have a go at some rework on top to make this more consistent,
but I'd rather not muddy the water further for the moment.

Any view on that?

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 16/27] KVM: arm64: Factor out core register ID enumeration
  2019-04-02  8:59       ` Dave Martin
@ 2019-04-02  9:32         ` Marc Zyngier
  -1 siblings, 0 replies; 224+ messages in thread
From: Marc Zyngier @ 2019-04-02  9:32 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Tue, 02 Apr 2019 09:59:19 +0100,
Dave Martin <Dave.Martin@arm.com> wrote:
> 
> On Tue, Apr 02, 2019 at 03:41:56AM +0100, Marc Zyngier wrote:
> > On Fri, 29 Mar 2019 13:00:41 +0000,
> > Dave Martin <Dave.Martin@arm.com> wrote:
> > > 
> > > In preparation for adding logic to filter out some KVM_REG_ARM_CORE
> > > registers from the KVM_GET_REG_LIST output, this patch factors out
> > > the core register enumeration into a separate function and rebuilds
> > > num_core_regs() on top of it.
> > > 
> > > This may be a little more expensive (depending on how good a job
> > > the compiler does of specialising the code), but KVM_GET_REG_LIST
> > > is not a hot path.
> > > 
> > > This will make it easier to consolidate ID filtering code in one
> > > place.
> > > 
> > > No functional change.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > 
> > > ---
> > > 
> > > Changes since v5:
> > > 
> > >  * New patch.
> > > 
> > >    This reimplements part of the separately-posted patch "KVM: arm64:
> > >    Factor out KVM_GET_REG_LIST core register enumeration", minus aspects
> > >    that potentially break the ABI.
> > > 
> > >    As a result, the opportunity to truly consolidate all the ID reg
> > >    filtering in one place is deliberately left on the floor, for now.
> > >    This will be addressed in a separate series later on.
> > > ---
> > >  arch/arm64/kvm/guest.c | 33 +++++++++++++++++++++++++--------
> > >  1 file changed, 25 insertions(+), 8 deletions(-)
> > > 
> > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > index 3e38eb2..a391a61 100644
> > > --- a/arch/arm64/kvm/guest.c
> > > +++ b/arch/arm64/kvm/guest.c
> 
> [...]
> 
> > > @@ -276,15 +296,12 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
> > >   */
> > >  int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
> > >  {
> > > -	unsigned int i;
> > > -	const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
> > >  	int ret;
> > >  
> > > -	for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
> > > -		if (put_user(core_reg | i, uindices))
> > > -			return -EFAULT;
> > > -		uindices++;
> > > -	}
> > > +	ret = kvm_arm_copy_core_reg_indices(uindices);
> > > +	if (ret)
> > > +		return ret;
> > > +	uindices += ret;
> > 
> > Interesting snippet. Given that most implementations have at least one
> > register, this can hardly work. Please do test things with QEMU, and
> > not only kvmtool which obviously doesn't exercise this path.
> 
> My bad: this used to work to do the right thing, but I broke it when
> splitting up [1] for v6 to avoid the dependency.
> 
> kvm_arm_copy_core_reg_indices() used to take &uindices and update it
> directly, returning 0 on success instead of the number of registers.
> But this seemed less consistent with the way the other functions are
> called.
> 
> > For the sake of getting -next back to a vaguely usable state, I've now
> > queued the following patch on top.
> > 
> > 	M.
> > 
> > From 832401c8912680ee56dc5cb6ab101266b3db416a Mon Sep 17 00:00:00 2001
> > From: Marc Zyngier <marc.zyngier@arm.com>
> > Date: Tue, 2 Apr 2019 03:28:39 +0100
> > Subject: [PATCH] arm64: KVM: Fix system register enumeration
> > 
> > The introduction of the SVE registers to userspace started with a
> > refactoring of the way we expose any register via the ONE_REG
> > interface.
> > 
> > Unfortunately, this change doesn't exactly behave as expected
> > if the number of registers is non-zero and consider everything
> > to be an error. The visible result is that QEMU barfs very early
> > when creating vcpus.
> > 
> > Make sure we only exit early in case there is an actual error, rather
> > than a positive number of registers...
> > 
> > be25bbb392fa ("KVM: arm64: Factor out core register ID enumeration")
> > Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> > ---
> >  arch/arm64/kvm/guest.c | 8 ++++----
> >  1 file changed, 4 insertions(+), 4 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > index 086ab0508d69..4f7b26bbf671 100644
> > --- a/arch/arm64/kvm/guest.c
> > +++ b/arch/arm64/kvm/guest.c
> > @@ -604,22 +604,22 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
> >  	int ret;
> >  
> >  	ret = copy_core_reg_indices(vcpu, uindices);
> > -	if (ret)
> > +	if (ret < 0)
> >  		return ret;
> >  	uindices += ret;
> >  
> >  	ret = copy_sve_reg_indices(vcpu, uindices);
> > -	if (ret)
> > +	if (ret < 0)
> >  		return ret;
> >  	uindices += ret;
> 
> ^ Ack
> 
> >  	ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
> > -	if (ret)
> > +	if (ret < 0)
> >  		return ret;
> >  	uindices += kvm_arm_get_fw_num_regs(vcpu);
> >  
> >  	ret = copy_timer_indices(vcpu, uindices);
> > -	if (ret)
> > +	if (ret < 0)
> >  		return ret;
> >  	uindices += NUM_TIMER_REGS;
> 
> For these two, the interface is not really the same.  These don't
> return the number of registers, so return 0 on success.  "< 0" here
> could be a trap for the future, though the risk looks low.

I realised that, but since they all return a negative value on error,
I went for a similar error handling.

> I can have a go at some rework on top to make this more consistent,
> but I'd rather not muddy the water further for the moment.
> 
> Any view on that?

I don't think there is any urgency on that front. For now, I'd like to
make sure things do not regress. Once we're sure we have something
stable, we'll be able to make it shiny.

Thanks,

	M.

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

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

* Re: [PATCH v7 16/27] KVM: arm64: Factor out core register ID enumeration
@ 2019-04-02  9:32         ` Marc Zyngier
  0 siblings, 0 replies; 224+ messages in thread
From: Marc Zyngier @ 2019-04-02  9:32 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Tue, 02 Apr 2019 09:59:19 +0100,
Dave Martin <Dave.Martin@arm.com> wrote:
> 
> On Tue, Apr 02, 2019 at 03:41:56AM +0100, Marc Zyngier wrote:
> > On Fri, 29 Mar 2019 13:00:41 +0000,
> > Dave Martin <Dave.Martin@arm.com> wrote:
> > > 
> > > In preparation for adding logic to filter out some KVM_REG_ARM_CORE
> > > registers from the KVM_GET_REG_LIST output, this patch factors out
> > > the core register enumeration into a separate function and rebuilds
> > > num_core_regs() on top of it.
> > > 
> > > This may be a little more expensive (depending on how good a job
> > > the compiler does of specialising the code), but KVM_GET_REG_LIST
> > > is not a hot path.
> > > 
> > > This will make it easier to consolidate ID filtering code in one
> > > place.
> > > 
> > > No functional change.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > 
> > > ---
> > > 
> > > Changes since v5:
> > > 
> > >  * New patch.
> > > 
> > >    This reimplements part of the separately-posted patch "KVM: arm64:
> > >    Factor out KVM_GET_REG_LIST core register enumeration", minus aspects
> > >    that potentially break the ABI.
> > > 
> > >    As a result, the opportunity to truly consolidate all the ID reg
> > >    filtering in one place is deliberately left on the floor, for now.
> > >    This will be addressed in a separate series later on.
> > > ---
> > >  arch/arm64/kvm/guest.c | 33 +++++++++++++++++++++++++--------
> > >  1 file changed, 25 insertions(+), 8 deletions(-)
> > > 
> > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > index 3e38eb2..a391a61 100644
> > > --- a/arch/arm64/kvm/guest.c
> > > +++ b/arch/arm64/kvm/guest.c
> 
> [...]
> 
> > > @@ -276,15 +296,12 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
> > >   */
> > >  int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
> > >  {
> > > -	unsigned int i;
> > > -	const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
> > >  	int ret;
> > >  
> > > -	for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
> > > -		if (put_user(core_reg | i, uindices))
> > > -			return -EFAULT;
> > > -		uindices++;
> > > -	}
> > > +	ret = kvm_arm_copy_core_reg_indices(uindices);
> > > +	if (ret)
> > > +		return ret;
> > > +	uindices += ret;
> > 
> > Interesting snippet. Given that most implementations have at least one
> > register, this can hardly work. Please do test things with QEMU, and
> > not only kvmtool which obviously doesn't exercise this path.
> 
> My bad: this used to work to do the right thing, but I broke it when
> splitting up [1] for v6 to avoid the dependency.
> 
> kvm_arm_copy_core_reg_indices() used to take &uindices and update it
> directly, returning 0 on success instead of the number of registers.
> But this seemed less consistent with the way the other functions are
> called.
> 
> > For the sake of getting -next back to a vaguely usable state, I've now
> > queued the following patch on top.
> > 
> > 	M.
> > 
> > From 832401c8912680ee56dc5cb6ab101266b3db416a Mon Sep 17 00:00:00 2001
> > From: Marc Zyngier <marc.zyngier@arm.com>
> > Date: Tue, 2 Apr 2019 03:28:39 +0100
> > Subject: [PATCH] arm64: KVM: Fix system register enumeration
> > 
> > The introduction of the SVE registers to userspace started with a
> > refactoring of the way we expose any register via the ONE_REG
> > interface.
> > 
> > Unfortunately, this change doesn't exactly behave as expected
> > if the number of registers is non-zero and consider everything
> > to be an error. The visible result is that QEMU barfs very early
> > when creating vcpus.
> > 
> > Make sure we only exit early in case there is an actual error, rather
> > than a positive number of registers...
> > 
> > be25bbb392fa ("KVM: arm64: Factor out core register ID enumeration")
> > Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> > ---
> >  arch/arm64/kvm/guest.c | 8 ++++----
> >  1 file changed, 4 insertions(+), 4 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > index 086ab0508d69..4f7b26bbf671 100644
> > --- a/arch/arm64/kvm/guest.c
> > +++ b/arch/arm64/kvm/guest.c
> > @@ -604,22 +604,22 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
> >  	int ret;
> >  
> >  	ret = copy_core_reg_indices(vcpu, uindices);
> > -	if (ret)
> > +	if (ret < 0)
> >  		return ret;
> >  	uindices += ret;
> >  
> >  	ret = copy_sve_reg_indices(vcpu, uindices);
> > -	if (ret)
> > +	if (ret < 0)
> >  		return ret;
> >  	uindices += ret;
> 
> ^ Ack
> 
> >  	ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
> > -	if (ret)
> > +	if (ret < 0)
> >  		return ret;
> >  	uindices += kvm_arm_get_fw_num_regs(vcpu);
> >  
> >  	ret = copy_timer_indices(vcpu, uindices);
> > -	if (ret)
> > +	if (ret < 0)
> >  		return ret;
> >  	uindices += NUM_TIMER_REGS;
> 
> For these two, the interface is not really the same.  These don't
> return the number of registers, so return 0 on success.  "< 0" here
> could be a trap for the future, though the risk looks low.

I realised that, but since they all return a negative value on error,
I went for a similar error handling.

> I can have a go at some rework on top to make this more consistent,
> but I'd rather not muddy the water further for the moment.
> 
> Any view on that?

I don't think there is any urgency on that front. For now, I'd like to
make sure things do not regress. Once we're sure we have something
stable, we'll be able to make it shiny.

Thanks,

	M.

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

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 16/27] KVM: arm64: Factor out core register ID enumeration
  2019-04-02  9:32         ` Marc Zyngier
@ 2019-04-02  9:54           ` Dave P Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave P Martin @ 2019-04-02  9:54 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: tokamoto, Christoffer Dall, Ard Biesheuvel, Catalin Marinas,
	Will Deacon, Zhang Lei, Julien Grall, kvmarm, linux-arm-kernel

On Tue, Apr 02, 2019 at 10:32:34AM +0100, Marc Zyngier wrote:
> On Tue, 02 Apr 2019 09:59:19 +0100,
> Dave Martin <Dave.Martin@arm.com> wrote:
> >
> > On Tue, Apr 02, 2019 at 03:41:56AM +0100, Marc Zyngier wrote:

[...]

> > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > index 086ab0508d69..4f7b26bbf671 100644
> > > --- a/arch/arm64/kvm/guest.c
> > > +++ b/arch/arm64/kvm/guest.c
> > > @@ -604,22 +604,22 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)

[...]

> > >  ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
> > > -if (ret)
> > > +if (ret < 0)
> > >  return ret;
> > >  uindices += kvm_arm_get_fw_num_regs(vcpu);
> > >
> > >  ret = copy_timer_indices(vcpu, uindices);
> > > -if (ret)
> > > +if (ret < 0)
> > >  return ret;
> > >  uindices += NUM_TIMER_REGS;
> >
> > For these two, the interface is not really the same.  These don't
> > return the number of registers, so return 0 on success.  "< 0" here
> > could be a trap for the future, though the risk looks low.
>
> I realised that, but since they all return a negative value on error,
> I went for a similar error handling.

Sure, this is more potential future maintenance thing -- and anyway not
a big deal.

I agree that your changes look like they work.

> > I can have a go at some rework on top to make this more consistent,
> > but I'd rather not muddy the water further for the moment.
> >
> > Any view on that?
>
> I don't think there is any urgency on that front. For now, I'd like to
> make sure things do not regress. Once we're sure we have something
> stable, we'll be able to make it shiny.

Agreed.

I won't worry about this for now, but we can discuss it later.

Cheers
---Dave
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

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

* Re: [PATCH v7 16/27] KVM: arm64: Factor out core register ID enumeration
@ 2019-04-02  9:54           ` Dave P Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave P Martin @ 2019-04-02  9:54 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: tokamoto, Christoffer Dall, Ard Biesheuvel, Catalin Marinas,
	Will Deacon, Zhang Lei, Julien Grall, kvmarm, linux-arm-kernel

On Tue, Apr 02, 2019 at 10:32:34AM +0100, Marc Zyngier wrote:
> On Tue, 02 Apr 2019 09:59:19 +0100,
> Dave Martin <Dave.Martin@arm.com> wrote:
> >
> > On Tue, Apr 02, 2019 at 03:41:56AM +0100, Marc Zyngier wrote:

[...]

> > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > index 086ab0508d69..4f7b26bbf671 100644
> > > --- a/arch/arm64/kvm/guest.c
> > > +++ b/arch/arm64/kvm/guest.c
> > > @@ -604,22 +604,22 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)

[...]

> > >  ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
> > > -if (ret)
> > > +if (ret < 0)
> > >  return ret;
> > >  uindices += kvm_arm_get_fw_num_regs(vcpu);
> > >
> > >  ret = copy_timer_indices(vcpu, uindices);
> > > -if (ret)
> > > +if (ret < 0)
> > >  return ret;
> > >  uindices += NUM_TIMER_REGS;
> >
> > For these two, the interface is not really the same.  These don't
> > return the number of registers, so return 0 on success.  "< 0" here
> > could be a trap for the future, though the risk looks low.
>
> I realised that, but since they all return a negative value on error,
> I went for a similar error handling.

Sure, this is more potential future maintenance thing -- and anyway not
a big deal.

I agree that your changes look like they work.

> > I can have a go at some rework on top to make this more consistent,
> > but I'd rather not muddy the water further for the moment.
> >
> > Any view on that?
>
> I don't think there is any urgency on that front. For now, I'd like to
> make sure things do not regress. Once we're sure we have something
> stable, we'll be able to make it shiny.

Agreed.

I won't worry about this for now, but we can discuss it later.

Cheers
---Dave
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 09/27] KVM: arm64: Add a vcpu flag to control SVE visibility for the guest
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-03 19:14     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-03 19:14 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:34PM +0000, Dave Martin wrote:
> Since SVE will be enabled or disabled on a per-vcpu basis, a flag
> is needed in order to track which vcpus have it enabled.
> 
> This patch adds a suitable flag and a helper for checking it.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> ---
>  arch/arm64/include/asm/kvm_host.h | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 6d10100..ad4f7f0 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -328,6 +328,10 @@ struct kvm_vcpu_arch {
>  #define KVM_ARM64_FP_HOST		(1 << 2) /* host FP regs loaded */
>  #define KVM_ARM64_HOST_SVE_IN_USE	(1 << 3) /* backup for host TIF_SVE */
>  #define KVM_ARM64_HOST_SVE_ENABLED	(1 << 4) /* SVE enabled for EL0 */
> +#define KVM_ARM64_GUEST_HAS_SVE		(1 << 5) /* SVE exposed to guest */
> +
> +#define vcpu_has_sve(vcpu) (system_supports_sve() && \
> +			    ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))

We shouldn't need the system_supports_sve() here. vcpu->arch.flags can
only have the KVM_ARM64_GUEST_HAS_SVE flag set when system_supports_sve()
is true, and it can't change later.

Thanks,
drew

>  
>  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
>  
> -- 
> 2.1.4
> 
> _______________________________________________
> kvmarm mailing list
> kvmarm@lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v7 09/27] KVM: arm64: Add a vcpu flag to control SVE visibility for the guest
@ 2019-04-03 19:14     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-03 19:14 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:34PM +0000, Dave Martin wrote:
> Since SVE will be enabled or disabled on a per-vcpu basis, a flag
> is needed in order to track which vcpus have it enabled.
> 
> This patch adds a suitable flag and a helper for checking it.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> ---
>  arch/arm64/include/asm/kvm_host.h | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 6d10100..ad4f7f0 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -328,6 +328,10 @@ struct kvm_vcpu_arch {
>  #define KVM_ARM64_FP_HOST		(1 << 2) /* host FP regs loaded */
>  #define KVM_ARM64_HOST_SVE_IN_USE	(1 << 3) /* backup for host TIF_SVE */
>  #define KVM_ARM64_HOST_SVE_ENABLED	(1 << 4) /* SVE enabled for EL0 */
> +#define KVM_ARM64_GUEST_HAS_SVE		(1 << 5) /* SVE exposed to guest */
> +
> +#define vcpu_has_sve(vcpu) (system_supports_sve() && \
> +			    ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))

We shouldn't need the system_supports_sve() here. vcpu->arch.flags can
only have the KVM_ARM64_GUEST_HAS_SVE flag set when system_supports_sve()
is true, and it can't change later.

Thanks,
drew

>  
>  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
>  
> -- 
> 2.1.4
> 
> _______________________________________________
> kvmarm mailing list
> kvmarm@lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 11/27] KVM: arm64: Support runtime sysreg visibility filtering
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-03 19:17     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-03 19:17 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:36PM +0000, Dave Martin wrote:
> Some optional features of the Arm architecture add new system
> registers that are not present in the base architecture.
> 
> Where these features are optional for the guest, the visibility of
> these registers may need to depend on some runtime configuration,
> such as a flag passed to KVM_ARM_VCPU_INIT.
> 
> For example, ZCR_EL1 and ID_AA64ZFR0_EL1 need to be hidden if SVE
> is not enabled for the guest, even though these registers may be
> present in the hardware and visible to the host at EL2.
> 
> Adding special-case checks all over the place for individual
> registers is going to get messy as the number of conditionally-
> visible registers grows.
> 
> In order to help solve this problem, this patch adds a new sysreg
> method visibility() that can be used to hook in any needed runtime
> visibility checks.  This method can currently return
> REG_HIDDEN_USER to inhibit enumeration and ioctl access to the
> register for userspace, and REG_HIDDEN_GUEST to inhibit runtime
> access by the guest using MSR/MRS.  Wrappers are added to allow
> these flags to be conveniently queried.
> 
> This approach allows a conditionally modified view of individual
> system registers such as the CPU ID registers, in addition to
> completely hiding register where appropriate.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * Rename the visibility override flags, add some comments, and rename/
>    introduce helpers to make the purpose of this code clearer.
> ---
>  arch/arm64/kvm/sys_regs.c | 24 +++++++++++++++++++++---
>  arch/arm64/kvm/sys_regs.h | 25 +++++++++++++++++++++++++
>  2 files changed, 46 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index a5d14b5..c86a7b0 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -1927,6 +1927,12 @@ static void perform_access(struct kvm_vcpu *vcpu,
>  {
>  	trace_kvm_sys_access(*vcpu_pc(vcpu), params, r);
>  
> +	/* Check for regs disabled by runtime config */
> +	if (sysreg_hidden_from_guest(vcpu, r)) {
> +		kvm_inject_undefined(vcpu);
> +		return;
> +	}
> +
>  	/*
>  	 * Not having an accessor means that we have configured a trap
>  	 * that we don't know how to handle. This certainly qualifies
> @@ -2438,6 +2444,10 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
>  	if (!r)
>  		return get_invariant_sys_reg(reg->id, uaddr);
>  
> +	/* Check for regs disabled by runtime config */
> +	if (sysreg_hidden_from_user(vcpu, r))
> +		return -ENOENT;
> +
>  	if (r->get_user)
>  		return (r->get_user)(vcpu, r, reg, uaddr);
>  
> @@ -2459,6 +2469,10 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
>  	if (!r)
>  		return set_invariant_sys_reg(reg->id, uaddr);
>  
> +	/* Check for regs disabled by runtime config */
> +	if (sysreg_hidden_from_user(vcpu, r))
> +		return -ENOENT;
> +
>  	if (r->set_user)
>  		return (r->set_user)(vcpu, r, reg, uaddr);
>  
> @@ -2515,7 +2529,8 @@ static bool copy_reg_to_user(const struct sys_reg_desc *reg, u64 __user **uind)
>  	return true;
>  }
>  
> -static int walk_one_sys_reg(const struct sys_reg_desc *rd,
> +static int walk_one_sys_reg(const struct kvm_vcpu *vcpu,
> +			    const struct sys_reg_desc *rd,
>  			    u64 __user **uind,
>  			    unsigned int *total)
>  {
> @@ -2526,6 +2541,9 @@ static int walk_one_sys_reg(const struct sys_reg_desc *rd,
>  	if (!(rd->reg || rd->get_user))
>  		return 0;
>  
> +	if (sysreg_hidden_from_user(vcpu, rd))
> +		return 0;
> +
>  	if (!copy_reg_to_user(rd, uind))
>  		return -EFAULT;
>  
> @@ -2554,9 +2572,9 @@ static int walk_sys_regs(struct kvm_vcpu *vcpu, u64 __user *uind)
>  		int cmp = cmp_sys_reg(i1, i2);
>  		/* target-specific overrides generic entry. */
>  		if (cmp <= 0)
> -			err = walk_one_sys_reg(i1, &uind, &total);
> +			err = walk_one_sys_reg(vcpu, i1, &uind, &total);
>  		else
> -			err = walk_one_sys_reg(i2, &uind, &total);
> +			err = walk_one_sys_reg(vcpu, i2, &uind, &total);
>  
>  		if (err)
>  			return err;
> diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
> index 3b1bc7f..2be9950 100644
> --- a/arch/arm64/kvm/sys_regs.h
> +++ b/arch/arm64/kvm/sys_regs.h
> @@ -64,8 +64,15 @@ struct sys_reg_desc {
>  			const struct kvm_one_reg *reg, void __user *uaddr);
>  	int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
>  			const struct kvm_one_reg *reg, void __user *uaddr);
> +
> +	/* Return mask of REG_* runtime visibility overrides */
> +	unsigned int (*visibility)(const struct kvm_vcpu *vcpu,
> +				   const struct sys_reg_desc *rd);
>  };
>  
> +#define REG_HIDDEN_USER		(1 << 0) /* hidden from userspace ioctls */
> +#define REG_HIDDEN_GUEST	(1 << 1) /* hidden from guest */
> +
>  static inline void print_sys_reg_instr(const struct sys_reg_params *p)
>  {
>  	/* Look, we even formatted it for you to paste into the table! */
> @@ -102,6 +109,24 @@ static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r
>  	__vcpu_sys_reg(vcpu, r->reg) = r->val;
>  }
>  
> +static inline bool sysreg_hidden_from_guest(const struct kvm_vcpu *vcpu,
> +					    const struct sys_reg_desc *r)
> +{
> +	if (likely(!r->visibility))
> +		return false;
> +
> +	return r->visibility(vcpu, r) & REG_HIDDEN_GUEST;
> +}
> +
> +static inline bool sysreg_hidden_from_user(const struct kvm_vcpu *vcpu,
> +					   const struct sys_reg_desc *r)
> +{
> +	if (likely(!r->visibility))
> +		return false;
> +
> +	return r->visibility(vcpu, r) & REG_HIDDEN_USER;
> +}
> +
>  static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
>  			      const struct sys_reg_desc *i2)
>  {
> -- 
> 2.1.4
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v7 11/27] KVM: arm64: Support runtime sysreg visibility filtering
@ 2019-04-03 19:17     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-03 19:17 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:36PM +0000, Dave Martin wrote:
> Some optional features of the Arm architecture add new system
> registers that are not present in the base architecture.
> 
> Where these features are optional for the guest, the visibility of
> these registers may need to depend on some runtime configuration,
> such as a flag passed to KVM_ARM_VCPU_INIT.
> 
> For example, ZCR_EL1 and ID_AA64ZFR0_EL1 need to be hidden if SVE
> is not enabled for the guest, even though these registers may be
> present in the hardware and visible to the host at EL2.
> 
> Adding special-case checks all over the place for individual
> registers is going to get messy as the number of conditionally-
> visible registers grows.
> 
> In order to help solve this problem, this patch adds a new sysreg
> method visibility() that can be used to hook in any needed runtime
> visibility checks.  This method can currently return
> REG_HIDDEN_USER to inhibit enumeration and ioctl access to the
> register for userspace, and REG_HIDDEN_GUEST to inhibit runtime
> access by the guest using MSR/MRS.  Wrappers are added to allow
> these flags to be conveniently queried.
> 
> This approach allows a conditionally modified view of individual
> system registers such as the CPU ID registers, in addition to
> completely hiding register where appropriate.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * Rename the visibility override flags, add some comments, and rename/
>    introduce helpers to make the purpose of this code clearer.
> ---
>  arch/arm64/kvm/sys_regs.c | 24 +++++++++++++++++++++---
>  arch/arm64/kvm/sys_regs.h | 25 +++++++++++++++++++++++++
>  2 files changed, 46 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index a5d14b5..c86a7b0 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -1927,6 +1927,12 @@ static void perform_access(struct kvm_vcpu *vcpu,
>  {
>  	trace_kvm_sys_access(*vcpu_pc(vcpu), params, r);
>  
> +	/* Check for regs disabled by runtime config */
> +	if (sysreg_hidden_from_guest(vcpu, r)) {
> +		kvm_inject_undefined(vcpu);
> +		return;
> +	}
> +
>  	/*
>  	 * Not having an accessor means that we have configured a trap
>  	 * that we don't know how to handle. This certainly qualifies
> @@ -2438,6 +2444,10 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
>  	if (!r)
>  		return get_invariant_sys_reg(reg->id, uaddr);
>  
> +	/* Check for regs disabled by runtime config */
> +	if (sysreg_hidden_from_user(vcpu, r))
> +		return -ENOENT;
> +
>  	if (r->get_user)
>  		return (r->get_user)(vcpu, r, reg, uaddr);
>  
> @@ -2459,6 +2469,10 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
>  	if (!r)
>  		return set_invariant_sys_reg(reg->id, uaddr);
>  
> +	/* Check for regs disabled by runtime config */
> +	if (sysreg_hidden_from_user(vcpu, r))
> +		return -ENOENT;
> +
>  	if (r->set_user)
>  		return (r->set_user)(vcpu, r, reg, uaddr);
>  
> @@ -2515,7 +2529,8 @@ static bool copy_reg_to_user(const struct sys_reg_desc *reg, u64 __user **uind)
>  	return true;
>  }
>  
> -static int walk_one_sys_reg(const struct sys_reg_desc *rd,
> +static int walk_one_sys_reg(const struct kvm_vcpu *vcpu,
> +			    const struct sys_reg_desc *rd,
>  			    u64 __user **uind,
>  			    unsigned int *total)
>  {
> @@ -2526,6 +2541,9 @@ static int walk_one_sys_reg(const struct sys_reg_desc *rd,
>  	if (!(rd->reg || rd->get_user))
>  		return 0;
>  
> +	if (sysreg_hidden_from_user(vcpu, rd))
> +		return 0;
> +
>  	if (!copy_reg_to_user(rd, uind))
>  		return -EFAULT;
>  
> @@ -2554,9 +2572,9 @@ static int walk_sys_regs(struct kvm_vcpu *vcpu, u64 __user *uind)
>  		int cmp = cmp_sys_reg(i1, i2);
>  		/* target-specific overrides generic entry. */
>  		if (cmp <= 0)
> -			err = walk_one_sys_reg(i1, &uind, &total);
> +			err = walk_one_sys_reg(vcpu, i1, &uind, &total);
>  		else
> -			err = walk_one_sys_reg(i2, &uind, &total);
> +			err = walk_one_sys_reg(vcpu, i2, &uind, &total);
>  
>  		if (err)
>  			return err;
> diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
> index 3b1bc7f..2be9950 100644
> --- a/arch/arm64/kvm/sys_regs.h
> +++ b/arch/arm64/kvm/sys_regs.h
> @@ -64,8 +64,15 @@ struct sys_reg_desc {
>  			const struct kvm_one_reg *reg, void __user *uaddr);
>  	int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
>  			const struct kvm_one_reg *reg, void __user *uaddr);
> +
> +	/* Return mask of REG_* runtime visibility overrides */
> +	unsigned int (*visibility)(const struct kvm_vcpu *vcpu,
> +				   const struct sys_reg_desc *rd);
>  };
>  
> +#define REG_HIDDEN_USER		(1 << 0) /* hidden from userspace ioctls */
> +#define REG_HIDDEN_GUEST	(1 << 1) /* hidden from guest */
> +
>  static inline void print_sys_reg_instr(const struct sys_reg_params *p)
>  {
>  	/* Look, we even formatted it for you to paste into the table! */
> @@ -102,6 +109,24 @@ static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r
>  	__vcpu_sys_reg(vcpu, r->reg) = r->val;
>  }
>  
> +static inline bool sysreg_hidden_from_guest(const struct kvm_vcpu *vcpu,
> +					    const struct sys_reg_desc *r)
> +{
> +	if (likely(!r->visibility))
> +		return false;
> +
> +	return r->visibility(vcpu, r) & REG_HIDDEN_GUEST;
> +}
> +
> +static inline bool sysreg_hidden_from_user(const struct kvm_vcpu *vcpu,
> +					   const struct sys_reg_desc *r)
> +{
> +	if (likely(!r->visibility))
> +		return false;
> +
> +	return r->visibility(vcpu, r) & REG_HIDDEN_USER;
> +}
> +
>  static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
>  			      const struct sys_reg_desc *i2)
>  {
> -- 
> 2.1.4
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 12/27] KVM: arm64/sve: System register context switch and access support
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-03 19:39     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-03 19:39 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:37PM +0000, Dave Martin wrote:
> This patch adds the necessary support for context switching ZCR_EL1
> for each vcpu.
> 
> ZCR_EL1 is trapped alongside the FPSIMD/SVE registers, so it makes
> sense for it to be handled as part of the guest FPSIMD/SVE context
> for context switch purposes instead of handling it as a general
> system register.  This means that it can be switched in lazily at
> the appropriate time.  No effort is made to track host context for
> this register, since SVE requires VHE: thus the hosts's value for
> this register lives permanently in ZCR_EL2 and does not alias the
> guest's value at any time.
> 
> The Hyp switch and fpsimd context handling code is extended
> appropriately.
> 
> Accessors are added in sys_regs.c to expose the SVE system
> registers and ID register fields.  Because these need to be
> conditionally visible based on the guest configuration, they are
> implemented separately for now rather than by use of the generic
> system register helpers.  This may be abstracted better later on
> when/if there are more features requiring this model.
> 
> ID_AA64ZFR0_EL1 is RO-RAZ for MRS/MSR when SVE is disabled for the
> guest, but for compatibility with non-SVE aware KVM implementations
> the register should not be enumerated at all for KVM_GET_REG_LIST
> in this case.  For consistency we also reject ioctl access to the
> register.  This ensures that a non-SVE-enabled guest looks the same
> to userspace, irrespective of whether the kernel KVM implementation
> supports SVE.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * Port to the renamed visibility() framework.
> 
>  * Swap visiblity() helpers so that they appear by the relevant accessor
>    functions.
> 
>  * [Julien Grall] With the visibility() checks, {get,set}_zcr_el1()
>    degenerate to doing exactly what the common code does, so drop them.
> 
>    The ID_AA64ZFR0_EL1 handlers are still needed to provide contitional
>    RAZ behaviour.  This could be moved to the common code too, but since
>    this is a one-off case I don't do this for now.  We can address this
>    later if other regs need to follow the same pattern.
> 
>  * [Julien Thierry] Reset ZCR_EL1 to a fixed value using reset_val
>    instead of using relying on reset_unknown() honouring set bits in val
>    as RES0.
> 
>    Most of the bits in ZCR_EL1 are RES0 anyway, and many implementations
>    of SVE will support larger vectors than 128 bits, so 0 seems as good
>    a value as any to expose guests that forget to initialise this
>    register properly.
> ---
>  arch/arm64/include/asm/kvm_host.h |  1 +
>  arch/arm64/include/asm/sysreg.h   |  3 ++
>  arch/arm64/kvm/fpsimd.c           |  9 ++++-
>  arch/arm64/kvm/hyp/switch.c       |  3 ++
>  arch/arm64/kvm/sys_regs.c         | 83 ++++++++++++++++++++++++++++++++++++---
>  5 files changed, 93 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index ad4f7f0..22cf484 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -121,6 +121,7 @@ enum vcpu_sysreg {
>  	SCTLR_EL1,	/* System Control Register */
>  	ACTLR_EL1,	/* Auxiliary Control Register */
>  	CPACR_EL1,	/* Coprocessor Access Control */
> +	ZCR_EL1,	/* SVE Control */
>  	TTBR0_EL1,	/* Translation Table Base Register 0 */
>  	TTBR1_EL1,	/* Translation Table Base Register 1 */
>  	TCR_EL1,	/* Translation Control Register */
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index 5b267de..4d6262d 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -454,6 +454,9 @@
>  #define SYS_ICH_LR14_EL2		__SYS__LR8_EL2(6)
>  #define SYS_ICH_LR15_EL2		__SYS__LR8_EL2(7)
>  
> +/* VHE encodings for architectural EL0/1 system registers */
> +#define SYS_ZCR_EL12			sys_reg(3, 5, 1, 2, 0)
> +
>  /* Common SCTLR_ELx flags. */
>  #define SCTLR_ELx_DSSBS	(_BITUL(44))
>  #define SCTLR_ELx_ENIA	(_BITUL(31))
> diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
> index 1cf4f02..7053bf4 100644
> --- a/arch/arm64/kvm/fpsimd.c
> +++ b/arch/arm64/kvm/fpsimd.c
> @@ -103,14 +103,21 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
>  void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
>  {
>  	unsigned long flags;
> +	bool host_has_sve = system_supports_sve();
> +	bool guest_has_sve = vcpu_has_sve(vcpu);
>  
>  	local_irq_save(flags);
>  
>  	if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
> +		u64 *guest_zcr = &vcpu->arch.ctxt.sys_regs[ZCR_EL1];
> +
>  		/* Clean guest FP state to memory and invalidate cpu view */
>  		fpsimd_save();
>  		fpsimd_flush_cpu_state();
> -	} else if (system_supports_sve()) {
> +
> +		if (guest_has_sve)
> +			*guest_zcr = read_sysreg_s(SYS_ZCR_EL12);
> +	} else if (host_has_sve) {
>  		/*
>  		 * The FPSIMD/SVE state in the CPU has not been touched, and we
>  		 * have SVE (and VHE): CPACR_EL1 (alias CPTR_EL2) has been
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 3563fe6..9d46066 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -351,6 +351,9 @@ static bool __hyp_text __hyp_switch_fpsimd(struct kvm_vcpu *vcpu)
>  
>  	__fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
>  
> +	if (vcpu_has_sve(vcpu))
> +		write_sysreg_s(vcpu->arch.ctxt.sys_regs[ZCR_EL1], SYS_ZCR_EL12);
> +
>  	/* Skip restoring fpexc32 for AArch64 guests */
>  	if (!(read_sysreg(hcr_el2) & HCR_RW))
>  		write_sysreg(vcpu->arch.ctxt.sys_regs[FPEXC32_EL2],
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index c86a7b0..09e9b06 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -1051,10 +1051,7 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
>  			 (u32)r->CRn, (u32)r->CRm, (u32)r->Op2);
>  	u64 val = raz ? 0 : read_sanitised_ftr_reg(id);
>  
> -	if (id == SYS_ID_AA64PFR0_EL1) {
> -		if (val & (0xfUL << ID_AA64PFR0_SVE_SHIFT))
> -			kvm_debug("SVE unsupported for guests, suppressing\n");
> -
> +	if (id == SYS_ID_AA64PFR0_EL1 && !vcpu_has_sve(vcpu)) {
>  		val &= ~(0xfUL << ID_AA64PFR0_SVE_SHIFT);
>  	} else if (id == SYS_ID_AA64ISAR1_EL1) {
>  		const u64 ptrauth_mask = (0xfUL << ID_AA64ISAR1_APA_SHIFT) |
> @@ -1101,6 +1098,81 @@ static int reg_from_user(u64 *val, const void __user *uaddr, u64 id);
>  static int reg_to_user(void __user *uaddr, const u64 *val, u64 id);
>  static u64 sys_reg_to_index(const struct sys_reg_desc *reg);
>  
> +/* Visibility overrides for SVE-specific control registers */
> +static unsigned int sve_visibility(const struct kvm_vcpu *vcpu,
> +				   const struct sys_reg_desc *rd)
> +{
> +	if (vcpu_has_sve(vcpu))
> +		return 0;
> +
> +	return REG_HIDDEN_USER | REG_HIDDEN_GUEST;
> +}
> +
> +/* Visibility overrides for SVE-specific ID registers */
> +static unsigned int sve_id_visibility(const struct kvm_vcpu *vcpu,
> +				      const struct sys_reg_desc *rd)
> +{
> +	if (vcpu_has_sve(vcpu))
> +		return 0;
> +
> +	return REG_HIDDEN_USER;
> +}
> +
> +/* Generate the emulated ID_AA64ZFR0_EL1 value exposed to the guest */
> +static u64 guest_id_aa64zfr0_el1(const struct kvm_vcpu *vcpu)
> +{
> +	if (!vcpu_has_sve(vcpu))
> +		return 0;
> +
> +	return read_sanitised_ftr_reg(SYS_ID_AA64ZFR0_EL1);
> +}
> +
> +static bool access_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> +				   struct sys_reg_params *p,
> +				   const struct sys_reg_desc *rd)
> +{
> +	if (p->is_write)
> +		return write_to_read_only(vcpu, p, rd);
> +
> +	p->regval = guest_id_aa64zfr0_el1(vcpu);
> +	return true;
> +}
> +
> +static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> +		const struct sys_reg_desc *rd,
> +		const struct kvm_one_reg *reg, void __user *uaddr)
> +{
> +	u64 val;
> +
> +	if (!vcpu_has_sve(vcpu))
> +		return -ENOENT;

This shouldn't be necessary. The visibility check in
kvm_arm_sys_reg_get_reg already covers it.

> +
> +	val = guest_id_aa64zfr0_el1(vcpu);
> +	return reg_to_user(uaddr, &val, reg->id);
> +}
> +
> +static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> +		const struct sys_reg_desc *rd,
> +		const struct kvm_one_reg *reg, void __user *uaddr)
> +{
> +	const u64 id = sys_reg_to_index(rd);
> +	int err;
> +	u64 val;
> +
> +	if (!vcpu_has_sve(vcpu))
> +		return -ENOENT;

Also not necessary.

> +
> +	err = reg_from_user(&val, uaddr, id);
> +	if (err)
> +		return err;
> +
> +	/* This is what we mean by invariant: you can't change it. */
> +	if (val != guest_id_aa64zfr0_el1(vcpu))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /*
>   * cpufeature ID register user accessors
>   *
> @@ -1346,7 +1418,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  	ID_SANITISED(ID_AA64PFR1_EL1),
>  	ID_UNALLOCATED(4,2),
>  	ID_UNALLOCATED(4,3),
> -	ID_UNALLOCATED(4,4),
> +	{ SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility },
>  	ID_UNALLOCATED(4,5),
>  	ID_UNALLOCATED(4,6),
>  	ID_UNALLOCATED(4,7),
> @@ -1383,6 +1455,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  
>  	{ SYS_DESC(SYS_SCTLR_EL1), access_vm_reg, reset_val, SCTLR_EL1, 0x00C50078 },
>  	{ SYS_DESC(SYS_CPACR_EL1), NULL, reset_val, CPACR_EL1, 0 },
> +	{ SYS_DESC(SYS_ZCR_EL1), NULL, reset_val, ZCR_EL1, 0, .visibility = sve_visibility },
>  	{ SYS_DESC(SYS_TTBR0_EL1), access_vm_reg, reset_unknown, TTBR0_EL1 },
>  	{ SYS_DESC(SYS_TTBR1_EL1), access_vm_reg, reset_unknown, TTBR1_EL1 },
>  	{ SYS_DESC(SYS_TCR_EL1), access_vm_reg, reset_val, TCR_EL1, 0 },

Mixing designated and non-designated initializers isn't particularly nice,
but I guess it's valid, and the simple alternatives are probably worse.

Thanks,
drew

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

* Re: [PATCH v7 12/27] KVM: arm64/sve: System register context switch and access support
@ 2019-04-03 19:39     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-03 19:39 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:37PM +0000, Dave Martin wrote:
> This patch adds the necessary support for context switching ZCR_EL1
> for each vcpu.
> 
> ZCR_EL1 is trapped alongside the FPSIMD/SVE registers, so it makes
> sense for it to be handled as part of the guest FPSIMD/SVE context
> for context switch purposes instead of handling it as a general
> system register.  This means that it can be switched in lazily at
> the appropriate time.  No effort is made to track host context for
> this register, since SVE requires VHE: thus the hosts's value for
> this register lives permanently in ZCR_EL2 and does not alias the
> guest's value at any time.
> 
> The Hyp switch and fpsimd context handling code is extended
> appropriately.
> 
> Accessors are added in sys_regs.c to expose the SVE system
> registers and ID register fields.  Because these need to be
> conditionally visible based on the guest configuration, they are
> implemented separately for now rather than by use of the generic
> system register helpers.  This may be abstracted better later on
> when/if there are more features requiring this model.
> 
> ID_AA64ZFR0_EL1 is RO-RAZ for MRS/MSR when SVE is disabled for the
> guest, but for compatibility with non-SVE aware KVM implementations
> the register should not be enumerated at all for KVM_GET_REG_LIST
> in this case.  For consistency we also reject ioctl access to the
> register.  This ensures that a non-SVE-enabled guest looks the same
> to userspace, irrespective of whether the kernel KVM implementation
> supports SVE.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * Port to the renamed visibility() framework.
> 
>  * Swap visiblity() helpers so that they appear by the relevant accessor
>    functions.
> 
>  * [Julien Grall] With the visibility() checks, {get,set}_zcr_el1()
>    degenerate to doing exactly what the common code does, so drop them.
> 
>    The ID_AA64ZFR0_EL1 handlers are still needed to provide contitional
>    RAZ behaviour.  This could be moved to the common code too, but since
>    this is a one-off case I don't do this for now.  We can address this
>    later if other regs need to follow the same pattern.
> 
>  * [Julien Thierry] Reset ZCR_EL1 to a fixed value using reset_val
>    instead of using relying on reset_unknown() honouring set bits in val
>    as RES0.
> 
>    Most of the bits in ZCR_EL1 are RES0 anyway, and many implementations
>    of SVE will support larger vectors than 128 bits, so 0 seems as good
>    a value as any to expose guests that forget to initialise this
>    register properly.
> ---
>  arch/arm64/include/asm/kvm_host.h |  1 +
>  arch/arm64/include/asm/sysreg.h   |  3 ++
>  arch/arm64/kvm/fpsimd.c           |  9 ++++-
>  arch/arm64/kvm/hyp/switch.c       |  3 ++
>  arch/arm64/kvm/sys_regs.c         | 83 ++++++++++++++++++++++++++++++++++++---
>  5 files changed, 93 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index ad4f7f0..22cf484 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -121,6 +121,7 @@ enum vcpu_sysreg {
>  	SCTLR_EL1,	/* System Control Register */
>  	ACTLR_EL1,	/* Auxiliary Control Register */
>  	CPACR_EL1,	/* Coprocessor Access Control */
> +	ZCR_EL1,	/* SVE Control */
>  	TTBR0_EL1,	/* Translation Table Base Register 0 */
>  	TTBR1_EL1,	/* Translation Table Base Register 1 */
>  	TCR_EL1,	/* Translation Control Register */
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index 5b267de..4d6262d 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -454,6 +454,9 @@
>  #define SYS_ICH_LR14_EL2		__SYS__LR8_EL2(6)
>  #define SYS_ICH_LR15_EL2		__SYS__LR8_EL2(7)
>  
> +/* VHE encodings for architectural EL0/1 system registers */
> +#define SYS_ZCR_EL12			sys_reg(3, 5, 1, 2, 0)
> +
>  /* Common SCTLR_ELx flags. */
>  #define SCTLR_ELx_DSSBS	(_BITUL(44))
>  #define SCTLR_ELx_ENIA	(_BITUL(31))
> diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
> index 1cf4f02..7053bf4 100644
> --- a/arch/arm64/kvm/fpsimd.c
> +++ b/arch/arm64/kvm/fpsimd.c
> @@ -103,14 +103,21 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
>  void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
>  {
>  	unsigned long flags;
> +	bool host_has_sve = system_supports_sve();
> +	bool guest_has_sve = vcpu_has_sve(vcpu);
>  
>  	local_irq_save(flags);
>  
>  	if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
> +		u64 *guest_zcr = &vcpu->arch.ctxt.sys_regs[ZCR_EL1];
> +
>  		/* Clean guest FP state to memory and invalidate cpu view */
>  		fpsimd_save();
>  		fpsimd_flush_cpu_state();
> -	} else if (system_supports_sve()) {
> +
> +		if (guest_has_sve)
> +			*guest_zcr = read_sysreg_s(SYS_ZCR_EL12);
> +	} else if (host_has_sve) {
>  		/*
>  		 * The FPSIMD/SVE state in the CPU has not been touched, and we
>  		 * have SVE (and VHE): CPACR_EL1 (alias CPTR_EL2) has been
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 3563fe6..9d46066 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -351,6 +351,9 @@ static bool __hyp_text __hyp_switch_fpsimd(struct kvm_vcpu *vcpu)
>  
>  	__fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
>  
> +	if (vcpu_has_sve(vcpu))
> +		write_sysreg_s(vcpu->arch.ctxt.sys_regs[ZCR_EL1], SYS_ZCR_EL12);
> +
>  	/* Skip restoring fpexc32 for AArch64 guests */
>  	if (!(read_sysreg(hcr_el2) & HCR_RW))
>  		write_sysreg(vcpu->arch.ctxt.sys_regs[FPEXC32_EL2],
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index c86a7b0..09e9b06 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -1051,10 +1051,7 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
>  			 (u32)r->CRn, (u32)r->CRm, (u32)r->Op2);
>  	u64 val = raz ? 0 : read_sanitised_ftr_reg(id);
>  
> -	if (id == SYS_ID_AA64PFR0_EL1) {
> -		if (val & (0xfUL << ID_AA64PFR0_SVE_SHIFT))
> -			kvm_debug("SVE unsupported for guests, suppressing\n");
> -
> +	if (id == SYS_ID_AA64PFR0_EL1 && !vcpu_has_sve(vcpu)) {
>  		val &= ~(0xfUL << ID_AA64PFR0_SVE_SHIFT);
>  	} else if (id == SYS_ID_AA64ISAR1_EL1) {
>  		const u64 ptrauth_mask = (0xfUL << ID_AA64ISAR1_APA_SHIFT) |
> @@ -1101,6 +1098,81 @@ static int reg_from_user(u64 *val, const void __user *uaddr, u64 id);
>  static int reg_to_user(void __user *uaddr, const u64 *val, u64 id);
>  static u64 sys_reg_to_index(const struct sys_reg_desc *reg);
>  
> +/* Visibility overrides for SVE-specific control registers */
> +static unsigned int sve_visibility(const struct kvm_vcpu *vcpu,
> +				   const struct sys_reg_desc *rd)
> +{
> +	if (vcpu_has_sve(vcpu))
> +		return 0;
> +
> +	return REG_HIDDEN_USER | REG_HIDDEN_GUEST;
> +}
> +
> +/* Visibility overrides for SVE-specific ID registers */
> +static unsigned int sve_id_visibility(const struct kvm_vcpu *vcpu,
> +				      const struct sys_reg_desc *rd)
> +{
> +	if (vcpu_has_sve(vcpu))
> +		return 0;
> +
> +	return REG_HIDDEN_USER;
> +}
> +
> +/* Generate the emulated ID_AA64ZFR0_EL1 value exposed to the guest */
> +static u64 guest_id_aa64zfr0_el1(const struct kvm_vcpu *vcpu)
> +{
> +	if (!vcpu_has_sve(vcpu))
> +		return 0;
> +
> +	return read_sanitised_ftr_reg(SYS_ID_AA64ZFR0_EL1);
> +}
> +
> +static bool access_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> +				   struct sys_reg_params *p,
> +				   const struct sys_reg_desc *rd)
> +{
> +	if (p->is_write)
> +		return write_to_read_only(vcpu, p, rd);
> +
> +	p->regval = guest_id_aa64zfr0_el1(vcpu);
> +	return true;
> +}
> +
> +static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> +		const struct sys_reg_desc *rd,
> +		const struct kvm_one_reg *reg, void __user *uaddr)
> +{
> +	u64 val;
> +
> +	if (!vcpu_has_sve(vcpu))
> +		return -ENOENT;

This shouldn't be necessary. The visibility check in
kvm_arm_sys_reg_get_reg already covers it.

> +
> +	val = guest_id_aa64zfr0_el1(vcpu);
> +	return reg_to_user(uaddr, &val, reg->id);
> +}
> +
> +static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> +		const struct sys_reg_desc *rd,
> +		const struct kvm_one_reg *reg, void __user *uaddr)
> +{
> +	const u64 id = sys_reg_to_index(rd);
> +	int err;
> +	u64 val;
> +
> +	if (!vcpu_has_sve(vcpu))
> +		return -ENOENT;

Also not necessary.

> +
> +	err = reg_from_user(&val, uaddr, id);
> +	if (err)
> +		return err;
> +
> +	/* This is what we mean by invariant: you can't change it. */
> +	if (val != guest_id_aa64zfr0_el1(vcpu))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /*
>   * cpufeature ID register user accessors
>   *
> @@ -1346,7 +1418,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  	ID_SANITISED(ID_AA64PFR1_EL1),
>  	ID_UNALLOCATED(4,2),
>  	ID_UNALLOCATED(4,3),
> -	ID_UNALLOCATED(4,4),
> +	{ SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility },
>  	ID_UNALLOCATED(4,5),
>  	ID_UNALLOCATED(4,6),
>  	ID_UNALLOCATED(4,7),
> @@ -1383,6 +1455,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  
>  	{ SYS_DESC(SYS_SCTLR_EL1), access_vm_reg, reset_val, SCTLR_EL1, 0x00C50078 },
>  	{ SYS_DESC(SYS_CPACR_EL1), NULL, reset_val, CPACR_EL1, 0 },
> +	{ SYS_DESC(SYS_ZCR_EL1), NULL, reset_val, ZCR_EL1, 0, .visibility = sve_visibility },
>  	{ SYS_DESC(SYS_TTBR0_EL1), access_vm_reg, reset_unknown, TTBR0_EL1 },
>  	{ SYS_DESC(SYS_TTBR1_EL1), access_vm_reg, reset_unknown, TTBR1_EL1 },
>  	{ SYS_DESC(SYS_TCR_EL1), access_vm_reg, reset_val, TCR_EL1, 0 },

Mixing designated and non-designated initializers isn't particularly nice,
but I guess it's valid, and the simple alternatives are probably worse.

Thanks,
drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 13/27] KVM: arm64/sve: Context switch the SVE registers
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-03 20:01     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-03 20:01 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:38PM +0000, Dave Martin wrote:
> In order to give each vcpu its own view of the SVE registers, this
> patch adds context storage via a new sve_state pointer in struct
> vcpu_arch.  An additional member sve_max_vl is also added for each
> vcpu, to determine the maximum vector length visible to the guest
> and thus the value to be configured in ZCR_EL2.LEN while the vcpu
> is active.  This also determines the layout and size of the storage
> in sve_state, which is read and written by the same backend
> functions that are used for context-switching the SVE state for
> host tasks.
> 
> On SVE-enabled vcpus, SVE access traps are now handled by switching
> in the vcpu's SVE context and disabling the trap before returning
> to the guest.  On other vcpus, the trap is not handled and an exit
> back to the host occurs, where the handle_sve() fallback path
> reflects an undefined instruction exception back to the guest,
> consistently with the behaviour of non-SVE-capable hardware (as was
> done unconditionally prior to this patch).
> 
> No SVE handling is added on non-VHE-only paths, since VHE is an
> architectural and Kconfig prerequisite of SVE.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * [Julien Thierry, Julien Grall] Commit message typo fixes
> 
>  * [Mark Rutland] Rename trap_class to hsr_ec, for consistency with
>    existing code.
> 
>  * [Mark Rutland] Simplify condition for refusing to handle an
>    FPSIMD/SVE trap, using multiple if () statements for clarity.  The
>    previous condition was a bit tortuous, and how that the static_key
>    checks have been hoisted out, it makes little difference to the
>    compiler how we express the condition here.
> ---
>  arch/arm64/include/asm/kvm_host.h |  6 ++++
>  arch/arm64/kvm/fpsimd.c           |  5 +--
>  arch/arm64/kvm/hyp/switch.c       | 75 +++++++++++++++++++++++++++++----------
>  3 files changed, 66 insertions(+), 20 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 22cf484..4fabfd2 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -228,6 +228,8 @@ struct vcpu_reset_state {
>  
>  struct kvm_vcpu_arch {
>  	struct kvm_cpu_context ctxt;
> +	void *sve_state;
> +	unsigned int sve_max_vl;
>  
>  	/* HYP configuration */
>  	u64 hcr_el2;
> @@ -323,6 +325,10 @@ struct kvm_vcpu_arch {
>  	bool sysregs_loaded_on_cpu;
>  };
>  
> +/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
> +#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
> +				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))

Maybe an inline function instead?

> +
>  /* vcpu_arch flags field values: */
>  #define KVM_ARM64_DEBUG_DIRTY		(1 << 0)
>  #define KVM_ARM64_FP_ENABLED		(1 << 1) /* guest FP regs loaded */
> diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
> index 7053bf4..6e3c9c8 100644
> --- a/arch/arm64/kvm/fpsimd.c
> +++ b/arch/arm64/kvm/fpsimd.c
> @@ -87,10 +87,11 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
>  
>  	if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
>  		fpsimd_bind_state_to_cpu(&vcpu->arch.ctxt.gp_regs.fp_regs,
> -					 NULL, SVE_VL_MIN);
> +					 vcpu->arch.sve_state,
> +					 vcpu->arch.sve_max_vl);
>  
>  		clear_thread_flag(TIF_FOREIGN_FPSTATE);
> -		clear_thread_flag(TIF_SVE);
> +		update_thread_flag(TIF_SVE, vcpu_has_sve(vcpu));
>  	}
>  }
>  
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 9d46066..5444b9c 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -100,7 +100,10 @@ static void activate_traps_vhe(struct kvm_vcpu *vcpu)
>  	val = read_sysreg(cpacr_el1);
>  	val |= CPACR_EL1_TTA;
>  	val &= ~CPACR_EL1_ZEN;
> -	if (!update_fp_enabled(vcpu)) {
> +	if (update_fp_enabled(vcpu)) {
> +		if (vcpu_has_sve(vcpu))
> +			val |= CPACR_EL1_ZEN;
> +	} else {
>  		val &= ~CPACR_EL1_FPEN;
>  		__activate_traps_fpsimd32(vcpu);
>  	}
> @@ -317,16 +320,48 @@ static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
>  	return true;
>  }
>  
> -static bool __hyp_text __hyp_switch_fpsimd(struct kvm_vcpu *vcpu)
> +/* Check for an FPSIMD/SVE trap and handle as appropriate */
> +static bool __hyp_text __hyp_handle_fpsimd(struct kvm_vcpu *vcpu)
>  {
> -	struct user_fpsimd_state *host_fpsimd = vcpu->arch.host_fpsimd_state;
> +	bool vhe, sve_guest, sve_host;
> +	u8 hsr_ec;
>  
> -	if (has_vhe())
> -		write_sysreg(read_sysreg(cpacr_el1) | CPACR_EL1_FPEN,
> -			     cpacr_el1);
> -	else
> +	if (!system_supports_fpsimd())
> +		return false;
> +
> +	if (system_supports_sve()) {
> +		sve_guest = vcpu_has_sve(vcpu);
> +		sve_host = vcpu->arch.flags & KVM_ARM64_HOST_SVE_IN_USE;
> +		vhe = true;
> +	} else {
> +		sve_guest = false;
> +		sve_host = false;
> +		vhe = has_vhe();
> +	}
> +
> +	hsr_ec = kvm_vcpu_trap_get_class(vcpu);
> +	if (hsr_ec != ESR_ELx_EC_FP_ASIMD &&
> +	    hsr_ec != ESR_ELx_EC_SVE)
> +		return false;
> +
> +	/* Don't handle SVE traps for non-SVE vcpus here: */
> +	if (!sve_guest)
> +		if (hsr_ec != ESR_ELx_EC_FP_ASIMD)
> +			return false;
> +
> +	/* Valid trap.  Switch the context: */
> +
> +	if (vhe) {
> +		u64 reg = read_sysreg(cpacr_el1) | CPACR_EL1_FPEN;
> +
> +		if (sve_guest)
> +			reg |= CPACR_EL1_ZEN;
> +
> +		write_sysreg(reg, cpacr_el1);
> +	} else {
>  		write_sysreg(read_sysreg(cptr_el2) & ~(u64)CPTR_EL2_TFP,
>  			     cptr_el2);
> +	}
>  
>  	isb();
>  
> @@ -335,24 +370,28 @@ static bool __hyp_text __hyp_switch_fpsimd(struct kvm_vcpu *vcpu)
>  		 * In the SVE case, VHE is assumed: it is enforced by
>  		 * Kconfig and kvm_arch_init().
>  		 */
> -		if (system_supports_sve() &&
> -		    (vcpu->arch.flags & KVM_ARM64_HOST_SVE_IN_USE)) {
> +		if (sve_host) {
>  			struct thread_struct *thread = container_of(
> -				host_fpsimd,
> +				vcpu->arch.host_fpsimd_state,
>  				struct thread_struct, uw.fpsimd_state);
>  
> -			sve_save_state(sve_pffr(thread), &host_fpsimd->fpsr);
> +			sve_save_state(sve_pffr(thread),
> +				       &vcpu->arch.host_fpsimd_state->fpsr);
>  		} else {
> -			__fpsimd_save_state(host_fpsimd);
> +			__fpsimd_save_state(vcpu->arch.host_fpsimd_state);
>  		}
>  
>  		vcpu->arch.flags &= ~KVM_ARM64_FP_HOST;
>  	}
>  
> -	__fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
> -
> -	if (vcpu_has_sve(vcpu))
> +	if (sve_guest) {
> +		sve_load_state(vcpu_sve_pffr(vcpu),
> +			       &vcpu->arch.ctxt.gp_regs.fp_regs.fpsr,
> +			       sve_vq_from_vl(vcpu->arch.sve_max_vl) - 1);
>  		write_sysreg_s(vcpu->arch.ctxt.sys_regs[ZCR_EL1], SYS_ZCR_EL12);
> +	} else {
> +		__fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
> +	}
>  
>  	/* Skip restoring fpexc32 for AArch64 guests */
>  	if (!(read_sysreg(hcr_el2) & HCR_RW))
> @@ -388,10 +427,10 @@ static bool __hyp_text fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
>  	 * and restore the guest context lazily.
>  	 * If FP/SIMD is not implemented, handle the trap and inject an
>  	 * undefined instruction exception to the guest.
> +	 * Similarly for trapped SVE accesses.
>  	 */
> -	if (system_supports_fpsimd() &&
> -	    kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_FP_ASIMD)
> -		return __hyp_switch_fpsimd(vcpu);
> +	if (__hyp_handle_fpsimd(vcpu))
> +		return true;
>  
>  	if (!__populate_fault_info(vcpu))
>  		return true;

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v7 13/27] KVM: arm64/sve: Context switch the SVE registers
@ 2019-04-03 20:01     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-03 20:01 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:38PM +0000, Dave Martin wrote:
> In order to give each vcpu its own view of the SVE registers, this
> patch adds context storage via a new sve_state pointer in struct
> vcpu_arch.  An additional member sve_max_vl is also added for each
> vcpu, to determine the maximum vector length visible to the guest
> and thus the value to be configured in ZCR_EL2.LEN while the vcpu
> is active.  This also determines the layout and size of the storage
> in sve_state, which is read and written by the same backend
> functions that are used for context-switching the SVE state for
> host tasks.
> 
> On SVE-enabled vcpus, SVE access traps are now handled by switching
> in the vcpu's SVE context and disabling the trap before returning
> to the guest.  On other vcpus, the trap is not handled and an exit
> back to the host occurs, where the handle_sve() fallback path
> reflects an undefined instruction exception back to the guest,
> consistently with the behaviour of non-SVE-capable hardware (as was
> done unconditionally prior to this patch).
> 
> No SVE handling is added on non-VHE-only paths, since VHE is an
> architectural and Kconfig prerequisite of SVE.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * [Julien Thierry, Julien Grall] Commit message typo fixes
> 
>  * [Mark Rutland] Rename trap_class to hsr_ec, for consistency with
>    existing code.
> 
>  * [Mark Rutland] Simplify condition for refusing to handle an
>    FPSIMD/SVE trap, using multiple if () statements for clarity.  The
>    previous condition was a bit tortuous, and how that the static_key
>    checks have been hoisted out, it makes little difference to the
>    compiler how we express the condition here.
> ---
>  arch/arm64/include/asm/kvm_host.h |  6 ++++
>  arch/arm64/kvm/fpsimd.c           |  5 +--
>  arch/arm64/kvm/hyp/switch.c       | 75 +++++++++++++++++++++++++++++----------
>  3 files changed, 66 insertions(+), 20 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 22cf484..4fabfd2 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -228,6 +228,8 @@ struct vcpu_reset_state {
>  
>  struct kvm_vcpu_arch {
>  	struct kvm_cpu_context ctxt;
> +	void *sve_state;
> +	unsigned int sve_max_vl;
>  
>  	/* HYP configuration */
>  	u64 hcr_el2;
> @@ -323,6 +325,10 @@ struct kvm_vcpu_arch {
>  	bool sysregs_loaded_on_cpu;
>  };
>  
> +/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
> +#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
> +				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))

Maybe an inline function instead?

> +
>  /* vcpu_arch flags field values: */
>  #define KVM_ARM64_DEBUG_DIRTY		(1 << 0)
>  #define KVM_ARM64_FP_ENABLED		(1 << 1) /* guest FP regs loaded */
> diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
> index 7053bf4..6e3c9c8 100644
> --- a/arch/arm64/kvm/fpsimd.c
> +++ b/arch/arm64/kvm/fpsimd.c
> @@ -87,10 +87,11 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
>  
>  	if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
>  		fpsimd_bind_state_to_cpu(&vcpu->arch.ctxt.gp_regs.fp_regs,
> -					 NULL, SVE_VL_MIN);
> +					 vcpu->arch.sve_state,
> +					 vcpu->arch.sve_max_vl);
>  
>  		clear_thread_flag(TIF_FOREIGN_FPSTATE);
> -		clear_thread_flag(TIF_SVE);
> +		update_thread_flag(TIF_SVE, vcpu_has_sve(vcpu));
>  	}
>  }
>  
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 9d46066..5444b9c 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -100,7 +100,10 @@ static void activate_traps_vhe(struct kvm_vcpu *vcpu)
>  	val = read_sysreg(cpacr_el1);
>  	val |= CPACR_EL1_TTA;
>  	val &= ~CPACR_EL1_ZEN;
> -	if (!update_fp_enabled(vcpu)) {
> +	if (update_fp_enabled(vcpu)) {
> +		if (vcpu_has_sve(vcpu))
> +			val |= CPACR_EL1_ZEN;
> +	} else {
>  		val &= ~CPACR_EL1_FPEN;
>  		__activate_traps_fpsimd32(vcpu);
>  	}
> @@ -317,16 +320,48 @@ static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
>  	return true;
>  }
>  
> -static bool __hyp_text __hyp_switch_fpsimd(struct kvm_vcpu *vcpu)
> +/* Check for an FPSIMD/SVE trap and handle as appropriate */
> +static bool __hyp_text __hyp_handle_fpsimd(struct kvm_vcpu *vcpu)
>  {
> -	struct user_fpsimd_state *host_fpsimd = vcpu->arch.host_fpsimd_state;
> +	bool vhe, sve_guest, sve_host;
> +	u8 hsr_ec;
>  
> -	if (has_vhe())
> -		write_sysreg(read_sysreg(cpacr_el1) | CPACR_EL1_FPEN,
> -			     cpacr_el1);
> -	else
> +	if (!system_supports_fpsimd())
> +		return false;
> +
> +	if (system_supports_sve()) {
> +		sve_guest = vcpu_has_sve(vcpu);
> +		sve_host = vcpu->arch.flags & KVM_ARM64_HOST_SVE_IN_USE;
> +		vhe = true;
> +	} else {
> +		sve_guest = false;
> +		sve_host = false;
> +		vhe = has_vhe();
> +	}
> +
> +	hsr_ec = kvm_vcpu_trap_get_class(vcpu);
> +	if (hsr_ec != ESR_ELx_EC_FP_ASIMD &&
> +	    hsr_ec != ESR_ELx_EC_SVE)
> +		return false;
> +
> +	/* Don't handle SVE traps for non-SVE vcpus here: */
> +	if (!sve_guest)
> +		if (hsr_ec != ESR_ELx_EC_FP_ASIMD)
> +			return false;
> +
> +	/* Valid trap.  Switch the context: */
> +
> +	if (vhe) {
> +		u64 reg = read_sysreg(cpacr_el1) | CPACR_EL1_FPEN;
> +
> +		if (sve_guest)
> +			reg |= CPACR_EL1_ZEN;
> +
> +		write_sysreg(reg, cpacr_el1);
> +	} else {
>  		write_sysreg(read_sysreg(cptr_el2) & ~(u64)CPTR_EL2_TFP,
>  			     cptr_el2);
> +	}
>  
>  	isb();
>  
> @@ -335,24 +370,28 @@ static bool __hyp_text __hyp_switch_fpsimd(struct kvm_vcpu *vcpu)
>  		 * In the SVE case, VHE is assumed: it is enforced by
>  		 * Kconfig and kvm_arch_init().
>  		 */
> -		if (system_supports_sve() &&
> -		    (vcpu->arch.flags & KVM_ARM64_HOST_SVE_IN_USE)) {
> +		if (sve_host) {
>  			struct thread_struct *thread = container_of(
> -				host_fpsimd,
> +				vcpu->arch.host_fpsimd_state,
>  				struct thread_struct, uw.fpsimd_state);
>  
> -			sve_save_state(sve_pffr(thread), &host_fpsimd->fpsr);
> +			sve_save_state(sve_pffr(thread),
> +				       &vcpu->arch.host_fpsimd_state->fpsr);
>  		} else {
> -			__fpsimd_save_state(host_fpsimd);
> +			__fpsimd_save_state(vcpu->arch.host_fpsimd_state);
>  		}
>  
>  		vcpu->arch.flags &= ~KVM_ARM64_FP_HOST;
>  	}
>  
> -	__fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
> -
> -	if (vcpu_has_sve(vcpu))
> +	if (sve_guest) {
> +		sve_load_state(vcpu_sve_pffr(vcpu),
> +			       &vcpu->arch.ctxt.gp_regs.fp_regs.fpsr,
> +			       sve_vq_from_vl(vcpu->arch.sve_max_vl) - 1);
>  		write_sysreg_s(vcpu->arch.ctxt.sys_regs[ZCR_EL1], SYS_ZCR_EL12);
> +	} else {
> +		__fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
> +	}
>  
>  	/* Skip restoring fpexc32 for AArch64 guests */
>  	if (!(read_sysreg(hcr_el2) & HCR_RW))
> @@ -388,10 +427,10 @@ static bool __hyp_text fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
>  	 * and restore the guest context lazily.
>  	 * If FP/SIMD is not implemented, handle the trap and inject an
>  	 * undefined instruction exception to the guest.
> +	 * Similarly for trapped SVE accesses.
>  	 */
> -	if (system_supports_fpsimd() &&
> -	    kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_FP_ASIMD)
> -		return __hyp_switch_fpsimd(vcpu);
> +	if (__hyp_handle_fpsimd(vcpu))
> +		return true;
>  
>  	if (!__populate_fault_info(vcpu))
>  		return true;

Reviewed-by: Andrew Jones <drjones@redhat.com>

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 17/27] KVM: arm64: Reject ioctl access to FPSIMD V-regs on SVE vcpus
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-03 20:15     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-03 20:15 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:42PM +0000, Dave Martin wrote:
> In order to avoid the pointless complexity of maintaining two ioctl
> register access views of the same data, this patch blocks ioctl
> access to the FPSIMD V-registers on vcpus that support SVE.
> 
> This will make it more straightforward to add SVE register access
> support.
> 
> Since SVE is an opt-in feature for userspace, this will not affect
> existing users.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * Refactored to cope with the removal of core_reg_size_from_offset()
>    (which was added by another series which will now be handled
>    independently).
> 
>    This leaves some duplication in that we still filter the V-regs out
>    in two places, but this no worse than other existing code in guest.c.
>    I plan to tidy this up independently later on.
> ---
>  arch/arm64/kvm/guest.c | 48 ++++++++++++++++++++++++++++++++++++------------
>  1 file changed, 36 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index a391a61..756d0d6 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -54,12 +54,19 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
>  	return 0;
>  }
>  
> +static bool core_reg_offset_is_vreg(u64 off)
> +{
> +	return off >= KVM_REG_ARM_CORE_REG(fp_regs.vregs) &&
> +		off < KVM_REG_ARM_CORE_REG(fp_regs.fpsr);
> +}
> +
>  static u64 core_reg_offset_from_id(u64 id)
>  {
>  	return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
>  }
>  
> -static int validate_core_offset(const struct kvm_one_reg *reg)
> +static int validate_core_offset(const struct kvm_vcpu *vcpu,
> +				const struct kvm_one_reg *reg)
>  {
>  	u64 off = core_reg_offset_from_id(reg->id);
>  	int size;
> @@ -91,11 +98,19 @@ static int validate_core_offset(const struct kvm_one_reg *reg)
>  		return -EINVAL;
>  	}
>  
> -	if (KVM_REG_SIZE(reg->id) == size &&
> -	    IS_ALIGNED(off, size / sizeof(__u32)))
> -		return 0;
> +	if (KVM_REG_SIZE(reg->id) != size ||
> +	    !IS_ALIGNED(off, size / sizeof(__u32)))
> +		return -EINVAL;
>  
> -	return -EINVAL;
> +	/*
> +	 * The KVM_REG_ARM64_SVE regs must be used instead of
> +	 * KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on
> +	 * SVE-enabled vcpus:
> +	 */
> +	if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(off))
> +		return -EINVAL;
> +
> +	return 0;
>  }
>  
>  static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> @@ -117,7 +132,7 @@ static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	    (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
>  		return -ENOENT;
>  
> -	if (validate_core_offset(reg))
> +	if (validate_core_offset(vcpu, reg))
>  		return -EINVAL;
>  
>  	if (copy_to_user(uaddr, ((u32 *)regs) + off, KVM_REG_SIZE(reg->id)))
> @@ -142,7 +157,7 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	    (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
>  		return -ENOENT;
>  
> -	if (validate_core_offset(reg))
> +	if (validate_core_offset(vcpu, reg))
>  		return -EINVAL;
>  
>  	if (KVM_REG_SIZE(reg->id) > sizeof(tmp))
> @@ -195,13 +210,22 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
>  	return -EINVAL;
>  }
>  
> -static int kvm_arm_copy_core_reg_indices(u64 __user *uindices)
> +static int copy_core_reg_indices(const struct kvm_vcpu *vcpu,
> +				 u64 __user *uindices)
>  {
>  	unsigned int i;
>  	int n = 0;
>  	const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
>  
>  	for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
> +		/*
> +		 * The KVM_REG_ARM64_SVE regs must be used instead of
> +		 * KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on
> +		 * SVE-enabled vcpus:
> +		 */
> +		if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(i))
> +			continue;
> +
>  		if (uindices) {
>  			if (put_user(core_reg | i, uindices))
>  				return -EFAULT;
> @@ -214,9 +238,9 @@ static int kvm_arm_copy_core_reg_indices(u64 __user *uindices)
>  	return n;
>  }
>  
> -static unsigned long num_core_regs(void)
> +static unsigned long num_core_regs(const struct kvm_vcpu *vcpu)
>  {
> -	return kvm_arm_copy_core_reg_indices(NULL);
> +	return copy_core_reg_indices(vcpu, NULL);
>  }
>  
>  /**
> @@ -281,7 +305,7 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
>  {
>  	unsigned long res = 0;
>  
> -	res += num_core_regs();
> +	res += num_core_regs(vcpu);
>  	res += kvm_arm_num_sys_reg_descs(vcpu);
>  	res += kvm_arm_get_fw_num_regs(vcpu);
>  	res += NUM_TIMER_REGS;
> @@ -298,7 +322,7 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
>  {
>  	int ret;
>  
> -	ret = kvm_arm_copy_core_reg_indices(uindices);
> +	ret = copy_core_reg_indices(vcpu, uindices);
>  	if (ret)
>  		return ret;
>  	uindices += ret;
> -- 
> 2.1.4
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v7 17/27] KVM: arm64: Reject ioctl access to FPSIMD V-regs on SVE vcpus
@ 2019-04-03 20:15     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-03 20:15 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:42PM +0000, Dave Martin wrote:
> In order to avoid the pointless complexity of maintaining two ioctl
> register access views of the same data, this patch blocks ioctl
> access to the FPSIMD V-registers on vcpus that support SVE.
> 
> This will make it more straightforward to add SVE register access
> support.
> 
> Since SVE is an opt-in feature for userspace, this will not affect
> existing users.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * Refactored to cope with the removal of core_reg_size_from_offset()
>    (which was added by another series which will now be handled
>    independently).
> 
>    This leaves some duplication in that we still filter the V-regs out
>    in two places, but this no worse than other existing code in guest.c.
>    I plan to tidy this up independently later on.
> ---
>  arch/arm64/kvm/guest.c | 48 ++++++++++++++++++++++++++++++++++++------------
>  1 file changed, 36 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index a391a61..756d0d6 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -54,12 +54,19 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
>  	return 0;
>  }
>  
> +static bool core_reg_offset_is_vreg(u64 off)
> +{
> +	return off >= KVM_REG_ARM_CORE_REG(fp_regs.vregs) &&
> +		off < KVM_REG_ARM_CORE_REG(fp_regs.fpsr);
> +}
> +
>  static u64 core_reg_offset_from_id(u64 id)
>  {
>  	return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
>  }
>  
> -static int validate_core_offset(const struct kvm_one_reg *reg)
> +static int validate_core_offset(const struct kvm_vcpu *vcpu,
> +				const struct kvm_one_reg *reg)
>  {
>  	u64 off = core_reg_offset_from_id(reg->id);
>  	int size;
> @@ -91,11 +98,19 @@ static int validate_core_offset(const struct kvm_one_reg *reg)
>  		return -EINVAL;
>  	}
>  
> -	if (KVM_REG_SIZE(reg->id) == size &&
> -	    IS_ALIGNED(off, size / sizeof(__u32)))
> -		return 0;
> +	if (KVM_REG_SIZE(reg->id) != size ||
> +	    !IS_ALIGNED(off, size / sizeof(__u32)))
> +		return -EINVAL;
>  
> -	return -EINVAL;
> +	/*
> +	 * The KVM_REG_ARM64_SVE regs must be used instead of
> +	 * KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on
> +	 * SVE-enabled vcpus:
> +	 */
> +	if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(off))
> +		return -EINVAL;
> +
> +	return 0;
>  }
>  
>  static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> @@ -117,7 +132,7 @@ static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	    (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
>  		return -ENOENT;
>  
> -	if (validate_core_offset(reg))
> +	if (validate_core_offset(vcpu, reg))
>  		return -EINVAL;
>  
>  	if (copy_to_user(uaddr, ((u32 *)regs) + off, KVM_REG_SIZE(reg->id)))
> @@ -142,7 +157,7 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	    (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
>  		return -ENOENT;
>  
> -	if (validate_core_offset(reg))
> +	if (validate_core_offset(vcpu, reg))
>  		return -EINVAL;
>  
>  	if (KVM_REG_SIZE(reg->id) > sizeof(tmp))
> @@ -195,13 +210,22 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
>  	return -EINVAL;
>  }
>  
> -static int kvm_arm_copy_core_reg_indices(u64 __user *uindices)
> +static int copy_core_reg_indices(const struct kvm_vcpu *vcpu,
> +				 u64 __user *uindices)
>  {
>  	unsigned int i;
>  	int n = 0;
>  	const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
>  
>  	for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
> +		/*
> +		 * The KVM_REG_ARM64_SVE regs must be used instead of
> +		 * KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on
> +		 * SVE-enabled vcpus:
> +		 */
> +		if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(i))
> +			continue;
> +
>  		if (uindices) {
>  			if (put_user(core_reg | i, uindices))
>  				return -EFAULT;
> @@ -214,9 +238,9 @@ static int kvm_arm_copy_core_reg_indices(u64 __user *uindices)
>  	return n;
>  }
>  
> -static unsigned long num_core_regs(void)
> +static unsigned long num_core_regs(const struct kvm_vcpu *vcpu)
>  {
> -	return kvm_arm_copy_core_reg_indices(NULL);
> +	return copy_core_reg_indices(vcpu, NULL);
>  }
>  
>  /**
> @@ -281,7 +305,7 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
>  {
>  	unsigned long res = 0;
>  
> -	res += num_core_regs();
> +	res += num_core_regs(vcpu);
>  	res += kvm_arm_num_sys_reg_descs(vcpu);
>  	res += kvm_arm_get_fw_num_regs(vcpu);
>  	res += NUM_TIMER_REGS;
> @@ -298,7 +322,7 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
>  {
>  	int ret;
>  
> -	ret = kvm_arm_copy_core_reg_indices(uindices);
> +	ret = copy_core_reg_indices(vcpu, uindices);
>  	if (ret)
>  		return ret;
>  	uindices += ret;
> -- 
> 2.1.4
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 26/27] KVM: Document errors for KVM_GET_ONE_REG and KVM_SET_ONE_REG
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-03 20:27     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-03 20:27 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:51PM +0000, Dave Martin wrote:
> KVM_GET_ONE_REG and KVM_SET_ONE_REG return some error codes that
> are not documented (but hopefully not surprising either).  To give
> an indication of what these may mean, this patch adds brief
> documentation.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> ---
>  Documentation/virtual/kvm/api.txt | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index 2d4f7ce..cd920dd 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -1871,6 +1871,9 @@ Architectures: all
>  Type: vcpu ioctl
>  Parameters: struct kvm_one_reg (in)
>  Returns: 0 on success, negative value on failure
> +Errors:
> +  ENOENT:   no such register
> +  EINVAL:   other errors, such as bad size encoding for a known register
>  
>  struct kvm_one_reg {
>         __u64 id;
> @@ -2192,6 +2195,9 @@ Architectures: all
>  Type: vcpu ioctl
>  Parameters: struct kvm_one_reg (in and out)
>  Returns: 0 on success, negative value on failure
> +Errors:
> +  ENOENT:   no such register
> +  EINVAL:   other errors, such as bad size encoding for a known register
>  
>  This ioctl allows to receive the value of a single register implemented
>  in a vcpu. The register to read is indicated by the "id" field of the
> -- 
> 2.1.4
>

Are we sure all architectures have these, and only these errors? A quick
grep indicates not. I'm not sure we can document this easily here due to
it addressing all architectures at once. Maybe we could add arch-specific
subsections, but I'm not sure it's worth it.

drew

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

* Re: [PATCH v7 26/27] KVM: Document errors for KVM_GET_ONE_REG and KVM_SET_ONE_REG
@ 2019-04-03 20:27     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-03 20:27 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:51PM +0000, Dave Martin wrote:
> KVM_GET_ONE_REG and KVM_SET_ONE_REG return some error codes that
> are not documented (but hopefully not surprising either).  To give
> an indication of what these may mean, this patch adds brief
> documentation.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> ---
>  Documentation/virtual/kvm/api.txt | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index 2d4f7ce..cd920dd 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -1871,6 +1871,9 @@ Architectures: all
>  Type: vcpu ioctl
>  Parameters: struct kvm_one_reg (in)
>  Returns: 0 on success, negative value on failure
> +Errors:
> +  ENOENT:   no such register
> +  EINVAL:   other errors, such as bad size encoding for a known register
>  
>  struct kvm_one_reg {
>         __u64 id;
> @@ -2192,6 +2195,9 @@ Architectures: all
>  Type: vcpu ioctl
>  Parameters: struct kvm_one_reg (in and out)
>  Returns: 0 on success, negative value on failure
> +Errors:
> +  ENOENT:   no such register
> +  EINVAL:   other errors, such as bad size encoding for a known register
>  
>  This ioctl allows to receive the value of a single register implemented
>  in a vcpu. The register to read is indicated by the "id" field of the
> -- 
> 2.1.4
>

Are we sure all architectures have these, and only these errors? A quick
grep indicates not. I'm not sure we can document this easily here due to
it addressing all architectures at once. Maybe we could add arch-specific
subsections, but I'm not sure it's worth it.

drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 09/27] KVM: arm64: Add a vcpu flag to control SVE visibility for the guest
  2019-04-03 19:14     ` Andrew Jones
@ 2019-04-04  3:17       ` Marc Zyngier
  -1 siblings, 0 replies; 224+ messages in thread
From: Marc Zyngier @ 2019-04-04  3:17 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel,
	Catalin Marinas, Will Deacon, kvmarm, Julien Grall, Zhang Lei,
	Dave Martin, linux-arm-kernel

On Wed, 03 Apr 2019 20:14:13 +0100,
Andrew Jones <drjones@redhat.com> wrote:
> 
> On Fri, Mar 29, 2019 at 01:00:34PM +0000, Dave Martin wrote:
> > Since SVE will be enabled or disabled on a per-vcpu basis, a flag
> > is needed in order to track which vcpus have it enabled.
> > 
> > This patch adds a suitable flag and a helper for checking it.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > ---
> >  arch/arm64/include/asm/kvm_host.h | 4 ++++
> >  1 file changed, 4 insertions(+)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 6d10100..ad4f7f0 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -328,6 +328,10 @@ struct kvm_vcpu_arch {
> >  #define KVM_ARM64_FP_HOST		(1 << 2) /* host FP regs loaded */
> >  #define KVM_ARM64_HOST_SVE_IN_USE	(1 << 3) /* backup for host TIF_SVE */
> >  #define KVM_ARM64_HOST_SVE_ENABLED	(1 << 4) /* SVE enabled for EL0 */
> > +#define KVM_ARM64_GUEST_HAS_SVE		(1 << 5) /* SVE exposed to guest */
> > +
> > +#define vcpu_has_sve(vcpu) (system_supports_sve() && \
> > +			    ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))
> 
> We shouldn't need the system_supports_sve() here. vcpu->arch.flags can
> only have the KVM_ARM64_GUEST_HAS_SVE flag set when system_supports_sve()
> is true, and it can't change later.

This is a performance optimisation. system_supports_sve() results in a
static key being emitted, and that avoids a number of loads on the
fast path for non-SVE systems (which is likely to be the absolute
majority for the foreseeable future).

Thanks,

	M.

-- 
Jazz is not dead, it just smell funny.
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v7 09/27] KVM: arm64: Add a vcpu flag to control SVE visibility for the guest
@ 2019-04-04  3:17       ` Marc Zyngier
  0 siblings, 0 replies; 224+ messages in thread
From: Marc Zyngier @ 2019-04-04  3:17 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel,
	Catalin Marinas, Will Deacon, kvmarm, Julien Grall, Zhang Lei,
	Dave Martin, linux-arm-kernel

On Wed, 03 Apr 2019 20:14:13 +0100,
Andrew Jones <drjones@redhat.com> wrote:
> 
> On Fri, Mar 29, 2019 at 01:00:34PM +0000, Dave Martin wrote:
> > Since SVE will be enabled or disabled on a per-vcpu basis, a flag
> > is needed in order to track which vcpus have it enabled.
> > 
> > This patch adds a suitable flag and a helper for checking it.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > ---
> >  arch/arm64/include/asm/kvm_host.h | 4 ++++
> >  1 file changed, 4 insertions(+)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 6d10100..ad4f7f0 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -328,6 +328,10 @@ struct kvm_vcpu_arch {
> >  #define KVM_ARM64_FP_HOST		(1 << 2) /* host FP regs loaded */
> >  #define KVM_ARM64_HOST_SVE_IN_USE	(1 << 3) /* backup for host TIF_SVE */
> >  #define KVM_ARM64_HOST_SVE_ENABLED	(1 << 4) /* SVE enabled for EL0 */
> > +#define KVM_ARM64_GUEST_HAS_SVE		(1 << 5) /* SVE exposed to guest */
> > +
> > +#define vcpu_has_sve(vcpu) (system_supports_sve() && \
> > +			    ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))
> 
> We shouldn't need the system_supports_sve() here. vcpu->arch.flags can
> only have the KVM_ARM64_GUEST_HAS_SVE flag set when system_supports_sve()
> is true, and it can't change later.

This is a performance optimisation. system_supports_sve() results in a
static key being emitted, and that avoids a number of loads on the
fast path for non-SVE systems (which is likely to be the absolute
majority for the foreseeable future).

Thanks,

	M.

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

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 09/27] KVM: arm64: Add a vcpu flag to control SVE visibility for the guest
  2019-04-04  3:17       ` Marc Zyngier
@ 2019-04-04  7:53         ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04  7:53 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, Ard Biesheuvel, Catalin Marinas, Will Deacon,
	Okamoto Takayuki, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 04:17:24AM +0100, Marc Zyngier wrote:
> On Wed, 03 Apr 2019 20:14:13 +0100,
> Andrew Jones <drjones@redhat.com> wrote:
> > 
> > On Fri, Mar 29, 2019 at 01:00:34PM +0000, Dave Martin wrote:
> > > Since SVE will be enabled or disabled on a per-vcpu basis, a flag
> > > is needed in order to track which vcpus have it enabled.
> > > 
> > > This patch adds a suitable flag and a helper for checking it.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > ---
> > >  arch/arm64/include/asm/kvm_host.h | 4 ++++
> > >  1 file changed, 4 insertions(+)
> > > 
> > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > index 6d10100..ad4f7f0 100644
> > > --- a/arch/arm64/include/asm/kvm_host.h
> > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > @@ -328,6 +328,10 @@ struct kvm_vcpu_arch {
> > >  #define KVM_ARM64_FP_HOST		(1 << 2) /* host FP regs loaded */
> > >  #define KVM_ARM64_HOST_SVE_IN_USE	(1 << 3) /* backup for host TIF_SVE */
> > >  #define KVM_ARM64_HOST_SVE_ENABLED	(1 << 4) /* SVE enabled for EL0 */
> > > +#define KVM_ARM64_GUEST_HAS_SVE		(1 << 5) /* SVE exposed to guest */
> > > +
> > > +#define vcpu_has_sve(vcpu) (system_supports_sve() && \
> > > +			    ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))
> > 
> > We shouldn't need the system_supports_sve() here. vcpu->arch.flags can
> > only have the KVM_ARM64_GUEST_HAS_SVE flag set when system_supports_sve()
> > is true, and it can't change later.
> 
> This is a performance optimisation. system_supports_sve() results in a
> static key being emitted, and that avoids a number of loads on the
> fast path for non-SVE systems (which is likely to be the absolute
> majority for the foreseeable future).

Exactly so.  The same applies to many of the other call sites for
system_supports_sve().

Cheers
---Dave

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

* Re: [PATCH v7 09/27] KVM: arm64: Add a vcpu flag to control SVE visibility for the guest
@ 2019-04-04  7:53         ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04  7:53 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Andrew Jones, Christoffer Dall, Ard Biesheuvel, Catalin Marinas,
	Will Deacon, Okamoto Takayuki, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 04:17:24AM +0100, Marc Zyngier wrote:
> On Wed, 03 Apr 2019 20:14:13 +0100,
> Andrew Jones <drjones@redhat.com> wrote:
> > 
> > On Fri, Mar 29, 2019 at 01:00:34PM +0000, Dave Martin wrote:
> > > Since SVE will be enabled or disabled on a per-vcpu basis, a flag
> > > is needed in order to track which vcpus have it enabled.
> > > 
> > > This patch adds a suitable flag and a helper for checking it.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > ---
> > >  arch/arm64/include/asm/kvm_host.h | 4 ++++
> > >  1 file changed, 4 insertions(+)
> > > 
> > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > index 6d10100..ad4f7f0 100644
> > > --- a/arch/arm64/include/asm/kvm_host.h
> > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > @@ -328,6 +328,10 @@ struct kvm_vcpu_arch {
> > >  #define KVM_ARM64_FP_HOST		(1 << 2) /* host FP regs loaded */
> > >  #define KVM_ARM64_HOST_SVE_IN_USE	(1 << 3) /* backup for host TIF_SVE */
> > >  #define KVM_ARM64_HOST_SVE_ENABLED	(1 << 4) /* SVE enabled for EL0 */
> > > +#define KVM_ARM64_GUEST_HAS_SVE		(1 << 5) /* SVE exposed to guest */
> > > +
> > > +#define vcpu_has_sve(vcpu) (system_supports_sve() && \
> > > +			    ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))
> > 
> > We shouldn't need the system_supports_sve() here. vcpu->arch.flags can
> > only have the KVM_ARM64_GUEST_HAS_SVE flag set when system_supports_sve()
> > is true, and it can't change later.
> 
> This is a performance optimisation. system_supports_sve() results in a
> static key being emitted, and that avoids a number of loads on the
> fast path for non-SVE systems (which is likely to be the absolute
> majority for the foreseeable future).

Exactly so.  The same applies to many of the other call sites for
system_supports_sve().

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 12/27] KVM: arm64/sve: System register context switch and access support
  2019-04-03 19:39     ` Andrew Jones
@ 2019-04-04  8:06       ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04  8:06 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Wed, Apr 03, 2019 at 09:39:43PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:37PM +0000, Dave Martin wrote:
> > This patch adds the necessary support for context switching ZCR_EL1
> > for each vcpu.
> > 
> > ZCR_EL1 is trapped alongside the FPSIMD/SVE registers, so it makes
> > sense for it to be handled as part of the guest FPSIMD/SVE context
> > for context switch purposes instead of handling it as a general
> > system register.  This means that it can be switched in lazily at
> > the appropriate time.  No effort is made to track host context for
> > this register, since SVE requires VHE: thus the hosts's value for
> > this register lives permanently in ZCR_EL2 and does not alias the
> > guest's value at any time.
> > 
> > The Hyp switch and fpsimd context handling code is extended
> > appropriately.
> > 
> > Accessors are added in sys_regs.c to expose the SVE system
> > registers and ID register fields.  Because these need to be
> > conditionally visible based on the guest configuration, they are
> > implemented separately for now rather than by use of the generic
> > system register helpers.  This may be abstracted better later on
> > when/if there are more features requiring this model.
> > 
> > ID_AA64ZFR0_EL1 is RO-RAZ for MRS/MSR when SVE is disabled for the
> > guest, but for compatibility with non-SVE aware KVM implementations
> > the register should not be enumerated at all for KVM_GET_REG_LIST
> > in this case.  For consistency we also reject ioctl access to the
> > register.  This ensures that a non-SVE-enabled guest looks the same
> > to userspace, irrespective of whether the kernel KVM implementation
> > supports SVE.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > 
> > ---
> > 
> > Changes since v5:
> > 
> >  * Port to the renamed visibility() framework.
> > 
> >  * Swap visiblity() helpers so that they appear by the relevant accessor
> >    functions.
> > 
> >  * [Julien Grall] With the visibility() checks, {get,set}_zcr_el1()
> >    degenerate to doing exactly what the common code does, so drop them.
> > 
> >    The ID_AA64ZFR0_EL1 handlers are still needed to provide contitional
> >    RAZ behaviour.  This could be moved to the common code too, but since
> >    this is a one-off case I don't do this for now.  We can address this
> >    later if other regs need to follow the same pattern.
> > 
> >  * [Julien Thierry] Reset ZCR_EL1 to a fixed value using reset_val
> >    instead of using relying on reset_unknown() honouring set bits in val
> >    as RES0.
> > 
> >    Most of the bits in ZCR_EL1 are RES0 anyway, and many implementations
> >    of SVE will support larger vectors than 128 bits, so 0 seems as good
> >    a value as any to expose guests that forget to initialise this
> >    register properly.
> > ---

[...]

> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index 3563fe6..9d46066 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c

[...]

> > +static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> > +		const struct sys_reg_desc *rd,
> > +		const struct kvm_one_reg *reg, void __user *uaddr)
> > +{
> > +	u64 val;
> > +
> > +	if (!vcpu_has_sve(vcpu))
> > +		return -ENOENT;
> 
> This shouldn't be necessary. The visibility check in
> kvm_arm_sys_reg_get_reg already covers it.
> 
> > +
> > +	val = guest_id_aa64zfr0_el1(vcpu);
> > +	return reg_to_user(uaddr, &val, reg->id);
> > +}
> > +
> > +static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> > +		const struct sys_reg_desc *rd,
> > +		const struct kvm_one_reg *reg, void __user *uaddr)
> > +{
> > +	const u64 id = sys_reg_to_index(rd);
> > +	int err;
> > +	u64 val;
> > +
> > +	if (!vcpu_has_sve(vcpu))
> > +		return -ENOENT;
> 
> Also not necessary.

Hmm, true.  Because the logic is a bit spread out I felt uneasy with
simply deleting these checks, but if they fire, something has
definitely gone wrong elsewhere.

In its current form the code makes it look like it could be legitimate
to get here with !vcpu_has_sve(vcpu), which is misleading.

What if we demote these to WARN_ON()?  This isn't a fast path.

[...]

> >  /*
> >   * cpufeature ID register user accessors
> >   *
> > @@ -1346,7 +1418,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> >  	ID_SANITISED(ID_AA64PFR1_EL1),
> >  	ID_UNALLOCATED(4,2),
> >  	ID_UNALLOCATED(4,3),
> > -	ID_UNALLOCATED(4,4),
> > +	{ SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility },
> >  	ID_UNALLOCATED(4,5),
> >  	ID_UNALLOCATED(4,6),
> >  	ID_UNALLOCATED(4,7),
> > @@ -1383,6 +1455,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> >  
> >  	{ SYS_DESC(SYS_SCTLR_EL1), access_vm_reg, reset_val, SCTLR_EL1, 0x00C50078 },
> >  	{ SYS_DESC(SYS_CPACR_EL1), NULL, reset_val, CPACR_EL1, 0 },
> > +	{ SYS_DESC(SYS_ZCR_EL1), NULL, reset_val, ZCR_EL1, 0, .visibility = sve_visibility },
> >  	{ SYS_DESC(SYS_TTBR0_EL1), access_vm_reg, reset_unknown, TTBR0_EL1 },
> >  	{ SYS_DESC(SYS_TTBR1_EL1), access_vm_reg, reset_unknown, TTBR1_EL1 },
> >  	{ SYS_DESC(SYS_TCR_EL1), access_vm_reg, reset_val, TCR_EL1, 0 },
> 
> Mixing designated and non-designated initializers isn't particularly nice,
> but I guess it's valid, and the simple alternatives are probably worse.

Agreed.  We could add designators everywhere or more wrapper macros, but
I couldn't see any option that didn't have drawbacks.

Since this is a rare case today, I preferred to keep it as explicit in
the source as possible.

Cheers
---Dave

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

* Re: [PATCH v7 12/27] KVM: arm64/sve: System register context switch and access support
@ 2019-04-04  8:06       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04  8:06 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Wed, Apr 03, 2019 at 09:39:43PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:37PM +0000, Dave Martin wrote:
> > This patch adds the necessary support for context switching ZCR_EL1
> > for each vcpu.
> > 
> > ZCR_EL1 is trapped alongside the FPSIMD/SVE registers, so it makes
> > sense for it to be handled as part of the guest FPSIMD/SVE context
> > for context switch purposes instead of handling it as a general
> > system register.  This means that it can be switched in lazily at
> > the appropriate time.  No effort is made to track host context for
> > this register, since SVE requires VHE: thus the hosts's value for
> > this register lives permanently in ZCR_EL2 and does not alias the
> > guest's value at any time.
> > 
> > The Hyp switch and fpsimd context handling code is extended
> > appropriately.
> > 
> > Accessors are added in sys_regs.c to expose the SVE system
> > registers and ID register fields.  Because these need to be
> > conditionally visible based on the guest configuration, they are
> > implemented separately for now rather than by use of the generic
> > system register helpers.  This may be abstracted better later on
> > when/if there are more features requiring this model.
> > 
> > ID_AA64ZFR0_EL1 is RO-RAZ for MRS/MSR when SVE is disabled for the
> > guest, but for compatibility with non-SVE aware KVM implementations
> > the register should not be enumerated at all for KVM_GET_REG_LIST
> > in this case.  For consistency we also reject ioctl access to the
> > register.  This ensures that a non-SVE-enabled guest looks the same
> > to userspace, irrespective of whether the kernel KVM implementation
> > supports SVE.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > 
> > ---
> > 
> > Changes since v5:
> > 
> >  * Port to the renamed visibility() framework.
> > 
> >  * Swap visiblity() helpers so that they appear by the relevant accessor
> >    functions.
> > 
> >  * [Julien Grall] With the visibility() checks, {get,set}_zcr_el1()
> >    degenerate to doing exactly what the common code does, so drop them.
> > 
> >    The ID_AA64ZFR0_EL1 handlers are still needed to provide contitional
> >    RAZ behaviour.  This could be moved to the common code too, but since
> >    this is a one-off case I don't do this for now.  We can address this
> >    later if other regs need to follow the same pattern.
> > 
> >  * [Julien Thierry] Reset ZCR_EL1 to a fixed value using reset_val
> >    instead of using relying on reset_unknown() honouring set bits in val
> >    as RES0.
> > 
> >    Most of the bits in ZCR_EL1 are RES0 anyway, and many implementations
> >    of SVE will support larger vectors than 128 bits, so 0 seems as good
> >    a value as any to expose guests that forget to initialise this
> >    register properly.
> > ---

[...]

> > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > index 3563fe6..9d46066 100644
> > --- a/arch/arm64/kvm/hyp/switch.c
> > +++ b/arch/arm64/kvm/hyp/switch.c

[...]

> > +static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> > +		const struct sys_reg_desc *rd,
> > +		const struct kvm_one_reg *reg, void __user *uaddr)
> > +{
> > +	u64 val;
> > +
> > +	if (!vcpu_has_sve(vcpu))
> > +		return -ENOENT;
> 
> This shouldn't be necessary. The visibility check in
> kvm_arm_sys_reg_get_reg already covers it.
> 
> > +
> > +	val = guest_id_aa64zfr0_el1(vcpu);
> > +	return reg_to_user(uaddr, &val, reg->id);
> > +}
> > +
> > +static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> > +		const struct sys_reg_desc *rd,
> > +		const struct kvm_one_reg *reg, void __user *uaddr)
> > +{
> > +	const u64 id = sys_reg_to_index(rd);
> > +	int err;
> > +	u64 val;
> > +
> > +	if (!vcpu_has_sve(vcpu))
> > +		return -ENOENT;
> 
> Also not necessary.

Hmm, true.  Because the logic is a bit spread out I felt uneasy with
simply deleting these checks, but if they fire, something has
definitely gone wrong elsewhere.

In its current form the code makes it look like it could be legitimate
to get here with !vcpu_has_sve(vcpu), which is misleading.

What if we demote these to WARN_ON()?  This isn't a fast path.

[...]

> >  /*
> >   * cpufeature ID register user accessors
> >   *
> > @@ -1346,7 +1418,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> >  	ID_SANITISED(ID_AA64PFR1_EL1),
> >  	ID_UNALLOCATED(4,2),
> >  	ID_UNALLOCATED(4,3),
> > -	ID_UNALLOCATED(4,4),
> > +	{ SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility },
> >  	ID_UNALLOCATED(4,5),
> >  	ID_UNALLOCATED(4,6),
> >  	ID_UNALLOCATED(4,7),
> > @@ -1383,6 +1455,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> >  
> >  	{ SYS_DESC(SYS_SCTLR_EL1), access_vm_reg, reset_val, SCTLR_EL1, 0x00C50078 },
> >  	{ SYS_DESC(SYS_CPACR_EL1), NULL, reset_val, CPACR_EL1, 0 },
> > +	{ SYS_DESC(SYS_ZCR_EL1), NULL, reset_val, ZCR_EL1, 0, .visibility = sve_visibility },
> >  	{ SYS_DESC(SYS_TTBR0_EL1), access_vm_reg, reset_unknown, TTBR0_EL1 },
> >  	{ SYS_DESC(SYS_TTBR1_EL1), access_vm_reg, reset_unknown, TTBR1_EL1 },
> >  	{ SYS_DESC(SYS_TCR_EL1), access_vm_reg, reset_val, TCR_EL1, 0 },
> 
> Mixing designated and non-designated initializers isn't particularly nice,
> but I guess it's valid, and the simple alternatives are probably worse.

Agreed.  We could add designators everywhere or more wrapper macros, but
I couldn't see any option that didn't have drawbacks.

Since this is a rare case today, I preferred to keep it as explicit in
the source as possible.

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 13/27] KVM: arm64/sve: Context switch the SVE registers
  2019-04-03 20:01     ` Andrew Jones
@ 2019-04-04  8:10       ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04  8:10 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Wed, Apr 03, 2019 at 10:01:45PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:38PM +0000, Dave Martin wrote:
> > In order to give each vcpu its own view of the SVE registers, this
> > patch adds context storage via a new sve_state pointer in struct
> > vcpu_arch.  An additional member sve_max_vl is also added for each
> > vcpu, to determine the maximum vector length visible to the guest
> > and thus the value to be configured in ZCR_EL2.LEN while the vcpu
> > is active.  This also determines the layout and size of the storage
> > in sve_state, which is read and written by the same backend
> > functions that are used for context-switching the SVE state for
> > host tasks.
> > 
> > On SVE-enabled vcpus, SVE access traps are now handled by switching
> > in the vcpu's SVE context and disabling the trap before returning
> > to the guest.  On other vcpus, the trap is not handled and an exit
> > back to the host occurs, where the handle_sve() fallback path
> > reflects an undefined instruction exception back to the guest,
> > consistently with the behaviour of non-SVE-capable hardware (as was
> > done unconditionally prior to this patch).
> > 
> > No SVE handling is added on non-VHE-only paths, since VHE is an
> > architectural and Kconfig prerequisite of SVE.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > 
> > ---
> > 
> > Changes since v5:
> > 
> >  * [Julien Thierry, Julien Grall] Commit message typo fixes
> > 
> >  * [Mark Rutland] Rename trap_class to hsr_ec, for consistency with
> >    existing code.
> > 
> >  * [Mark Rutland] Simplify condition for refusing to handle an
> >    FPSIMD/SVE trap, using multiple if () statements for clarity.  The
> >    previous condition was a bit tortuous, and how that the static_key
> >    checks have been hoisted out, it makes little difference to the
> >    compiler how we express the condition here.
> > ---
> >  arch/arm64/include/asm/kvm_host.h |  6 ++++
> >  arch/arm64/kvm/fpsimd.c           |  5 +--
> >  arch/arm64/kvm/hyp/switch.c       | 75 +++++++++++++++++++++++++++++----------
> >  3 files changed, 66 insertions(+), 20 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 22cf484..4fabfd2 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -228,6 +228,8 @@ struct vcpu_reset_state {
> >  
> >  struct kvm_vcpu_arch {
> >  	struct kvm_cpu_context ctxt;
> > +	void *sve_state;
> > +	unsigned int sve_max_vl;
> >  
> >  	/* HYP configuration */
> >  	u64 hcr_el2;
> > @@ -323,6 +325,10 @@ struct kvm_vcpu_arch {
> >  	bool sysregs_loaded_on_cpu;
> >  };
> >  
> > +/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
> > +#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
> > +				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
> 
> Maybe an inline function instead?

I tried, but that requires the definition of struct kvm_vcpu to be
visible.  I failed to get that here without circular #include problems,
and it looked tricky to fix.

Since this is a small bit of code which is unlikely to get used by
accident, I decided it was OK to keep it as a macro.

Can you see another way around this?

[...]

> Reviewed-by: Andrew Jones <drjones@redhat.com>

Thanks

---Dave

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

* Re: [PATCH v7 13/27] KVM: arm64/sve: Context switch the SVE registers
@ 2019-04-04  8:10       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04  8:10 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Wed, Apr 03, 2019 at 10:01:45PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:38PM +0000, Dave Martin wrote:
> > In order to give each vcpu its own view of the SVE registers, this
> > patch adds context storage via a new sve_state pointer in struct
> > vcpu_arch.  An additional member sve_max_vl is also added for each
> > vcpu, to determine the maximum vector length visible to the guest
> > and thus the value to be configured in ZCR_EL2.LEN while the vcpu
> > is active.  This also determines the layout and size of the storage
> > in sve_state, which is read and written by the same backend
> > functions that are used for context-switching the SVE state for
> > host tasks.
> > 
> > On SVE-enabled vcpus, SVE access traps are now handled by switching
> > in the vcpu's SVE context and disabling the trap before returning
> > to the guest.  On other vcpus, the trap is not handled and an exit
> > back to the host occurs, where the handle_sve() fallback path
> > reflects an undefined instruction exception back to the guest,
> > consistently with the behaviour of non-SVE-capable hardware (as was
> > done unconditionally prior to this patch).
> > 
> > No SVE handling is added on non-VHE-only paths, since VHE is an
> > architectural and Kconfig prerequisite of SVE.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > 
> > ---
> > 
> > Changes since v5:
> > 
> >  * [Julien Thierry, Julien Grall] Commit message typo fixes
> > 
> >  * [Mark Rutland] Rename trap_class to hsr_ec, for consistency with
> >    existing code.
> > 
> >  * [Mark Rutland] Simplify condition for refusing to handle an
> >    FPSIMD/SVE trap, using multiple if () statements for clarity.  The
> >    previous condition was a bit tortuous, and how that the static_key
> >    checks have been hoisted out, it makes little difference to the
> >    compiler how we express the condition here.
> > ---
> >  arch/arm64/include/asm/kvm_host.h |  6 ++++
> >  arch/arm64/kvm/fpsimd.c           |  5 +--
> >  arch/arm64/kvm/hyp/switch.c       | 75 +++++++++++++++++++++++++++++----------
> >  3 files changed, 66 insertions(+), 20 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 22cf484..4fabfd2 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -228,6 +228,8 @@ struct vcpu_reset_state {
> >  
> >  struct kvm_vcpu_arch {
> >  	struct kvm_cpu_context ctxt;
> > +	void *sve_state;
> > +	unsigned int sve_max_vl;
> >  
> >  	/* HYP configuration */
> >  	u64 hcr_el2;
> > @@ -323,6 +325,10 @@ struct kvm_vcpu_arch {
> >  	bool sysregs_loaded_on_cpu;
> >  };
> >  
> > +/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
> > +#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
> > +				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
> 
> Maybe an inline function instead?

I tried, but that requires the definition of struct kvm_vcpu to be
visible.  I failed to get that here without circular #include problems,
and it looked tricky to fix.

Since this is a small bit of code which is unlikely to get used by
accident, I decided it was OK to keep it as a macro.

Can you see another way around this?

[...]

> Reviewed-by: Andrew Jones <drjones@redhat.com>

Thanks

---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 12/27] KVM: arm64/sve: System register context switch and access support
  2019-04-04  8:06       ` Dave Martin
@ 2019-04-04  8:32         ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04  8:32 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 09:06:58AM +0100, Dave Martin wrote:
> On Wed, Apr 03, 2019 at 09:39:43PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:37PM +0000, Dave Martin wrote:
> > > This patch adds the necessary support for context switching ZCR_EL1
> > > for each vcpu.
> > > 
> > > ZCR_EL1 is trapped alongside the FPSIMD/SVE registers, so it makes
> > > sense for it to be handled as part of the guest FPSIMD/SVE context
> > > for context switch purposes instead of handling it as a general
> > > system register.  This means that it can be switched in lazily at
> > > the appropriate time.  No effort is made to track host context for
> > > this register, since SVE requires VHE: thus the hosts's value for
> > > this register lives permanently in ZCR_EL2 and does not alias the
> > > guest's value at any time.
> > > 
> > > The Hyp switch and fpsimd context handling code is extended
> > > appropriately.
> > > 
> > > Accessors are added in sys_regs.c to expose the SVE system
> > > registers and ID register fields.  Because these need to be
> > > conditionally visible based on the guest configuration, they are
> > > implemented separately for now rather than by use of the generic
> > > system register helpers.  This may be abstracted better later on
> > > when/if there are more features requiring this model.
> > > 
> > > ID_AA64ZFR0_EL1 is RO-RAZ for MRS/MSR when SVE is disabled for the
> > > guest, but for compatibility with non-SVE aware KVM implementations
> > > the register should not be enumerated at all for KVM_GET_REG_LIST
> > > in this case.  For consistency we also reject ioctl access to the
> > > register.  This ensures that a non-SVE-enabled guest looks the same
> > > to userspace, irrespective of whether the kernel KVM implementation
> > > supports SVE.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > 
> > > ---
> > > 
> > > Changes since v5:
> > > 
> > >  * Port to the renamed visibility() framework.
> > > 
> > >  * Swap visiblity() helpers so that they appear by the relevant accessor
> > >    functions.
> > > 
> > >  * [Julien Grall] With the visibility() checks, {get,set}_zcr_el1()
> > >    degenerate to doing exactly what the common code does, so drop them.
> > > 
> > >    The ID_AA64ZFR0_EL1 handlers are still needed to provide contitional
> > >    RAZ behaviour.  This could be moved to the common code too, but since
> > >    this is a one-off case I don't do this for now.  We can address this
> > >    later if other regs need to follow the same pattern.
> > > 
> > >  * [Julien Thierry] Reset ZCR_EL1 to a fixed value using reset_val
> > >    instead of using relying on reset_unknown() honouring set bits in val
> > >    as RES0.
> > > 
> > >    Most of the bits in ZCR_EL1 are RES0 anyway, and many implementations
> > >    of SVE will support larger vectors than 128 bits, so 0 seems as good
> > >    a value as any to expose guests that forget to initialise this
> > >    register properly.
> > > ---
> 
> [...]
> 
> > > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > > index 3563fe6..9d46066 100644
> > > --- a/arch/arm64/kvm/hyp/switch.c
> > > +++ b/arch/arm64/kvm/hyp/switch.c
> 
> [...]
> 
> > > +static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> > > +		const struct sys_reg_desc *rd,
> > > +		const struct kvm_one_reg *reg, void __user *uaddr)
> > > +{
> > > +	u64 val;
> > > +
> > > +	if (!vcpu_has_sve(vcpu))
> > > +		return -ENOENT;
> > 
> > This shouldn't be necessary. The visibility check in
> > kvm_arm_sys_reg_get_reg already covers it.
> > 
> > > +
> > > +	val = guest_id_aa64zfr0_el1(vcpu);
> > > +	return reg_to_user(uaddr, &val, reg->id);
> > > +}
> > > +
> > > +static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> > > +		const struct sys_reg_desc *rd,
> > > +		const struct kvm_one_reg *reg, void __user *uaddr)
> > > +{
> > > +	const u64 id = sys_reg_to_index(rd);
> > > +	int err;
> > > +	u64 val;
> > > +
> > > +	if (!vcpu_has_sve(vcpu))
> > > +		return -ENOENT;
> > 
> > Also not necessary.
> 
> Hmm, true.  Because the logic is a bit spread out I felt uneasy with
> simply deleting these checks, but if they fire, something has
> definitely gone wrong elsewhere.
> 
> In its current form the code makes it look like it could be legitimate
> to get here with !vcpu_has_sve(vcpu), which is misleading.
> 
> What if we demote these to WARN_ON()?  This isn't a fast path.

A WARN_ON sounds good to me.

Thanks,
drew

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

* Re: [PATCH v7 12/27] KVM: arm64/sve: System register context switch and access support
@ 2019-04-04  8:32         ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04  8:32 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 09:06:58AM +0100, Dave Martin wrote:
> On Wed, Apr 03, 2019 at 09:39:43PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:37PM +0000, Dave Martin wrote:
> > > This patch adds the necessary support for context switching ZCR_EL1
> > > for each vcpu.
> > > 
> > > ZCR_EL1 is trapped alongside the FPSIMD/SVE registers, so it makes
> > > sense for it to be handled as part of the guest FPSIMD/SVE context
> > > for context switch purposes instead of handling it as a general
> > > system register.  This means that it can be switched in lazily at
> > > the appropriate time.  No effort is made to track host context for
> > > this register, since SVE requires VHE: thus the hosts's value for
> > > this register lives permanently in ZCR_EL2 and does not alias the
> > > guest's value at any time.
> > > 
> > > The Hyp switch and fpsimd context handling code is extended
> > > appropriately.
> > > 
> > > Accessors are added in sys_regs.c to expose the SVE system
> > > registers and ID register fields.  Because these need to be
> > > conditionally visible based on the guest configuration, they are
> > > implemented separately for now rather than by use of the generic
> > > system register helpers.  This may be abstracted better later on
> > > when/if there are more features requiring this model.
> > > 
> > > ID_AA64ZFR0_EL1 is RO-RAZ for MRS/MSR when SVE is disabled for the
> > > guest, but for compatibility with non-SVE aware KVM implementations
> > > the register should not be enumerated at all for KVM_GET_REG_LIST
> > > in this case.  For consistency we also reject ioctl access to the
> > > register.  This ensures that a non-SVE-enabled guest looks the same
> > > to userspace, irrespective of whether the kernel KVM implementation
> > > supports SVE.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > 
> > > ---
> > > 
> > > Changes since v5:
> > > 
> > >  * Port to the renamed visibility() framework.
> > > 
> > >  * Swap visiblity() helpers so that they appear by the relevant accessor
> > >    functions.
> > > 
> > >  * [Julien Grall] With the visibility() checks, {get,set}_zcr_el1()
> > >    degenerate to doing exactly what the common code does, so drop them.
> > > 
> > >    The ID_AA64ZFR0_EL1 handlers are still needed to provide contitional
> > >    RAZ behaviour.  This could be moved to the common code too, but since
> > >    this is a one-off case I don't do this for now.  We can address this
> > >    later if other regs need to follow the same pattern.
> > > 
> > >  * [Julien Thierry] Reset ZCR_EL1 to a fixed value using reset_val
> > >    instead of using relying on reset_unknown() honouring set bits in val
> > >    as RES0.
> > > 
> > >    Most of the bits in ZCR_EL1 are RES0 anyway, and many implementations
> > >    of SVE will support larger vectors than 128 bits, so 0 seems as good
> > >    a value as any to expose guests that forget to initialise this
> > >    register properly.
> > > ---
> 
> [...]
> 
> > > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> > > index 3563fe6..9d46066 100644
> > > --- a/arch/arm64/kvm/hyp/switch.c
> > > +++ b/arch/arm64/kvm/hyp/switch.c
> 
> [...]
> 
> > > +static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> > > +		const struct sys_reg_desc *rd,
> > > +		const struct kvm_one_reg *reg, void __user *uaddr)
> > > +{
> > > +	u64 val;
> > > +
> > > +	if (!vcpu_has_sve(vcpu))
> > > +		return -ENOENT;
> > 
> > This shouldn't be necessary. The visibility check in
> > kvm_arm_sys_reg_get_reg already covers it.
> > 
> > > +
> > > +	val = guest_id_aa64zfr0_el1(vcpu);
> > > +	return reg_to_user(uaddr, &val, reg->id);
> > > +}
> > > +
> > > +static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> > > +		const struct sys_reg_desc *rd,
> > > +		const struct kvm_one_reg *reg, void __user *uaddr)
> > > +{
> > > +	const u64 id = sys_reg_to_index(rd);
> > > +	int err;
> > > +	u64 val;
> > > +
> > > +	if (!vcpu_has_sve(vcpu))
> > > +		return -ENOENT;
> > 
> > Also not necessary.
> 
> Hmm, true.  Because the logic is a bit spread out I felt uneasy with
> simply deleting these checks, but if they fire, something has
> definitely gone wrong elsewhere.
> 
> In its current form the code makes it look like it could be legitimate
> to get here with !vcpu_has_sve(vcpu), which is misleading.
> 
> What if we demote these to WARN_ON()?  This isn't a fast path.

A WARN_ON sounds good to me.

Thanks,
drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 13/27] KVM: arm64/sve: Context switch the SVE registers
  2019-04-04  8:10       ` Dave Martin
@ 2019-04-04  8:35         ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04  8:35 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 09:10:08AM +0100, Dave Martin wrote:
> On Wed, Apr 03, 2019 at 10:01:45PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:38PM +0000, Dave Martin wrote:
> > > In order to give each vcpu its own view of the SVE registers, this
> > > patch adds context storage via a new sve_state pointer in struct
> > > vcpu_arch.  An additional member sve_max_vl is also added for each
> > > vcpu, to determine the maximum vector length visible to the guest
> > > and thus the value to be configured in ZCR_EL2.LEN while the vcpu
> > > is active.  This also determines the layout and size of the storage
> > > in sve_state, which is read and written by the same backend
> > > functions that are used for context-switching the SVE state for
> > > host tasks.
> > > 
> > > On SVE-enabled vcpus, SVE access traps are now handled by switching
> > > in the vcpu's SVE context and disabling the trap before returning
> > > to the guest.  On other vcpus, the trap is not handled and an exit
> > > back to the host occurs, where the handle_sve() fallback path
> > > reflects an undefined instruction exception back to the guest,
> > > consistently with the behaviour of non-SVE-capable hardware (as was
> > > done unconditionally prior to this patch).
> > > 
> > > No SVE handling is added on non-VHE-only paths, since VHE is an
> > > architectural and Kconfig prerequisite of SVE.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > 
> > > ---
> > > 
> > > Changes since v5:
> > > 
> > >  * [Julien Thierry, Julien Grall] Commit message typo fixes
> > > 
> > >  * [Mark Rutland] Rename trap_class to hsr_ec, for consistency with
> > >    existing code.
> > > 
> > >  * [Mark Rutland] Simplify condition for refusing to handle an
> > >    FPSIMD/SVE trap, using multiple if () statements for clarity.  The
> > >    previous condition was a bit tortuous, and how that the static_key
> > >    checks have been hoisted out, it makes little difference to the
> > >    compiler how we express the condition here.
> > > ---
> > >  arch/arm64/include/asm/kvm_host.h |  6 ++++
> > >  arch/arm64/kvm/fpsimd.c           |  5 +--
> > >  arch/arm64/kvm/hyp/switch.c       | 75 +++++++++++++++++++++++++++++----------
> > >  3 files changed, 66 insertions(+), 20 deletions(-)
> > > 
> > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > index 22cf484..4fabfd2 100644
> > > --- a/arch/arm64/include/asm/kvm_host.h
> > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > @@ -228,6 +228,8 @@ struct vcpu_reset_state {
> > >  
> > >  struct kvm_vcpu_arch {
> > >  	struct kvm_cpu_context ctxt;
> > > +	void *sve_state;
> > > +	unsigned int sve_max_vl;
> > >  
> > >  	/* HYP configuration */
> > >  	u64 hcr_el2;
> > > @@ -323,6 +325,10 @@ struct kvm_vcpu_arch {
> > >  	bool sysregs_loaded_on_cpu;
> > >  };
> > >  
> > > +/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
> > > +#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
> > > +				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
> > 
> > Maybe an inline function instead?
> 
> I tried, but that requires the definition of struct kvm_vcpu to be
> visible.  I failed to get that here without circular #include problems,
> and it looked tricky to fix.

Ah, OK

> 
> Since this is a small bit of code which is unlikely to get used by
> accident, I decided it was OK to keep it as a macro.
> 
> Can you see another way around this?

Nope

drew

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

* Re: [PATCH v7 13/27] KVM: arm64/sve: Context switch the SVE registers
@ 2019-04-04  8:35         ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04  8:35 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 09:10:08AM +0100, Dave Martin wrote:
> On Wed, Apr 03, 2019 at 10:01:45PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:38PM +0000, Dave Martin wrote:
> > > In order to give each vcpu its own view of the SVE registers, this
> > > patch adds context storage via a new sve_state pointer in struct
> > > vcpu_arch.  An additional member sve_max_vl is also added for each
> > > vcpu, to determine the maximum vector length visible to the guest
> > > and thus the value to be configured in ZCR_EL2.LEN while the vcpu
> > > is active.  This also determines the layout and size of the storage
> > > in sve_state, which is read and written by the same backend
> > > functions that are used for context-switching the SVE state for
> > > host tasks.
> > > 
> > > On SVE-enabled vcpus, SVE access traps are now handled by switching
> > > in the vcpu's SVE context and disabling the trap before returning
> > > to the guest.  On other vcpus, the trap is not handled and an exit
> > > back to the host occurs, where the handle_sve() fallback path
> > > reflects an undefined instruction exception back to the guest,
> > > consistently with the behaviour of non-SVE-capable hardware (as was
> > > done unconditionally prior to this patch).
> > > 
> > > No SVE handling is added on non-VHE-only paths, since VHE is an
> > > architectural and Kconfig prerequisite of SVE.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > 
> > > ---
> > > 
> > > Changes since v5:
> > > 
> > >  * [Julien Thierry, Julien Grall] Commit message typo fixes
> > > 
> > >  * [Mark Rutland] Rename trap_class to hsr_ec, for consistency with
> > >    existing code.
> > > 
> > >  * [Mark Rutland] Simplify condition for refusing to handle an
> > >    FPSIMD/SVE trap, using multiple if () statements for clarity.  The
> > >    previous condition was a bit tortuous, and how that the static_key
> > >    checks have been hoisted out, it makes little difference to the
> > >    compiler how we express the condition here.
> > > ---
> > >  arch/arm64/include/asm/kvm_host.h |  6 ++++
> > >  arch/arm64/kvm/fpsimd.c           |  5 +--
> > >  arch/arm64/kvm/hyp/switch.c       | 75 +++++++++++++++++++++++++++++----------
> > >  3 files changed, 66 insertions(+), 20 deletions(-)
> > > 
> > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > index 22cf484..4fabfd2 100644
> > > --- a/arch/arm64/include/asm/kvm_host.h
> > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > @@ -228,6 +228,8 @@ struct vcpu_reset_state {
> > >  
> > >  struct kvm_vcpu_arch {
> > >  	struct kvm_cpu_context ctxt;
> > > +	void *sve_state;
> > > +	unsigned int sve_max_vl;
> > >  
> > >  	/* HYP configuration */
> > >  	u64 hcr_el2;
> > > @@ -323,6 +325,10 @@ struct kvm_vcpu_arch {
> > >  	bool sysregs_loaded_on_cpu;
> > >  };
> > >  
> > > +/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
> > > +#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
> > > +				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
> > 
> > Maybe an inline function instead?
> 
> I tried, but that requires the definition of struct kvm_vcpu to be
> visible.  I failed to get that here without circular #include problems,
> and it looked tricky to fix.

Ah, OK

> 
> Since this is a small bit of code which is unlikely to get used by
> accident, I decided it was OK to keep it as a macro.
> 
> Can you see another way around this?

Nope

drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 26/27] KVM: Document errors for KVM_GET_ONE_REG and KVM_SET_ONE_REG
  2019-04-03 20:27     ` Andrew Jones
@ 2019-04-04  8:35       ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04  8:35 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Wed, Apr 03, 2019 at 10:27:46PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:51PM +0000, Dave Martin wrote:
> > KVM_GET_ONE_REG and KVM_SET_ONE_REG return some error codes that
> > are not documented (but hopefully not surprising either).  To give
> > an indication of what these may mean, this patch adds brief
> > documentation.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > ---
> >  Documentation/virtual/kvm/api.txt | 6 ++++++
> >  1 file changed, 6 insertions(+)
> > 
> > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> > index 2d4f7ce..cd920dd 100644
> > --- a/Documentation/virtual/kvm/api.txt
> > +++ b/Documentation/virtual/kvm/api.txt
> > @@ -1871,6 +1871,9 @@ Architectures: all
> >  Type: vcpu ioctl
> >  Parameters: struct kvm_one_reg (in)
> >  Returns: 0 on success, negative value on failure
> > +Errors:
> > +  ENOENT:   no such register
> > +  EINVAL:   other errors, such as bad size encoding for a known register
> >  
> >  struct kvm_one_reg {
> >         __u64 id;
> > @@ -2192,6 +2195,9 @@ Architectures: all
> >  Type: vcpu ioctl
> >  Parameters: struct kvm_one_reg (in and out)
> >  Returns: 0 on success, negative value on failure
> > +Errors:
> > +  ENOENT:   no such register
> > +  EINVAL:   other errors, such as bad size encoding for a known register
> >  
> >  This ioctl allows to receive the value of a single register implemented
> >  in a vcpu. The register to read is indicated by the "id" field of the
> > -- 
> > 2.1.4
> >
> 
> Are we sure all architectures have these, and only these errors? A quick
> grep indicates not. I'm not sure we can document this easily here due to
> it addressing all architectures at once. Maybe we could add arch-specific
> subsections, but I'm not sure it's worth it.

Error codes are generally indicative at best, and rarely mutually
exclusive in a given situation.

Writing a caveat to say that you shouldn't make assumptions about
precisely what error code will be returned in a given situation would
look odd: that really applies widely all over the kernel/user ABI, not
just here.

_Maybe_ everything is exhaustively correct in this file already, but
given the size of it, and the fact that many things are implemented
per-arch, the chance of this seems zero.

I could add "invalid register ID" for EINVAL.  This allows some
ambiguity about which error code applies for a nonexistent register.

Alternatively, we could revert this documentation instead.

It seemed appropriate to document the EPERM error for finalization
ordering (added later), but since correct userspace code should never
see this maybe it's reasonable to leave it undocumented(?)

Cheers
---Dave

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

* Re: [PATCH v7 26/27] KVM: Document errors for KVM_GET_ONE_REG and KVM_SET_ONE_REG
@ 2019-04-04  8:35       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04  8:35 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Wed, Apr 03, 2019 at 10:27:46PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:51PM +0000, Dave Martin wrote:
> > KVM_GET_ONE_REG and KVM_SET_ONE_REG return some error codes that
> > are not documented (but hopefully not surprising either).  To give
> > an indication of what these may mean, this patch adds brief
> > documentation.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > ---
> >  Documentation/virtual/kvm/api.txt | 6 ++++++
> >  1 file changed, 6 insertions(+)
> > 
> > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> > index 2d4f7ce..cd920dd 100644
> > --- a/Documentation/virtual/kvm/api.txt
> > +++ b/Documentation/virtual/kvm/api.txt
> > @@ -1871,6 +1871,9 @@ Architectures: all
> >  Type: vcpu ioctl
> >  Parameters: struct kvm_one_reg (in)
> >  Returns: 0 on success, negative value on failure
> > +Errors:
> > +  ENOENT:   no such register
> > +  EINVAL:   other errors, such as bad size encoding for a known register
> >  
> >  struct kvm_one_reg {
> >         __u64 id;
> > @@ -2192,6 +2195,9 @@ Architectures: all
> >  Type: vcpu ioctl
> >  Parameters: struct kvm_one_reg (in and out)
> >  Returns: 0 on success, negative value on failure
> > +Errors:
> > +  ENOENT:   no such register
> > +  EINVAL:   other errors, such as bad size encoding for a known register
> >  
> >  This ioctl allows to receive the value of a single register implemented
> >  in a vcpu. The register to read is indicated by the "id" field of the
> > -- 
> > 2.1.4
> >
> 
> Are we sure all architectures have these, and only these errors? A quick
> grep indicates not. I'm not sure we can document this easily here due to
> it addressing all architectures at once. Maybe we could add arch-specific
> subsections, but I'm not sure it's worth it.

Error codes are generally indicative at best, and rarely mutually
exclusive in a given situation.

Writing a caveat to say that you shouldn't make assumptions about
precisely what error code will be returned in a given situation would
look odd: that really applies widely all over the kernel/user ABI, not
just here.

_Maybe_ everything is exhaustively correct in this file already, but
given the size of it, and the fact that many things are implemented
per-arch, the chance of this seems zero.

I could add "invalid register ID" for EINVAL.  This allows some
ambiguity about which error code applies for a nonexistent register.

Alternatively, we could revert this documentation instead.

It seemed appropriate to document the EPERM error for finalization
ordering (added later), but since correct userspace code should never
see this maybe it's reasonable to leave it undocumented(?)

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 13/27] KVM: arm64/sve: Context switch the SVE registers
  2019-04-04  8:35         ` Andrew Jones
@ 2019-04-04  8:36           ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04  8:36 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 10:35:02AM +0200, Andrew Jones wrote:
> On Thu, Apr 04, 2019 at 09:10:08AM +0100, Dave Martin wrote:
> > On Wed, Apr 03, 2019 at 10:01:45PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:38PM +0000, Dave Martin wrote:
> > > > In order to give each vcpu its own view of the SVE registers, this
> > > > patch adds context storage via a new sve_state pointer in struct
> > > > vcpu_arch.  An additional member sve_max_vl is also added for each
> > > > vcpu, to determine the maximum vector length visible to the guest
> > > > and thus the value to be configured in ZCR_EL2.LEN while the vcpu
> > > > is active.  This also determines the layout and size of the storage
> > > > in sve_state, which is read and written by the same backend
> > > > functions that are used for context-switching the SVE state for
> > > > host tasks.
> > > > 
> > > > On SVE-enabled vcpus, SVE access traps are now handled by switching
> > > > in the vcpu's SVE context and disabling the trap before returning
> > > > to the guest.  On other vcpus, the trap is not handled and an exit
> > > > back to the host occurs, where the handle_sve() fallback path
> > > > reflects an undefined instruction exception back to the guest,
> > > > consistently with the behaviour of non-SVE-capable hardware (as was
> > > > done unconditionally prior to this patch).
> > > > 
> > > > No SVE handling is added on non-VHE-only paths, since VHE is an
> > > > architectural and Kconfig prerequisite of SVE.
> > > > 
> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > > 
> > > > ---
> > > > 
> > > > Changes since v5:
> > > > 
> > > >  * [Julien Thierry, Julien Grall] Commit message typo fixes
> > > > 
> > > >  * [Mark Rutland] Rename trap_class to hsr_ec, for consistency with
> > > >    existing code.
> > > > 
> > > >  * [Mark Rutland] Simplify condition for refusing to handle an
> > > >    FPSIMD/SVE trap, using multiple if () statements for clarity.  The
> > > >    previous condition was a bit tortuous, and how that the static_key
> > > >    checks have been hoisted out, it makes little difference to the
> > > >    compiler how we express the condition here.
> > > > ---
> > > >  arch/arm64/include/asm/kvm_host.h |  6 ++++
> > > >  arch/arm64/kvm/fpsimd.c           |  5 +--
> > > >  arch/arm64/kvm/hyp/switch.c       | 75 +++++++++++++++++++++++++++++----------
> > > >  3 files changed, 66 insertions(+), 20 deletions(-)
> > > > 
> > > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > > index 22cf484..4fabfd2 100644
> > > > --- a/arch/arm64/include/asm/kvm_host.h
> > > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > > @@ -228,6 +228,8 @@ struct vcpu_reset_state {
> > > >  
> > > >  struct kvm_vcpu_arch {
> > > >  	struct kvm_cpu_context ctxt;
> > > > +	void *sve_state;
> > > > +	unsigned int sve_max_vl;
> > > >  
> > > >  	/* HYP configuration */
> > > >  	u64 hcr_el2;
> > > > @@ -323,6 +325,10 @@ struct kvm_vcpu_arch {
> > > >  	bool sysregs_loaded_on_cpu;
> > > >  };
> > > >  
> > > > +/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
> > > > +#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
> > > > +				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
> > > 
> > > Maybe an inline function instead?
> > 
> > I tried, but that requires the definition of struct kvm_vcpu to be
> > visible.  I failed to get that here without circular #include problems,
> > and it looked tricky to fix.
> 
> Ah, OK
> 
> > 
> > Since this is a small bit of code which is unlikely to get used by
> > accident, I decided it was OK to keep it as a macro.
> > 
> > Can you see another way around this?
> 
> Nope

OK.  If someone eventually solves this, I'd be happy to change to an
inline function.

Cheers
---Dave

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

* Re: [PATCH v7 13/27] KVM: arm64/sve: Context switch the SVE registers
@ 2019-04-04  8:36           ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04  8:36 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 10:35:02AM +0200, Andrew Jones wrote:
> On Thu, Apr 04, 2019 at 09:10:08AM +0100, Dave Martin wrote:
> > On Wed, Apr 03, 2019 at 10:01:45PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:38PM +0000, Dave Martin wrote:
> > > > In order to give each vcpu its own view of the SVE registers, this
> > > > patch adds context storage via a new sve_state pointer in struct
> > > > vcpu_arch.  An additional member sve_max_vl is also added for each
> > > > vcpu, to determine the maximum vector length visible to the guest
> > > > and thus the value to be configured in ZCR_EL2.LEN while the vcpu
> > > > is active.  This also determines the layout and size of the storage
> > > > in sve_state, which is read and written by the same backend
> > > > functions that are used for context-switching the SVE state for
> > > > host tasks.
> > > > 
> > > > On SVE-enabled vcpus, SVE access traps are now handled by switching
> > > > in the vcpu's SVE context and disabling the trap before returning
> > > > to the guest.  On other vcpus, the trap is not handled and an exit
> > > > back to the host occurs, where the handle_sve() fallback path
> > > > reflects an undefined instruction exception back to the guest,
> > > > consistently with the behaviour of non-SVE-capable hardware (as was
> > > > done unconditionally prior to this patch).
> > > > 
> > > > No SVE handling is added on non-VHE-only paths, since VHE is an
> > > > architectural and Kconfig prerequisite of SVE.
> > > > 
> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > > 
> > > > ---
> > > > 
> > > > Changes since v5:
> > > > 
> > > >  * [Julien Thierry, Julien Grall] Commit message typo fixes
> > > > 
> > > >  * [Mark Rutland] Rename trap_class to hsr_ec, for consistency with
> > > >    existing code.
> > > > 
> > > >  * [Mark Rutland] Simplify condition for refusing to handle an
> > > >    FPSIMD/SVE trap, using multiple if () statements for clarity.  The
> > > >    previous condition was a bit tortuous, and how that the static_key
> > > >    checks have been hoisted out, it makes little difference to the
> > > >    compiler how we express the condition here.
> > > > ---
> > > >  arch/arm64/include/asm/kvm_host.h |  6 ++++
> > > >  arch/arm64/kvm/fpsimd.c           |  5 +--
> > > >  arch/arm64/kvm/hyp/switch.c       | 75 +++++++++++++++++++++++++++++----------
> > > >  3 files changed, 66 insertions(+), 20 deletions(-)
> > > > 
> > > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > > index 22cf484..4fabfd2 100644
> > > > --- a/arch/arm64/include/asm/kvm_host.h
> > > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > > @@ -228,6 +228,8 @@ struct vcpu_reset_state {
> > > >  
> > > >  struct kvm_vcpu_arch {
> > > >  	struct kvm_cpu_context ctxt;
> > > > +	void *sve_state;
> > > > +	unsigned int sve_max_vl;
> > > >  
> > > >  	/* HYP configuration */
> > > >  	u64 hcr_el2;
> > > > @@ -323,6 +325,10 @@ struct kvm_vcpu_arch {
> > > >  	bool sysregs_loaded_on_cpu;
> > > >  };
> > > >  
> > > > +/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
> > > > +#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
> > > > +				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
> > > 
> > > Maybe an inline function instead?
> > 
> > I tried, but that requires the definition of struct kvm_vcpu to be
> > visible.  I failed to get that here without circular #include problems,
> > and it looked tricky to fix.
> 
> Ah, OK
> 
> > 
> > Since this is a small bit of code which is unlikely to get used by
> > accident, I decided it was OK to keep it as a macro.
> > 
> > Can you see another way around this?
> 
> Nope

OK.  If someone eventually solves this, I'd be happy to change to an
inline function.

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 12/27] KVM: arm64/sve: System register context switch and access support
  2019-04-04  8:32         ` Andrew Jones
@ 2019-04-04  8:47           ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04  8:47 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 10:32:18AM +0200, Andrew Jones wrote:
> On Thu, Apr 04, 2019 at 09:06:58AM +0100, Dave Martin wrote:
> > On Wed, Apr 03, 2019 at 09:39:43PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:37PM +0000, Dave Martin wrote:

[...]

> > > > +static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> > > > +		const struct sys_reg_desc *rd,
> > > > +		const struct kvm_one_reg *reg, void __user *uaddr)
> > > > +{
> > > > +	u64 val;
> > > > +
> > > > +	if (!vcpu_has_sve(vcpu))
> > > > +		return -ENOENT;
> > > 
> > > This shouldn't be necessary. The visibility check in
> > > kvm_arm_sys_reg_get_reg already covers it.
> > > 
> > > > +
> > > > +	val = guest_id_aa64zfr0_el1(vcpu);
> > > > +	return reg_to_user(uaddr, &val, reg->id);
> > > > +}
> > > > +
> > > > +static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> > > > +		const struct sys_reg_desc *rd,
> > > > +		const struct kvm_one_reg *reg, void __user *uaddr)
> > > > +{
> > > > +	const u64 id = sys_reg_to_index(rd);
> > > > +	int err;
> > > > +	u64 val;
> > > > +
> > > > +	if (!vcpu_has_sve(vcpu))
> > > > +		return -ENOENT;
> > > 
> > > Also not necessary.
> > 
> > Hmm, true.  Because the logic is a bit spread out I felt uneasy with
> > simply deleting these checks, but if they fire, something has
> > definitely gone wrong elsewhere.
> > 
> > In its current form the code makes it look like it could be legitimate
> > to get here with !vcpu_has_sve(vcpu), which is misleading.
> > 
> > What if we demote these to WARN_ON()?  This isn't a fast path.
> 
> A WARN_ON sounds good to me.

OK.  Are you happy to give your Reviewed-by on the following?

--8<--

>From 88aeb182ba787102e627e33728a08b70f467758c Mon Sep 17 00:00:00 2001
From: Dave Martin <Dave.Martin@arm.com>
Date: Thu, 4 Apr 2019 09:41:46 +0100
Subject: [PATCH] KVM: arm64/sve: Demote redundant sysreg vcpu_has_sve() checks
 to WARNs

Because of the logic in kvm_arm_sys_reg_{get,set}_reg() and
sve_id_visibility(), we should never call
{get,set}_id_aa64zfr0_el1() for a vcpu where !vcpu_has_sve(vcpu).

To avoid the code giving the impression that it is valid for these
functions to be called in this situation, and to help the compiler
make the right optimisation decisions, this patch adds WARN_ON()
for these cases.

Given the way the logic is spread out, this seems preferable to
dropping the checks altogether.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/kvm/sys_regs.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 09e9b06..7046c76 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1144,7 +1144,7 @@ static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
 {
 	u64 val;
 
-	if (!vcpu_has_sve(vcpu))
+	if (WARN_ON(!vcpu_has_sve(vcpu)))
 		return -ENOENT;
 
 	val = guest_id_aa64zfr0_el1(vcpu);
@@ -1159,7 +1159,7 @@ static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
 	int err;
 	u64 val;
 
-	if (!vcpu_has_sve(vcpu))
+	if (WARN_ON(!vcpu_has_sve(vcpu)))
 		return -ENOENT;
 
 	err = reg_from_user(&val, uaddr, id);
-- 
2.1.4

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

* Re: [PATCH v7 12/27] KVM: arm64/sve: System register context switch and access support
@ 2019-04-04  8:47           ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04  8:47 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 10:32:18AM +0200, Andrew Jones wrote:
> On Thu, Apr 04, 2019 at 09:06:58AM +0100, Dave Martin wrote:
> > On Wed, Apr 03, 2019 at 09:39:43PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:37PM +0000, Dave Martin wrote:

[...]

> > > > +static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> > > > +		const struct sys_reg_desc *rd,
> > > > +		const struct kvm_one_reg *reg, void __user *uaddr)
> > > > +{
> > > > +	u64 val;
> > > > +
> > > > +	if (!vcpu_has_sve(vcpu))
> > > > +		return -ENOENT;
> > > 
> > > This shouldn't be necessary. The visibility check in
> > > kvm_arm_sys_reg_get_reg already covers it.
> > > 
> > > > +
> > > > +	val = guest_id_aa64zfr0_el1(vcpu);
> > > > +	return reg_to_user(uaddr, &val, reg->id);
> > > > +}
> > > > +
> > > > +static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> > > > +		const struct sys_reg_desc *rd,
> > > > +		const struct kvm_one_reg *reg, void __user *uaddr)
> > > > +{
> > > > +	const u64 id = sys_reg_to_index(rd);
> > > > +	int err;
> > > > +	u64 val;
> > > > +
> > > > +	if (!vcpu_has_sve(vcpu))
> > > > +		return -ENOENT;
> > > 
> > > Also not necessary.
> > 
> > Hmm, true.  Because the logic is a bit spread out I felt uneasy with
> > simply deleting these checks, but if they fire, something has
> > definitely gone wrong elsewhere.
> > 
> > In its current form the code makes it look like it could be legitimate
> > to get here with !vcpu_has_sve(vcpu), which is misleading.
> > 
> > What if we demote these to WARN_ON()?  This isn't a fast path.
> 
> A WARN_ON sounds good to me.

OK.  Are you happy to give your Reviewed-by on the following?

--8<--

From 88aeb182ba787102e627e33728a08b70f467758c Mon Sep 17 00:00:00 2001
From: Dave Martin <Dave.Martin@arm.com>
Date: Thu, 4 Apr 2019 09:41:46 +0100
Subject: [PATCH] KVM: arm64/sve: Demote redundant sysreg vcpu_has_sve() checks
 to WARNs

Because of the logic in kvm_arm_sys_reg_{get,set}_reg() and
sve_id_visibility(), we should never call
{get,set}_id_aa64zfr0_el1() for a vcpu where !vcpu_has_sve(vcpu).

To avoid the code giving the impression that it is valid for these
functions to be called in this situation, and to help the compiler
make the right optimisation decisions, this patch adds WARN_ON()
for these cases.

Given the way the logic is spread out, this seems preferable to
dropping the checks altogether.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/kvm/sys_regs.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 09e9b06..7046c76 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1144,7 +1144,7 @@ static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
 {
 	u64 val;
 
-	if (!vcpu_has_sve(vcpu))
+	if (WARN_ON(!vcpu_has_sve(vcpu)))
 		return -ENOENT;
 
 	val = guest_id_aa64zfr0_el1(vcpu);
@@ -1159,7 +1159,7 @@ static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
 	int err;
 	u64 val;
 
-	if (!vcpu_has_sve(vcpu))
+	if (WARN_ON(!vcpu_has_sve(vcpu)))
 		return -ENOENT;
 
 	err = reg_from_user(&val, uaddr, id);
-- 
2.1.4


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

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

* Re: [PATCH v7 12/27] KVM: arm64/sve: System register context switch and access support
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-04  8:59     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04  8:59 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:37PM +0000, Dave Martin wrote:
> This patch adds the necessary support for context switching ZCR_EL1
> for each vcpu.
> 
> ZCR_EL1 is trapped alongside the FPSIMD/SVE registers, so it makes
> sense for it to be handled as part of the guest FPSIMD/SVE context
> for context switch purposes instead of handling it as a general
> system register.  This means that it can be switched in lazily at
> the appropriate time.  No effort is made to track host context for
> this register, since SVE requires VHE: thus the hosts's value for
> this register lives permanently in ZCR_EL2 and does not alias the
> guest's value at any time.
> 
> The Hyp switch and fpsimd context handling code is extended
> appropriately.
> 
> Accessors are added in sys_regs.c to expose the SVE system
> registers and ID register fields.  Because these need to be
> conditionally visible based on the guest configuration, they are
> implemented separately for now rather than by use of the generic
> system register helpers.  This may be abstracted better later on
> when/if there are more features requiring this model.
> 
> ID_AA64ZFR0_EL1 is RO-RAZ for MRS/MSR when SVE is disabled for the
> guest, but for compatibility with non-SVE aware KVM implementations
> the register should not be enumerated at all for KVM_GET_REG_LIST
> in this case.  For consistency we also reject ioctl access to the
> register.  This ensures that a non-SVE-enabled guest looks the same
> to userspace, irrespective of whether the kernel KVM implementation
> supports SVE.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * Port to the renamed visibility() framework.
> 
>  * Swap visiblity() helpers so that they appear by the relevant accessor
>    functions.
> 
>  * [Julien Grall] With the visibility() checks, {get,set}_zcr_el1()
>    degenerate to doing exactly what the common code does, so drop them.
> 
>    The ID_AA64ZFR0_EL1 handlers are still needed to provide contitional
>    RAZ behaviour.  This could be moved to the common code too, but since
>    this is a one-off case I don't do this for now.  We can address this
>    later if other regs need to follow the same pattern.
> 
>  * [Julien Thierry] Reset ZCR_EL1 to a fixed value using reset_val
>    instead of using relying on reset_unknown() honouring set bits in val
>    as RES0.
> 
>    Most of the bits in ZCR_EL1 are RES0 anyway, and many implementations
>    of SVE will support larger vectors than 128 bits, so 0 seems as good
>    a value as any to expose guests that forget to initialise this
>    register properly.
> ---
>  arch/arm64/include/asm/kvm_host.h |  1 +
>  arch/arm64/include/asm/sysreg.h   |  3 ++
>  arch/arm64/kvm/fpsimd.c           |  9 ++++-
>  arch/arm64/kvm/hyp/switch.c       |  3 ++
>  arch/arm64/kvm/sys_regs.c         | 83 ++++++++++++++++++++++++++++++++++++---
>  5 files changed, 93 insertions(+), 6 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v7 12/27] KVM: arm64/sve: System register context switch and access support
@ 2019-04-04  8:59     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04  8:59 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:37PM +0000, Dave Martin wrote:
> This patch adds the necessary support for context switching ZCR_EL1
> for each vcpu.
> 
> ZCR_EL1 is trapped alongside the FPSIMD/SVE registers, so it makes
> sense for it to be handled as part of the guest FPSIMD/SVE context
> for context switch purposes instead of handling it as a general
> system register.  This means that it can be switched in lazily at
> the appropriate time.  No effort is made to track host context for
> this register, since SVE requires VHE: thus the hosts's value for
> this register lives permanently in ZCR_EL2 and does not alias the
> guest's value at any time.
> 
> The Hyp switch and fpsimd context handling code is extended
> appropriately.
> 
> Accessors are added in sys_regs.c to expose the SVE system
> registers and ID register fields.  Because these need to be
> conditionally visible based on the guest configuration, they are
> implemented separately for now rather than by use of the generic
> system register helpers.  This may be abstracted better later on
> when/if there are more features requiring this model.
> 
> ID_AA64ZFR0_EL1 is RO-RAZ for MRS/MSR when SVE is disabled for the
> guest, but for compatibility with non-SVE aware KVM implementations
> the register should not be enumerated at all for KVM_GET_REG_LIST
> in this case.  For consistency we also reject ioctl access to the
> register.  This ensures that a non-SVE-enabled guest looks the same
> to userspace, irrespective of whether the kernel KVM implementation
> supports SVE.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * Port to the renamed visibility() framework.
> 
>  * Swap visiblity() helpers so that they appear by the relevant accessor
>    functions.
> 
>  * [Julien Grall] With the visibility() checks, {get,set}_zcr_el1()
>    degenerate to doing exactly what the common code does, so drop them.
> 
>    The ID_AA64ZFR0_EL1 handlers are still needed to provide contitional
>    RAZ behaviour.  This could be moved to the common code too, but since
>    this is a one-off case I don't do this for now.  We can address this
>    later if other regs need to follow the same pattern.
> 
>  * [Julien Thierry] Reset ZCR_EL1 to a fixed value using reset_val
>    instead of using relying on reset_unknown() honouring set bits in val
>    as RES0.
> 
>    Most of the bits in ZCR_EL1 are RES0 anyway, and many implementations
>    of SVE will support larger vectors than 128 bits, so 0 seems as good
>    a value as any to expose guests that forget to initialise this
>    register properly.
> ---
>  arch/arm64/include/asm/kvm_host.h |  1 +
>  arch/arm64/include/asm/sysreg.h   |  3 ++
>  arch/arm64/kvm/fpsimd.c           |  9 ++++-
>  arch/arm64/kvm/hyp/switch.c       |  3 ++
>  arch/arm64/kvm/sys_regs.c         | 83 ++++++++++++++++++++++++++++++++++++---
>  5 files changed, 93 insertions(+), 6 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 26/27] KVM: Document errors for KVM_GET_ONE_REG and KVM_SET_ONE_REG
  2019-04-04  8:35       ` Dave Martin
@ 2019-04-04  9:34         ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04  9:34 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 09:35:26AM +0100, Dave Martin wrote:
> On Wed, Apr 03, 2019 at 10:27:46PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:51PM +0000, Dave Martin wrote:
> > > KVM_GET_ONE_REG and KVM_SET_ONE_REG return some error codes that
> > > are not documented (but hopefully not surprising either).  To give
> > > an indication of what these may mean, this patch adds brief
> > > documentation.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > ---
> > >  Documentation/virtual/kvm/api.txt | 6 ++++++
> > >  1 file changed, 6 insertions(+)
> > > 
> > > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> > > index 2d4f7ce..cd920dd 100644
> > > --- a/Documentation/virtual/kvm/api.txt
> > > +++ b/Documentation/virtual/kvm/api.txt
> > > @@ -1871,6 +1871,9 @@ Architectures: all
> > >  Type: vcpu ioctl
> > >  Parameters: struct kvm_one_reg (in)
> > >  Returns: 0 on success, negative value on failure
> > > +Errors:
> > > +  ENOENT:   no such register
> > > +  EINVAL:   other errors, such as bad size encoding for a known register
> > >  
> > >  struct kvm_one_reg {
> > >         __u64 id;
> > > @@ -2192,6 +2195,9 @@ Architectures: all
> > >  Type: vcpu ioctl
> > >  Parameters: struct kvm_one_reg (in and out)
> > >  Returns: 0 on success, negative value on failure
> > > +Errors:
> > > +  ENOENT:   no such register
> > > +  EINVAL:   other errors, such as bad size encoding for a known register
> > >  
> > >  This ioctl allows to receive the value of a single register implemented
> > >  in a vcpu. The register to read is indicated by the "id" field of the
> > > -- 
> > > 2.1.4
> > >
> > 
> > Are we sure all architectures have these, and only these errors? A quick
> > grep indicates not. I'm not sure we can document this easily here due to
> > it addressing all architectures at once. Maybe we could add arch-specific
> > subsections, but I'm not sure it's worth it.
> 
> Error codes are generally indicative at best, and rarely mutually
> exclusive in a given situation.
> 
> Writing a caveat to say that you shouldn't make assumptions about
> precisely what error code will be returned in a given situation would
> look odd: that really applies widely all over the kernel/user ABI, not
> just here.
> 
> _Maybe_ everything is exhaustively correct in this file already, but
> given the size of it, and the fact that many things are implemented
> per-arch, the chance of this seems zero.
> 
> I could add "invalid register ID" for EINVAL.  This allows some
> ambiguity about which error code applies for a nonexistent register.
> 
> Alternatively, we could revert this documentation instead.

Yeah, I vote we just drop this patch. It could add more confusion
when people start here to determine what to grep and then, when
grepping for it, can't find any occurrences, as would be the case
for ENOENT on at least a couple arches.

Thanks,
drew

> 
> It seemed appropriate to document the EPERM error for finalization
> ordering (added later), but since correct userspace code should never
> see this maybe it's reasonable to leave it undocumented(?)
> 
> Cheers
> ---Dave

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

* Re: [PATCH v7 26/27] KVM: Document errors for KVM_GET_ONE_REG and KVM_SET_ONE_REG
@ 2019-04-04  9:34         ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04  9:34 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 09:35:26AM +0100, Dave Martin wrote:
> On Wed, Apr 03, 2019 at 10:27:46PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:51PM +0000, Dave Martin wrote:
> > > KVM_GET_ONE_REG and KVM_SET_ONE_REG return some error codes that
> > > are not documented (but hopefully not surprising either).  To give
> > > an indication of what these may mean, this patch adds brief
> > > documentation.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > ---
> > >  Documentation/virtual/kvm/api.txt | 6 ++++++
> > >  1 file changed, 6 insertions(+)
> > > 
> > > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> > > index 2d4f7ce..cd920dd 100644
> > > --- a/Documentation/virtual/kvm/api.txt
> > > +++ b/Documentation/virtual/kvm/api.txt
> > > @@ -1871,6 +1871,9 @@ Architectures: all
> > >  Type: vcpu ioctl
> > >  Parameters: struct kvm_one_reg (in)
> > >  Returns: 0 on success, negative value on failure
> > > +Errors:
> > > +  ENOENT:   no such register
> > > +  EINVAL:   other errors, such as bad size encoding for a known register
> > >  
> > >  struct kvm_one_reg {
> > >         __u64 id;
> > > @@ -2192,6 +2195,9 @@ Architectures: all
> > >  Type: vcpu ioctl
> > >  Parameters: struct kvm_one_reg (in and out)
> > >  Returns: 0 on success, negative value on failure
> > > +Errors:
> > > +  ENOENT:   no such register
> > > +  EINVAL:   other errors, such as bad size encoding for a known register
> > >  
> > >  This ioctl allows to receive the value of a single register implemented
> > >  in a vcpu. The register to read is indicated by the "id" field of the
> > > -- 
> > > 2.1.4
> > >
> > 
> > Are we sure all architectures have these, and only these errors? A quick
> > grep indicates not. I'm not sure we can document this easily here due to
> > it addressing all architectures at once. Maybe we could add arch-specific
> > subsections, but I'm not sure it's worth it.
> 
> Error codes are generally indicative at best, and rarely mutually
> exclusive in a given situation.
> 
> Writing a caveat to say that you shouldn't make assumptions about
> precisely what error code will be returned in a given situation would
> look odd: that really applies widely all over the kernel/user ABI, not
> just here.
> 
> _Maybe_ everything is exhaustively correct in this file already, but
> given the size of it, and the fact that many things are implemented
> per-arch, the chance of this seems zero.
> 
> I could add "invalid register ID" for EINVAL.  This allows some
> ambiguity about which error code applies for a nonexistent register.
> 
> Alternatively, we could revert this documentation instead.

Yeah, I vote we just drop this patch. It could add more confusion
when people start here to determine what to grep and then, when
grepping for it, can't find any occurrences, as would be the case
for ENOENT on at least a couple arches.

Thanks,
drew

> 
> It seemed appropriate to document the EPERM error for finalization
> ordering (added later), but since correct userspace code should never
> see this maybe it's reasonable to leave it undocumented(?)
> 
> Cheers
> ---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 26/27] KVM: Document errors for KVM_GET_ONE_REG and KVM_SET_ONE_REG
  2019-04-04  9:34         ` Andrew Jones
@ 2019-04-04  9:38           ` Dave P Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave P Martin @ 2019-04-04  9:38 UTC (permalink / raw)
  To: Andrew Jones
  Cc: tokamoto, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 10:34:15AM +0100, Andrew Jones wrote:
> On Thu, Apr 04, 2019 at 09:35:26AM +0100, Dave Martin wrote:
> > On Wed, Apr 03, 2019 at 10:27:46PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:51PM +0000, Dave Martin wrote:
> > > > KVM_GET_ONE_REG and KVM_SET_ONE_REG return some error codes that
> > > > are not documented (but hopefully not surprising either).  To give
> > > > an indication of what these may mean, this patch adds brief
> > > > documentation.
> > > >
> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > ---
> > > >  Documentation/virtual/kvm/api.txt | 6 ++++++
> > > >  1 file changed, 6 insertions(+)
> > > >
> > > > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> > > > index 2d4f7ce..cd920dd 100644
> > > > --- a/Documentation/virtual/kvm/api.txt
> > > > +++ b/Documentation/virtual/kvm/api.txt
> > > > @@ -1871,6 +1871,9 @@ Architectures: all
> > > >  Type: vcpu ioctl
> > > >  Parameters: struct kvm_one_reg (in)
> > > >  Returns: 0 on success, negative value on failure
> > > > +Errors:
> > > > +  ENOENT:   no such register
> > > > +  EINVAL:   other errors, such as bad size encoding for a known register
> > > >
> > > >  struct kvm_one_reg {
> > > >         __u64 id;
> > > > @@ -2192,6 +2195,9 @@ Architectures: all
> > > >  Type: vcpu ioctl
> > > >  Parameters: struct kvm_one_reg (in and out)
> > > >  Returns: 0 on success, negative value on failure
> > > > +Errors:
> > > > +  ENOENT:   no such register
> > > > +  EINVAL:   other errors, such as bad size encoding for a known register
> > > >
> > > >  This ioctl allows to receive the value of a single register implemented
> > > >  in a vcpu. The register to read is indicated by the "id" field of the
> > > > --
> > > > 2.1.4
> > > >
> > >
> > > Are we sure all architectures have these, and only these errors? A quick
> > > grep indicates not. I'm not sure we can document this easily here due to
> > > it addressing all architectures at once. Maybe we could add arch-specific
> > > subsections, but I'm not sure it's worth it.
> >
> > Error codes are generally indicative at best, and rarely mutually
> > exclusive in a given situation.
> >
> > Writing a caveat to say that you shouldn't make assumptions about
> > precisely what error code will be returned in a given situation would
> > look odd: that really applies widely all over the kernel/user ABI, not
> > just here.
> >
> > _Maybe_ everything is exhaustively correct in this file already, but
> > given the size of it, and the fact that many things are implemented
> > per-arch, the chance of this seems zero.
> >
> > I could add "invalid register ID" for EINVAL.  This allows some
> > ambiguity about which error code applies for a nonexistent register.
> >
> > Alternatively, we could revert this documentation instead.
>
> Yeah, I vote we just drop this patch. It could add more confusion
> when people start here to determine what to grep and then, when
> grepping for it, can't find any occurrences, as would be the case
> for ENOENT on at least a couple arches.

I guess so.  It's not like we're claiming this ioctl _can't_ fail.
So leaving interpretation of the errno values to common sense is
reasonable.

> > It seemed appropriate to document the EPERM error for finalization
> > ordering (added later), but since correct userspace code should never
> > see this maybe it's reasonable to leave it undocumented(?)

I assume you mean to remove this too?

I don't think correctly written userspace should be relying on seeing
this error code (as opposed to e.g., KVM_GET_REG_LIST's E2BIG which you
must observe in order to allocate the right amount of memory for the reg
list).

Cheers
---Dave
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

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

* Re: [PATCH v7 26/27] KVM: Document errors for KVM_GET_ONE_REG and KVM_SET_ONE_REG
@ 2019-04-04  9:38           ` Dave P Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave P Martin @ 2019-04-04  9:38 UTC (permalink / raw)
  To: Andrew Jones
  Cc: tokamoto, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 10:34:15AM +0100, Andrew Jones wrote:
> On Thu, Apr 04, 2019 at 09:35:26AM +0100, Dave Martin wrote:
> > On Wed, Apr 03, 2019 at 10:27:46PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:51PM +0000, Dave Martin wrote:
> > > > KVM_GET_ONE_REG and KVM_SET_ONE_REG return some error codes that
> > > > are not documented (but hopefully not surprising either).  To give
> > > > an indication of what these may mean, this patch adds brief
> > > > documentation.
> > > >
> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > ---
> > > >  Documentation/virtual/kvm/api.txt | 6 ++++++
> > > >  1 file changed, 6 insertions(+)
> > > >
> > > > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> > > > index 2d4f7ce..cd920dd 100644
> > > > --- a/Documentation/virtual/kvm/api.txt
> > > > +++ b/Documentation/virtual/kvm/api.txt
> > > > @@ -1871,6 +1871,9 @@ Architectures: all
> > > >  Type: vcpu ioctl
> > > >  Parameters: struct kvm_one_reg (in)
> > > >  Returns: 0 on success, negative value on failure
> > > > +Errors:
> > > > +  ENOENT:   no such register
> > > > +  EINVAL:   other errors, such as bad size encoding for a known register
> > > >
> > > >  struct kvm_one_reg {
> > > >         __u64 id;
> > > > @@ -2192,6 +2195,9 @@ Architectures: all
> > > >  Type: vcpu ioctl
> > > >  Parameters: struct kvm_one_reg (in and out)
> > > >  Returns: 0 on success, negative value on failure
> > > > +Errors:
> > > > +  ENOENT:   no such register
> > > > +  EINVAL:   other errors, such as bad size encoding for a known register
> > > >
> > > >  This ioctl allows to receive the value of a single register implemented
> > > >  in a vcpu. The register to read is indicated by the "id" field of the
> > > > --
> > > > 2.1.4
> > > >
> > >
> > > Are we sure all architectures have these, and only these errors? A quick
> > > grep indicates not. I'm not sure we can document this easily here due to
> > > it addressing all architectures at once. Maybe we could add arch-specific
> > > subsections, but I'm not sure it's worth it.
> >
> > Error codes are generally indicative at best, and rarely mutually
> > exclusive in a given situation.
> >
> > Writing a caveat to say that you shouldn't make assumptions about
> > precisely what error code will be returned in a given situation would
> > look odd: that really applies widely all over the kernel/user ABI, not
> > just here.
> >
> > _Maybe_ everything is exhaustively correct in this file already, but
> > given the size of it, and the fact that many things are implemented
> > per-arch, the chance of this seems zero.
> >
> > I could add "invalid register ID" for EINVAL.  This allows some
> > ambiguity about which error code applies for a nonexistent register.
> >
> > Alternatively, we could revert this documentation instead.
>
> Yeah, I vote we just drop this patch. It could add more confusion
> when people start here to determine what to grep and then, when
> grepping for it, can't find any occurrences, as would be the case
> for ENOENT on at least a couple arches.

I guess so.  It's not like we're claiming this ioctl _can't_ fail.
So leaving interpretation of the errno values to common sense is
reasonable.

> > It seemed appropriate to document the EPERM error for finalization
> > ordering (added later), but since correct userspace code should never
> > see this maybe it's reasonable to leave it undocumented(?)

I assume you mean to remove this too?

I don't think correctly written userspace should be relying on seeing
this error code (as opposed to e.g., KVM_GET_REG_LIST's E2BIG which you
must observe in order to allocate the right amount of memory for the reg
list).

Cheers
---Dave
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 26/27] KVM: Document errors for KVM_GET_ONE_REG and KVM_SET_ONE_REG
  2019-04-04  9:38           ` Dave P Martin
@ 2019-04-04  9:45             ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04  9:45 UTC (permalink / raw)
  To: Dave P Martin
  Cc: tokamoto, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 09:38:49AM +0000, Dave P Martin wrote:
> On Thu, Apr 04, 2019 at 10:34:15AM +0100, Andrew Jones wrote:
> > On Thu, Apr 04, 2019 at 09:35:26AM +0100, Dave Martin wrote:
> > > On Wed, Apr 03, 2019 at 10:27:46PM +0200, Andrew Jones wrote:
> > > > On Fri, Mar 29, 2019 at 01:00:51PM +0000, Dave Martin wrote:
> > > > > KVM_GET_ONE_REG and KVM_SET_ONE_REG return some error codes that
> > > > > are not documented (but hopefully not surprising either).  To give
> > > > > an indication of what these may mean, this patch adds brief
> > > > > documentation.
> > > > >
> > > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > > ---
> > > > >  Documentation/virtual/kvm/api.txt | 6 ++++++
> > > > >  1 file changed, 6 insertions(+)
> > > > >
> > > > > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> > > > > index 2d4f7ce..cd920dd 100644
> > > > > --- a/Documentation/virtual/kvm/api.txt
> > > > > +++ b/Documentation/virtual/kvm/api.txt
> > > > > @@ -1871,6 +1871,9 @@ Architectures: all
> > > > >  Type: vcpu ioctl
> > > > >  Parameters: struct kvm_one_reg (in)
> > > > >  Returns: 0 on success, negative value on failure
> > > > > +Errors:
> > > > > +  ENOENT:   no such register
> > > > > +  EINVAL:   other errors, such as bad size encoding for a known register
> > > > >
> > > > >  struct kvm_one_reg {
> > > > >         __u64 id;
> > > > > @@ -2192,6 +2195,9 @@ Architectures: all
> > > > >  Type: vcpu ioctl
> > > > >  Parameters: struct kvm_one_reg (in and out)
> > > > >  Returns: 0 on success, negative value on failure
> > > > > +Errors:
> > > > > +  ENOENT:   no such register
> > > > > +  EINVAL:   other errors, such as bad size encoding for a known register
> > > > >
> > > > >  This ioctl allows to receive the value of a single register implemented
> > > > >  in a vcpu. The register to read is indicated by the "id" field of the
> > > > > --
> > > > > 2.1.4
> > > > >
> > > >
> > > > Are we sure all architectures have these, and only these errors? A quick
> > > > grep indicates not. I'm not sure we can document this easily here due to
> > > > it addressing all architectures at once. Maybe we could add arch-specific
> > > > subsections, but I'm not sure it's worth it.
> > >
> > > Error codes are generally indicative at best, and rarely mutually
> > > exclusive in a given situation.
> > >
> > > Writing a caveat to say that you shouldn't make assumptions about
> > > precisely what error code will be returned in a given situation would
> > > look odd: that really applies widely all over the kernel/user ABI, not
> > > just here.
> > >
> > > _Maybe_ everything is exhaustively correct in this file already, but
> > > given the size of it, and the fact that many things are implemented
> > > per-arch, the chance of this seems zero.
> > >
> > > I could add "invalid register ID" for EINVAL.  This allows some
> > > ambiguity about which error code applies for a nonexistent register.
> > >
> > > Alternatively, we could revert this documentation instead.
> >
> > Yeah, I vote we just drop this patch. It could add more confusion
> > when people start here to determine what to grep and then, when
> > grepping for it, can't find any occurrences, as would be the case
> > for ENOENT on at least a couple arches.
> 
> I guess so.  It's not like we're claiming this ioctl _can't_ fail.
> So leaving interpretation of the errno values to common sense is
> reasonable.
> 
> > > It seemed appropriate to document the EPERM error for finalization
> > > ordering (added later), but since correct userspace code should never
> > > see this maybe it's reasonable to leave it undocumented(?)
> 
> I assume you mean to remove this too?

I haven't reviewed that stuff yet, so I don't yet have an opinion :)
I'll get through it all today, but I'm trashing on mail and bugzilla
this morning, so progress on the review hasn't started back up since
last night yet...

drew

> 
> I don't think correctly written userspace should be relying on seeing
> this error code (as opposed to e.g., KVM_GET_REG_LIST's E2BIG which you
> must observe in order to allocate the right amount of memory for the reg
> list).
> 
> Cheers
> ---Dave
> IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

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

* Re: [PATCH v7 26/27] KVM: Document errors for KVM_GET_ONE_REG and KVM_SET_ONE_REG
@ 2019-04-04  9:45             ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04  9:45 UTC (permalink / raw)
  To: Dave P Martin
  Cc: tokamoto, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 09:38:49AM +0000, Dave P Martin wrote:
> On Thu, Apr 04, 2019 at 10:34:15AM +0100, Andrew Jones wrote:
> > On Thu, Apr 04, 2019 at 09:35:26AM +0100, Dave Martin wrote:
> > > On Wed, Apr 03, 2019 at 10:27:46PM +0200, Andrew Jones wrote:
> > > > On Fri, Mar 29, 2019 at 01:00:51PM +0000, Dave Martin wrote:
> > > > > KVM_GET_ONE_REG and KVM_SET_ONE_REG return some error codes that
> > > > > are not documented (but hopefully not surprising either).  To give
> > > > > an indication of what these may mean, this patch adds brief
> > > > > documentation.
> > > > >
> > > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > > ---
> > > > >  Documentation/virtual/kvm/api.txt | 6 ++++++
> > > > >  1 file changed, 6 insertions(+)
> > > > >
> > > > > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> > > > > index 2d4f7ce..cd920dd 100644
> > > > > --- a/Documentation/virtual/kvm/api.txt
> > > > > +++ b/Documentation/virtual/kvm/api.txt
> > > > > @@ -1871,6 +1871,9 @@ Architectures: all
> > > > >  Type: vcpu ioctl
> > > > >  Parameters: struct kvm_one_reg (in)
> > > > >  Returns: 0 on success, negative value on failure
> > > > > +Errors:
> > > > > +  ENOENT:   no such register
> > > > > +  EINVAL:   other errors, such as bad size encoding for a known register
> > > > >
> > > > >  struct kvm_one_reg {
> > > > >         __u64 id;
> > > > > @@ -2192,6 +2195,9 @@ Architectures: all
> > > > >  Type: vcpu ioctl
> > > > >  Parameters: struct kvm_one_reg (in and out)
> > > > >  Returns: 0 on success, negative value on failure
> > > > > +Errors:
> > > > > +  ENOENT:   no such register
> > > > > +  EINVAL:   other errors, such as bad size encoding for a known register
> > > > >
> > > > >  This ioctl allows to receive the value of a single register implemented
> > > > >  in a vcpu. The register to read is indicated by the "id" field of the
> > > > > --
> > > > > 2.1.4
> > > > >
> > > >
> > > > Are we sure all architectures have these, and only these errors? A quick
> > > > grep indicates not. I'm not sure we can document this easily here due to
> > > > it addressing all architectures at once. Maybe we could add arch-specific
> > > > subsections, but I'm not sure it's worth it.
> > >
> > > Error codes are generally indicative at best, and rarely mutually
> > > exclusive in a given situation.
> > >
> > > Writing a caveat to say that you shouldn't make assumptions about
> > > precisely what error code will be returned in a given situation would
> > > look odd: that really applies widely all over the kernel/user ABI, not
> > > just here.
> > >
> > > _Maybe_ everything is exhaustively correct in this file already, but
> > > given the size of it, and the fact that many things are implemented
> > > per-arch, the chance of this seems zero.
> > >
> > > I could add "invalid register ID" for EINVAL.  This allows some
> > > ambiguity about which error code applies for a nonexistent register.
> > >
> > > Alternatively, we could revert this documentation instead.
> >
> > Yeah, I vote we just drop this patch. It could add more confusion
> > when people start here to determine what to grep and then, when
> > grepping for it, can't find any occurrences, as would be the case
> > for ENOENT on at least a couple arches.
> 
> I guess so.  It's not like we're claiming this ioctl _can't_ fail.
> So leaving interpretation of the errno values to common sense is
> reasonable.
> 
> > > It seemed appropriate to document the EPERM error for finalization
> > > ordering (added later), but since correct userspace code should never
> > > see this maybe it's reasonable to leave it undocumented(?)
> 
> I assume you mean to remove this too?

I haven't reviewed that stuff yet, so I don't yet have an opinion :)
I'll get through it all today, but I'm trashing on mail and bugzilla
this morning, so progress on the review hasn't started back up since
last night yet...

drew

> 
> I don't think correctly written userspace should be relying on seeing
> this error code (as opposed to e.g., KVM_GET_REG_LIST's E2BIG which you
> must observe in order to allocate the right amount of memory for the reg
> list).
> 
> Cheers
> ---Dave
> IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 18/27] KVM: arm64/sve: Add SVE support to register access ioctl interface
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-04 13:57     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 13:57 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:43PM +0000, Dave Martin wrote:
> This patch adds the following registers for access via the
> KVM_{GET,SET}_ONE_REG interface:
> 
>  * KVM_REG_ARM64_SVE_ZREG(n, i) (n = 0..31) (in 2048-bit slices)
>  * KVM_REG_ARM64_SVE_PREG(n, i) (n = 0..15) (in 256-bit slices)
>  * KVM_REG_ARM64_SVE_FFR(i) (in 256-bit slices)
> 
> In order to adapt gracefully to future architectural extensions,
> the registers are logically divided up into slices as noted above:
> the i parameter denotes the slice index.
> 
> This allows us to reserve space in the ABI for future expansion of
> these registers.  However, as of today the architecture does not
> permit registers to be larger than a single slice, so no code is
> needed in the kernel to expose additional slices, for now.  The
> code can be extended later as needed to expose them up to a maximum
> of 32 slices (as carved out in the architecture itself) if they
> really exist someday.
> 
> The registers are only visible for vcpus that have SVE enabled.
> They are not enumerated by KVM_GET_REG_LIST on vcpus that do not
> have SVE.
> 
> Accesses to the FPSIMD registers via KVM_REG_ARM_CORE is not
> allowed for SVE-enabled vcpus: SVE-aware userspace can use the
> KVM_REG_ARM64_SVE_ZREG() interface instead to access the same
> register state.  This avoids some complex and pointless emulation
> in the kernel to convert between the two views of these aliased
> registers.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * [Julien Thierry] rename sve_reg_region() to sve_reg_to_region() to
>    make its purpose a bit clearer.
> 
>  * [Julien Thierry] rename struct sve_state_region to
>    sve_state_reg_region to make it clearer this this struct only
>    describes the bounds of (part of) a single register within
>    sve_state.
> 
>  * [Julien Thierry] Add a comment to clarify the purpose of struct
>    sve_state_reg_region.
> ---
>  arch/arm64/include/asm/kvm_host.h |  14 ++++
>  arch/arm64/include/uapi/asm/kvm.h |  17 +++++
>  arch/arm64/kvm/guest.c            | 139 ++++++++++++++++++++++++++++++++++----
>  3 files changed, 158 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 4fabfd2..205438a 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -329,6 +329,20 @@ struct kvm_vcpu_arch {
>  #define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
>  				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
>  
> +#define vcpu_sve_state_size(vcpu) ({					\
> +	size_t __size_ret;						\
> +	unsigned int __vcpu_vq;						\
> +									\
> +	if (WARN_ON(!sve_vl_valid((vcpu)->arch.sve_max_vl))) {		\
> +		__size_ret = 0;						\
> +	} else {							\
> +		__vcpu_vq = sve_vq_from_vl((vcpu)->arch.sve_max_vl);	\
> +		__size_ret = SVE_SIG_REGS_SIZE(__vcpu_vq);		\
> +	}								\
> +									\
> +	__size_ret;							\
> +})

I know why this is a macro instead of an inline :)

> +
>  /* vcpu_arch flags field values: */
>  #define KVM_ARM64_DEBUG_DIRTY		(1 << 0)
>  #define KVM_ARM64_FP_ENABLED		(1 << 1) /* guest FP regs loaded */
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 97c3478..ced760c 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -226,6 +226,23 @@ struct kvm_vcpu_events {
>  					 KVM_REG_ARM_FW | ((r) & 0xffff))
>  #define KVM_REG_ARM_PSCI_VERSION	KVM_REG_ARM_FW_REG(0)
>  
> +/* SVE registers */
> +#define KVM_REG_ARM64_SVE		(0x15 << KVM_REG_ARM_COPROC_SHIFT)
> +
> +/* Z- and P-regs occupy blocks at the following offsets within this range: */
> +#define KVM_REG_ARM64_SVE_ZREG_BASE	0
> +#define KVM_REG_ARM64_SVE_PREG_BASE	0x400
> +
> +#define KVM_REG_ARM64_SVE_ZREG(n, i)	(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
> +					 KVM_REG_ARM64_SVE_ZREG_BASE |	\
> +					 KVM_REG_SIZE_U2048 |		\
> +					 ((n) << 5) | (i))
> +#define KVM_REG_ARM64_SVE_PREG(n, i)	(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
> +					 KVM_REG_ARM64_SVE_PREG_BASE |	\
> +					 KVM_REG_SIZE_U256 |		\
> +					 ((n) << 5) | (i))

I think (n) in the above two macros should be masked to document their
size constraints. Since KVM_REG_ARM_COPROC_SHIFT is 16 they can't be
larger than 1 << (16 - 5), which would be a mask of 0x7ff, but as there
are only 32 zregs and 16 pregs so we should use 0x1f and 0xf respectively.

> +#define KVM_REG_ARM64_SVE_FFR(i)	KVM_REG_ARM64_SVE_PREG(16, i)

Since this is user api and a user may want to construct their own register
indices, then shouldn't we instead provide KVM_REG_ARM64_SVE_FFR_BASE as

 #define KVM_REG_ARM64_SVE_FFR_BASE KVM_REG_ARM64_SVE_PREG_BASE | (16 << 5)

and then KVM_REG_ARM64_SVE_FFR(i) would follow the typical pattern

 #define KVM_REG_ARM64_SVE_FFR(i) (KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
                                   KVM_REG_ARM64_SVE_FFR_BASE | \
                                   KVM_REG_SIZE_U256 | (i))

> +
>  /* Device Control API: ARM VGIC */
>  #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
>  #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 756d0d6..736d8cb 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -19,8 +19,11 @@
>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>   */
>  
> +#include <linux/bits.h>
>  #include <linux/errno.h>
>  #include <linux/err.h>
> +#include <linux/nospec.h>
> +#include <linux/kernel.h>
>  #include <linux/kvm_host.h>
>  #include <linux/module.h>
>  #include <linux/stddef.h>
> @@ -30,9 +33,12 @@
>  #include <kvm/arm_psci.h>
>  #include <asm/cputype.h>
>  #include <linux/uaccess.h>
> +#include <asm/fpsimd.h>
>  #include <asm/kvm.h>
>  #include <asm/kvm_emulate.h>
>  #include <asm/kvm_coproc.h>
> +#include <asm/kvm_host.h>
> +#include <asm/sigcontext.h>
>  
>  #include "trace.h"
>  
> @@ -200,6 +206,115 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	return err;
>  }
>  
> +#define SVE_REG_SLICE_SHIFT	0
> +#define SVE_REG_SLICE_BITS	5
> +#define SVE_REG_ID_SHIFT	(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS)
> +#define SVE_REG_ID_BITS		5
> +
> +#define SVE_REG_SLICE_MASK					\
> +	GENMASK(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS - 1,	\
> +		SVE_REG_SLICE_SHIFT)
> +#define SVE_REG_ID_MASK							\
> +	GENMASK(SVE_REG_ID_SHIFT + SVE_REG_ID_BITS - 1, SVE_REG_ID_SHIFT)
> +
> +#define SVE_NUM_SLICES (1 << SVE_REG_SLICE_BITS)
> +
> +#define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0))
> +#define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0))
> +
> +/* Bounds of a single SVE register slice within vcpu->arch.sve_state */
> +struct sve_state_reg_region {
> +	unsigned int koffset;	/* offset into sve_state in kernel memory */
> +	unsigned int klen;	/* length in kernel memory */
> +	unsigned int upad;	/* extra trailing padding in user memory */
> +};
> +
> +/* Get sanitised bounds for user/kernel SVE register copy */
> +static int sve_reg_to_region(struct sve_state_reg_region *region,
> +			     struct kvm_vcpu *vcpu,
> +			     const struct kvm_one_reg *reg)
> +{
> +	/* reg ID ranges for Z- registers */
> +	const u64 zreg_id_min = KVM_REG_ARM64_SVE_ZREG(0, 0);
> +	const u64 zreg_id_max = KVM_REG_ARM64_SVE_ZREG(SVE_NUM_ZREGS - 1,
> +						       SVE_NUM_SLICES - 1);
> +
> +	/* reg ID ranges for P- registers and FFR (which are contiguous) */
> +	const u64 preg_id_min = KVM_REG_ARM64_SVE_PREG(0, 0);
> +	const u64 preg_id_max = KVM_REG_ARM64_SVE_FFR(SVE_NUM_SLICES - 1);
> +
> +	unsigned int vq;
> +	unsigned int reg_num;
> +
> +	unsigned int reqoffset, reqlen; /* User-requested offset and length */
> +	unsigned int maxlen; /* Maxmimum permitted length */
> +
> +	size_t sve_state_size;
> +
> +	/* Only the first slice ever exists, for now: */
> +	if ((reg->id & SVE_REG_SLICE_MASK) != 0)
> +		return -ENOENT;
> +
> +	vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
> +
> +	reg_num = (reg->id & SVE_REG_ID_MASK) >> SVE_REG_ID_SHIFT;
> +
> +	if (reg->id >= zreg_id_min && reg->id <= zreg_id_max) {
> +		reqoffset = SVE_SIG_ZREG_OFFSET(vq, reg_num) -
> +				SVE_SIG_REGS_OFFSET;
> +		reqlen = KVM_SVE_ZREG_SIZE;
> +		maxlen = SVE_SIG_ZREG_SIZE(vq);
> +	} else if (reg->id >= preg_id_min && reg->id <= preg_id_max) {
> +		reqoffset = SVE_SIG_PREG_OFFSET(vq, reg_num) -
> +				SVE_SIG_REGS_OFFSET;
> +		reqlen = KVM_SVE_PREG_SIZE;
> +		maxlen = SVE_SIG_PREG_SIZE(vq);
> +	} else {
> +		return -ENOENT;
> +	}
> +
> +	sve_state_size = vcpu_sve_state_size(vcpu);
> +	if (!sve_state_size)
> +		return -EINVAL;
> +
> +	region->koffset = array_index_nospec(reqoffset, sve_state_size);
> +	region->klen = min(maxlen, reqlen);
> +	region->upad = reqlen - region->klen;
> +
> +	return 0;
> +}
> +
> +static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> +{
> +	struct sve_state_reg_region region;
> +	char __user *uptr = (char __user *)reg->addr;
> +
> +	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> +		return -ENOENT;

sve_reg_to_region() can return EINVAL, but here it would get changed to
ENOENT.

> +
> +	if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
> +			 region.klen) ||
> +	    clear_user(uptr + region.klen, region.upad))
> +		return -EFAULT;
> +
> +	return 0;
> +}
> +
> +static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> +{
> +	struct sve_state_reg_region region;
> +	const char __user *uptr = (const char __user *)reg->addr;
> +
> +	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> +		return -ENOENT;

Same as above.

> +
> +	if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
> +			   region.klen))
> +		return -EFAULT;
> +
> +	return 0;
> +}
> +
>  int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
>  {
>  	return -EINVAL;
> @@ -346,12 +461,12 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
>  		return -EINVAL;
>  
> -	/* Register group 16 means we want a core register. */
> -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
> -		return get_core_reg(vcpu, reg);
> -
> -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
> -		return kvm_arm_get_fw_reg(vcpu, reg);
> +	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> +	case KVM_REG_ARM_CORE:	return get_core_reg(vcpu, reg);
> +	case KVM_REG_ARM_FW:	return kvm_arm_get_fw_reg(vcpu, reg);
> +	case KVM_REG_ARM64_SVE:	return get_sve_reg(vcpu, reg);
> +	default: break; /* fall through */

This case has a 'break', so it's not a 'fall through'. Do we require
default cases even when they're unused? If not, why have it?

> +	}
>  
>  	if (is_timer_reg(reg->id))
>  		return get_timer_reg(vcpu, reg);
> @@ -365,12 +480,12 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
>  		return -EINVAL;
>  
> -	/* Register group 16 means we set a core register. */
> -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
> -		return set_core_reg(vcpu, reg);
> -
> -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
> -		return kvm_arm_set_fw_reg(vcpu, reg);
> +	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> +	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
> +	case KVM_REG_ARM_FW:	return kvm_arm_set_fw_reg(vcpu, reg);
> +	case KVM_REG_ARM64_SVE:	return set_sve_reg(vcpu, reg);
> +	default: break; /* fall through */

Same as above.

> +	}
>  
>  	if (is_timer_reg(reg->id))
>  		return set_timer_reg(vcpu, reg);
> -- 
> 2.1.4
>

Thanks,
drew 

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

* Re: [PATCH v7 18/27] KVM: arm64/sve: Add SVE support to register access ioctl interface
@ 2019-04-04 13:57     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 13:57 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:43PM +0000, Dave Martin wrote:
> This patch adds the following registers for access via the
> KVM_{GET,SET}_ONE_REG interface:
> 
>  * KVM_REG_ARM64_SVE_ZREG(n, i) (n = 0..31) (in 2048-bit slices)
>  * KVM_REG_ARM64_SVE_PREG(n, i) (n = 0..15) (in 256-bit slices)
>  * KVM_REG_ARM64_SVE_FFR(i) (in 256-bit slices)
> 
> In order to adapt gracefully to future architectural extensions,
> the registers are logically divided up into slices as noted above:
> the i parameter denotes the slice index.
> 
> This allows us to reserve space in the ABI for future expansion of
> these registers.  However, as of today the architecture does not
> permit registers to be larger than a single slice, so no code is
> needed in the kernel to expose additional slices, for now.  The
> code can be extended later as needed to expose them up to a maximum
> of 32 slices (as carved out in the architecture itself) if they
> really exist someday.
> 
> The registers are only visible for vcpus that have SVE enabled.
> They are not enumerated by KVM_GET_REG_LIST on vcpus that do not
> have SVE.
> 
> Accesses to the FPSIMD registers via KVM_REG_ARM_CORE is not
> allowed for SVE-enabled vcpus: SVE-aware userspace can use the
> KVM_REG_ARM64_SVE_ZREG() interface instead to access the same
> register state.  This avoids some complex and pointless emulation
> in the kernel to convert between the two views of these aliased
> registers.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * [Julien Thierry] rename sve_reg_region() to sve_reg_to_region() to
>    make its purpose a bit clearer.
> 
>  * [Julien Thierry] rename struct sve_state_region to
>    sve_state_reg_region to make it clearer this this struct only
>    describes the bounds of (part of) a single register within
>    sve_state.
> 
>  * [Julien Thierry] Add a comment to clarify the purpose of struct
>    sve_state_reg_region.
> ---
>  arch/arm64/include/asm/kvm_host.h |  14 ++++
>  arch/arm64/include/uapi/asm/kvm.h |  17 +++++
>  arch/arm64/kvm/guest.c            | 139 ++++++++++++++++++++++++++++++++++----
>  3 files changed, 158 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 4fabfd2..205438a 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -329,6 +329,20 @@ struct kvm_vcpu_arch {
>  #define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
>  				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
>  
> +#define vcpu_sve_state_size(vcpu) ({					\
> +	size_t __size_ret;						\
> +	unsigned int __vcpu_vq;						\
> +									\
> +	if (WARN_ON(!sve_vl_valid((vcpu)->arch.sve_max_vl))) {		\
> +		__size_ret = 0;						\
> +	} else {							\
> +		__vcpu_vq = sve_vq_from_vl((vcpu)->arch.sve_max_vl);	\
> +		__size_ret = SVE_SIG_REGS_SIZE(__vcpu_vq);		\
> +	}								\
> +									\
> +	__size_ret;							\
> +})

I know why this is a macro instead of an inline :)

> +
>  /* vcpu_arch flags field values: */
>  #define KVM_ARM64_DEBUG_DIRTY		(1 << 0)
>  #define KVM_ARM64_FP_ENABLED		(1 << 1) /* guest FP regs loaded */
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 97c3478..ced760c 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -226,6 +226,23 @@ struct kvm_vcpu_events {
>  					 KVM_REG_ARM_FW | ((r) & 0xffff))
>  #define KVM_REG_ARM_PSCI_VERSION	KVM_REG_ARM_FW_REG(0)
>  
> +/* SVE registers */
> +#define KVM_REG_ARM64_SVE		(0x15 << KVM_REG_ARM_COPROC_SHIFT)
> +
> +/* Z- and P-regs occupy blocks at the following offsets within this range: */
> +#define KVM_REG_ARM64_SVE_ZREG_BASE	0
> +#define KVM_REG_ARM64_SVE_PREG_BASE	0x400
> +
> +#define KVM_REG_ARM64_SVE_ZREG(n, i)	(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
> +					 KVM_REG_ARM64_SVE_ZREG_BASE |	\
> +					 KVM_REG_SIZE_U2048 |		\
> +					 ((n) << 5) | (i))
> +#define KVM_REG_ARM64_SVE_PREG(n, i)	(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
> +					 KVM_REG_ARM64_SVE_PREG_BASE |	\
> +					 KVM_REG_SIZE_U256 |		\
> +					 ((n) << 5) | (i))

I think (n) in the above two macros should be masked to document their
size constraints. Since KVM_REG_ARM_COPROC_SHIFT is 16 they can't be
larger than 1 << (16 - 5), which would be a mask of 0x7ff, but as there
are only 32 zregs and 16 pregs so we should use 0x1f and 0xf respectively.

> +#define KVM_REG_ARM64_SVE_FFR(i)	KVM_REG_ARM64_SVE_PREG(16, i)

Since this is user api and a user may want to construct their own register
indices, then shouldn't we instead provide KVM_REG_ARM64_SVE_FFR_BASE as

 #define KVM_REG_ARM64_SVE_FFR_BASE KVM_REG_ARM64_SVE_PREG_BASE | (16 << 5)

and then KVM_REG_ARM64_SVE_FFR(i) would follow the typical pattern

 #define KVM_REG_ARM64_SVE_FFR(i) (KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
                                   KVM_REG_ARM64_SVE_FFR_BASE | \
                                   KVM_REG_SIZE_U256 | (i))

> +
>  /* Device Control API: ARM VGIC */
>  #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
>  #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 756d0d6..736d8cb 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -19,8 +19,11 @@
>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>   */
>  
> +#include <linux/bits.h>
>  #include <linux/errno.h>
>  #include <linux/err.h>
> +#include <linux/nospec.h>
> +#include <linux/kernel.h>
>  #include <linux/kvm_host.h>
>  #include <linux/module.h>
>  #include <linux/stddef.h>
> @@ -30,9 +33,12 @@
>  #include <kvm/arm_psci.h>
>  #include <asm/cputype.h>
>  #include <linux/uaccess.h>
> +#include <asm/fpsimd.h>
>  #include <asm/kvm.h>
>  #include <asm/kvm_emulate.h>
>  #include <asm/kvm_coproc.h>
> +#include <asm/kvm_host.h>
> +#include <asm/sigcontext.h>
>  
>  #include "trace.h"
>  
> @@ -200,6 +206,115 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	return err;
>  }
>  
> +#define SVE_REG_SLICE_SHIFT	0
> +#define SVE_REG_SLICE_BITS	5
> +#define SVE_REG_ID_SHIFT	(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS)
> +#define SVE_REG_ID_BITS		5
> +
> +#define SVE_REG_SLICE_MASK					\
> +	GENMASK(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS - 1,	\
> +		SVE_REG_SLICE_SHIFT)
> +#define SVE_REG_ID_MASK							\
> +	GENMASK(SVE_REG_ID_SHIFT + SVE_REG_ID_BITS - 1, SVE_REG_ID_SHIFT)
> +
> +#define SVE_NUM_SLICES (1 << SVE_REG_SLICE_BITS)
> +
> +#define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0))
> +#define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0))
> +
> +/* Bounds of a single SVE register slice within vcpu->arch.sve_state */
> +struct sve_state_reg_region {
> +	unsigned int koffset;	/* offset into sve_state in kernel memory */
> +	unsigned int klen;	/* length in kernel memory */
> +	unsigned int upad;	/* extra trailing padding in user memory */
> +};
> +
> +/* Get sanitised bounds for user/kernel SVE register copy */
> +static int sve_reg_to_region(struct sve_state_reg_region *region,
> +			     struct kvm_vcpu *vcpu,
> +			     const struct kvm_one_reg *reg)
> +{
> +	/* reg ID ranges for Z- registers */
> +	const u64 zreg_id_min = KVM_REG_ARM64_SVE_ZREG(0, 0);
> +	const u64 zreg_id_max = KVM_REG_ARM64_SVE_ZREG(SVE_NUM_ZREGS - 1,
> +						       SVE_NUM_SLICES - 1);
> +
> +	/* reg ID ranges for P- registers and FFR (which are contiguous) */
> +	const u64 preg_id_min = KVM_REG_ARM64_SVE_PREG(0, 0);
> +	const u64 preg_id_max = KVM_REG_ARM64_SVE_FFR(SVE_NUM_SLICES - 1);
> +
> +	unsigned int vq;
> +	unsigned int reg_num;
> +
> +	unsigned int reqoffset, reqlen; /* User-requested offset and length */
> +	unsigned int maxlen; /* Maxmimum permitted length */
> +
> +	size_t sve_state_size;
> +
> +	/* Only the first slice ever exists, for now: */
> +	if ((reg->id & SVE_REG_SLICE_MASK) != 0)
> +		return -ENOENT;
> +
> +	vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
> +
> +	reg_num = (reg->id & SVE_REG_ID_MASK) >> SVE_REG_ID_SHIFT;
> +
> +	if (reg->id >= zreg_id_min && reg->id <= zreg_id_max) {
> +		reqoffset = SVE_SIG_ZREG_OFFSET(vq, reg_num) -
> +				SVE_SIG_REGS_OFFSET;
> +		reqlen = KVM_SVE_ZREG_SIZE;
> +		maxlen = SVE_SIG_ZREG_SIZE(vq);
> +	} else if (reg->id >= preg_id_min && reg->id <= preg_id_max) {
> +		reqoffset = SVE_SIG_PREG_OFFSET(vq, reg_num) -
> +				SVE_SIG_REGS_OFFSET;
> +		reqlen = KVM_SVE_PREG_SIZE;
> +		maxlen = SVE_SIG_PREG_SIZE(vq);
> +	} else {
> +		return -ENOENT;
> +	}
> +
> +	sve_state_size = vcpu_sve_state_size(vcpu);
> +	if (!sve_state_size)
> +		return -EINVAL;
> +
> +	region->koffset = array_index_nospec(reqoffset, sve_state_size);
> +	region->klen = min(maxlen, reqlen);
> +	region->upad = reqlen - region->klen;
> +
> +	return 0;
> +}
> +
> +static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> +{
> +	struct sve_state_reg_region region;
> +	char __user *uptr = (char __user *)reg->addr;
> +
> +	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> +		return -ENOENT;

sve_reg_to_region() can return EINVAL, but here it would get changed to
ENOENT.

> +
> +	if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
> +			 region.klen) ||
> +	    clear_user(uptr + region.klen, region.upad))
> +		return -EFAULT;
> +
> +	return 0;
> +}
> +
> +static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> +{
> +	struct sve_state_reg_region region;
> +	const char __user *uptr = (const char __user *)reg->addr;
> +
> +	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> +		return -ENOENT;

Same as above.

> +
> +	if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
> +			   region.klen))
> +		return -EFAULT;
> +
> +	return 0;
> +}
> +
>  int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
>  {
>  	return -EINVAL;
> @@ -346,12 +461,12 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
>  		return -EINVAL;
>  
> -	/* Register group 16 means we want a core register. */
> -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
> -		return get_core_reg(vcpu, reg);
> -
> -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
> -		return kvm_arm_get_fw_reg(vcpu, reg);
> +	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> +	case KVM_REG_ARM_CORE:	return get_core_reg(vcpu, reg);
> +	case KVM_REG_ARM_FW:	return kvm_arm_get_fw_reg(vcpu, reg);
> +	case KVM_REG_ARM64_SVE:	return get_sve_reg(vcpu, reg);
> +	default: break; /* fall through */

This case has a 'break', so it's not a 'fall through'. Do we require
default cases even when they're unused? If not, why have it?

> +	}
>  
>  	if (is_timer_reg(reg->id))
>  		return get_timer_reg(vcpu, reg);
> @@ -365,12 +480,12 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
>  		return -EINVAL;
>  
> -	/* Register group 16 means we set a core register. */
> -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
> -		return set_core_reg(vcpu, reg);
> -
> -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
> -		return kvm_arm_set_fw_reg(vcpu, reg);
> +	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> +	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
> +	case KVM_REG_ARM_FW:	return kvm_arm_set_fw_reg(vcpu, reg);
> +	case KVM_REG_ARM64_SVE:	return set_sve_reg(vcpu, reg);
> +	default: break; /* fall through */

Same as above.

> +	}
>  
>  	if (is_timer_reg(reg->id))
>  		return set_timer_reg(vcpu, reg);
> -- 
> 2.1.4
>

Thanks,
drew 

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 19/27] KVM: arm64: Enumerate SVE register indices for KVM_GET_REG_LIST
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-04 14:08     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 14:08 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:44PM +0000, Dave Martin wrote:
> This patch includes the SVE register IDs in the list returned by
> KVM_GET_REG_LIST, as appropriate.
> 
> On a non-SVE-enabled vcpu, no new IDs are added.
> 
> On an SVE-enabled vcpu, IDs for the FPSIMD V-registers are removed
> from the list, since userspace is required to access the Z-
> registers instead in order to access the V-register content.  For
> the variably-sized SVE registers, the appropriate set of slice IDs
> are enumerated, depending on the maximum vector length for the
> vcpu.
> 
> As it currently stands, the SVE architecture never requires more
> than one slice to exist per register, so this patch adds no
> explicit support for enumerating multiple slices.  The code can be
> extended straightforwardly to support this in the future, if
> needed.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v6:
> 
>  * [Julien Thierry] Add a #define to replace the magic "slices = 1",
>    and add a comment explaining to maintainers what needs to happen if
>    this is updated in the future.
> 
> Changes since v5:
> 
> (Dropped Julien Thierry's Reviewed-by due to non-trivial rebasing)
> 
>  * Move mis-split reword to prevent put_user()s being accidentally the
>    correct size from KVM: arm64/sve: Add pseudo-register for the guest's
>    vector lengths.
> ---
>  arch/arm64/kvm/guest.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 63 insertions(+)
> 
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 736d8cb..2aa80a5 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -222,6 +222,13 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  #define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0))
>  #define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0))
>  
> +/*
> + * number of register slices required to cover each whole SVE register on vcpu

s/number/Number/
s/on vcpu//

> + * NOTE: If you are tempted to modify this, you must also to rework

s/to rework/rework/

> + * sve_reg_to_region() to match:
> + */
> +#define vcpu_sve_slices(vcpu) 1
> +
>  /* Bounds of a single SVE register slice within vcpu->arch.sve_state */
>  struct sve_state_reg_region {
>  	unsigned int koffset;	/* offset into sve_state in kernel memory */
> @@ -411,6 +418,56 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0;
>  }
>  
> +static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
> +{
> +	/* Only the first slice ever exists, for now */

I'd move this comment up into the one above vcpu_sve_slices(),
and then nothing needs to change here when more slices come.

> +	const unsigned int slices = vcpu_sve_slices(vcpu);
> +
> +	if (!vcpu_has_sve(vcpu))
> +		return 0;
> +
> +	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */);
> +}
> +
> +static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
> +				u64 __user *uindices)
> +{
> +	/* Only the first slice ever exists, for now */

Same comment as above.

> +	const unsigned int slices = vcpu_sve_slices(vcpu);
> +	u64 reg;
> +	unsigned int i, n;
> +	int num_regs = 0;
> +
> +	if (!vcpu_has_sve(vcpu))
> +		return 0;
> +
> +	for (i = 0; i < slices; i++) {
> +		for (n = 0; n < SVE_NUM_ZREGS; n++) {
> +			reg = KVM_REG_ARM64_SVE_ZREG(n, i);
> +			if (put_user(reg, uindices++))
> +				return -EFAULT;
> +
> +			num_regs++;
> +		}
> +
> +		for (n = 0; n < SVE_NUM_PREGS; n++) {
> +			reg = KVM_REG_ARM64_SVE_PREG(n, i);
> +			if (put_user(reg, uindices++))
> +				return -EFAULT;
> +
> +			num_regs++;
> +		}
> +
> +		reg = KVM_REG_ARM64_SVE_FFR(i);
> +		if (put_user(reg, uindices++))
> +			return -EFAULT;
> +
> +		num_regs++;
> +	}

nit: the extra blank lines above the num_regs++'s give the code an odd
     look (to me)

> +
> +	return num_regs;
> +}
> +
>  /**
>   * kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG
>   *
> @@ -421,6 +478,7 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
>  	unsigned long res = 0;
>  
>  	res += num_core_regs(vcpu);
> +	res += num_sve_regs(vcpu);
>  	res += kvm_arm_num_sys_reg_descs(vcpu);
>  	res += kvm_arm_get_fw_num_regs(vcpu);
>  	res += NUM_TIMER_REGS;
> @@ -442,6 +500,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
>  		return ret;
>  	uindices += ret;
>  
> +	ret = copy_sve_reg_indices(vcpu, uindices);
> +	if (ret)
> +		return ret;
> +	uindices += ret;

I know this if ret vs. if ret < 0 is being addressed already.

> +
>  	ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
>  	if (ret)
>  		return ret;
> -- 
> 2.1.4
> 

Thanks,
drew

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

* Re: [PATCH v7 19/27] KVM: arm64: Enumerate SVE register indices for KVM_GET_REG_LIST
@ 2019-04-04 14:08     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 14:08 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:44PM +0000, Dave Martin wrote:
> This patch includes the SVE register IDs in the list returned by
> KVM_GET_REG_LIST, as appropriate.
> 
> On a non-SVE-enabled vcpu, no new IDs are added.
> 
> On an SVE-enabled vcpu, IDs for the FPSIMD V-registers are removed
> from the list, since userspace is required to access the Z-
> registers instead in order to access the V-register content.  For
> the variably-sized SVE registers, the appropriate set of slice IDs
> are enumerated, depending on the maximum vector length for the
> vcpu.
> 
> As it currently stands, the SVE architecture never requires more
> than one slice to exist per register, so this patch adds no
> explicit support for enumerating multiple slices.  The code can be
> extended straightforwardly to support this in the future, if
> needed.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v6:
> 
>  * [Julien Thierry] Add a #define to replace the magic "slices = 1",
>    and add a comment explaining to maintainers what needs to happen if
>    this is updated in the future.
> 
> Changes since v5:
> 
> (Dropped Julien Thierry's Reviewed-by due to non-trivial rebasing)
> 
>  * Move mis-split reword to prevent put_user()s being accidentally the
>    correct size from KVM: arm64/sve: Add pseudo-register for the guest's
>    vector lengths.
> ---
>  arch/arm64/kvm/guest.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 63 insertions(+)
> 
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 736d8cb..2aa80a5 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -222,6 +222,13 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  #define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0))
>  #define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0))
>  
> +/*
> + * number of register slices required to cover each whole SVE register on vcpu

s/number/Number/
s/on vcpu//

> + * NOTE: If you are tempted to modify this, you must also to rework

s/to rework/rework/

> + * sve_reg_to_region() to match:
> + */
> +#define vcpu_sve_slices(vcpu) 1
> +
>  /* Bounds of a single SVE register slice within vcpu->arch.sve_state */
>  struct sve_state_reg_region {
>  	unsigned int koffset;	/* offset into sve_state in kernel memory */
> @@ -411,6 +418,56 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0;
>  }
>  
> +static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
> +{
> +	/* Only the first slice ever exists, for now */

I'd move this comment up into the one above vcpu_sve_slices(),
and then nothing needs to change here when more slices come.

> +	const unsigned int slices = vcpu_sve_slices(vcpu);
> +
> +	if (!vcpu_has_sve(vcpu))
> +		return 0;
> +
> +	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */);
> +}
> +
> +static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
> +				u64 __user *uindices)
> +{
> +	/* Only the first slice ever exists, for now */

Same comment as above.

> +	const unsigned int slices = vcpu_sve_slices(vcpu);
> +	u64 reg;
> +	unsigned int i, n;
> +	int num_regs = 0;
> +
> +	if (!vcpu_has_sve(vcpu))
> +		return 0;
> +
> +	for (i = 0; i < slices; i++) {
> +		for (n = 0; n < SVE_NUM_ZREGS; n++) {
> +			reg = KVM_REG_ARM64_SVE_ZREG(n, i);
> +			if (put_user(reg, uindices++))
> +				return -EFAULT;
> +
> +			num_regs++;
> +		}
> +
> +		for (n = 0; n < SVE_NUM_PREGS; n++) {
> +			reg = KVM_REG_ARM64_SVE_PREG(n, i);
> +			if (put_user(reg, uindices++))
> +				return -EFAULT;
> +
> +			num_regs++;
> +		}
> +
> +		reg = KVM_REG_ARM64_SVE_FFR(i);
> +		if (put_user(reg, uindices++))
> +			return -EFAULT;
> +
> +		num_regs++;
> +	}

nit: the extra blank lines above the num_regs++'s give the code an odd
     look (to me)

> +
> +	return num_regs;
> +}
> +
>  /**
>   * kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG
>   *
> @@ -421,6 +478,7 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
>  	unsigned long res = 0;
>  
>  	res += num_core_regs(vcpu);
> +	res += num_sve_regs(vcpu);
>  	res += kvm_arm_num_sys_reg_descs(vcpu);
>  	res += kvm_arm_get_fw_num_regs(vcpu);
>  	res += NUM_TIMER_REGS;
> @@ -442,6 +500,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
>  		return ret;
>  	uindices += ret;
>  
> +	ret = copy_sve_reg_indices(vcpu, uindices);
> +	if (ret)
> +		return ret;
> +	uindices += ret;

I know this if ret vs. if ret < 0 is being addressed already.

> +
>  	ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices);
>  	if (ret)
>  		return ret;
> -- 
> 2.1.4
> 

Thanks,
drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 20/27] arm64/sve: In-kernel vector length availability query interface
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-04 14:20     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 14:20 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:45PM +0000, Dave Martin wrote:
> KVM will need to interrogate the set of SVE vector lengths
> available on the system.
> 
> This patch exposes the relevant bits to the kernel, along with a
> sve_vq_available() helper to check whether a particular vector
> length is supported.
> 
> __vq_to_bit() and __bit_to_vq() are not intended for use outside
> these functions: now that these are exposed outside fpsimd.c, they
> are prefixed with __ in order to provide an extra hint that they
> are not intended for general-purpose use.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> ---
>  arch/arm64/include/asm/fpsimd.h | 29 +++++++++++++++++++++++++++++
>  arch/arm64/kernel/fpsimd.c      | 35 ++++++++---------------------------
>  2 files changed, 37 insertions(+), 27 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
> index df7a143..ad6d2e4 100644
> --- a/arch/arm64/include/asm/fpsimd.h
> +++ b/arch/arm64/include/asm/fpsimd.h
> @@ -24,10 +24,13 @@
>  
>  #ifndef __ASSEMBLY__
>  
> +#include <linux/bitmap.h>
>  #include <linux/build_bug.h>
> +#include <linux/bug.h>
>  #include <linux/cache.h>
>  #include <linux/init.h>
>  #include <linux/stddef.h>
> +#include <linux/types.h>
>  
>  #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
>  /* Masks for extracting the FPSR and FPCR from the FPSCR */
> @@ -89,6 +92,32 @@ extern u64 read_zcr_features(void);
>  
>  extern int __ro_after_init sve_max_vl;
>  extern int __ro_after_init sve_max_virtualisable_vl;
> +/* Set of available vector lengths, as vq_to_bit(vq): */

s/as/for use with/ ?
s/vq_to_bit/__vq_to_bit/

> +extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
> +
> +/*
> + * Helpers to translate bit indices in sve_vq_map to VQ values (and
> + * vice versa).  This allows find_next_bit() to be used to find the
> + * _maximum_ VQ not exceeding a certain value.
> + */
> +static inline unsigned int __vq_to_bit(unsigned int vq)
> +{

Why not have the same WARN_ON and clamping here as we do
in __bit_to_vq. Here a vq > SVE_VQ_MAX will wrap around
to a super high bit.

> +	return SVE_VQ_MAX - vq;
> +}
> +
> +static inline unsigned int __bit_to_vq(unsigned int bit)
> +{
> +	if (WARN_ON(bit >= SVE_VQ_MAX))
> +		bit = SVE_VQ_MAX - 1;
> +
> +	return SVE_VQ_MAX - bit;
> +}
> +
> +/* Ensure vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX before calling this function */

Are we avoiding putting these tests and WARN_ONs in this function to
keep it fast?

> +static inline bool sve_vq_available(unsigned int vq)
> +{
> +	return test_bit(__vq_to_bit(vq), sve_vq_map);
> +}
>  
>  #ifdef CONFIG_ARM64_SVE
>  
> diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
> index 8a93afa..577296b 100644
> --- a/arch/arm64/kernel/fpsimd.c
> +++ b/arch/arm64/kernel/fpsimd.c
> @@ -136,7 +136,7 @@ static int sve_default_vl = -1;
>  int __ro_after_init sve_max_vl = SVE_VL_MIN;
>  int __ro_after_init sve_max_virtualisable_vl = SVE_VL_MIN;
>  /* Set of available vector lengths, as vq_to_bit(vq): */
> -static __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
> +__ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
>  /* Set of vector lengths present on at least one cpu: */
>  static __ro_after_init DECLARE_BITMAP(sve_vq_partial_map, SVE_VQ_MAX);
>  static void __percpu *efi_sve_state;
> @@ -270,25 +270,6 @@ void fpsimd_save(void)
>  }
>  
>  /*
> - * Helpers to translate bit indices in sve_vq_map to VQ values (and
> - * vice versa).  This allows find_next_bit() to be used to find the
> - * _maximum_ VQ not exceeding a certain value.
> - */
> -
> -static unsigned int vq_to_bit(unsigned int vq)
> -{
> -	return SVE_VQ_MAX - vq;
> -}
> -
> -static unsigned int bit_to_vq(unsigned int bit)
> -{
> -	if (WARN_ON(bit >= SVE_VQ_MAX))
> -		bit = SVE_VQ_MAX - 1;
> -
> -	return SVE_VQ_MAX - bit;
> -}
> -
> -/*
>   * All vector length selection from userspace comes through here.
>   * We're on a slow path, so some sanity-checks are included.
>   * If things go wrong there's a bug somewhere, but try to fall back to a
> @@ -309,8 +290,8 @@ static unsigned int find_supported_vector_length(unsigned int vl)
>  		vl = max_vl;
>  
>  	bit = find_next_bit(sve_vq_map, SVE_VQ_MAX,
> -			    vq_to_bit(sve_vq_from_vl(vl)));
> -	return sve_vl_from_vq(bit_to_vq(bit));
> +			    __vq_to_bit(sve_vq_from_vl(vl)));
> +	return sve_vl_from_vq(__bit_to_vq(bit));
>  }
>  
>  #ifdef CONFIG_SYSCTL
> @@ -648,7 +629,7 @@ static void sve_probe_vqs(DECLARE_BITMAP(map, SVE_VQ_MAX))
>  		write_sysreg_s(zcr | (vq - 1), SYS_ZCR_EL1); /* self-syncing */
>  		vl = sve_get_vl();
>  		vq = sve_vq_from_vl(vl); /* skip intervening lengths */
> -		set_bit(vq_to_bit(vq), map);
> +		set_bit(__vq_to_bit(vq), map);
>  	}
>  }
>  
> @@ -717,7 +698,7 @@ int sve_verify_vq_map(void)
>  	 * Mismatches above sve_max_virtualisable_vl are fine, since
>  	 * no guest is allowed to configure ZCR_EL2.LEN to exceed this:
>  	 */
> -	if (sve_vl_from_vq(bit_to_vq(b)) <= sve_max_virtualisable_vl) {
> +	if (sve_vl_from_vq(__bit_to_vq(b)) <= sve_max_virtualisable_vl) {
>  		pr_warn("SVE: cpu%d: Unsupported vector length(s) present\n",
>  			smp_processor_id());
>  		return -EINVAL;
> @@ -801,8 +782,8 @@ void __init sve_setup(void)
>  	 * so sve_vq_map must have at least SVE_VQ_MIN set.
>  	 * If something went wrong, at least try to patch it up:
>  	 */
> -	if (WARN_ON(!test_bit(vq_to_bit(SVE_VQ_MIN), sve_vq_map)))
> -		set_bit(vq_to_bit(SVE_VQ_MIN), sve_vq_map);
> +	if (WARN_ON(!test_bit(__vq_to_bit(SVE_VQ_MIN), sve_vq_map)))
> +		set_bit(__vq_to_bit(SVE_VQ_MIN), sve_vq_map);
>  
>  	zcr = read_sanitised_ftr_reg(SYS_ZCR_EL1);
>  	sve_max_vl = sve_vl_from_vq((zcr & ZCR_ELx_LEN_MASK) + 1);
> @@ -831,7 +812,7 @@ void __init sve_setup(void)
>  		/* No virtualisable VLs?  This is architecturally forbidden. */
>  		sve_max_virtualisable_vl = SVE_VQ_MIN;
>  	else /* b + 1 < SVE_VQ_MAX */
> -		sve_max_virtualisable_vl = sve_vl_from_vq(bit_to_vq(b + 1));
> +		sve_max_virtualisable_vl = sve_vl_from_vq(__bit_to_vq(b + 1));
>  
>  	if (sve_max_virtualisable_vl > sve_max_vl)
>  		sve_max_virtualisable_vl = sve_max_vl;
> -- 
> 2.1.4

Thanks,
drew

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

* Re: [PATCH v7 20/27] arm64/sve: In-kernel vector length availability query interface
@ 2019-04-04 14:20     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 14:20 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:45PM +0000, Dave Martin wrote:
> KVM will need to interrogate the set of SVE vector lengths
> available on the system.
> 
> This patch exposes the relevant bits to the kernel, along with a
> sve_vq_available() helper to check whether a particular vector
> length is supported.
> 
> __vq_to_bit() and __bit_to_vq() are not intended for use outside
> these functions: now that these are exposed outside fpsimd.c, they
> are prefixed with __ in order to provide an extra hint that they
> are not intended for general-purpose use.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> ---
>  arch/arm64/include/asm/fpsimd.h | 29 +++++++++++++++++++++++++++++
>  arch/arm64/kernel/fpsimd.c      | 35 ++++++++---------------------------
>  2 files changed, 37 insertions(+), 27 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
> index df7a143..ad6d2e4 100644
> --- a/arch/arm64/include/asm/fpsimd.h
> +++ b/arch/arm64/include/asm/fpsimd.h
> @@ -24,10 +24,13 @@
>  
>  #ifndef __ASSEMBLY__
>  
> +#include <linux/bitmap.h>
>  #include <linux/build_bug.h>
> +#include <linux/bug.h>
>  #include <linux/cache.h>
>  #include <linux/init.h>
>  #include <linux/stddef.h>
> +#include <linux/types.h>
>  
>  #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
>  /* Masks for extracting the FPSR and FPCR from the FPSCR */
> @@ -89,6 +92,32 @@ extern u64 read_zcr_features(void);
>  
>  extern int __ro_after_init sve_max_vl;
>  extern int __ro_after_init sve_max_virtualisable_vl;
> +/* Set of available vector lengths, as vq_to_bit(vq): */

s/as/for use with/ ?
s/vq_to_bit/__vq_to_bit/

> +extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
> +
> +/*
> + * Helpers to translate bit indices in sve_vq_map to VQ values (and
> + * vice versa).  This allows find_next_bit() to be used to find the
> + * _maximum_ VQ not exceeding a certain value.
> + */
> +static inline unsigned int __vq_to_bit(unsigned int vq)
> +{

Why not have the same WARN_ON and clamping here as we do
in __bit_to_vq. Here a vq > SVE_VQ_MAX will wrap around
to a super high bit.

> +	return SVE_VQ_MAX - vq;
> +}
> +
> +static inline unsigned int __bit_to_vq(unsigned int bit)
> +{
> +	if (WARN_ON(bit >= SVE_VQ_MAX))
> +		bit = SVE_VQ_MAX - 1;
> +
> +	return SVE_VQ_MAX - bit;
> +}
> +
> +/* Ensure vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX before calling this function */

Are we avoiding putting these tests and WARN_ONs in this function to
keep it fast?

> +static inline bool sve_vq_available(unsigned int vq)
> +{
> +	return test_bit(__vq_to_bit(vq), sve_vq_map);
> +}
>  
>  #ifdef CONFIG_ARM64_SVE
>  
> diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
> index 8a93afa..577296b 100644
> --- a/arch/arm64/kernel/fpsimd.c
> +++ b/arch/arm64/kernel/fpsimd.c
> @@ -136,7 +136,7 @@ static int sve_default_vl = -1;
>  int __ro_after_init sve_max_vl = SVE_VL_MIN;
>  int __ro_after_init sve_max_virtualisable_vl = SVE_VL_MIN;
>  /* Set of available vector lengths, as vq_to_bit(vq): */
> -static __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
> +__ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
>  /* Set of vector lengths present on at least one cpu: */
>  static __ro_after_init DECLARE_BITMAP(sve_vq_partial_map, SVE_VQ_MAX);
>  static void __percpu *efi_sve_state;
> @@ -270,25 +270,6 @@ void fpsimd_save(void)
>  }
>  
>  /*
> - * Helpers to translate bit indices in sve_vq_map to VQ values (and
> - * vice versa).  This allows find_next_bit() to be used to find the
> - * _maximum_ VQ not exceeding a certain value.
> - */
> -
> -static unsigned int vq_to_bit(unsigned int vq)
> -{
> -	return SVE_VQ_MAX - vq;
> -}
> -
> -static unsigned int bit_to_vq(unsigned int bit)
> -{
> -	if (WARN_ON(bit >= SVE_VQ_MAX))
> -		bit = SVE_VQ_MAX - 1;
> -
> -	return SVE_VQ_MAX - bit;
> -}
> -
> -/*
>   * All vector length selection from userspace comes through here.
>   * We're on a slow path, so some sanity-checks are included.
>   * If things go wrong there's a bug somewhere, but try to fall back to a
> @@ -309,8 +290,8 @@ static unsigned int find_supported_vector_length(unsigned int vl)
>  		vl = max_vl;
>  
>  	bit = find_next_bit(sve_vq_map, SVE_VQ_MAX,
> -			    vq_to_bit(sve_vq_from_vl(vl)));
> -	return sve_vl_from_vq(bit_to_vq(bit));
> +			    __vq_to_bit(sve_vq_from_vl(vl)));
> +	return sve_vl_from_vq(__bit_to_vq(bit));
>  }
>  
>  #ifdef CONFIG_SYSCTL
> @@ -648,7 +629,7 @@ static void sve_probe_vqs(DECLARE_BITMAP(map, SVE_VQ_MAX))
>  		write_sysreg_s(zcr | (vq - 1), SYS_ZCR_EL1); /* self-syncing */
>  		vl = sve_get_vl();
>  		vq = sve_vq_from_vl(vl); /* skip intervening lengths */
> -		set_bit(vq_to_bit(vq), map);
> +		set_bit(__vq_to_bit(vq), map);
>  	}
>  }
>  
> @@ -717,7 +698,7 @@ int sve_verify_vq_map(void)
>  	 * Mismatches above sve_max_virtualisable_vl are fine, since
>  	 * no guest is allowed to configure ZCR_EL2.LEN to exceed this:
>  	 */
> -	if (sve_vl_from_vq(bit_to_vq(b)) <= sve_max_virtualisable_vl) {
> +	if (sve_vl_from_vq(__bit_to_vq(b)) <= sve_max_virtualisable_vl) {
>  		pr_warn("SVE: cpu%d: Unsupported vector length(s) present\n",
>  			smp_processor_id());
>  		return -EINVAL;
> @@ -801,8 +782,8 @@ void __init sve_setup(void)
>  	 * so sve_vq_map must have at least SVE_VQ_MIN set.
>  	 * If something went wrong, at least try to patch it up:
>  	 */
> -	if (WARN_ON(!test_bit(vq_to_bit(SVE_VQ_MIN), sve_vq_map)))
> -		set_bit(vq_to_bit(SVE_VQ_MIN), sve_vq_map);
> +	if (WARN_ON(!test_bit(__vq_to_bit(SVE_VQ_MIN), sve_vq_map)))
> +		set_bit(__vq_to_bit(SVE_VQ_MIN), sve_vq_map);
>  
>  	zcr = read_sanitised_ftr_reg(SYS_ZCR_EL1);
>  	sve_max_vl = sve_vl_from_vq((zcr & ZCR_ELx_LEN_MASK) + 1);
> @@ -831,7 +812,7 @@ void __init sve_setup(void)
>  		/* No virtualisable VLs?  This is architecturally forbidden. */
>  		sve_max_virtualisable_vl = SVE_VQ_MIN;
>  	else /* b + 1 < SVE_VQ_MAX */
> -		sve_max_virtualisable_vl = sve_vl_from_vq(bit_to_vq(b + 1));
> +		sve_max_virtualisable_vl = sve_vl_from_vq(__bit_to_vq(b + 1));
>  
>  	if (sve_max_virtualisable_vl > sve_max_vl)
>  		sve_max_virtualisable_vl = sve_max_vl;
> -- 
> 2.1.4

Thanks,
drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 21/27] KVM: arm/arm64: Add hook for arch-specific KVM initialisation
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-04 14:25     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 14:25 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:46PM +0000, Dave Martin wrote:
> This patch adds a kvm_arm_init_arch_resources() hook to perform
> subarch-specific initialisation when starting up KVM.
> 
> This will be used in a subsequent patch for global SVE-related
> setup on arm64.
> 
> No functional change.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> ---
>  arch/arm/include/asm/kvm_host.h   | 2 ++
>  arch/arm64/include/asm/kvm_host.h | 2 ++
>  virt/kvm/arm/arm.c                | 4 ++++
>  3 files changed, 8 insertions(+)
> 
> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> index 770d732..a49ee01 100644
> --- a/arch/arm/include/asm/kvm_host.h
> +++ b/arch/arm/include/asm/kvm_host.h
> @@ -53,6 +53,8 @@
>  
>  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
>  
> +static inline int kvm_arm_init_arch_resources(void) { return 0; }
> +
>  u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
>  int __attribute_const__ kvm_target_cpu(void);
>  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 205438a..3e89509 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -58,6 +58,8 @@
>  
>  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
>  
> +static inline int kvm_arm_init_arch_resources(void) { return 0; }
> +
>  int __attribute_const__ kvm_target_cpu(void);
>  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
>  int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext);
> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> index 99c3738..c69e137 100644
> --- a/virt/kvm/arm/arm.c
> +++ b/virt/kvm/arm/arm.c
> @@ -1664,6 +1664,10 @@ int kvm_arch_init(void *opaque)
>  	if (err)
>  		return err;
>  
> +	err = kvm_arm_init_arch_resources();
> +	if (err)
> +		return err;
> +
>  	if (!in_hyp_mode) {
>  		err = init_hyp_mode();
>  		if (err)
> -- 
> 2.1.4
>

It's not clear to me from the commit message why init_common_resources()
won't work for this. Maybe it'll be more clear as I continue the review.

drew 

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

* Re: [PATCH v7 21/27] KVM: arm/arm64: Add hook for arch-specific KVM initialisation
@ 2019-04-04 14:25     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 14:25 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:46PM +0000, Dave Martin wrote:
> This patch adds a kvm_arm_init_arch_resources() hook to perform
> subarch-specific initialisation when starting up KVM.
> 
> This will be used in a subsequent patch for global SVE-related
> setup on arm64.
> 
> No functional change.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> ---
>  arch/arm/include/asm/kvm_host.h   | 2 ++
>  arch/arm64/include/asm/kvm_host.h | 2 ++
>  virt/kvm/arm/arm.c                | 4 ++++
>  3 files changed, 8 insertions(+)
> 
> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> index 770d732..a49ee01 100644
> --- a/arch/arm/include/asm/kvm_host.h
> +++ b/arch/arm/include/asm/kvm_host.h
> @@ -53,6 +53,8 @@
>  
>  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
>  
> +static inline int kvm_arm_init_arch_resources(void) { return 0; }
> +
>  u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
>  int __attribute_const__ kvm_target_cpu(void);
>  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 205438a..3e89509 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -58,6 +58,8 @@
>  
>  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
>  
> +static inline int kvm_arm_init_arch_resources(void) { return 0; }
> +
>  int __attribute_const__ kvm_target_cpu(void);
>  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
>  int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext);
> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> index 99c3738..c69e137 100644
> --- a/virt/kvm/arm/arm.c
> +++ b/virt/kvm/arm/arm.c
> @@ -1664,6 +1664,10 @@ int kvm_arch_init(void *opaque)
>  	if (err)
>  		return err;
>  
> +	err = kvm_arm_init_arch_resources();
> +	if (err)
> +		return err;
> +
>  	if (!in_hyp_mode) {
>  		err = init_hyp_mode();
>  		if (err)
> -- 
> 2.1.4
>

It's not clear to me from the commit message why init_common_resources()
won't work for this. Maybe it'll be more clear as I continue the review.

drew 

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 18/27] KVM: arm64/sve: Add SVE support to register access ioctl interface
  2019-04-04 13:57     ` Andrew Jones
@ 2019-04-04 14:50       ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04 14:50 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 03:57:06PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:43PM +0000, Dave Martin wrote:
> > This patch adds the following registers for access via the
> > KVM_{GET,SET}_ONE_REG interface:
> > 
> >  * KVM_REG_ARM64_SVE_ZREG(n, i) (n = 0..31) (in 2048-bit slices)
> >  * KVM_REG_ARM64_SVE_PREG(n, i) (n = 0..15) (in 256-bit slices)
> >  * KVM_REG_ARM64_SVE_FFR(i) (in 256-bit slices)
> > 
> > In order to adapt gracefully to future architectural extensions,
> > the registers are logically divided up into slices as noted above:
> > the i parameter denotes the slice index.
> > 
> > This allows us to reserve space in the ABI for future expansion of
> > these registers.  However, as of today the architecture does not
> > permit registers to be larger than a single slice, so no code is
> > needed in the kernel to expose additional slices, for now.  The
> > code can be extended later as needed to expose them up to a maximum
> > of 32 slices (as carved out in the architecture itself) if they
> > really exist someday.
> > 
> > The registers are only visible for vcpus that have SVE enabled.
> > They are not enumerated by KVM_GET_REG_LIST on vcpus that do not
> > have SVE.
> > 
> > Accesses to the FPSIMD registers via KVM_REG_ARM_CORE is not
> > allowed for SVE-enabled vcpus: SVE-aware userspace can use the
> > KVM_REG_ARM64_SVE_ZREG() interface instead to access the same
> > register state.  This avoids some complex and pointless emulation
> > in the kernel to convert between the two views of these aliased
> > registers.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > 
> > ---
> > 
> > Changes since v5:
> > 
> >  * [Julien Thierry] rename sve_reg_region() to sve_reg_to_region() to
> >    make its purpose a bit clearer.
> > 
> >  * [Julien Thierry] rename struct sve_state_region to
> >    sve_state_reg_region to make it clearer this this struct only
> >    describes the bounds of (part of) a single register within
> >    sve_state.
> > 
> >  * [Julien Thierry] Add a comment to clarify the purpose of struct
> >    sve_state_reg_region.
> > ---
> >  arch/arm64/include/asm/kvm_host.h |  14 ++++
> >  arch/arm64/include/uapi/asm/kvm.h |  17 +++++
> >  arch/arm64/kvm/guest.c            | 139 ++++++++++++++++++++++++++++++++++----
> >  3 files changed, 158 insertions(+), 12 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 4fabfd2..205438a 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -329,6 +329,20 @@ struct kvm_vcpu_arch {
> >  #define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
> >  				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
> >  
> > +#define vcpu_sve_state_size(vcpu) ({					\
> > +	size_t __size_ret;						\
> > +	unsigned int __vcpu_vq;						\
> > +									\
> > +	if (WARN_ON(!sve_vl_valid((vcpu)->arch.sve_max_vl))) {		\
> > +		__size_ret = 0;						\
> > +	} else {							\
> > +		__vcpu_vq = sve_vq_from_vl((vcpu)->arch.sve_max_vl);	\
> > +		__size_ret = SVE_SIG_REGS_SIZE(__vcpu_vq);		\
> > +	}								\
> > +									\
> > +	__size_ret;							\
> > +})
> 
> I know why this is a macro instead of an inline :)

Yep

I can't claim this one is a one-liner :/

> > +
> >  /* vcpu_arch flags field values: */
> >  #define KVM_ARM64_DEBUG_DIRTY		(1 << 0)
> >  #define KVM_ARM64_FP_ENABLED		(1 << 1) /* guest FP regs loaded */
> > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > index 97c3478..ced760c 100644
> > --- a/arch/arm64/include/uapi/asm/kvm.h
> > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > @@ -226,6 +226,23 @@ struct kvm_vcpu_events {
> >  					 KVM_REG_ARM_FW | ((r) & 0xffff))
> >  #define KVM_REG_ARM_PSCI_VERSION	KVM_REG_ARM_FW_REG(0)
> >  
> > +/* SVE registers */
> > +#define KVM_REG_ARM64_SVE		(0x15 << KVM_REG_ARM_COPROC_SHIFT)
> > +
> > +/* Z- and P-regs occupy blocks at the following offsets within this range: */
> > +#define KVM_REG_ARM64_SVE_ZREG_BASE	0
> > +#define KVM_REG_ARM64_SVE_PREG_BASE	0x400
> > +
> > +#define KVM_REG_ARM64_SVE_ZREG(n, i)	(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
> > +					 KVM_REG_ARM64_SVE_ZREG_BASE |	\
> > +					 KVM_REG_SIZE_U2048 |		\
> > +					 ((n) << 5) | (i))
> > +#define KVM_REG_ARM64_SVE_PREG(n, i)	(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
> > +					 KVM_REG_ARM64_SVE_PREG_BASE |	\
> > +					 KVM_REG_SIZE_U256 |		\
> > +					 ((n) << 5) | (i))
> 
> I think (n) in the above two macros should be masked to document their
> size constraints. Since KVM_REG_ARM_COPROC_SHIFT is 16 they can't be
> larger than 1 << (16 - 5), which would be a mask of 0x7ff, but as there
> are only 32 zregs and 16 pregs so we should use 0x1f and 0xf respectively.

I don't object to that.  How about this sort of thing:

#include <asm/sve_context.h>

#define KVM_ARM64_SVE_NUM_ZREGS __SVE_NUM_ZREGS
#define KVM_ARM64_SVE_NUM_PREGS __SVE_NUM_PREGS

#define KVM_ARM64_SVE_MAX_SLICES 32

ZREGs:
	... | (((n) & (KVM_ARM64_SVE_NUM_ZREGS - 1)) << 5) |
		((i) & (KVM_ARM64_SVE_MAX_SLICES - 1))


The shadow _NUM_xREGS defines are sort of overkill, but
<asm/sigcontext.h> is not really appropriate to include here.
<asm/sve_context.h> is intended as a backend only, and I prefer to hide
it behind other headers.


> > +#define KVM_REG_ARM64_SVE_FFR(i)	KVM_REG_ARM64_SVE_PREG(16, i)
> 
> Since this is user api and a user may want to construct their own register
> indices, then shouldn't we instead provide KVM_REG_ARM64_SVE_FFR_BASE as
> 
>  #define KVM_REG_ARM64_SVE_FFR_BASE KVM_REG_ARM64_SVE_PREG_BASE | (16 << 5)

Can do, or just

#define KVM_REG_ARM64_SVE_FFR_BASE KVM_REG_ARM64_SVE_PREG(0, 0)

(which is what I tend to do elsewhere).

> and then KVM_REG_ARM64_SVE_FFR(i) would follow the typical pattern
> 
>  #define KVM_REG_ARM64_SVE_FFR(i) (KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
>                                    KVM_REG_ARM64_SVE_FFR_BASE | \
>                                    KVM_REG_SIZE_U256 | (i))

Yes, we could do that.

> 
> > +
> >  /* Device Control API: ARM VGIC */
> >  #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
> >  #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
> > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > index 756d0d6..736d8cb 100644
> > --- a/arch/arm64/kvm/guest.c
> > +++ b/arch/arm64/kvm/guest.c
> > @@ -19,8 +19,11 @@
> >   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> >   */
> >  
> > +#include <linux/bits.h>
> >  #include <linux/errno.h>
> >  #include <linux/err.h>
> > +#include <linux/nospec.h>
> > +#include <linux/kernel.h>
> >  #include <linux/kvm_host.h>
> >  #include <linux/module.h>
> >  #include <linux/stddef.h>
> > @@ -30,9 +33,12 @@
> >  #include <kvm/arm_psci.h>
> >  #include <asm/cputype.h>
> >  #include <linux/uaccess.h>
> > +#include <asm/fpsimd.h>
> >  #include <asm/kvm.h>
> >  #include <asm/kvm_emulate.h>
> >  #include <asm/kvm_coproc.h>
> > +#include <asm/kvm_host.h>
> > +#include <asm/sigcontext.h>
> >  
> >  #include "trace.h"
> >  
> > @@ -200,6 +206,115 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >  	return err;
> >  }
> >  
> > +#define SVE_REG_SLICE_SHIFT	0
> > +#define SVE_REG_SLICE_BITS	5
> > +#define SVE_REG_ID_SHIFT	(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS)
> > +#define SVE_REG_ID_BITS		5
> > +
> > +#define SVE_REG_SLICE_MASK					\
> > +	GENMASK(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS - 1,	\
> > +		SVE_REG_SLICE_SHIFT)
> > +#define SVE_REG_ID_MASK							\
> > +	GENMASK(SVE_REG_ID_SHIFT + SVE_REG_ID_BITS - 1, SVE_REG_ID_SHIFT)
> > +
> > +#define SVE_NUM_SLICES (1 << SVE_REG_SLICE_BITS)
> > +
> > +#define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0))
> > +#define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0))
> > +
> > +/* Bounds of a single SVE register slice within vcpu->arch.sve_state */
> > +struct sve_state_reg_region {
> > +	unsigned int koffset;	/* offset into sve_state in kernel memory */
> > +	unsigned int klen;	/* length in kernel memory */
> > +	unsigned int upad;	/* extra trailing padding in user memory */
> > +};
> > +
> > +/* Get sanitised bounds for user/kernel SVE register copy */
> > +static int sve_reg_to_region(struct sve_state_reg_region *region,
> > +			     struct kvm_vcpu *vcpu,
> > +			     const struct kvm_one_reg *reg)
> > +{
> > +	/* reg ID ranges for Z- registers */
> > +	const u64 zreg_id_min = KVM_REG_ARM64_SVE_ZREG(0, 0);
> > +	const u64 zreg_id_max = KVM_REG_ARM64_SVE_ZREG(SVE_NUM_ZREGS - 1,
> > +						       SVE_NUM_SLICES - 1);
> > +
> > +	/* reg ID ranges for P- registers and FFR (which are contiguous) */
> > +	const u64 preg_id_min = KVM_REG_ARM64_SVE_PREG(0, 0);
> > +	const u64 preg_id_max = KVM_REG_ARM64_SVE_FFR(SVE_NUM_SLICES - 1);
> > +
> > +	unsigned int vq;
> > +	unsigned int reg_num;
> > +
> > +	unsigned int reqoffset, reqlen; /* User-requested offset and length */
> > +	unsigned int maxlen; /* Maxmimum permitted length */
> > +
> > +	size_t sve_state_size;
> > +
> > +	/* Only the first slice ever exists, for now: */
> > +	if ((reg->id & SVE_REG_SLICE_MASK) != 0)
> > +		return -ENOENT;
> > +
> > +	vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
> > +
> > +	reg_num = (reg->id & SVE_REG_ID_MASK) >> SVE_REG_ID_SHIFT;
> > +
> > +	if (reg->id >= zreg_id_min && reg->id <= zreg_id_max) {
> > +		reqoffset = SVE_SIG_ZREG_OFFSET(vq, reg_num) -
> > +				SVE_SIG_REGS_OFFSET;
> > +		reqlen = KVM_SVE_ZREG_SIZE;
> > +		maxlen = SVE_SIG_ZREG_SIZE(vq);
> > +	} else if (reg->id >= preg_id_min && reg->id <= preg_id_max) {
> > +		reqoffset = SVE_SIG_PREG_OFFSET(vq, reg_num) -
> > +				SVE_SIG_REGS_OFFSET;
> > +		reqlen = KVM_SVE_PREG_SIZE;
> > +		maxlen = SVE_SIG_PREG_SIZE(vq);
> > +	} else {
> > +		return -ENOENT;
> > +	}
> > +
> > +	sve_state_size = vcpu_sve_state_size(vcpu);
> > +	if (!sve_state_size)
> > +		return -EINVAL;
> > +
> > +	region->koffset = array_index_nospec(reqoffset, sve_state_size);
> > +	region->klen = min(maxlen, reqlen);
> > +	region->upad = reqlen - region->klen;
> > +
> > +	return 0;
> > +}
> > +
> > +static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > +{
> > +	struct sve_state_reg_region region;
> > +	char __user *uptr = (char __user *)reg->addr;
> > +
> > +	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> > +		return -ENOENT;
> 
> sve_reg_to_region() can return EINVAL, but here it would get changed to
> ENOENT.

Hmm, I'd say the affected code in sve_reg_to_region() should really be
a WARN_ON(): we're not supposed to hit it because we can't get here
until the vcpu is finalized.  It's really just a defensive check before
dividing by some potentially invalid value.  In such a case, it's
reasonable to have that EINVAL show through to userspace.

Does that make sense?

> > +
> > +	if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
> > +			 region.klen) ||
> > +	    clear_user(uptr + region.klen, region.upad))
> > +		return -EFAULT;
> > +
> > +	return 0;
> > +}
> > +
> > +static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > +{
> > +	struct sve_state_reg_region region;
> > +	const char __user *uptr = (const char __user *)reg->addr;
> > +
> > +	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> > +		return -ENOENT;
> 
> Same as above.

Ditto

> > +
> > +	if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
> > +			   region.klen))
> > +		return -EFAULT;
> > +
> > +	return 0;
> > +}
> > +
> >  int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
> >  {
> >  	return -EINVAL;
> > @@ -346,12 +461,12 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >  	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
> >  		return -EINVAL;
> >  
> > -	/* Register group 16 means we want a core register. */
> > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
> > -		return get_core_reg(vcpu, reg);
> > -
> > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
> > -		return kvm_arm_get_fw_reg(vcpu, reg);
> > +	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > +	case KVM_REG_ARM_CORE:	return get_core_reg(vcpu, reg);
> > +	case KVM_REG_ARM_FW:	return kvm_arm_get_fw_reg(vcpu, reg);
> > +	case KVM_REG_ARM64_SVE:	return get_sve_reg(vcpu, reg);
> > +	default: break; /* fall through */
> 
> This case has a 'break', so it's not a 'fall through'. Do we require
> default cases even when they're unused? If not, why have it?

My reason for having that was to highlight that we fall through to the
code following the switch only in this case, because the other cases
all consist of return statements.

> > +	}
> >  
> >  	if (is_timer_reg(reg->id))
> >  		return get_timer_reg(vcpu, reg);
> > @@ -365,12 +480,12 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >  	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
> >  		return -EINVAL;
> >  
> > -	/* Register group 16 means we set a core register. */
> > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
> > -		return set_core_reg(vcpu, reg);
> > -
> > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
> > -		return kvm_arm_set_fw_reg(vcpu, reg);
> > +	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > +	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
> > +	case KVM_REG_ARM_FW:	return kvm_arm_set_fw_reg(vcpu, reg);
> > +	case KVM_REG_ARM64_SVE:	return set_sve_reg(vcpu, reg);
> > +	default: break; /* fall through */
> 
> Same as above.

I could move the trailing code into the default case, but that felt a
bit ugly.

Thoughts?

Cheers
---Dave

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

* Re: [PATCH v7 18/27] KVM: arm64/sve: Add SVE support to register access ioctl interface
@ 2019-04-04 14:50       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04 14:50 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 03:57:06PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:43PM +0000, Dave Martin wrote:
> > This patch adds the following registers for access via the
> > KVM_{GET,SET}_ONE_REG interface:
> > 
> >  * KVM_REG_ARM64_SVE_ZREG(n, i) (n = 0..31) (in 2048-bit slices)
> >  * KVM_REG_ARM64_SVE_PREG(n, i) (n = 0..15) (in 256-bit slices)
> >  * KVM_REG_ARM64_SVE_FFR(i) (in 256-bit slices)
> > 
> > In order to adapt gracefully to future architectural extensions,
> > the registers are logically divided up into slices as noted above:
> > the i parameter denotes the slice index.
> > 
> > This allows us to reserve space in the ABI for future expansion of
> > these registers.  However, as of today the architecture does not
> > permit registers to be larger than a single slice, so no code is
> > needed in the kernel to expose additional slices, for now.  The
> > code can be extended later as needed to expose them up to a maximum
> > of 32 slices (as carved out in the architecture itself) if they
> > really exist someday.
> > 
> > The registers are only visible for vcpus that have SVE enabled.
> > They are not enumerated by KVM_GET_REG_LIST on vcpus that do not
> > have SVE.
> > 
> > Accesses to the FPSIMD registers via KVM_REG_ARM_CORE is not
> > allowed for SVE-enabled vcpus: SVE-aware userspace can use the
> > KVM_REG_ARM64_SVE_ZREG() interface instead to access the same
> > register state.  This avoids some complex and pointless emulation
> > in the kernel to convert between the two views of these aliased
> > registers.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > 
> > ---
> > 
> > Changes since v5:
> > 
> >  * [Julien Thierry] rename sve_reg_region() to sve_reg_to_region() to
> >    make its purpose a bit clearer.
> > 
> >  * [Julien Thierry] rename struct sve_state_region to
> >    sve_state_reg_region to make it clearer this this struct only
> >    describes the bounds of (part of) a single register within
> >    sve_state.
> > 
> >  * [Julien Thierry] Add a comment to clarify the purpose of struct
> >    sve_state_reg_region.
> > ---
> >  arch/arm64/include/asm/kvm_host.h |  14 ++++
> >  arch/arm64/include/uapi/asm/kvm.h |  17 +++++
> >  arch/arm64/kvm/guest.c            | 139 ++++++++++++++++++++++++++++++++++----
> >  3 files changed, 158 insertions(+), 12 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 4fabfd2..205438a 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -329,6 +329,20 @@ struct kvm_vcpu_arch {
> >  #define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
> >  				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
> >  
> > +#define vcpu_sve_state_size(vcpu) ({					\
> > +	size_t __size_ret;						\
> > +	unsigned int __vcpu_vq;						\
> > +									\
> > +	if (WARN_ON(!sve_vl_valid((vcpu)->arch.sve_max_vl))) {		\
> > +		__size_ret = 0;						\
> > +	} else {							\
> > +		__vcpu_vq = sve_vq_from_vl((vcpu)->arch.sve_max_vl);	\
> > +		__size_ret = SVE_SIG_REGS_SIZE(__vcpu_vq);		\
> > +	}								\
> > +									\
> > +	__size_ret;							\
> > +})
> 
> I know why this is a macro instead of an inline :)

Yep

I can't claim this one is a one-liner :/

> > +
> >  /* vcpu_arch flags field values: */
> >  #define KVM_ARM64_DEBUG_DIRTY		(1 << 0)
> >  #define KVM_ARM64_FP_ENABLED		(1 << 1) /* guest FP regs loaded */
> > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > index 97c3478..ced760c 100644
> > --- a/arch/arm64/include/uapi/asm/kvm.h
> > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > @@ -226,6 +226,23 @@ struct kvm_vcpu_events {
> >  					 KVM_REG_ARM_FW | ((r) & 0xffff))
> >  #define KVM_REG_ARM_PSCI_VERSION	KVM_REG_ARM_FW_REG(0)
> >  
> > +/* SVE registers */
> > +#define KVM_REG_ARM64_SVE		(0x15 << KVM_REG_ARM_COPROC_SHIFT)
> > +
> > +/* Z- and P-regs occupy blocks at the following offsets within this range: */
> > +#define KVM_REG_ARM64_SVE_ZREG_BASE	0
> > +#define KVM_REG_ARM64_SVE_PREG_BASE	0x400
> > +
> > +#define KVM_REG_ARM64_SVE_ZREG(n, i)	(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
> > +					 KVM_REG_ARM64_SVE_ZREG_BASE |	\
> > +					 KVM_REG_SIZE_U2048 |		\
> > +					 ((n) << 5) | (i))
> > +#define KVM_REG_ARM64_SVE_PREG(n, i)	(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
> > +					 KVM_REG_ARM64_SVE_PREG_BASE |	\
> > +					 KVM_REG_SIZE_U256 |		\
> > +					 ((n) << 5) | (i))
> 
> I think (n) in the above two macros should be masked to document their
> size constraints. Since KVM_REG_ARM_COPROC_SHIFT is 16 they can't be
> larger than 1 << (16 - 5), which would be a mask of 0x7ff, but as there
> are only 32 zregs and 16 pregs so we should use 0x1f and 0xf respectively.

I don't object to that.  How about this sort of thing:

#include <asm/sve_context.h>

#define KVM_ARM64_SVE_NUM_ZREGS __SVE_NUM_ZREGS
#define KVM_ARM64_SVE_NUM_PREGS __SVE_NUM_PREGS

#define KVM_ARM64_SVE_MAX_SLICES 32

ZREGs:
	... | (((n) & (KVM_ARM64_SVE_NUM_ZREGS - 1)) << 5) |
		((i) & (KVM_ARM64_SVE_MAX_SLICES - 1))


The shadow _NUM_xREGS defines are sort of overkill, but
<asm/sigcontext.h> is not really appropriate to include here.
<asm/sve_context.h> is intended as a backend only, and I prefer to hide
it behind other headers.


> > +#define KVM_REG_ARM64_SVE_FFR(i)	KVM_REG_ARM64_SVE_PREG(16, i)
> 
> Since this is user api and a user may want to construct their own register
> indices, then shouldn't we instead provide KVM_REG_ARM64_SVE_FFR_BASE as
> 
>  #define KVM_REG_ARM64_SVE_FFR_BASE KVM_REG_ARM64_SVE_PREG_BASE | (16 << 5)

Can do, or just

#define KVM_REG_ARM64_SVE_FFR_BASE KVM_REG_ARM64_SVE_PREG(0, 0)

(which is what I tend to do elsewhere).

> and then KVM_REG_ARM64_SVE_FFR(i) would follow the typical pattern
> 
>  #define KVM_REG_ARM64_SVE_FFR(i) (KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
>                                    KVM_REG_ARM64_SVE_FFR_BASE | \
>                                    KVM_REG_SIZE_U256 | (i))

Yes, we could do that.

> 
> > +
> >  /* Device Control API: ARM VGIC */
> >  #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
> >  #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
> > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > index 756d0d6..736d8cb 100644
> > --- a/arch/arm64/kvm/guest.c
> > +++ b/arch/arm64/kvm/guest.c
> > @@ -19,8 +19,11 @@
> >   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> >   */
> >  
> > +#include <linux/bits.h>
> >  #include <linux/errno.h>
> >  #include <linux/err.h>
> > +#include <linux/nospec.h>
> > +#include <linux/kernel.h>
> >  #include <linux/kvm_host.h>
> >  #include <linux/module.h>
> >  #include <linux/stddef.h>
> > @@ -30,9 +33,12 @@
> >  #include <kvm/arm_psci.h>
> >  #include <asm/cputype.h>
> >  #include <linux/uaccess.h>
> > +#include <asm/fpsimd.h>
> >  #include <asm/kvm.h>
> >  #include <asm/kvm_emulate.h>
> >  #include <asm/kvm_coproc.h>
> > +#include <asm/kvm_host.h>
> > +#include <asm/sigcontext.h>
> >  
> >  #include "trace.h"
> >  
> > @@ -200,6 +206,115 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >  	return err;
> >  }
> >  
> > +#define SVE_REG_SLICE_SHIFT	0
> > +#define SVE_REG_SLICE_BITS	5
> > +#define SVE_REG_ID_SHIFT	(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS)
> > +#define SVE_REG_ID_BITS		5
> > +
> > +#define SVE_REG_SLICE_MASK					\
> > +	GENMASK(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS - 1,	\
> > +		SVE_REG_SLICE_SHIFT)
> > +#define SVE_REG_ID_MASK							\
> > +	GENMASK(SVE_REG_ID_SHIFT + SVE_REG_ID_BITS - 1, SVE_REG_ID_SHIFT)
> > +
> > +#define SVE_NUM_SLICES (1 << SVE_REG_SLICE_BITS)
> > +
> > +#define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0))
> > +#define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0))
> > +
> > +/* Bounds of a single SVE register slice within vcpu->arch.sve_state */
> > +struct sve_state_reg_region {
> > +	unsigned int koffset;	/* offset into sve_state in kernel memory */
> > +	unsigned int klen;	/* length in kernel memory */
> > +	unsigned int upad;	/* extra trailing padding in user memory */
> > +};
> > +
> > +/* Get sanitised bounds for user/kernel SVE register copy */
> > +static int sve_reg_to_region(struct sve_state_reg_region *region,
> > +			     struct kvm_vcpu *vcpu,
> > +			     const struct kvm_one_reg *reg)
> > +{
> > +	/* reg ID ranges for Z- registers */
> > +	const u64 zreg_id_min = KVM_REG_ARM64_SVE_ZREG(0, 0);
> > +	const u64 zreg_id_max = KVM_REG_ARM64_SVE_ZREG(SVE_NUM_ZREGS - 1,
> > +						       SVE_NUM_SLICES - 1);
> > +
> > +	/* reg ID ranges for P- registers and FFR (which are contiguous) */
> > +	const u64 preg_id_min = KVM_REG_ARM64_SVE_PREG(0, 0);
> > +	const u64 preg_id_max = KVM_REG_ARM64_SVE_FFR(SVE_NUM_SLICES - 1);
> > +
> > +	unsigned int vq;
> > +	unsigned int reg_num;
> > +
> > +	unsigned int reqoffset, reqlen; /* User-requested offset and length */
> > +	unsigned int maxlen; /* Maxmimum permitted length */
> > +
> > +	size_t sve_state_size;
> > +
> > +	/* Only the first slice ever exists, for now: */
> > +	if ((reg->id & SVE_REG_SLICE_MASK) != 0)
> > +		return -ENOENT;
> > +
> > +	vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
> > +
> > +	reg_num = (reg->id & SVE_REG_ID_MASK) >> SVE_REG_ID_SHIFT;
> > +
> > +	if (reg->id >= zreg_id_min && reg->id <= zreg_id_max) {
> > +		reqoffset = SVE_SIG_ZREG_OFFSET(vq, reg_num) -
> > +				SVE_SIG_REGS_OFFSET;
> > +		reqlen = KVM_SVE_ZREG_SIZE;
> > +		maxlen = SVE_SIG_ZREG_SIZE(vq);
> > +	} else if (reg->id >= preg_id_min && reg->id <= preg_id_max) {
> > +		reqoffset = SVE_SIG_PREG_OFFSET(vq, reg_num) -
> > +				SVE_SIG_REGS_OFFSET;
> > +		reqlen = KVM_SVE_PREG_SIZE;
> > +		maxlen = SVE_SIG_PREG_SIZE(vq);
> > +	} else {
> > +		return -ENOENT;
> > +	}
> > +
> > +	sve_state_size = vcpu_sve_state_size(vcpu);
> > +	if (!sve_state_size)
> > +		return -EINVAL;
> > +
> > +	region->koffset = array_index_nospec(reqoffset, sve_state_size);
> > +	region->klen = min(maxlen, reqlen);
> > +	region->upad = reqlen - region->klen;
> > +
> > +	return 0;
> > +}
> > +
> > +static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > +{
> > +	struct sve_state_reg_region region;
> > +	char __user *uptr = (char __user *)reg->addr;
> > +
> > +	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> > +		return -ENOENT;
> 
> sve_reg_to_region() can return EINVAL, but here it would get changed to
> ENOENT.

Hmm, I'd say the affected code in sve_reg_to_region() should really be
a WARN_ON(): we're not supposed to hit it because we can't get here
until the vcpu is finalized.  It's really just a defensive check before
dividing by some potentially invalid value.  In such a case, it's
reasonable to have that EINVAL show through to userspace.

Does that make sense?

> > +
> > +	if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
> > +			 region.klen) ||
> > +	    clear_user(uptr + region.klen, region.upad))
> > +		return -EFAULT;
> > +
> > +	return 0;
> > +}
> > +
> > +static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > +{
> > +	struct sve_state_reg_region region;
> > +	const char __user *uptr = (const char __user *)reg->addr;
> > +
> > +	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> > +		return -ENOENT;
> 
> Same as above.

Ditto

> > +
> > +	if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
> > +			   region.klen))
> > +		return -EFAULT;
> > +
> > +	return 0;
> > +}
> > +
> >  int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
> >  {
> >  	return -EINVAL;
> > @@ -346,12 +461,12 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >  	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
> >  		return -EINVAL;
> >  
> > -	/* Register group 16 means we want a core register. */
> > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
> > -		return get_core_reg(vcpu, reg);
> > -
> > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
> > -		return kvm_arm_get_fw_reg(vcpu, reg);
> > +	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > +	case KVM_REG_ARM_CORE:	return get_core_reg(vcpu, reg);
> > +	case KVM_REG_ARM_FW:	return kvm_arm_get_fw_reg(vcpu, reg);
> > +	case KVM_REG_ARM64_SVE:	return get_sve_reg(vcpu, reg);
> > +	default: break; /* fall through */
> 
> This case has a 'break', so it's not a 'fall through'. Do we require
> default cases even when they're unused? If not, why have it?

My reason for having that was to highlight that we fall through to the
code following the switch only in this case, because the other cases
all consist of return statements.

> > +	}
> >  
> >  	if (is_timer_reg(reg->id))
> >  		return get_timer_reg(vcpu, reg);
> > @@ -365,12 +480,12 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >  	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
> >  		return -EINVAL;
> >  
> > -	/* Register group 16 means we set a core register. */
> > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
> > -		return set_core_reg(vcpu, reg);
> > -
> > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
> > -		return kvm_arm_set_fw_reg(vcpu, reg);
> > +	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > +	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
> > +	case KVM_REG_ARM_FW:	return kvm_arm_set_fw_reg(vcpu, reg);
> > +	case KVM_REG_ARM64_SVE:	return set_sve_reg(vcpu, reg);
> > +	default: break; /* fall through */
> 
> Same as above.

I could move the trailing code into the default case, but that felt a
bit ugly.

Thoughts?

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 21/27] KVM: arm/arm64: Add hook for arch-specific KVM initialisation
  2019-04-04 14:25     ` Andrew Jones
@ 2019-04-04 14:53       ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04 14:53 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 04:25:28PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:46PM +0000, Dave Martin wrote:
> > This patch adds a kvm_arm_init_arch_resources() hook to perform
> > subarch-specific initialisation when starting up KVM.
> > 
> > This will be used in a subsequent patch for global SVE-related
> > setup on arm64.
> > 
> > No functional change.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > ---
> >  arch/arm/include/asm/kvm_host.h   | 2 ++
> >  arch/arm64/include/asm/kvm_host.h | 2 ++
> >  virt/kvm/arm/arm.c                | 4 ++++
> >  3 files changed, 8 insertions(+)
> > 
> > diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> > index 770d732..a49ee01 100644
> > --- a/arch/arm/include/asm/kvm_host.h
> > +++ b/arch/arm/include/asm/kvm_host.h
> > @@ -53,6 +53,8 @@
> >  
> >  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> >  
> > +static inline int kvm_arm_init_arch_resources(void) { return 0; }
> > +
> >  u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
> >  int __attribute_const__ kvm_target_cpu(void);
> >  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 205438a..3e89509 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -58,6 +58,8 @@
> >  
> >  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> >  
> > +static inline int kvm_arm_init_arch_resources(void) { return 0; }
> > +
> >  int __attribute_const__ kvm_target_cpu(void);
> >  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> >  int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext);
> > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > index 99c3738..c69e137 100644
> > --- a/virt/kvm/arm/arm.c
> > +++ b/virt/kvm/arm/arm.c
> > @@ -1664,6 +1664,10 @@ int kvm_arch_init(void *opaque)
> >  	if (err)
> >  		return err;
> >  
> > +	err = kvm_arm_init_arch_resources();
> > +	if (err)
> > +		return err;
> > +
> >  	if (!in_hyp_mode) {
> >  		err = init_hyp_mode();
> >  		if (err)
> > -- 
> > 2.1.4
> >
> 
> It's not clear to me from the commit message why init_common_resources()
> won't work for this. Maybe it'll be more clear as I continue the review.

init_common_resources() is for stuff common to arm and arm64.

kvm_arm_init_arch_resources() is intended for stuff specific to the
particular arch backend.

Maybe there is a better name for this.

Cheers
---Dave

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

* Re: [PATCH v7 21/27] KVM: arm/arm64: Add hook for arch-specific KVM initialisation
@ 2019-04-04 14:53       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04 14:53 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 04:25:28PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:46PM +0000, Dave Martin wrote:
> > This patch adds a kvm_arm_init_arch_resources() hook to perform
> > subarch-specific initialisation when starting up KVM.
> > 
> > This will be used in a subsequent patch for global SVE-related
> > setup on arm64.
> > 
> > No functional change.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > ---
> >  arch/arm/include/asm/kvm_host.h   | 2 ++
> >  arch/arm64/include/asm/kvm_host.h | 2 ++
> >  virt/kvm/arm/arm.c                | 4 ++++
> >  3 files changed, 8 insertions(+)
> > 
> > diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> > index 770d732..a49ee01 100644
> > --- a/arch/arm/include/asm/kvm_host.h
> > +++ b/arch/arm/include/asm/kvm_host.h
> > @@ -53,6 +53,8 @@
> >  
> >  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> >  
> > +static inline int kvm_arm_init_arch_resources(void) { return 0; }
> > +
> >  u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
> >  int __attribute_const__ kvm_target_cpu(void);
> >  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 205438a..3e89509 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -58,6 +58,8 @@
> >  
> >  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> >  
> > +static inline int kvm_arm_init_arch_resources(void) { return 0; }
> > +
> >  int __attribute_const__ kvm_target_cpu(void);
> >  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> >  int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext);
> > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > index 99c3738..c69e137 100644
> > --- a/virt/kvm/arm/arm.c
> > +++ b/virt/kvm/arm/arm.c
> > @@ -1664,6 +1664,10 @@ int kvm_arch_init(void *opaque)
> >  	if (err)
> >  		return err;
> >  
> > +	err = kvm_arm_init_arch_resources();
> > +	if (err)
> > +		return err;
> > +
> >  	if (!in_hyp_mode) {
> >  		err = init_hyp_mode();
> >  		if (err)
> > -- 
> > 2.1.4
> >
> 
> It's not clear to me from the commit message why init_common_resources()
> won't work for this. Maybe it'll be more clear as I continue the review.

init_common_resources() is for stuff common to arm and arm64.

kvm_arm_init_arch_resources() is intended for stuff specific to the
particular arch backend.

Maybe there is a better name for this.

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 22/27] KVM: arm/arm64: Add KVM_ARM_VCPU_FINALIZE ioctl
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-04 15:07     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 15:07 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:47PM +0000, Dave Martin wrote:
> Some aspects of vcpu configuration may be too complex to be
> completed inside KVM_ARM_VCPU_INIT.  Thus, there may be a
> requirement for userspace to do some additional configuration
> before various other ioctls will work in a consistent way.
> 
> In particular this will be the case for SVE, where userspace will
> need to negotiate the set of vector lengths to be made available to
> the guest before the vcpu becomes fully usable.
> 
> In order to provide an explicit way for userspace to confirm that
> it has finished setting up a particular vcpu feature, this patch
> adds a new ioctl KVM_ARM_VCPU_FINALIZE.
> 
> When userspace has opted into a feature that requires finalization,
> typically by means of a feature flag passed to KVM_ARM_VCPU_INIT, a
> matching call to KVM_ARM_VCPU_FINALIZE is now required before
> KVM_RUN or KVM_GET_REG_LIST is allowed.  Individual features may
> impose additional restrictions where appropriate.
> 
> No existing vcpu features are affected by this, so current
> userspace implementations will continue to work exactly as before,
> with no need to issue KVM_ARM_VCPU_FINALIZE.
> 
> As implemented in this patch, KVM_ARM_VCPU_FINALIZE is currently a
> placeholder: no finalizable features exist yet, so ioctl is not
> required and will always yield EINVAL.  Subsequent patches will add
> the finalization logic to make use of this ioctl for SVE.
> 
> No functional change for existing userspace.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * Commit message, including subject line, rewritten.
> 
>    This patch is a rework of "KVM: arm/arm64: Add hook to finalize the
>    vcpu configuration".  The old subject line and commit message no
>    longer accurately described what the patch does.  However, the code
>    is an evolution of the previous patch rather than a wholesale
>    rewrite.
> 
>  * Added an explicit KVM_ARM_VCPU_FINALIZE ioctl, rather than just
>    providing internal hooks in the kernel to finalize the vcpu
>    configuration implicitly.  This allows userspace to confirm exactly
>    when it has finished configuring the vcpu and is ready to use it.
> 
>    This results in simpler (and hopefully more maintainable) ioctl
>    ordering rules.
> ---
>  arch/arm/include/asm/kvm_host.h   |  4 ++++
>  arch/arm64/include/asm/kvm_host.h |  4 ++++
>  include/uapi/linux/kvm.h          |  3 +++
>  virt/kvm/arm/arm.c                | 18 ++++++++++++++++++
>  4 files changed, 29 insertions(+)
> 
> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> index a49ee01..e80cfc1 100644
> --- a/arch/arm/include/asm/kvm_host.h
> +++ b/arch/arm/include/asm/kvm_host.h
> @@ -19,6 +19,7 @@
>  #ifndef __ARM_KVM_HOST_H__
>  #define __ARM_KVM_HOST_H__
>  
> +#include <linux/errno.h>
>  #include <linux/types.h>
>  #include <linux/kvm_types.h>
>  #include <asm/cputype.h>
> @@ -411,4 +412,7 @@ static inline int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type)
>  	return 0;
>  }
>  
> +#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
> +#define kvm_arm_vcpu_is_finalized(vcpu) true
> +

We usually use inline functions for the stubs.

>  #endif /* __ARM_KVM_HOST_H__ */
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 3e89509..98658f7 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -23,6 +23,7 @@
>  #define __ARM64_KVM_HOST_H__
>  
>  #include <linux/bitmap.h>
> +#include <linux/errno.h>
>  #include <linux/types.h>
>  #include <linux/jump_label.h>
>  #include <linux/kvm_types.h>
> @@ -625,4 +626,7 @@ void kvm_arch_free_vm(struct kvm *kvm);
>  
>  int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type);
>  
> +#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
> +#define kvm_arm_vcpu_is_finalized(vcpu) true

Same as above.

> +
>  #endif /* __ARM64_KVM_HOST_H__ */
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index dc77a5a..c3b8e7a 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -1441,6 +1441,9 @@ struct kvm_enc_region {
>  /* Available with KVM_CAP_HYPERV_CPUID */
>  #define KVM_GET_SUPPORTED_HV_CPUID _IOWR(KVMIO, 0xc1, struct kvm_cpuid2)
>  
> +/* Available with KVM_CAP_ARM_SVE */
> +#define KVM_ARM_VCPU_FINALIZE	  _IOW(KVMIO,  0xc2, int)
> +
>  /* Secure Encrypted Virtualization command */
>  enum sev_cmd_id {
>  	/* Guest initialization commands */
> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> index c69e137..9edbf0f 100644
> --- a/virt/kvm/arm/arm.c
> +++ b/virt/kvm/arm/arm.c
> @@ -545,6 +545,9 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
>  	if (likely(vcpu->arch.has_run_once))
>  		return 0;
>  
> +	if (!kvm_arm_vcpu_is_finalized(vcpu))
> +		return -EPERM;
> +
>  	vcpu->arch.has_run_once = true;
>  
>  	if (likely(irqchip_in_kernel(kvm))) {
> @@ -1116,6 +1119,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
>  		if (unlikely(!kvm_vcpu_initialized(vcpu)))
>  			break;
>  
> +		r = -EPERM;
> +		if (!kvm_arm_vcpu_is_finalized(vcpu))
> +			break;
> +

What's the rationale for using EPERM? The finalized concept is very
similar to the initialized one. So why not also use ENOEXEC for it too?

>  		r = -EFAULT;
>  		if (copy_from_user(&reg_list, user_list, sizeof(reg_list)))
>  			break;
> @@ -1169,6 +1176,17 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
>  
>  		return kvm_arm_vcpu_set_events(vcpu, &events);
>  	}
> +	case KVM_ARM_VCPU_FINALIZE: {
> +		int what;
> +
> +		if (!kvm_vcpu_initialized(vcpu))
> +			return -ENOEXEC;
> +
> +		if (get_user(what, (const int __user *)argp))
> +			return -EFAULT;
> +
> +		return kvm_arm_vcpu_finalize(vcpu, what);

Almost all the cases use the 'r = ...; break;' type of pattern, leaving
it to the 'return r' at the end of the function. I guess that's in case
at some point more stuff is added after the switch. The only cases that
don't do that are the most recent ones KVM_GET/SET_VCPU_EVENTS, which
should probably be changed to fit the pattern too, rather than this
new ioctl following there pattern.

> +	}
>  	default:
>  		r = -EINVAL;
>  	}
> -- 
> 2.1.4
> 

Thanks,
drew

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

* Re: [PATCH v7 22/27] KVM: arm/arm64: Add KVM_ARM_VCPU_FINALIZE ioctl
@ 2019-04-04 15:07     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 15:07 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:47PM +0000, Dave Martin wrote:
> Some aspects of vcpu configuration may be too complex to be
> completed inside KVM_ARM_VCPU_INIT.  Thus, there may be a
> requirement for userspace to do some additional configuration
> before various other ioctls will work in a consistent way.
> 
> In particular this will be the case for SVE, where userspace will
> need to negotiate the set of vector lengths to be made available to
> the guest before the vcpu becomes fully usable.
> 
> In order to provide an explicit way for userspace to confirm that
> it has finished setting up a particular vcpu feature, this patch
> adds a new ioctl KVM_ARM_VCPU_FINALIZE.
> 
> When userspace has opted into a feature that requires finalization,
> typically by means of a feature flag passed to KVM_ARM_VCPU_INIT, a
> matching call to KVM_ARM_VCPU_FINALIZE is now required before
> KVM_RUN or KVM_GET_REG_LIST is allowed.  Individual features may
> impose additional restrictions where appropriate.
> 
> No existing vcpu features are affected by this, so current
> userspace implementations will continue to work exactly as before,
> with no need to issue KVM_ARM_VCPU_FINALIZE.
> 
> As implemented in this patch, KVM_ARM_VCPU_FINALIZE is currently a
> placeholder: no finalizable features exist yet, so ioctl is not
> required and will always yield EINVAL.  Subsequent patches will add
> the finalization logic to make use of this ioctl for SVE.
> 
> No functional change for existing userspace.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * Commit message, including subject line, rewritten.
> 
>    This patch is a rework of "KVM: arm/arm64: Add hook to finalize the
>    vcpu configuration".  The old subject line and commit message no
>    longer accurately described what the patch does.  However, the code
>    is an evolution of the previous patch rather than a wholesale
>    rewrite.
> 
>  * Added an explicit KVM_ARM_VCPU_FINALIZE ioctl, rather than just
>    providing internal hooks in the kernel to finalize the vcpu
>    configuration implicitly.  This allows userspace to confirm exactly
>    when it has finished configuring the vcpu and is ready to use it.
> 
>    This results in simpler (and hopefully more maintainable) ioctl
>    ordering rules.
> ---
>  arch/arm/include/asm/kvm_host.h   |  4 ++++
>  arch/arm64/include/asm/kvm_host.h |  4 ++++
>  include/uapi/linux/kvm.h          |  3 +++
>  virt/kvm/arm/arm.c                | 18 ++++++++++++++++++
>  4 files changed, 29 insertions(+)
> 
> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> index a49ee01..e80cfc1 100644
> --- a/arch/arm/include/asm/kvm_host.h
> +++ b/arch/arm/include/asm/kvm_host.h
> @@ -19,6 +19,7 @@
>  #ifndef __ARM_KVM_HOST_H__
>  #define __ARM_KVM_HOST_H__
>  
> +#include <linux/errno.h>
>  #include <linux/types.h>
>  #include <linux/kvm_types.h>
>  #include <asm/cputype.h>
> @@ -411,4 +412,7 @@ static inline int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type)
>  	return 0;
>  }
>  
> +#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
> +#define kvm_arm_vcpu_is_finalized(vcpu) true
> +

We usually use inline functions for the stubs.

>  #endif /* __ARM_KVM_HOST_H__ */
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 3e89509..98658f7 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -23,6 +23,7 @@
>  #define __ARM64_KVM_HOST_H__
>  
>  #include <linux/bitmap.h>
> +#include <linux/errno.h>
>  #include <linux/types.h>
>  #include <linux/jump_label.h>
>  #include <linux/kvm_types.h>
> @@ -625,4 +626,7 @@ void kvm_arch_free_vm(struct kvm *kvm);
>  
>  int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type);
>  
> +#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
> +#define kvm_arm_vcpu_is_finalized(vcpu) true

Same as above.

> +
>  #endif /* __ARM64_KVM_HOST_H__ */
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index dc77a5a..c3b8e7a 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -1441,6 +1441,9 @@ struct kvm_enc_region {
>  /* Available with KVM_CAP_HYPERV_CPUID */
>  #define KVM_GET_SUPPORTED_HV_CPUID _IOWR(KVMIO, 0xc1, struct kvm_cpuid2)
>  
> +/* Available with KVM_CAP_ARM_SVE */
> +#define KVM_ARM_VCPU_FINALIZE	  _IOW(KVMIO,  0xc2, int)
> +
>  /* Secure Encrypted Virtualization command */
>  enum sev_cmd_id {
>  	/* Guest initialization commands */
> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> index c69e137..9edbf0f 100644
> --- a/virt/kvm/arm/arm.c
> +++ b/virt/kvm/arm/arm.c
> @@ -545,6 +545,9 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
>  	if (likely(vcpu->arch.has_run_once))
>  		return 0;
>  
> +	if (!kvm_arm_vcpu_is_finalized(vcpu))
> +		return -EPERM;
> +
>  	vcpu->arch.has_run_once = true;
>  
>  	if (likely(irqchip_in_kernel(kvm))) {
> @@ -1116,6 +1119,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
>  		if (unlikely(!kvm_vcpu_initialized(vcpu)))
>  			break;
>  
> +		r = -EPERM;
> +		if (!kvm_arm_vcpu_is_finalized(vcpu))
> +			break;
> +

What's the rationale for using EPERM? The finalized concept is very
similar to the initialized one. So why not also use ENOEXEC for it too?

>  		r = -EFAULT;
>  		if (copy_from_user(&reg_list, user_list, sizeof(reg_list)))
>  			break;
> @@ -1169,6 +1176,17 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
>  
>  		return kvm_arm_vcpu_set_events(vcpu, &events);
>  	}
> +	case KVM_ARM_VCPU_FINALIZE: {
> +		int what;
> +
> +		if (!kvm_vcpu_initialized(vcpu))
> +			return -ENOEXEC;
> +
> +		if (get_user(what, (const int __user *)argp))
> +			return -EFAULT;
> +
> +		return kvm_arm_vcpu_finalize(vcpu, what);

Almost all the cases use the 'r = ...; break;' type of pattern, leaving
it to the 'return r' at the end of the function. I guess that's in case
at some point more stuff is added after the switch. The only cases that
don't do that are the most recent ones KVM_GET/SET_VCPU_EVENTS, which
should probably be changed to fit the pattern too, rather than this
new ioctl following there pattern.

> +	}
>  	default:
>  		r = -EINVAL;
>  	}
> -- 
> 2.1.4
> 

Thanks,
drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 18/27] KVM: arm64/sve: Add SVE support to register access ioctl interface
  2019-04-04 14:50       ` Dave Martin
@ 2019-04-04 16:25         ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 16:25 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 03:50:56PM +0100, Dave Martin wrote:
> On Thu, Apr 04, 2019 at 03:57:06PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:43PM +0000, Dave Martin wrote:
> > > This patch adds the following registers for access via the
> > > KVM_{GET,SET}_ONE_REG interface:
> > > 
> > >  * KVM_REG_ARM64_SVE_ZREG(n, i) (n = 0..31) (in 2048-bit slices)
> > >  * KVM_REG_ARM64_SVE_PREG(n, i) (n = 0..15) (in 256-bit slices)
> > >  * KVM_REG_ARM64_SVE_FFR(i) (in 256-bit slices)
> > > 
> > > In order to adapt gracefully to future architectural extensions,
> > > the registers are logically divided up into slices as noted above:
> > > the i parameter denotes the slice index.
> > > 
> > > This allows us to reserve space in the ABI for future expansion of
> > > these registers.  However, as of today the architecture does not
> > > permit registers to be larger than a single slice, so no code is
> > > needed in the kernel to expose additional slices, for now.  The
> > > code can be extended later as needed to expose them up to a maximum
> > > of 32 slices (as carved out in the architecture itself) if they
> > > really exist someday.
> > > 
> > > The registers are only visible for vcpus that have SVE enabled.
> > > They are not enumerated by KVM_GET_REG_LIST on vcpus that do not
> > > have SVE.
> > > 
> > > Accesses to the FPSIMD registers via KVM_REG_ARM_CORE is not
> > > allowed for SVE-enabled vcpus: SVE-aware userspace can use the
> > > KVM_REG_ARM64_SVE_ZREG() interface instead to access the same
> > > register state.  This avoids some complex and pointless emulation
> > > in the kernel to convert between the two views of these aliased
> > > registers.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > 
> > > ---
> > > 
> > > Changes since v5:
> > > 
> > >  * [Julien Thierry] rename sve_reg_region() to sve_reg_to_region() to
> > >    make its purpose a bit clearer.
> > > 
> > >  * [Julien Thierry] rename struct sve_state_region to
> > >    sve_state_reg_region to make it clearer this this struct only
> > >    describes the bounds of (part of) a single register within
> > >    sve_state.
> > > 
> > >  * [Julien Thierry] Add a comment to clarify the purpose of struct
> > >    sve_state_reg_region.
> > > ---
> > >  arch/arm64/include/asm/kvm_host.h |  14 ++++
> > >  arch/arm64/include/uapi/asm/kvm.h |  17 +++++
> > >  arch/arm64/kvm/guest.c            | 139 ++++++++++++++++++++++++++++++++++----
> > >  3 files changed, 158 insertions(+), 12 deletions(-)
> > > 
> > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > index 4fabfd2..205438a 100644
> > > --- a/arch/arm64/include/asm/kvm_host.h
> > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > @@ -329,6 +329,20 @@ struct kvm_vcpu_arch {
> > >  #define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
> > >  				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
> > >  
> > > +#define vcpu_sve_state_size(vcpu) ({					\
> > > +	size_t __size_ret;						\
> > > +	unsigned int __vcpu_vq;						\
> > > +									\
> > > +	if (WARN_ON(!sve_vl_valid((vcpu)->arch.sve_max_vl))) {		\
> > > +		__size_ret = 0;						\
> > > +	} else {							\
> > > +		__vcpu_vq = sve_vq_from_vl((vcpu)->arch.sve_max_vl);	\
> > > +		__size_ret = SVE_SIG_REGS_SIZE(__vcpu_vq);		\
> > > +	}								\
> > > +									\
> > > +	__size_ret;							\
> > > +})
> > 
> > I know why this is a macro instead of an inline :)
> 
> Yep
> 
> I can't claim this one is a one-liner :/
> 
> > > +
> > >  /* vcpu_arch flags field values: */
> > >  #define KVM_ARM64_DEBUG_DIRTY		(1 << 0)
> > >  #define KVM_ARM64_FP_ENABLED		(1 << 1) /* guest FP regs loaded */
> > > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > > index 97c3478..ced760c 100644
> > > --- a/arch/arm64/include/uapi/asm/kvm.h
> > > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > > @@ -226,6 +226,23 @@ struct kvm_vcpu_events {
> > >  					 KVM_REG_ARM_FW | ((r) & 0xffff))
> > >  #define KVM_REG_ARM_PSCI_VERSION	KVM_REG_ARM_FW_REG(0)
> > >  
> > > +/* SVE registers */
> > > +#define KVM_REG_ARM64_SVE		(0x15 << KVM_REG_ARM_COPROC_SHIFT)
> > > +
> > > +/* Z- and P-regs occupy blocks at the following offsets within this range: */
> > > +#define KVM_REG_ARM64_SVE_ZREG_BASE	0
> > > +#define KVM_REG_ARM64_SVE_PREG_BASE	0x400
> > > +
> > > +#define KVM_REG_ARM64_SVE_ZREG(n, i)	(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
> > > +					 KVM_REG_ARM64_SVE_ZREG_BASE |	\
> > > +					 KVM_REG_SIZE_U2048 |		\
> > > +					 ((n) << 5) | (i))
> > > +#define KVM_REG_ARM64_SVE_PREG(n, i)	(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
> > > +					 KVM_REG_ARM64_SVE_PREG_BASE |	\
> > > +					 KVM_REG_SIZE_U256 |		\
> > > +					 ((n) << 5) | (i))
> > 
> > I think (n) in the above two macros should be masked to document their
> > size constraints. Since KVM_REG_ARM_COPROC_SHIFT is 16 they can't be
> > larger than 1 << (16 - 5), which would be a mask of 0x7ff, but as there
> > are only 32 zregs and 16 pregs so we should use 0x1f and 0xf respectively.
> 
> I don't object to that.  How about this sort of thing:
> 
> #include <asm/sve_context.h>
> 
> #define KVM_ARM64_SVE_NUM_ZREGS __SVE_NUM_ZREGS
> #define KVM_ARM64_SVE_NUM_PREGS __SVE_NUM_PREGS
> 
> #define KVM_ARM64_SVE_MAX_SLICES 32
> 
> ZREGs:
> 	... | (((n) & (KVM_ARM64_SVE_NUM_ZREGS - 1)) << 5) |
> 		((i) & (KVM_ARM64_SVE_MAX_SLICES - 1))
> 
> 
> The shadow _NUM_xREGS defines are sort of overkill, but
> <asm/sigcontext.h> is not really appropriate to include here.
> <asm/sve_context.h> is intended as a backend only, and I prefer to hide
> it behind other headers.

Looks good to me

> 
> 
> > > +#define KVM_REG_ARM64_SVE_FFR(i)	KVM_REG_ARM64_SVE_PREG(16, i)
> > 
> > Since this is user api and a user may want to construct their own register
> > indices, then shouldn't we instead provide KVM_REG_ARM64_SVE_FFR_BASE as
> > 
> >  #define KVM_REG_ARM64_SVE_FFR_BASE KVM_REG_ARM64_SVE_PREG_BASE | (16 << 5)
> 
> Can do, or just
> 
> #define KVM_REG_ARM64_SVE_FFR_BASE KVM_REG_ARM64_SVE_PREG(0, 0)

I don't see how this would work for an FFR base.

> 
> (which is what I tend to do elsewhere).
> 
> > and then KVM_REG_ARM64_SVE_FFR(i) would follow the typical pattern
> > 
> >  #define KVM_REG_ARM64_SVE_FFR(i) (KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
> >                                    KVM_REG_ARM64_SVE_FFR_BASE | \
> >                                    KVM_REG_SIZE_U256 | (i))
> 
> Yes, we could do that.
> 
> > 
> > > +
> > >  /* Device Control API: ARM VGIC */
> > >  #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
> > >  #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
> > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > index 756d0d6..736d8cb 100644
> > > --- a/arch/arm64/kvm/guest.c
> > > +++ b/arch/arm64/kvm/guest.c
> > > @@ -19,8 +19,11 @@
> > >   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> > >   */
> > >  
> > > +#include <linux/bits.h>
> > >  #include <linux/errno.h>
> > >  #include <linux/err.h>
> > > +#include <linux/nospec.h>
> > > +#include <linux/kernel.h>
> > >  #include <linux/kvm_host.h>
> > >  #include <linux/module.h>
> > >  #include <linux/stddef.h>
> > > @@ -30,9 +33,12 @@
> > >  #include <kvm/arm_psci.h>
> > >  #include <asm/cputype.h>
> > >  #include <linux/uaccess.h>
> > > +#include <asm/fpsimd.h>
> > >  #include <asm/kvm.h>
> > >  #include <asm/kvm_emulate.h>
> > >  #include <asm/kvm_coproc.h>
> > > +#include <asm/kvm_host.h>
> > > +#include <asm/sigcontext.h>
> > >  
> > >  #include "trace.h"
> > >  
> > > @@ -200,6 +206,115 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >  	return err;
> > >  }
> > >  
> > > +#define SVE_REG_SLICE_SHIFT	0
> > > +#define SVE_REG_SLICE_BITS	5
> > > +#define SVE_REG_ID_SHIFT	(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS)
> > > +#define SVE_REG_ID_BITS		5
> > > +
> > > +#define SVE_REG_SLICE_MASK					\
> > > +	GENMASK(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS - 1,	\
> > > +		SVE_REG_SLICE_SHIFT)
> > > +#define SVE_REG_ID_MASK							\
> > > +	GENMASK(SVE_REG_ID_SHIFT + SVE_REG_ID_BITS - 1, SVE_REG_ID_SHIFT)
> > > +
> > > +#define SVE_NUM_SLICES (1 << SVE_REG_SLICE_BITS)
> > > +
> > > +#define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0))
> > > +#define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0))
> > > +
> > > +/* Bounds of a single SVE register slice within vcpu->arch.sve_state */
> > > +struct sve_state_reg_region {
> > > +	unsigned int koffset;	/* offset into sve_state in kernel memory */
> > > +	unsigned int klen;	/* length in kernel memory */
> > > +	unsigned int upad;	/* extra trailing padding in user memory */
> > > +};
> > > +
> > > +/* Get sanitised bounds for user/kernel SVE register copy */
> > > +static int sve_reg_to_region(struct sve_state_reg_region *region,
> > > +			     struct kvm_vcpu *vcpu,
> > > +			     const struct kvm_one_reg *reg)
> > > +{
> > > +	/* reg ID ranges for Z- registers */
> > > +	const u64 zreg_id_min = KVM_REG_ARM64_SVE_ZREG(0, 0);
> > > +	const u64 zreg_id_max = KVM_REG_ARM64_SVE_ZREG(SVE_NUM_ZREGS - 1,
> > > +						       SVE_NUM_SLICES - 1);
> > > +
> > > +	/* reg ID ranges for P- registers and FFR (which are contiguous) */
> > > +	const u64 preg_id_min = KVM_REG_ARM64_SVE_PREG(0, 0);
> > > +	const u64 preg_id_max = KVM_REG_ARM64_SVE_FFR(SVE_NUM_SLICES - 1);
> > > +
> > > +	unsigned int vq;
> > > +	unsigned int reg_num;
> > > +
> > > +	unsigned int reqoffset, reqlen; /* User-requested offset and length */
> > > +	unsigned int maxlen; /* Maxmimum permitted length */
> > > +
> > > +	size_t sve_state_size;
> > > +
> > > +	/* Only the first slice ever exists, for now: */
> > > +	if ((reg->id & SVE_REG_SLICE_MASK) != 0)
> > > +		return -ENOENT;
> > > +
> > > +	vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
> > > +
> > > +	reg_num = (reg->id & SVE_REG_ID_MASK) >> SVE_REG_ID_SHIFT;
> > > +
> > > +	if (reg->id >= zreg_id_min && reg->id <= zreg_id_max) {
> > > +		reqoffset = SVE_SIG_ZREG_OFFSET(vq, reg_num) -
> > > +				SVE_SIG_REGS_OFFSET;
> > > +		reqlen = KVM_SVE_ZREG_SIZE;
> > > +		maxlen = SVE_SIG_ZREG_SIZE(vq);
> > > +	} else if (reg->id >= preg_id_min && reg->id <= preg_id_max) {
> > > +		reqoffset = SVE_SIG_PREG_OFFSET(vq, reg_num) -
> > > +				SVE_SIG_REGS_OFFSET;
> > > +		reqlen = KVM_SVE_PREG_SIZE;
> > > +		maxlen = SVE_SIG_PREG_SIZE(vq);
> > > +	} else {
> > > +		return -ENOENT;
> > > +	}
> > > +
> > > +	sve_state_size = vcpu_sve_state_size(vcpu);
> > > +	if (!sve_state_size)
> > > +		return -EINVAL;
> > > +
> > > +	region->koffset = array_index_nospec(reqoffset, sve_state_size);
> > > +	region->klen = min(maxlen, reqlen);
> > > +	region->upad = reqlen - region->klen;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > +{
> > > +	struct sve_state_reg_region region;
> > > +	char __user *uptr = (char __user *)reg->addr;
> > > +
> > > +	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> > > +		return -ENOENT;
> > 
> > sve_reg_to_region() can return EINVAL, but here it would get changed to
> > ENOENT.
> 
> Hmm, I'd say the affected code in sve_reg_to_region() should really be
> a WARN_ON(): we're not supposed to hit it because we can't get here
> until the vcpu is finalized.  It's really just a defensive check before
> dividing by some potentially invalid value.  In such a case, it's
> reasonable to have that EINVAL show through to userspace.

Adding the WARN_ON is a good idea. The thing is that the EINVAL is *not*
going to show through to userspace. ENOENT will. Which might be fine,
but if so, then it would clear things up to just return ENOENT in
sve_reg_to_region() as well.

> 
> Does that make sense?
> 
> > > +
> > > +	if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
> > > +			 region.klen) ||
> > > +	    clear_user(uptr + region.klen, region.upad))
> > > +		return -EFAULT;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > +{
> > > +	struct sve_state_reg_region region;
> > > +	const char __user *uptr = (const char __user *)reg->addr;
> > > +
> > > +	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> > > +		return -ENOENT;
> > 
> > Same as above.
> 
> Ditto
> 
> > > +
> > > +	if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
> > > +			   region.klen))
> > > +		return -EFAULT;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > >  int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
> > >  {
> > >  	return -EINVAL;
> > > @@ -346,12 +461,12 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >  	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
> > >  		return -EINVAL;
> > >  
> > > -	/* Register group 16 means we want a core register. */
> > > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
> > > -		return get_core_reg(vcpu, reg);
> > > -
> > > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
> > > -		return kvm_arm_get_fw_reg(vcpu, reg);
> > > +	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > > +	case KVM_REG_ARM_CORE:	return get_core_reg(vcpu, reg);
> > > +	case KVM_REG_ARM_FW:	return kvm_arm_get_fw_reg(vcpu, reg);
> > > +	case KVM_REG_ARM64_SVE:	return get_sve_reg(vcpu, reg);
> > > +	default: break; /* fall through */
> > 
> > This case has a 'break', so it's not a 'fall through'. Do we require
> > default cases even when they're unused? If not, why have it?
> 
> My reason for having that was to highlight that we fall through to the
> code following the switch only in this case, because the other cases
> all consist of return statements.

I think it's pretty clear from the 'case,return' pattern what's going on
and the default case isn't needed at all. And since the fall through
comment is typically used to document why there is not a break, then
having both looks weird.

> 
> > > +	}
> > >  
> > >  	if (is_timer_reg(reg->id))
> > >  		return get_timer_reg(vcpu, reg);
> > > @@ -365,12 +480,12 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >  	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
> > >  		return -EINVAL;
> > >  
> > > -	/* Register group 16 means we set a core register. */
> > > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
> > > -		return set_core_reg(vcpu, reg);
> > > -
> > > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
> > > -		return kvm_arm_set_fw_reg(vcpu, reg);
> > > +	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > > +	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
> > > +	case KVM_REG_ARM_FW:	return kvm_arm_set_fw_reg(vcpu, reg);
> > > +	case KVM_REG_ARM64_SVE:	return set_sve_reg(vcpu, reg);
> > > +	default: break; /* fall through */
> > 
> > Same as above.
> 
> I could move the trailing code into the default case, but that felt a
> bit ugly.
> 
> Thoughts?

I'd remove the default case :)

Thanks,
drew

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

* Re: [PATCH v7 18/27] KVM: arm64/sve: Add SVE support to register access ioctl interface
@ 2019-04-04 16:25         ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 16:25 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 03:50:56PM +0100, Dave Martin wrote:
> On Thu, Apr 04, 2019 at 03:57:06PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:43PM +0000, Dave Martin wrote:
> > > This patch adds the following registers for access via the
> > > KVM_{GET,SET}_ONE_REG interface:
> > > 
> > >  * KVM_REG_ARM64_SVE_ZREG(n, i) (n = 0..31) (in 2048-bit slices)
> > >  * KVM_REG_ARM64_SVE_PREG(n, i) (n = 0..15) (in 256-bit slices)
> > >  * KVM_REG_ARM64_SVE_FFR(i) (in 256-bit slices)
> > > 
> > > In order to adapt gracefully to future architectural extensions,
> > > the registers are logically divided up into slices as noted above:
> > > the i parameter denotes the slice index.
> > > 
> > > This allows us to reserve space in the ABI for future expansion of
> > > these registers.  However, as of today the architecture does not
> > > permit registers to be larger than a single slice, so no code is
> > > needed in the kernel to expose additional slices, for now.  The
> > > code can be extended later as needed to expose them up to a maximum
> > > of 32 slices (as carved out in the architecture itself) if they
> > > really exist someday.
> > > 
> > > The registers are only visible for vcpus that have SVE enabled.
> > > They are not enumerated by KVM_GET_REG_LIST on vcpus that do not
> > > have SVE.
> > > 
> > > Accesses to the FPSIMD registers via KVM_REG_ARM_CORE is not
> > > allowed for SVE-enabled vcpus: SVE-aware userspace can use the
> > > KVM_REG_ARM64_SVE_ZREG() interface instead to access the same
> > > register state.  This avoids some complex and pointless emulation
> > > in the kernel to convert between the two views of these aliased
> > > registers.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > 
> > > ---
> > > 
> > > Changes since v5:
> > > 
> > >  * [Julien Thierry] rename sve_reg_region() to sve_reg_to_region() to
> > >    make its purpose a bit clearer.
> > > 
> > >  * [Julien Thierry] rename struct sve_state_region to
> > >    sve_state_reg_region to make it clearer this this struct only
> > >    describes the bounds of (part of) a single register within
> > >    sve_state.
> > > 
> > >  * [Julien Thierry] Add a comment to clarify the purpose of struct
> > >    sve_state_reg_region.
> > > ---
> > >  arch/arm64/include/asm/kvm_host.h |  14 ++++
> > >  arch/arm64/include/uapi/asm/kvm.h |  17 +++++
> > >  arch/arm64/kvm/guest.c            | 139 ++++++++++++++++++++++++++++++++++----
> > >  3 files changed, 158 insertions(+), 12 deletions(-)
> > > 
> > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > index 4fabfd2..205438a 100644
> > > --- a/arch/arm64/include/asm/kvm_host.h
> > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > @@ -329,6 +329,20 @@ struct kvm_vcpu_arch {
> > >  #define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
> > >  				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
> > >  
> > > +#define vcpu_sve_state_size(vcpu) ({					\
> > > +	size_t __size_ret;						\
> > > +	unsigned int __vcpu_vq;						\
> > > +									\
> > > +	if (WARN_ON(!sve_vl_valid((vcpu)->arch.sve_max_vl))) {		\
> > > +		__size_ret = 0;						\
> > > +	} else {							\
> > > +		__vcpu_vq = sve_vq_from_vl((vcpu)->arch.sve_max_vl);	\
> > > +		__size_ret = SVE_SIG_REGS_SIZE(__vcpu_vq);		\
> > > +	}								\
> > > +									\
> > > +	__size_ret;							\
> > > +})
> > 
> > I know why this is a macro instead of an inline :)
> 
> Yep
> 
> I can't claim this one is a one-liner :/
> 
> > > +
> > >  /* vcpu_arch flags field values: */
> > >  #define KVM_ARM64_DEBUG_DIRTY		(1 << 0)
> > >  #define KVM_ARM64_FP_ENABLED		(1 << 1) /* guest FP regs loaded */
> > > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> > > index 97c3478..ced760c 100644
> > > --- a/arch/arm64/include/uapi/asm/kvm.h
> > > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > > @@ -226,6 +226,23 @@ struct kvm_vcpu_events {
> > >  					 KVM_REG_ARM_FW | ((r) & 0xffff))
> > >  #define KVM_REG_ARM_PSCI_VERSION	KVM_REG_ARM_FW_REG(0)
> > >  
> > > +/* SVE registers */
> > > +#define KVM_REG_ARM64_SVE		(0x15 << KVM_REG_ARM_COPROC_SHIFT)
> > > +
> > > +/* Z- and P-regs occupy blocks at the following offsets within this range: */
> > > +#define KVM_REG_ARM64_SVE_ZREG_BASE	0
> > > +#define KVM_REG_ARM64_SVE_PREG_BASE	0x400
> > > +
> > > +#define KVM_REG_ARM64_SVE_ZREG(n, i)	(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
> > > +					 KVM_REG_ARM64_SVE_ZREG_BASE |	\
> > > +					 KVM_REG_SIZE_U2048 |		\
> > > +					 ((n) << 5) | (i))
> > > +#define KVM_REG_ARM64_SVE_PREG(n, i)	(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
> > > +					 KVM_REG_ARM64_SVE_PREG_BASE |	\
> > > +					 KVM_REG_SIZE_U256 |		\
> > > +					 ((n) << 5) | (i))
> > 
> > I think (n) in the above two macros should be masked to document their
> > size constraints. Since KVM_REG_ARM_COPROC_SHIFT is 16 they can't be
> > larger than 1 << (16 - 5), which would be a mask of 0x7ff, but as there
> > are only 32 zregs and 16 pregs so we should use 0x1f and 0xf respectively.
> 
> I don't object to that.  How about this sort of thing:
> 
> #include <asm/sve_context.h>
> 
> #define KVM_ARM64_SVE_NUM_ZREGS __SVE_NUM_ZREGS
> #define KVM_ARM64_SVE_NUM_PREGS __SVE_NUM_PREGS
> 
> #define KVM_ARM64_SVE_MAX_SLICES 32
> 
> ZREGs:
> 	... | (((n) & (KVM_ARM64_SVE_NUM_ZREGS - 1)) << 5) |
> 		((i) & (KVM_ARM64_SVE_MAX_SLICES - 1))
> 
> 
> The shadow _NUM_xREGS defines are sort of overkill, but
> <asm/sigcontext.h> is not really appropriate to include here.
> <asm/sve_context.h> is intended as a backend only, and I prefer to hide
> it behind other headers.

Looks good to me

> 
> 
> > > +#define KVM_REG_ARM64_SVE_FFR(i)	KVM_REG_ARM64_SVE_PREG(16, i)
> > 
> > Since this is user api and a user may want to construct their own register
> > indices, then shouldn't we instead provide KVM_REG_ARM64_SVE_FFR_BASE as
> > 
> >  #define KVM_REG_ARM64_SVE_FFR_BASE KVM_REG_ARM64_SVE_PREG_BASE | (16 << 5)
> 
> Can do, or just
> 
> #define KVM_REG_ARM64_SVE_FFR_BASE KVM_REG_ARM64_SVE_PREG(0, 0)

I don't see how this would work for an FFR base.

> 
> (which is what I tend to do elsewhere).
> 
> > and then KVM_REG_ARM64_SVE_FFR(i) would follow the typical pattern
> > 
> >  #define KVM_REG_ARM64_SVE_FFR(i) (KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
> >                                    KVM_REG_ARM64_SVE_FFR_BASE | \
> >                                    KVM_REG_SIZE_U256 | (i))
> 
> Yes, we could do that.
> 
> > 
> > > +
> > >  /* Device Control API: ARM VGIC */
> > >  #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
> > >  #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
> > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > index 756d0d6..736d8cb 100644
> > > --- a/arch/arm64/kvm/guest.c
> > > +++ b/arch/arm64/kvm/guest.c
> > > @@ -19,8 +19,11 @@
> > >   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> > >   */
> > >  
> > > +#include <linux/bits.h>
> > >  #include <linux/errno.h>
> > >  #include <linux/err.h>
> > > +#include <linux/nospec.h>
> > > +#include <linux/kernel.h>
> > >  #include <linux/kvm_host.h>
> > >  #include <linux/module.h>
> > >  #include <linux/stddef.h>
> > > @@ -30,9 +33,12 @@
> > >  #include <kvm/arm_psci.h>
> > >  #include <asm/cputype.h>
> > >  #include <linux/uaccess.h>
> > > +#include <asm/fpsimd.h>
> > >  #include <asm/kvm.h>
> > >  #include <asm/kvm_emulate.h>
> > >  #include <asm/kvm_coproc.h>
> > > +#include <asm/kvm_host.h>
> > > +#include <asm/sigcontext.h>
> > >  
> > >  #include "trace.h"
> > >  
> > > @@ -200,6 +206,115 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >  	return err;
> > >  }
> > >  
> > > +#define SVE_REG_SLICE_SHIFT	0
> > > +#define SVE_REG_SLICE_BITS	5
> > > +#define SVE_REG_ID_SHIFT	(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS)
> > > +#define SVE_REG_ID_BITS		5
> > > +
> > > +#define SVE_REG_SLICE_MASK					\
> > > +	GENMASK(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS - 1,	\
> > > +		SVE_REG_SLICE_SHIFT)
> > > +#define SVE_REG_ID_MASK							\
> > > +	GENMASK(SVE_REG_ID_SHIFT + SVE_REG_ID_BITS - 1, SVE_REG_ID_SHIFT)
> > > +
> > > +#define SVE_NUM_SLICES (1 << SVE_REG_SLICE_BITS)
> > > +
> > > +#define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0))
> > > +#define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0))
> > > +
> > > +/* Bounds of a single SVE register slice within vcpu->arch.sve_state */
> > > +struct sve_state_reg_region {
> > > +	unsigned int koffset;	/* offset into sve_state in kernel memory */
> > > +	unsigned int klen;	/* length in kernel memory */
> > > +	unsigned int upad;	/* extra trailing padding in user memory */
> > > +};
> > > +
> > > +/* Get sanitised bounds for user/kernel SVE register copy */
> > > +static int sve_reg_to_region(struct sve_state_reg_region *region,
> > > +			     struct kvm_vcpu *vcpu,
> > > +			     const struct kvm_one_reg *reg)
> > > +{
> > > +	/* reg ID ranges for Z- registers */
> > > +	const u64 zreg_id_min = KVM_REG_ARM64_SVE_ZREG(0, 0);
> > > +	const u64 zreg_id_max = KVM_REG_ARM64_SVE_ZREG(SVE_NUM_ZREGS - 1,
> > > +						       SVE_NUM_SLICES - 1);
> > > +
> > > +	/* reg ID ranges for P- registers and FFR (which are contiguous) */
> > > +	const u64 preg_id_min = KVM_REG_ARM64_SVE_PREG(0, 0);
> > > +	const u64 preg_id_max = KVM_REG_ARM64_SVE_FFR(SVE_NUM_SLICES - 1);
> > > +
> > > +	unsigned int vq;
> > > +	unsigned int reg_num;
> > > +
> > > +	unsigned int reqoffset, reqlen; /* User-requested offset and length */
> > > +	unsigned int maxlen; /* Maxmimum permitted length */
> > > +
> > > +	size_t sve_state_size;
> > > +
> > > +	/* Only the first slice ever exists, for now: */
> > > +	if ((reg->id & SVE_REG_SLICE_MASK) != 0)
> > > +		return -ENOENT;
> > > +
> > > +	vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
> > > +
> > > +	reg_num = (reg->id & SVE_REG_ID_MASK) >> SVE_REG_ID_SHIFT;
> > > +
> > > +	if (reg->id >= zreg_id_min && reg->id <= zreg_id_max) {
> > > +		reqoffset = SVE_SIG_ZREG_OFFSET(vq, reg_num) -
> > > +				SVE_SIG_REGS_OFFSET;
> > > +		reqlen = KVM_SVE_ZREG_SIZE;
> > > +		maxlen = SVE_SIG_ZREG_SIZE(vq);
> > > +	} else if (reg->id >= preg_id_min && reg->id <= preg_id_max) {
> > > +		reqoffset = SVE_SIG_PREG_OFFSET(vq, reg_num) -
> > > +				SVE_SIG_REGS_OFFSET;
> > > +		reqlen = KVM_SVE_PREG_SIZE;
> > > +		maxlen = SVE_SIG_PREG_SIZE(vq);
> > > +	} else {
> > > +		return -ENOENT;
> > > +	}
> > > +
> > > +	sve_state_size = vcpu_sve_state_size(vcpu);
> > > +	if (!sve_state_size)
> > > +		return -EINVAL;
> > > +
> > > +	region->koffset = array_index_nospec(reqoffset, sve_state_size);
> > > +	region->klen = min(maxlen, reqlen);
> > > +	region->upad = reqlen - region->klen;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > +{
> > > +	struct sve_state_reg_region region;
> > > +	char __user *uptr = (char __user *)reg->addr;
> > > +
> > > +	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> > > +		return -ENOENT;
> > 
> > sve_reg_to_region() can return EINVAL, but here it would get changed to
> > ENOENT.
> 
> Hmm, I'd say the affected code in sve_reg_to_region() should really be
> a WARN_ON(): we're not supposed to hit it because we can't get here
> until the vcpu is finalized.  It's really just a defensive check before
> dividing by some potentially invalid value.  In such a case, it's
> reasonable to have that EINVAL show through to userspace.

Adding the WARN_ON is a good idea. The thing is that the EINVAL is *not*
going to show through to userspace. ENOENT will. Which might be fine,
but if so, then it would clear things up to just return ENOENT in
sve_reg_to_region() as well.

> 
> Does that make sense?
> 
> > > +
> > > +	if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
> > > +			 region.klen) ||
> > > +	    clear_user(uptr + region.klen, region.upad))
> > > +		return -EFAULT;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > +{
> > > +	struct sve_state_reg_region region;
> > > +	const char __user *uptr = (const char __user *)reg->addr;
> > > +
> > > +	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> > > +		return -ENOENT;
> > 
> > Same as above.
> 
> Ditto
> 
> > > +
> > > +	if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
> > > +			   region.klen))
> > > +		return -EFAULT;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > >  int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
> > >  {
> > >  	return -EINVAL;
> > > @@ -346,12 +461,12 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >  	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
> > >  		return -EINVAL;
> > >  
> > > -	/* Register group 16 means we want a core register. */
> > > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
> > > -		return get_core_reg(vcpu, reg);
> > > -
> > > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
> > > -		return kvm_arm_get_fw_reg(vcpu, reg);
> > > +	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > > +	case KVM_REG_ARM_CORE:	return get_core_reg(vcpu, reg);
> > > +	case KVM_REG_ARM_FW:	return kvm_arm_get_fw_reg(vcpu, reg);
> > > +	case KVM_REG_ARM64_SVE:	return get_sve_reg(vcpu, reg);
> > > +	default: break; /* fall through */
> > 
> > This case has a 'break', so it's not a 'fall through'. Do we require
> > default cases even when they're unused? If not, why have it?
> 
> My reason for having that was to highlight that we fall through to the
> code following the switch only in this case, because the other cases
> all consist of return statements.

I think it's pretty clear from the 'case,return' pattern what's going on
and the default case isn't needed at all. And since the fall through
comment is typically used to document why there is not a break, then
having both looks weird.

> 
> > > +	}
> > >  
> > >  	if (is_timer_reg(reg->id))
> > >  		return get_timer_reg(vcpu, reg);
> > > @@ -365,12 +480,12 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >  	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
> > >  		return -EINVAL;
> > >  
> > > -	/* Register group 16 means we set a core register. */
> > > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
> > > -		return set_core_reg(vcpu, reg);
> > > -
> > > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
> > > -		return kvm_arm_set_fw_reg(vcpu, reg);
> > > +	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > > +	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
> > > +	case KVM_REG_ARM_FW:	return kvm_arm_set_fw_reg(vcpu, reg);
> > > +	case KVM_REG_ARM64_SVE:	return set_sve_reg(vcpu, reg);
> > > +	default: break; /* fall through */
> > 
> > Same as above.
> 
> I could move the trailing code into the default case, but that felt a
> bit ugly.
> 
> Thoughts?

I'd remove the default case :)

Thanks,
drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 21/27] KVM: arm/arm64: Add hook for arch-specific KVM initialisation
  2019-04-04 14:53       ` Dave Martin
@ 2019-04-04 16:33         ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 16:33 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 03:53:55PM +0100, Dave Martin wrote:
> On Thu, Apr 04, 2019 at 04:25:28PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:46PM +0000, Dave Martin wrote:
> > > This patch adds a kvm_arm_init_arch_resources() hook to perform
> > > subarch-specific initialisation when starting up KVM.
> > > 
> > > This will be used in a subsequent patch for global SVE-related
> > > setup on arm64.
> > > 
> > > No functional change.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > ---
> > >  arch/arm/include/asm/kvm_host.h   | 2 ++
> > >  arch/arm64/include/asm/kvm_host.h | 2 ++
> > >  virt/kvm/arm/arm.c                | 4 ++++
> > >  3 files changed, 8 insertions(+)
> > > 
> > > diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> > > index 770d732..a49ee01 100644
> > > --- a/arch/arm/include/asm/kvm_host.h
> > > +++ b/arch/arm/include/asm/kvm_host.h
> > > @@ -53,6 +53,8 @@
> > >  
> > >  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> > >  
> > > +static inline int kvm_arm_init_arch_resources(void) { return 0; }
> > > +
> > >  u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
> > >  int __attribute_const__ kvm_target_cpu(void);
> > >  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > index 205438a..3e89509 100644
> > > --- a/arch/arm64/include/asm/kvm_host.h
> > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > @@ -58,6 +58,8 @@
> > >  
> > >  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> > >  
> > > +static inline int kvm_arm_init_arch_resources(void) { return 0; }
> > > +
> > >  int __attribute_const__ kvm_target_cpu(void);
> > >  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> > >  int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext);
> > > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > > index 99c3738..c69e137 100644
> > > --- a/virt/kvm/arm/arm.c
> > > +++ b/virt/kvm/arm/arm.c
> > > @@ -1664,6 +1664,10 @@ int kvm_arch_init(void *opaque)
> > >  	if (err)
> > >  		return err;
> > >  
> > > +	err = kvm_arm_init_arch_resources();
> > > +	if (err)
> > > +		return err;
> > > +
> > >  	if (!in_hyp_mode) {
> > >  		err = init_hyp_mode();
> > >  		if (err)
> > > -- 
> > > 2.1.4
> > >
> > 
> > It's not clear to me from the commit message why init_common_resources()
> > won't work for this. Maybe it'll be more clear as I continue the review.
> 
> init_common_resources() is for stuff common to arm and arm64.

Well currently init_common_resources() only calls kvm_set_ipa_limit(),
which isn't implemented for arm. So if there was a plan to only use
that function for init that actually does something on both, it doesn't.

> 
> kvm_arm_init_arch_resources() is intended for stuff specific to the
> particular arch backend.

I'm not sure we need that yet. We just need an arm setup sve stub like
arm's kvm_set_ipa_limit() stub. OTOH, if we have to keep adding stubs
to arm we should probably have something like
kvm_arm_init_arch_resources() instead, and kvm_set_ipa_limit() should
be moved inside the arm64 one and the arm ipa limit stub can go. Then
since init_common_resources() would no longer be used, it could just
be deleted.

> 
> Maybe there is a better name for this.
>

The name is fine for me.

Thanks,
drew 

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

* Re: [PATCH v7 21/27] KVM: arm/arm64: Add hook for arch-specific KVM initialisation
@ 2019-04-04 16:33         ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 16:33 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 03:53:55PM +0100, Dave Martin wrote:
> On Thu, Apr 04, 2019 at 04:25:28PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:46PM +0000, Dave Martin wrote:
> > > This patch adds a kvm_arm_init_arch_resources() hook to perform
> > > subarch-specific initialisation when starting up KVM.
> > > 
> > > This will be used in a subsequent patch for global SVE-related
> > > setup on arm64.
> > > 
> > > No functional change.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > ---
> > >  arch/arm/include/asm/kvm_host.h   | 2 ++
> > >  arch/arm64/include/asm/kvm_host.h | 2 ++
> > >  virt/kvm/arm/arm.c                | 4 ++++
> > >  3 files changed, 8 insertions(+)
> > > 
> > > diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> > > index 770d732..a49ee01 100644
> > > --- a/arch/arm/include/asm/kvm_host.h
> > > +++ b/arch/arm/include/asm/kvm_host.h
> > > @@ -53,6 +53,8 @@
> > >  
> > >  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> > >  
> > > +static inline int kvm_arm_init_arch_resources(void) { return 0; }
> > > +
> > >  u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
> > >  int __attribute_const__ kvm_target_cpu(void);
> > >  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > > index 205438a..3e89509 100644
> > > --- a/arch/arm64/include/asm/kvm_host.h
> > > +++ b/arch/arm64/include/asm/kvm_host.h
> > > @@ -58,6 +58,8 @@
> > >  
> > >  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> > >  
> > > +static inline int kvm_arm_init_arch_resources(void) { return 0; }
> > > +
> > >  int __attribute_const__ kvm_target_cpu(void);
> > >  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> > >  int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext);
> > > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > > index 99c3738..c69e137 100644
> > > --- a/virt/kvm/arm/arm.c
> > > +++ b/virt/kvm/arm/arm.c
> > > @@ -1664,6 +1664,10 @@ int kvm_arch_init(void *opaque)
> > >  	if (err)
> > >  		return err;
> > >  
> > > +	err = kvm_arm_init_arch_resources();
> > > +	if (err)
> > > +		return err;
> > > +
> > >  	if (!in_hyp_mode) {
> > >  		err = init_hyp_mode();
> > >  		if (err)
> > > -- 
> > > 2.1.4
> > >
> > 
> > It's not clear to me from the commit message why init_common_resources()
> > won't work for this. Maybe it'll be more clear as I continue the review.
> 
> init_common_resources() is for stuff common to arm and arm64.

Well currently init_common_resources() only calls kvm_set_ipa_limit(),
which isn't implemented for arm. So if there was a plan to only use
that function for init that actually does something on both, it doesn't.

> 
> kvm_arm_init_arch_resources() is intended for stuff specific to the
> particular arch backend.

I'm not sure we need that yet. We just need an arm setup sve stub like
arm's kvm_set_ipa_limit() stub. OTOH, if we have to keep adding stubs
to arm we should probably have something like
kvm_arm_init_arch_resources() instead, and kvm_set_ipa_limit() should
be moved inside the arm64 one and the arm ipa limit stub can go. Then
since init_common_resources() would no longer be used, it could just
be deleted.

> 
> Maybe there is a better name for this.
>

The name is fine for me.

Thanks,
drew 

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 22/27] KVM: arm/arm64: Add KVM_ARM_VCPU_FINALIZE ioctl
  2019-04-04 15:07     ` Andrew Jones
@ 2019-04-04 16:47       ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04 16:47 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 05:07:09PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:47PM +0000, Dave Martin wrote:
> > Some aspects of vcpu configuration may be too complex to be
> > completed inside KVM_ARM_VCPU_INIT.  Thus, there may be a
> > requirement for userspace to do some additional configuration
> > before various other ioctls will work in a consistent way.
> > 
> > In particular this will be the case for SVE, where userspace will
> > need to negotiate the set of vector lengths to be made available to
> > the guest before the vcpu becomes fully usable.
> > 
> > In order to provide an explicit way for userspace to confirm that
> > it has finished setting up a particular vcpu feature, this patch
> > adds a new ioctl KVM_ARM_VCPU_FINALIZE.
> > 
> > When userspace has opted into a feature that requires finalization,
> > typically by means of a feature flag passed to KVM_ARM_VCPU_INIT, a
> > matching call to KVM_ARM_VCPU_FINALIZE is now required before
> > KVM_RUN or KVM_GET_REG_LIST is allowed.  Individual features may
> > impose additional restrictions where appropriate.
> > 
> > No existing vcpu features are affected by this, so current
> > userspace implementations will continue to work exactly as before,
> > with no need to issue KVM_ARM_VCPU_FINALIZE.
> > 
> > As implemented in this patch, KVM_ARM_VCPU_FINALIZE is currently a
> > placeholder: no finalizable features exist yet, so ioctl is not
> > required and will always yield EINVAL.  Subsequent patches will add
> > the finalization logic to make use of this ioctl for SVE.
> > 
> > No functional change for existing userspace.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > 
> > ---
> > 
> > Changes since v5:
> > 
> >  * Commit message, including subject line, rewritten.
> > 
> >    This patch is a rework of "KVM: arm/arm64: Add hook to finalize the
> >    vcpu configuration".  The old subject line and commit message no
> >    longer accurately described what the patch does.  However, the code
> >    is an evolution of the previous patch rather than a wholesale
> >    rewrite.
> > 
> >  * Added an explicit KVM_ARM_VCPU_FINALIZE ioctl, rather than just
> >    providing internal hooks in the kernel to finalize the vcpu
> >    configuration implicitly.  This allows userspace to confirm exactly
> >    when it has finished configuring the vcpu and is ready to use it.
> > 
> >    This results in simpler (and hopefully more maintainable) ioctl
> >    ordering rules.
> > ---
> >  arch/arm/include/asm/kvm_host.h   |  4 ++++
> >  arch/arm64/include/asm/kvm_host.h |  4 ++++
> >  include/uapi/linux/kvm.h          |  3 +++
> >  virt/kvm/arm/arm.c                | 18 ++++++++++++++++++
> >  4 files changed, 29 insertions(+)
> > 
> > diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> > index a49ee01..e80cfc1 100644
> > --- a/arch/arm/include/asm/kvm_host.h
> > +++ b/arch/arm/include/asm/kvm_host.h
> > @@ -19,6 +19,7 @@
> >  #ifndef __ARM_KVM_HOST_H__
> >  #define __ARM_KVM_HOST_H__
> >  
> > +#include <linux/errno.h>
> >  #include <linux/types.h>
> >  #include <linux/kvm_types.h>
> >  #include <asm/cputype.h>
> > @@ -411,4 +412,7 @@ static inline int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type)
> >  	return 0;
> >  }
> >  
> > +#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
> > +#define kvm_arm_vcpu_is_finalized(vcpu) true
> > +
> 
> We usually use inline functions for the stubs.

I guess we could.

The vcpu_has_sve() circular include problem applies here too if we put
the actual function bodies here, which is why I ended up with this.  Now
that the bodies (for arm64) are out of line, it actually doesn't matter.

> >  #endif /* __ARM_KVM_HOST_H__ */
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 3e89509..98658f7 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -23,6 +23,7 @@
> >  #define __ARM64_KVM_HOST_H__
> >  
> >  #include <linux/bitmap.h>
> > +#include <linux/errno.h>
> >  #include <linux/types.h>
> >  #include <linux/jump_label.h>
> >  #include <linux/kvm_types.h>
> > @@ -625,4 +626,7 @@ void kvm_arch_free_vm(struct kvm *kvm);
> >  
> >  int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type);
> >  
> > +#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
> > +#define kvm_arm_vcpu_is_finalized(vcpu) true
> 
> Same as above.

Ditto

> > +
> >  #endif /* __ARM64_KVM_HOST_H__ */
> > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> > index dc77a5a..c3b8e7a 100644
> > --- a/include/uapi/linux/kvm.h
> > +++ b/include/uapi/linux/kvm.h
> > @@ -1441,6 +1441,9 @@ struct kvm_enc_region {
> >  /* Available with KVM_CAP_HYPERV_CPUID */
> >  #define KVM_GET_SUPPORTED_HV_CPUID _IOWR(KVMIO, 0xc1, struct kvm_cpuid2)
> >  
> > +/* Available with KVM_CAP_ARM_SVE */
> > +#define KVM_ARM_VCPU_FINALIZE	  _IOW(KVMIO,  0xc2, int)
> > +
> >  /* Secure Encrypted Virtualization command */
> >  enum sev_cmd_id {
> >  	/* Guest initialization commands */
> > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > index c69e137..9edbf0f 100644
> > --- a/virt/kvm/arm/arm.c
> > +++ b/virt/kvm/arm/arm.c
> > @@ -545,6 +545,9 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
> >  	if (likely(vcpu->arch.has_run_once))
> >  		return 0;
> >  
> > +	if (!kvm_arm_vcpu_is_finalized(vcpu))
> > +		return -EPERM;
> > +
> >  	vcpu->arch.has_run_once = true;
> >  
> >  	if (likely(irqchip_in_kernel(kvm))) {
> > @@ -1116,6 +1119,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
> >  		if (unlikely(!kvm_vcpu_initialized(vcpu)))
> >  			break;
> >  
> > +		r = -EPERM;
> > +		if (!kvm_arm_vcpu_is_finalized(vcpu))
> > +			break;
> > +
> 
> What's the rationale for using EPERM? The finalized concept is very
> similar to the initialized one. So why not also use ENOEXEC for it too?

Hmm, I guess we could equally return ENOEXEC.  Initially this felt like
a more distinctive case.

Assuming Marc is happy to take an ABI fix into kvmarm/next, I'm can
change them.  We're not absolutely committed until this hits mainline...

> >  		r = -EFAULT;
> >  		if (copy_from_user(&reg_list, user_list, sizeof(reg_list)))
> >  			break;
> > @@ -1169,6 +1176,17 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
> >  
> >  		return kvm_arm_vcpu_set_events(vcpu, &events);
> >  	}
> > +	case KVM_ARM_VCPU_FINALIZE: {
> > +		int what;
> > +
> > +		if (!kvm_vcpu_initialized(vcpu))
> > +			return -ENOEXEC;
> > +
> > +		if (get_user(what, (const int __user *)argp))
> > +			return -EFAULT;
> > +
> > +		return kvm_arm_vcpu_finalize(vcpu, what);
> 
> Almost all the cases use the 'r = ...; break;' type of pattern, leaving
> it to the 'return r' at the end of the function. I guess that's in case
> at some point more stuff is added after the switch. The only cases that
> don't do that are the most recent ones KVM_GET/SET_VCPU_EVENTS, which
> should probably be changed to fit the pattern too, rather than this
> new ioctl following there pattern.

I have no strong opinion on this: it's basically a question of style.
I followed KVM_GET/SET_VCPU_EVENTS, but you're right, the
r = ...; break; style is used for the others.

If there's an intention of putting stuff at the end of the function,
it will make a difference.  But this seems unlikely to happen: this
function is really just a dispatcher.

I'm happy to change it (and the others) if there are strong views.

Cheers
---Dave

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

* Re: [PATCH v7 22/27] KVM: arm/arm64: Add KVM_ARM_VCPU_FINALIZE ioctl
@ 2019-04-04 16:47       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04 16:47 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 05:07:09PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:47PM +0000, Dave Martin wrote:
> > Some aspects of vcpu configuration may be too complex to be
> > completed inside KVM_ARM_VCPU_INIT.  Thus, there may be a
> > requirement for userspace to do some additional configuration
> > before various other ioctls will work in a consistent way.
> > 
> > In particular this will be the case for SVE, where userspace will
> > need to negotiate the set of vector lengths to be made available to
> > the guest before the vcpu becomes fully usable.
> > 
> > In order to provide an explicit way for userspace to confirm that
> > it has finished setting up a particular vcpu feature, this patch
> > adds a new ioctl KVM_ARM_VCPU_FINALIZE.
> > 
> > When userspace has opted into a feature that requires finalization,
> > typically by means of a feature flag passed to KVM_ARM_VCPU_INIT, a
> > matching call to KVM_ARM_VCPU_FINALIZE is now required before
> > KVM_RUN or KVM_GET_REG_LIST is allowed.  Individual features may
> > impose additional restrictions where appropriate.
> > 
> > No existing vcpu features are affected by this, so current
> > userspace implementations will continue to work exactly as before,
> > with no need to issue KVM_ARM_VCPU_FINALIZE.
> > 
> > As implemented in this patch, KVM_ARM_VCPU_FINALIZE is currently a
> > placeholder: no finalizable features exist yet, so ioctl is not
> > required and will always yield EINVAL.  Subsequent patches will add
> > the finalization logic to make use of this ioctl for SVE.
> > 
> > No functional change for existing userspace.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > 
> > ---
> > 
> > Changes since v5:
> > 
> >  * Commit message, including subject line, rewritten.
> > 
> >    This patch is a rework of "KVM: arm/arm64: Add hook to finalize the
> >    vcpu configuration".  The old subject line and commit message no
> >    longer accurately described what the patch does.  However, the code
> >    is an evolution of the previous patch rather than a wholesale
> >    rewrite.
> > 
> >  * Added an explicit KVM_ARM_VCPU_FINALIZE ioctl, rather than just
> >    providing internal hooks in the kernel to finalize the vcpu
> >    configuration implicitly.  This allows userspace to confirm exactly
> >    when it has finished configuring the vcpu and is ready to use it.
> > 
> >    This results in simpler (and hopefully more maintainable) ioctl
> >    ordering rules.
> > ---
> >  arch/arm/include/asm/kvm_host.h   |  4 ++++
> >  arch/arm64/include/asm/kvm_host.h |  4 ++++
> >  include/uapi/linux/kvm.h          |  3 +++
> >  virt/kvm/arm/arm.c                | 18 ++++++++++++++++++
> >  4 files changed, 29 insertions(+)
> > 
> > diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> > index a49ee01..e80cfc1 100644
> > --- a/arch/arm/include/asm/kvm_host.h
> > +++ b/arch/arm/include/asm/kvm_host.h
> > @@ -19,6 +19,7 @@
> >  #ifndef __ARM_KVM_HOST_H__
> >  #define __ARM_KVM_HOST_H__
> >  
> > +#include <linux/errno.h>
> >  #include <linux/types.h>
> >  #include <linux/kvm_types.h>
> >  #include <asm/cputype.h>
> > @@ -411,4 +412,7 @@ static inline int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type)
> >  	return 0;
> >  }
> >  
> > +#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
> > +#define kvm_arm_vcpu_is_finalized(vcpu) true
> > +
> 
> We usually use inline functions for the stubs.

I guess we could.

The vcpu_has_sve() circular include problem applies here too if we put
the actual function bodies here, which is why I ended up with this.  Now
that the bodies (for arm64) are out of line, it actually doesn't matter.

> >  #endif /* __ARM_KVM_HOST_H__ */
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 3e89509..98658f7 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -23,6 +23,7 @@
> >  #define __ARM64_KVM_HOST_H__
> >  
> >  #include <linux/bitmap.h>
> > +#include <linux/errno.h>
> >  #include <linux/types.h>
> >  #include <linux/jump_label.h>
> >  #include <linux/kvm_types.h>
> > @@ -625,4 +626,7 @@ void kvm_arch_free_vm(struct kvm *kvm);
> >  
> >  int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type);
> >  
> > +#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
> > +#define kvm_arm_vcpu_is_finalized(vcpu) true
> 
> Same as above.

Ditto

> > +
> >  #endif /* __ARM64_KVM_HOST_H__ */
> > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> > index dc77a5a..c3b8e7a 100644
> > --- a/include/uapi/linux/kvm.h
> > +++ b/include/uapi/linux/kvm.h
> > @@ -1441,6 +1441,9 @@ struct kvm_enc_region {
> >  /* Available with KVM_CAP_HYPERV_CPUID */
> >  #define KVM_GET_SUPPORTED_HV_CPUID _IOWR(KVMIO, 0xc1, struct kvm_cpuid2)
> >  
> > +/* Available with KVM_CAP_ARM_SVE */
> > +#define KVM_ARM_VCPU_FINALIZE	  _IOW(KVMIO,  0xc2, int)
> > +
> >  /* Secure Encrypted Virtualization command */
> >  enum sev_cmd_id {
> >  	/* Guest initialization commands */
> > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > index c69e137..9edbf0f 100644
> > --- a/virt/kvm/arm/arm.c
> > +++ b/virt/kvm/arm/arm.c
> > @@ -545,6 +545,9 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
> >  	if (likely(vcpu->arch.has_run_once))
> >  		return 0;
> >  
> > +	if (!kvm_arm_vcpu_is_finalized(vcpu))
> > +		return -EPERM;
> > +
> >  	vcpu->arch.has_run_once = true;
> >  
> >  	if (likely(irqchip_in_kernel(kvm))) {
> > @@ -1116,6 +1119,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
> >  		if (unlikely(!kvm_vcpu_initialized(vcpu)))
> >  			break;
> >  
> > +		r = -EPERM;
> > +		if (!kvm_arm_vcpu_is_finalized(vcpu))
> > +			break;
> > +
> 
> What's the rationale for using EPERM? The finalized concept is very
> similar to the initialized one. So why not also use ENOEXEC for it too?

Hmm, I guess we could equally return ENOEXEC.  Initially this felt like
a more distinctive case.

Assuming Marc is happy to take an ABI fix into kvmarm/next, I'm can
change them.  We're not absolutely committed until this hits mainline...

> >  		r = -EFAULT;
> >  		if (copy_from_user(&reg_list, user_list, sizeof(reg_list)))
> >  			break;
> > @@ -1169,6 +1176,17 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
> >  
> >  		return kvm_arm_vcpu_set_events(vcpu, &events);
> >  	}
> > +	case KVM_ARM_VCPU_FINALIZE: {
> > +		int what;
> > +
> > +		if (!kvm_vcpu_initialized(vcpu))
> > +			return -ENOEXEC;
> > +
> > +		if (get_user(what, (const int __user *)argp))
> > +			return -EFAULT;
> > +
> > +		return kvm_arm_vcpu_finalize(vcpu, what);
> 
> Almost all the cases use the 'r = ...; break;' type of pattern, leaving
> it to the 'return r' at the end of the function. I guess that's in case
> at some point more stuff is added after the switch. The only cases that
> don't do that are the most recent ones KVM_GET/SET_VCPU_EVENTS, which
> should probably be changed to fit the pattern too, rather than this
> new ioctl following there pattern.

I have no strong opinion on this: it's basically a question of style.
I followed KVM_GET/SET_VCPU_EVENTS, but you're right, the
r = ...; break; style is used for the others.

If there's an intention of putting stuff at the end of the function,
it will make a difference.  But this seems unlikely to happen: this
function is really just a dispatcher.

I'm happy to change it (and the others) if there are strong views.

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 18/27] KVM: arm64/sve: Add SVE support to register access ioctl interface
  2019-04-04 16:25         ` Andrew Jones
@ 2019-04-04 16:56           ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04 16:56 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 06:25:39PM +0200, Andrew Jones wrote:
> On Thu, Apr 04, 2019 at 03:50:56PM +0100, Dave Martin wrote:
> > On Thu, Apr 04, 2019 at 03:57:06PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:43PM +0000, Dave Martin wrote:
> > > > This patch adds the following registers for access via the
> > > > KVM_{GET,SET}_ONE_REG interface:
> > > > 
> > > >  * KVM_REG_ARM64_SVE_ZREG(n, i) (n = 0..31) (in 2048-bit slices)
> > > >  * KVM_REG_ARM64_SVE_PREG(n, i) (n = 0..15) (in 256-bit slices)
> > > >  * KVM_REG_ARM64_SVE_FFR(i) (in 256-bit slices)
> > > > 
> > > > In order to adapt gracefully to future architectural extensions,
> > > > the registers are logically divided up into slices as noted above:
> > > > the i parameter denotes the slice index.
> > > > 
> > > > This allows us to reserve space in the ABI for future expansion of
> > > > these registers.  However, as of today the architecture does not
> > > > permit registers to be larger than a single slice, so no code is
> > > > needed in the kernel to expose additional slices, for now.  The
> > > > code can be extended later as needed to expose them up to a maximum
> > > > of 32 slices (as carved out in the architecture itself) if they
> > > > really exist someday.
> > > > 
> > > > The registers are only visible for vcpus that have SVE enabled.
> > > > They are not enumerated by KVM_GET_REG_LIST on vcpus that do not
> > > > have SVE.
> > > > 
> > > > Accesses to the FPSIMD registers via KVM_REG_ARM_CORE is not
> > > > allowed for SVE-enabled vcpus: SVE-aware userspace can use the
> > > > KVM_REG_ARM64_SVE_ZREG() interface instead to access the same
> > > > register state.  This avoids some complex and pointless emulation
> > > > in the kernel to convert between the two views of these aliased
> > > > registers.
> > > > 
> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

[...]

> > > > +#define KVM_REG_ARM64_SVE_FFR(i)	KVM_REG_ARM64_SVE_PREG(16, i)
> > > 
> > > Since this is user api and a user may want to construct their own register
> > > indices, then shouldn't we instead provide KVM_REG_ARM64_SVE_FFR_BASE as
> > > 
> > >  #define KVM_REG_ARM64_SVE_FFR_BASE KVM_REG_ARM64_SVE_PREG_BASE | (16 << 5)
> > 
> > Can do, or just
> > 
> > #define KVM_REG_ARM64_SVE_FFR_BASE KVM_REG_ARM64_SVE_PREG(0, 0)
> 
> I don't see how this would work for an FFR base.

Err yes, scratch that.  But I'm happy to have it, however defined.

[...]

> > > > +/* Get sanitised bounds for user/kernel SVE register copy */
> > > > +static int sve_reg_to_region(struct sve_state_reg_region *region,
> > > > +			     struct kvm_vcpu *vcpu,
> > > > +			     const struct kvm_one_reg *reg)
> > > > +{

[...]

> > > > +	sve_state_size = vcpu_sve_state_size(vcpu);
> > > > +	if (!sve_state_size)
> > > > +		return -EINVAL;
> > > > +
> > > > +	region->koffset = array_index_nospec(reqoffset, sve_state_size);
> > > > +	region->klen = min(maxlen, reqlen);
> > > > +	region->upad = reqlen - region->klen;
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > > +{
> > > > +	struct sve_state_reg_region region;
> > > > +	char __user *uptr = (char __user *)reg->addr;
> > > > +
> > > > +	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> > > > +		return -ENOENT;
> > > 
> > > sve_reg_to_region() can return EINVAL, but here it would get changed to
> > > ENOENT.
> > 
> > Hmm, I'd say the affected code in sve_reg_to_region() should really be
> > a WARN_ON(): we're not supposed to hit it because we can't get here
> > until the vcpu is finalized.  It's really just a defensive check before
> > dividing by some potentially invalid value.  In such a case, it's
> > reasonable to have that EINVAL show through to userspace.
> 
> Adding the WARN_ON is a good idea. The thing is that the EINVAL is *not*
> going to show through to userspace. ENOENT will. Which might be fine,
> but if so, then it would clear things up to just return ENOENT in
> sve_reg_to_region() as well.

I meant that we can propagate the actual return value back.

It might be better just to merge the vcpu_has_sve() check into sve_reg_to_region(), and simply have

	int ret;

	ret = sve_reg_to_region(...);
	if (ret)
		return ret;

here.

Currently we return -ENOENT for a non-SVE-enabled vcpu, even if the reg
ID is complete garbage.  It would probably be useful to tidy that up at
the same time: -EINVAL would probably be more appropriate for such
cases.

[...]

> > > >  int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
> > > >  {
> > > >  	return -EINVAL;
> > > > @@ -346,12 +461,12 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >  	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
> > > >  		return -EINVAL;
> > > >  
> > > > -	/* Register group 16 means we want a core register. */
> > > > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
> > > > -		return get_core_reg(vcpu, reg);
> > > > -
> > > > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
> > > > -		return kvm_arm_get_fw_reg(vcpu, reg);
> > > > +	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > > > +	case KVM_REG_ARM_CORE:	return get_core_reg(vcpu, reg);
> > > > +	case KVM_REG_ARM_FW:	return kvm_arm_get_fw_reg(vcpu, reg);
> > > > +	case KVM_REG_ARM64_SVE:	return get_sve_reg(vcpu, reg);
> > > > +	default: break; /* fall through */
> > > 
> > > This case has a 'break', so it's not a 'fall through'. Do we require
> > > default cases even when they're unused? If not, why have it?
> > 
> > My reason for having that was to highlight that we fall through to the
> > code following the switch only in this case, because the other cases
> > all consist of return statements.
> 
> I think it's pretty clear from the 'case,return' pattern what's going on
> and the default case isn't needed at all. And since the fall through
> comment is typically used to document why there is not a break, then
> having both looks weird.

Sure, I'm more than happy to remove the redundant default case if you
feel its presence is confusing rather than helpful.

I didn't want it to look like the switch() was supposed to be exhaustive,
but the presence of code after it _should_ make that obvious.

> > 
> > > > +	}
> > > >  
> > > >  	if (is_timer_reg(reg->id))
> > > >  		return get_timer_reg(vcpu, reg);
> > > > @@ -365,12 +480,12 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >  	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
> > > >  		return -EINVAL;
> > > >  
> > > > -	/* Register group 16 means we set a core register. */
> > > > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
> > > > -		return set_core_reg(vcpu, reg);
> > > > -
> > > > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
> > > > -		return kvm_arm_set_fw_reg(vcpu, reg);
> > > > +	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > > > +	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
> > > > +	case KVM_REG_ARM_FW:	return kvm_arm_set_fw_reg(vcpu, reg);
> > > > +	case KVM_REG_ARM64_SVE:	return set_sve_reg(vcpu, reg);
> > > > +	default: break; /* fall through */
> > > 
> > > Same as above.
> > 
> > I could move the trailing code into the default case, but that felt a
> > bit ugly.
> > 
> > Thoughts?
> 
> I'd remove the default case :)

OK

Cheers
---Dave

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

* Re: [PATCH v7 18/27] KVM: arm64/sve: Add SVE support to register access ioctl interface
@ 2019-04-04 16:56           ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-04 16:56 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 06:25:39PM +0200, Andrew Jones wrote:
> On Thu, Apr 04, 2019 at 03:50:56PM +0100, Dave Martin wrote:
> > On Thu, Apr 04, 2019 at 03:57:06PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:43PM +0000, Dave Martin wrote:
> > > > This patch adds the following registers for access via the
> > > > KVM_{GET,SET}_ONE_REG interface:
> > > > 
> > > >  * KVM_REG_ARM64_SVE_ZREG(n, i) (n = 0..31) (in 2048-bit slices)
> > > >  * KVM_REG_ARM64_SVE_PREG(n, i) (n = 0..15) (in 256-bit slices)
> > > >  * KVM_REG_ARM64_SVE_FFR(i) (in 256-bit slices)
> > > > 
> > > > In order to adapt gracefully to future architectural extensions,
> > > > the registers are logically divided up into slices as noted above:
> > > > the i parameter denotes the slice index.
> > > > 
> > > > This allows us to reserve space in the ABI for future expansion of
> > > > these registers.  However, as of today the architecture does not
> > > > permit registers to be larger than a single slice, so no code is
> > > > needed in the kernel to expose additional slices, for now.  The
> > > > code can be extended later as needed to expose them up to a maximum
> > > > of 32 slices (as carved out in the architecture itself) if they
> > > > really exist someday.
> > > > 
> > > > The registers are only visible for vcpus that have SVE enabled.
> > > > They are not enumerated by KVM_GET_REG_LIST on vcpus that do not
> > > > have SVE.
> > > > 
> > > > Accesses to the FPSIMD registers via KVM_REG_ARM_CORE is not
> > > > allowed for SVE-enabled vcpus: SVE-aware userspace can use the
> > > > KVM_REG_ARM64_SVE_ZREG() interface instead to access the same
> > > > register state.  This avoids some complex and pointless emulation
> > > > in the kernel to convert between the two views of these aliased
> > > > registers.
> > > > 
> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

[...]

> > > > +#define KVM_REG_ARM64_SVE_FFR(i)	KVM_REG_ARM64_SVE_PREG(16, i)
> > > 
> > > Since this is user api and a user may want to construct their own register
> > > indices, then shouldn't we instead provide KVM_REG_ARM64_SVE_FFR_BASE as
> > > 
> > >  #define KVM_REG_ARM64_SVE_FFR_BASE KVM_REG_ARM64_SVE_PREG_BASE | (16 << 5)
> > 
> > Can do, or just
> > 
> > #define KVM_REG_ARM64_SVE_FFR_BASE KVM_REG_ARM64_SVE_PREG(0, 0)
> 
> I don't see how this would work for an FFR base.

Err yes, scratch that.  But I'm happy to have it, however defined.

[...]

> > > > +/* Get sanitised bounds for user/kernel SVE register copy */
> > > > +static int sve_reg_to_region(struct sve_state_reg_region *region,
> > > > +			     struct kvm_vcpu *vcpu,
> > > > +			     const struct kvm_one_reg *reg)
> > > > +{

[...]

> > > > +	sve_state_size = vcpu_sve_state_size(vcpu);
> > > > +	if (!sve_state_size)
> > > > +		return -EINVAL;
> > > > +
> > > > +	region->koffset = array_index_nospec(reqoffset, sve_state_size);
> > > > +	region->klen = min(maxlen, reqlen);
> > > > +	region->upad = reqlen - region->klen;
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > > +{
> > > > +	struct sve_state_reg_region region;
> > > > +	char __user *uptr = (char __user *)reg->addr;
> > > > +
> > > > +	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> > > > +		return -ENOENT;
> > > 
> > > sve_reg_to_region() can return EINVAL, but here it would get changed to
> > > ENOENT.
> > 
> > Hmm, I'd say the affected code in sve_reg_to_region() should really be
> > a WARN_ON(): we're not supposed to hit it because we can't get here
> > until the vcpu is finalized.  It's really just a defensive check before
> > dividing by some potentially invalid value.  In such a case, it's
> > reasonable to have that EINVAL show through to userspace.
> 
> Adding the WARN_ON is a good idea. The thing is that the EINVAL is *not*
> going to show through to userspace. ENOENT will. Which might be fine,
> but if so, then it would clear things up to just return ENOENT in
> sve_reg_to_region() as well.

I meant that we can propagate the actual return value back.

It might be better just to merge the vcpu_has_sve() check into sve_reg_to_region(), and simply have

	int ret;

	ret = sve_reg_to_region(...);
	if (ret)
		return ret;

here.

Currently we return -ENOENT for a non-SVE-enabled vcpu, even if the reg
ID is complete garbage.  It would probably be useful to tidy that up at
the same time: -EINVAL would probably be more appropriate for such
cases.

[...]

> > > >  int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
> > > >  {
> > > >  	return -EINVAL;
> > > > @@ -346,12 +461,12 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >  	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
> > > >  		return -EINVAL;
> > > >  
> > > > -	/* Register group 16 means we want a core register. */
> > > > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
> > > > -		return get_core_reg(vcpu, reg);
> > > > -
> > > > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
> > > > -		return kvm_arm_get_fw_reg(vcpu, reg);
> > > > +	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > > > +	case KVM_REG_ARM_CORE:	return get_core_reg(vcpu, reg);
> > > > +	case KVM_REG_ARM_FW:	return kvm_arm_get_fw_reg(vcpu, reg);
> > > > +	case KVM_REG_ARM64_SVE:	return get_sve_reg(vcpu, reg);
> > > > +	default: break; /* fall through */
> > > 
> > > This case has a 'break', so it's not a 'fall through'. Do we require
> > > default cases even when they're unused? If not, why have it?
> > 
> > My reason for having that was to highlight that we fall through to the
> > code following the switch only in this case, because the other cases
> > all consist of return statements.
> 
> I think it's pretty clear from the 'case,return' pattern what's going on
> and the default case isn't needed at all. And since the fall through
> comment is typically used to document why there is not a break, then
> having both looks weird.

Sure, I'm more than happy to remove the redundant default case if you
feel its presence is confusing rather than helpful.

I didn't want it to look like the switch() was supposed to be exhaustive,
but the presence of code after it _should_ make that obvious.

> > 
> > > > +	}
> > > >  
> > > >  	if (is_timer_reg(reg->id))
> > > >  		return get_timer_reg(vcpu, reg);
> > > > @@ -365,12 +480,12 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >  	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
> > > >  		return -EINVAL;
> > > >  
> > > > -	/* Register group 16 means we set a core register. */
> > > > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
> > > > -		return set_core_reg(vcpu, reg);
> > > > -
> > > > -	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
> > > > -		return kvm_arm_set_fw_reg(vcpu, reg);
> > > > +	switch (reg->id & KVM_REG_ARM_COPROC_MASK) {
> > > > +	case KVM_REG_ARM_CORE:	return set_core_reg(vcpu, reg);
> > > > +	case KVM_REG_ARM_FW:	return kvm_arm_set_fw_reg(vcpu, reg);
> > > > +	case KVM_REG_ARM64_SVE:	return set_sve_reg(vcpu, reg);
> > > > +	default: break; /* fall through */
> > > 
> > > Same as above.
> > 
> > I could move the trailing code into the default case, but that felt a
> > bit ugly.
> > 
> > Thoughts?
> 
> I'd remove the default case :)

OK

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-04 20:18     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 20:18 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> allow userspace to set and query the set of vector lengths visible
> to the guest.
> 
> In the future, multiple register slices per SVE register may be
> visible through the ioctl interface.  Once the set of slices has
> been determined we would not be able to allow the vector length set
> to be changed any more, in order to avoid userspace seeing
> inconsistent sets of registers.  For this reason, this patch adds
> support for explicit finalization of the SVE configuration via the
> KVM_ARM_VCPU_FINALIZE ioctl.
> 
> Finalization is the proper place to allocate the SVE register state
> storage in vcpu->arch.sve_state, so this patch adds that as
> appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> was previously a no-op on arm64.
> 
> To simplify the logic for determining what vector lengths can be
> supported, some code is added to KVM init to work this out, in the
> kvm_arm_init_arch_resources() hook.
> 
> The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> Subsequent patches will allow SVE to be turned on for guest vcpus,
> making it visible.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * [Julien Thierry] Delete overzealous BUILD_BUG_ON() checks.
>    It also turns out that these could cause kernel build failures in
>    some configurations, even though the checked condition is compile-
>    time constant.
> 
>    Because of the way the affected functions are called, the checks
>    are superfluous, so the simplest option is simply to get rid of
>    them.
> 
>  * [Julien Thierry] Free vcpu->arch.sve_state (if any) in
>    kvm_arch_vcpu_uninit() (which is currently a no-op).
> 
>    This was accidentally lost during a previous rebase.
> 
>  * Add kvm_arm_init_arch_resources() hook, and use it to probe SVE
>    configuration for KVM, to avoid duplicating the logic elsewhere.
>    We only need to do this once.
> 
>  * Move sve_state buffer allocation to kvm_arm_vcpu_finalize().
> 
>    As well as making the code more straightforward, this avoids the
>    need to allocate memory in kvm_reset_vcpu(), the meat of which is
>    non-preemptible since commit 358b28f09f0a ("arm/arm64: KVM: Allow a
>    VCPU to fully reset itself").
> 
>    The refactoring means that if this has not been done by the time
>    we hit KVM_RUN, then this allocation will happen on the
>    kvm_arm_first_run_init() path, where preemption remains enabled.
> 
>  * Add a couple of comments in {get,set}_sve_reg() to make the handling
>    of the KVM_REG_ARM64_SVE_VLS special case a little clearer.
> 
>  * Move mis-split rework to avoid put_user() being the correct size
>    by accident in KVM_GET_REG_LIST to KVM: arm64: Enumerate SVE register
>    indices for KVM_GET_REG_LIST.
> 
>  * Fix wrong WARN_ON() check sense when checking whether the
>    implementation may needs move SVE register slices than KVM can
>    support.
> 
>  * Fix erroneous setting of vcpu->arch.sve_max_vl based on stale loop
>    control veriable vq.
> 
>  * Move definition of KVM_ARM_VCPU_SVE from KVM: arm64/sve: Allow
>    userspace to enable SVE for vcpus.
> 
>  * Migrate to explicit finalization of the SVE configuration, using
>    KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
> ---
>  arch/arm64/include/asm/kvm_host.h |  15 +++--
>  arch/arm64/include/uapi/asm/kvm.h |   5 ++
>  arch/arm64/kvm/guest.c            | 114 +++++++++++++++++++++++++++++++++++++-
>  arch/arm64/kvm/reset.c            |  89 +++++++++++++++++++++++++++++
>  4 files changed, 215 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 98658f7..5475cc4 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -23,7 +23,6 @@
>  #define __ARM64_KVM_HOST_H__
>  
>  #include <linux/bitmap.h>
> -#include <linux/errno.h>
>  #include <linux/types.h>
>  #include <linux/jump_label.h>
>  #include <linux/kvm_types.h>
> @@ -50,6 +49,7 @@
>  
>  #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
>  
> +/* Will be incremented when KVM_ARM_VCPU_SVE is fully implemented: */
>  #define KVM_VCPU_MAX_FEATURES 4
>  
>  #define KVM_REQ_SLEEP \
> @@ -59,10 +59,12 @@
>  
>  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
>  
> -static inline int kvm_arm_init_arch_resources(void) { return 0; }
> +extern unsigned int kvm_sve_max_vl;
> +int kvm_arm_init_arch_resources(void);
>  
>  int __attribute_const__ kvm_target_cpu(void);
>  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> +void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu);
>  int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext);
>  void __extended_idmap_trampoline(phys_addr_t boot_pgd, phys_addr_t idmap_start);
>  
> @@ -353,6 +355,7 @@ struct kvm_vcpu_arch {
>  #define KVM_ARM64_HOST_SVE_IN_USE	(1 << 3) /* backup for host TIF_SVE */
>  #define KVM_ARM64_HOST_SVE_ENABLED	(1 << 4) /* SVE enabled for EL0 */
>  #define KVM_ARM64_GUEST_HAS_SVE		(1 << 5) /* SVE exposed to guest */
> +#define KVM_ARM64_VCPU_SVE_FINALIZED	(1 << 6) /* SVE config completed */
>  
>  #define vcpu_has_sve(vcpu) (system_supports_sve() && \
>  			    ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))
> @@ -525,7 +528,6 @@ static inline bool kvm_arch_requires_vhe(void)
>  
>  static inline void kvm_arch_hardware_unsetup(void) {}
>  static inline void kvm_arch_sync_events(struct kvm *kvm) {}
> -static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {}
>  static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
>  static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {}
>  
> @@ -626,7 +628,10 @@ void kvm_arch_free_vm(struct kvm *kvm);
>  
>  int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type);
>  
> -#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
> -#define kvm_arm_vcpu_is_finalized(vcpu) true
> +int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what);
> +bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
> +
> +#define kvm_arm_vcpu_sve_finalized(vcpu) \
> +	((vcpu)->arch.flags & KVM_ARM64_VCPU_SVE_FINALIZED)
>  
>  #endif /* __ARM64_KVM_HOST_H__ */
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index ced760c..6963b7e 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -102,6 +102,7 @@ struct kvm_regs {
>  #define KVM_ARM_VCPU_EL1_32BIT		1 /* CPU running a 32bit VM */
>  #define KVM_ARM_VCPU_PSCI_0_2		2 /* CPU uses PSCI v0.2 */
>  #define KVM_ARM_VCPU_PMU_V3		3 /* Support guest PMUv3 */
> +#define KVM_ARM_VCPU_SVE		4 /* enable SVE for this CPU */
>  
>  struct kvm_vcpu_init {
>  	__u32 target;
> @@ -243,6 +244,10 @@ struct kvm_vcpu_events {
>  					 ((n) << 5) | (i))
>  #define KVM_REG_ARM64_SVE_FFR(i)	KVM_REG_ARM64_SVE_PREG(16, i)
>  
> +/* Vector lengths pseudo-register: */
> +#define KVM_REG_ARM64_SVE_VLS		(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
> +					 KVM_REG_SIZE_U512 | 0xffff)
> +
>  /* Device Control API: ARM VGIC */
>  #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
>  #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 2aa80a5..086ab05 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -206,6 +206,73 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	return err;
>  }
>  
> +#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64)
> +#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64)
> +
> +static bool vq_present(
> +	const u64 (*const vqs)[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)],
> +	unsigned int vq)
> +{
> +	return (*vqs)[vq_word(vq)] & vq_mask(vq);
> +}
> +
> +static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> +{
> +	unsigned int max_vq, vq;
> +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> +
> +	if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl)))
> +		return -EINVAL;
> +
> +	memset(vqs, 0, sizeof(vqs));
> +
> +	max_vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
> +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> +		if (sve_vq_available(vq))
> +			vqs[vq_word(vq)] |= vq_mask(vq);
> +
> +	if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs)))
> +		return -EFAULT;
> +
> +	return 0;
> +}
> +
> +static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> +{
> +	unsigned int max_vq, vq;
> +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];

There are three of these long 'DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)'.
A macro is probably warranted.

> +
> +	if (kvm_arm_vcpu_sve_finalized(vcpu))
> +		return -EPERM; /* too late! */
> +
> +	if (WARN_ON(vcpu->arch.sve_state))
> +		return -EINVAL;
> +
> +	if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs)))
> +		return -EFAULT;
> +
> +	max_vq = 0;
> +	for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq)
> +		if (vq_present(&vqs, vq))
> +			max_vq = vq;
> +
> +	if (max_vq > sve_vq_from_vl(kvm_sve_max_vl))
> +		return -EINVAL;
> +
> +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> +		if (vq_present(&vqs, vq) != sve_vq_available(vq))
> +			return -EINVAL;

What about supporting the optional non-power-of-2 vector lengths? For
example, if the maximum VL is 512, then in addition to 512, 128, and
256 there could be a 384. If we plan to start a guest on a machine
that has all four and then migrate it to a machine that only has
128,256,512 we would want to set the VL set to 128,256,512, even on
the machine that supports 384. If I understand the above test correctly,
then that wouldn't work.

> +
> +	/* Can't run with no vector lengths at all: */
> +	if (max_vq < SVE_VQ_MIN)
> +		return -EINVAL;
> +
> +	/* vcpu->arch.sve_state will be alloc'd by kvm_vcpu_finalize_sve() */
> +	vcpu->arch.sve_max_vl = sve_vl_from_vq(max_vq);
> +
> +	return 0;
> +}
> +
>  #define SVE_REG_SLICE_SHIFT	0
>  #define SVE_REG_SLICE_BITS	5
>  #define SVE_REG_ID_SHIFT	(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS)
> @@ -296,7 +363,19 @@ static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	struct sve_state_reg_region region;
>  	char __user *uptr = (char __user *)reg->addr;
>  
> -	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> +	if (!vcpu_has_sve(vcpu))
> +		return -ENOENT;
> +
> +	/* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */
> +	if (reg->id == KVM_REG_ARM64_SVE_VLS)
> +		return get_sve_vls(vcpu, reg);
> +
> +	/* Otherwise, reg is an architectural SVE register... */
> +
> +	if (!kvm_arm_vcpu_sve_finalized(vcpu))
> +		return -EPERM;
> +
> +	if (sve_reg_to_region(&region, vcpu, reg))
>  		return -ENOENT;
>  
>  	if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
> @@ -312,7 +391,19 @@ static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	struct sve_state_reg_region region;
>  	const char __user *uptr = (const char __user *)reg->addr;
>  
> -	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> +	if (!vcpu_has_sve(vcpu))
> +		return -ENOENT;
> +
> +	/* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */
> +	if (reg->id == KVM_REG_ARM64_SVE_VLS)
> +		return set_sve_vls(vcpu, reg);
> +
> +	/* Otherwise, reg is an architectural SVE register... */
> +
> +	if (!kvm_arm_vcpu_sve_finalized(vcpu))
> +		return -EPERM;
> +
> +	if (sve_reg_to_region(&region, vcpu, reg))
>  		return -ENOENT;
>  
>  	if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
> @@ -426,7 +517,11 @@ static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
>  	if (!vcpu_has_sve(vcpu))
>  		return 0;
>  
> -	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */);
> +	/* Policed by KVM_GET_REG_LIST: */
> +	WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
> +
> +	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */)
> +		+ 1; /* KVM_REG_ARM64_SVE_VLS */
>  }
>  
>  static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
> @@ -441,6 +536,19 @@ static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
>  	if (!vcpu_has_sve(vcpu))
>  		return 0;
>  
> +	/* Policed by KVM_GET_REG_LIST: */
> +	WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
> +
> +	/*
> +	 * Enumerate this first, so that userspace can save/restore in
> +	 * the order reported by KVM_GET_REG_LIST:
> +	 */
> +	reg = KVM_REG_ARM64_SVE_VLS;
> +	if (put_user(reg, uindices++))
> +		return -EFAULT;
> +
> +	++num_regs;
> +
>  	for (i = 0; i < slices; i++) {
>  		for (n = 0; n < SVE_NUM_ZREGS; n++) {
>  			reg = KVM_REG_ARM64_SVE_ZREG(n, i);
> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> index f16a5f8..e7f9c06 100644
> --- a/arch/arm64/kvm/reset.c
> +++ b/arch/arm64/kvm/reset.c
> @@ -23,11 +23,14 @@
>  #include <linux/kvm_host.h>
>  #include <linux/kvm.h>
>  #include <linux/hw_breakpoint.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
>  
>  #include <kvm/arm_arch_timer.h>
>  
>  #include <asm/cpufeature.h>
>  #include <asm/cputype.h>
> +#include <asm/fpsimd.h>
>  #include <asm/ptrace.h>
>  #include <asm/kvm_arm.h>
>  #include <asm/kvm_asm.h>
> @@ -99,6 +102,92 @@ int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext)
>  	return r;
>  }
>  
> +unsigned int kvm_sve_max_vl;
> +
> +int kvm_arm_init_arch_resources(void)
> +{
> +	if (system_supports_sve()) {
> +		kvm_sve_max_vl = sve_max_virtualisable_vl;
> +
> +		/*
> +		 * The get_sve_reg()/set_sve_reg() ioctl interface will need
> +		 * to be extended with multiple register slice support in
> +		 * order to support vector lengths greater than
> +		 * SVE_VL_ARCH_MAX:
> +		 */
> +		if (WARN_ON(kvm_sve_max_vl > SVE_VL_ARCH_MAX))
> +			kvm_sve_max_vl = SVE_VL_ARCH_MAX;
> +
> +		/*
> +		 * Don't even try to make use of vector lengths that
> +		 * aren't available on all CPUs, for now:
> +		 */
> +		if (kvm_sve_max_vl < sve_max_vl)
> +			pr_warn("KVM: SVE vector length for guests limited to %u bytes\n",
> +				kvm_sve_max_vl);
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Finalize vcpu's maximum SVE vector length, allocating
> + * vcpu->arch.sve_state as necessary.
> + */
> +static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
> +{
> +	void *buf;
> +	unsigned int vl;
> +
> +	vl = vcpu->arch.sve_max_vl;
> +
> +	/*
> +	 * Resposibility for these properties is shared between
> +	 * kvm_arm_init_arch_resources(), kvm_vcpu_enable_sve() and
> +	 * set_sve_vls().  Double-check here just to be sure:
> +	 */
> +	if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl ||
> +		    vl > SVE_VL_ARCH_MAX))
> +		return -EIO;
> +
> +	buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	vcpu->arch.sve_state = buf;
> +	vcpu->arch.flags |= KVM_ARM64_VCPU_SVE_FINALIZED;
> +	return 0;
> +}
> +
> +int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what)
> +{
> +	switch (what) {
> +	case KVM_ARM_VCPU_SVE:
> +		if (!vcpu_has_sve(vcpu))
> +			return -EINVAL;
> +
> +		if (kvm_arm_vcpu_sve_finalized(vcpu))
> +			return -EPERM;
> +
> +		return kvm_vcpu_finalize_sve(vcpu);
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu)
> +{
> +	if (vcpu_has_sve(vcpu) && !kvm_arm_vcpu_sve_finalized(vcpu))
> +		return false;
> +
> +	return true;
> +}
> +
> +void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
> +{
> +	kfree(vcpu->arch.sve_state);
> +}
> +
>  /**
>   * kvm_reset_vcpu - sets core registers and sys_regs to reset value
>   * @vcpu: The VCPU pointer
> -- 
> 2.1.4
>

Thanks,
drew

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

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
@ 2019-04-04 20:18     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 20:18 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> allow userspace to set and query the set of vector lengths visible
> to the guest.
> 
> In the future, multiple register slices per SVE register may be
> visible through the ioctl interface.  Once the set of slices has
> been determined we would not be able to allow the vector length set
> to be changed any more, in order to avoid userspace seeing
> inconsistent sets of registers.  For this reason, this patch adds
> support for explicit finalization of the SVE configuration via the
> KVM_ARM_VCPU_FINALIZE ioctl.
> 
> Finalization is the proper place to allocate the SVE register state
> storage in vcpu->arch.sve_state, so this patch adds that as
> appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> was previously a no-op on arm64.
> 
> To simplify the logic for determining what vector lengths can be
> supported, some code is added to KVM init to work this out, in the
> kvm_arm_init_arch_resources() hook.
> 
> The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> Subsequent patches will allow SVE to be turned on for guest vcpus,
> making it visible.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * [Julien Thierry] Delete overzealous BUILD_BUG_ON() checks.
>    It also turns out that these could cause kernel build failures in
>    some configurations, even though the checked condition is compile-
>    time constant.
> 
>    Because of the way the affected functions are called, the checks
>    are superfluous, so the simplest option is simply to get rid of
>    them.
> 
>  * [Julien Thierry] Free vcpu->arch.sve_state (if any) in
>    kvm_arch_vcpu_uninit() (which is currently a no-op).
> 
>    This was accidentally lost during a previous rebase.
> 
>  * Add kvm_arm_init_arch_resources() hook, and use it to probe SVE
>    configuration for KVM, to avoid duplicating the logic elsewhere.
>    We only need to do this once.
> 
>  * Move sve_state buffer allocation to kvm_arm_vcpu_finalize().
> 
>    As well as making the code more straightforward, this avoids the
>    need to allocate memory in kvm_reset_vcpu(), the meat of which is
>    non-preemptible since commit 358b28f09f0a ("arm/arm64: KVM: Allow a
>    VCPU to fully reset itself").
> 
>    The refactoring means that if this has not been done by the time
>    we hit KVM_RUN, then this allocation will happen on the
>    kvm_arm_first_run_init() path, where preemption remains enabled.
> 
>  * Add a couple of comments in {get,set}_sve_reg() to make the handling
>    of the KVM_REG_ARM64_SVE_VLS special case a little clearer.
> 
>  * Move mis-split rework to avoid put_user() being the correct size
>    by accident in KVM_GET_REG_LIST to KVM: arm64: Enumerate SVE register
>    indices for KVM_GET_REG_LIST.
> 
>  * Fix wrong WARN_ON() check sense when checking whether the
>    implementation may needs move SVE register slices than KVM can
>    support.
> 
>  * Fix erroneous setting of vcpu->arch.sve_max_vl based on stale loop
>    control veriable vq.
> 
>  * Move definition of KVM_ARM_VCPU_SVE from KVM: arm64/sve: Allow
>    userspace to enable SVE for vcpus.
> 
>  * Migrate to explicit finalization of the SVE configuration, using
>    KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
> ---
>  arch/arm64/include/asm/kvm_host.h |  15 +++--
>  arch/arm64/include/uapi/asm/kvm.h |   5 ++
>  arch/arm64/kvm/guest.c            | 114 +++++++++++++++++++++++++++++++++++++-
>  arch/arm64/kvm/reset.c            |  89 +++++++++++++++++++++++++++++
>  4 files changed, 215 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 98658f7..5475cc4 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -23,7 +23,6 @@
>  #define __ARM64_KVM_HOST_H__
>  
>  #include <linux/bitmap.h>
> -#include <linux/errno.h>
>  #include <linux/types.h>
>  #include <linux/jump_label.h>
>  #include <linux/kvm_types.h>
> @@ -50,6 +49,7 @@
>  
>  #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
>  
> +/* Will be incremented when KVM_ARM_VCPU_SVE is fully implemented: */
>  #define KVM_VCPU_MAX_FEATURES 4
>  
>  #define KVM_REQ_SLEEP \
> @@ -59,10 +59,12 @@
>  
>  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
>  
> -static inline int kvm_arm_init_arch_resources(void) { return 0; }
> +extern unsigned int kvm_sve_max_vl;
> +int kvm_arm_init_arch_resources(void);
>  
>  int __attribute_const__ kvm_target_cpu(void);
>  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> +void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu);
>  int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext);
>  void __extended_idmap_trampoline(phys_addr_t boot_pgd, phys_addr_t idmap_start);
>  
> @@ -353,6 +355,7 @@ struct kvm_vcpu_arch {
>  #define KVM_ARM64_HOST_SVE_IN_USE	(1 << 3) /* backup for host TIF_SVE */
>  #define KVM_ARM64_HOST_SVE_ENABLED	(1 << 4) /* SVE enabled for EL0 */
>  #define KVM_ARM64_GUEST_HAS_SVE		(1 << 5) /* SVE exposed to guest */
> +#define KVM_ARM64_VCPU_SVE_FINALIZED	(1 << 6) /* SVE config completed */
>  
>  #define vcpu_has_sve(vcpu) (system_supports_sve() && \
>  			    ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))
> @@ -525,7 +528,6 @@ static inline bool kvm_arch_requires_vhe(void)
>  
>  static inline void kvm_arch_hardware_unsetup(void) {}
>  static inline void kvm_arch_sync_events(struct kvm *kvm) {}
> -static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {}
>  static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
>  static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {}
>  
> @@ -626,7 +628,10 @@ void kvm_arch_free_vm(struct kvm *kvm);
>  
>  int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type);
>  
> -#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
> -#define kvm_arm_vcpu_is_finalized(vcpu) true
> +int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what);
> +bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
> +
> +#define kvm_arm_vcpu_sve_finalized(vcpu) \
> +	((vcpu)->arch.flags & KVM_ARM64_VCPU_SVE_FINALIZED)
>  
>  #endif /* __ARM64_KVM_HOST_H__ */
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index ced760c..6963b7e 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -102,6 +102,7 @@ struct kvm_regs {
>  #define KVM_ARM_VCPU_EL1_32BIT		1 /* CPU running a 32bit VM */
>  #define KVM_ARM_VCPU_PSCI_0_2		2 /* CPU uses PSCI v0.2 */
>  #define KVM_ARM_VCPU_PMU_V3		3 /* Support guest PMUv3 */
> +#define KVM_ARM_VCPU_SVE		4 /* enable SVE for this CPU */
>  
>  struct kvm_vcpu_init {
>  	__u32 target;
> @@ -243,6 +244,10 @@ struct kvm_vcpu_events {
>  					 ((n) << 5) | (i))
>  #define KVM_REG_ARM64_SVE_FFR(i)	KVM_REG_ARM64_SVE_PREG(16, i)
>  
> +/* Vector lengths pseudo-register: */
> +#define KVM_REG_ARM64_SVE_VLS		(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
> +					 KVM_REG_SIZE_U512 | 0xffff)
> +
>  /* Device Control API: ARM VGIC */
>  #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
>  #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 2aa80a5..086ab05 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -206,6 +206,73 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	return err;
>  }
>  
> +#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64)
> +#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64)
> +
> +static bool vq_present(
> +	const u64 (*const vqs)[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)],
> +	unsigned int vq)
> +{
> +	return (*vqs)[vq_word(vq)] & vq_mask(vq);
> +}
> +
> +static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> +{
> +	unsigned int max_vq, vq;
> +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> +
> +	if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl)))
> +		return -EINVAL;
> +
> +	memset(vqs, 0, sizeof(vqs));
> +
> +	max_vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
> +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> +		if (sve_vq_available(vq))
> +			vqs[vq_word(vq)] |= vq_mask(vq);
> +
> +	if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs)))
> +		return -EFAULT;
> +
> +	return 0;
> +}
> +
> +static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> +{
> +	unsigned int max_vq, vq;
> +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];

There are three of these long 'DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)'.
A macro is probably warranted.

> +
> +	if (kvm_arm_vcpu_sve_finalized(vcpu))
> +		return -EPERM; /* too late! */
> +
> +	if (WARN_ON(vcpu->arch.sve_state))
> +		return -EINVAL;
> +
> +	if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs)))
> +		return -EFAULT;
> +
> +	max_vq = 0;
> +	for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq)
> +		if (vq_present(&vqs, vq))
> +			max_vq = vq;
> +
> +	if (max_vq > sve_vq_from_vl(kvm_sve_max_vl))
> +		return -EINVAL;
> +
> +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> +		if (vq_present(&vqs, vq) != sve_vq_available(vq))
> +			return -EINVAL;

What about supporting the optional non-power-of-2 vector lengths? For
example, if the maximum VL is 512, then in addition to 512, 128, and
256 there could be a 384. If we plan to start a guest on a machine
that has all four and then migrate it to a machine that only has
128,256,512 we would want to set the VL set to 128,256,512, even on
the machine that supports 384. If I understand the above test correctly,
then that wouldn't work.

> +
> +	/* Can't run with no vector lengths at all: */
> +	if (max_vq < SVE_VQ_MIN)
> +		return -EINVAL;
> +
> +	/* vcpu->arch.sve_state will be alloc'd by kvm_vcpu_finalize_sve() */
> +	vcpu->arch.sve_max_vl = sve_vl_from_vq(max_vq);
> +
> +	return 0;
> +}
> +
>  #define SVE_REG_SLICE_SHIFT	0
>  #define SVE_REG_SLICE_BITS	5
>  #define SVE_REG_ID_SHIFT	(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS)
> @@ -296,7 +363,19 @@ static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	struct sve_state_reg_region region;
>  	char __user *uptr = (char __user *)reg->addr;
>  
> -	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> +	if (!vcpu_has_sve(vcpu))
> +		return -ENOENT;
> +
> +	/* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */
> +	if (reg->id == KVM_REG_ARM64_SVE_VLS)
> +		return get_sve_vls(vcpu, reg);
> +
> +	/* Otherwise, reg is an architectural SVE register... */
> +
> +	if (!kvm_arm_vcpu_sve_finalized(vcpu))
> +		return -EPERM;
> +
> +	if (sve_reg_to_region(&region, vcpu, reg))
>  		return -ENOENT;
>  
>  	if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
> @@ -312,7 +391,19 @@ static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	struct sve_state_reg_region region;
>  	const char __user *uptr = (const char __user *)reg->addr;
>  
> -	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> +	if (!vcpu_has_sve(vcpu))
> +		return -ENOENT;
> +
> +	/* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */
> +	if (reg->id == KVM_REG_ARM64_SVE_VLS)
> +		return set_sve_vls(vcpu, reg);
> +
> +	/* Otherwise, reg is an architectural SVE register... */
> +
> +	if (!kvm_arm_vcpu_sve_finalized(vcpu))
> +		return -EPERM;
> +
> +	if (sve_reg_to_region(&region, vcpu, reg))
>  		return -ENOENT;
>  
>  	if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
> @@ -426,7 +517,11 @@ static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
>  	if (!vcpu_has_sve(vcpu))
>  		return 0;
>  
> -	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */);
> +	/* Policed by KVM_GET_REG_LIST: */
> +	WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
> +
> +	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */)
> +		+ 1; /* KVM_REG_ARM64_SVE_VLS */
>  }
>  
>  static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
> @@ -441,6 +536,19 @@ static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
>  	if (!vcpu_has_sve(vcpu))
>  		return 0;
>  
> +	/* Policed by KVM_GET_REG_LIST: */
> +	WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
> +
> +	/*
> +	 * Enumerate this first, so that userspace can save/restore in
> +	 * the order reported by KVM_GET_REG_LIST:
> +	 */
> +	reg = KVM_REG_ARM64_SVE_VLS;
> +	if (put_user(reg, uindices++))
> +		return -EFAULT;
> +
> +	++num_regs;
> +
>  	for (i = 0; i < slices; i++) {
>  		for (n = 0; n < SVE_NUM_ZREGS; n++) {
>  			reg = KVM_REG_ARM64_SVE_ZREG(n, i);
> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> index f16a5f8..e7f9c06 100644
> --- a/arch/arm64/kvm/reset.c
> +++ b/arch/arm64/kvm/reset.c
> @@ -23,11 +23,14 @@
>  #include <linux/kvm_host.h>
>  #include <linux/kvm.h>
>  #include <linux/hw_breakpoint.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
>  
>  #include <kvm/arm_arch_timer.h>
>  
>  #include <asm/cpufeature.h>
>  #include <asm/cputype.h>
> +#include <asm/fpsimd.h>
>  #include <asm/ptrace.h>
>  #include <asm/kvm_arm.h>
>  #include <asm/kvm_asm.h>
> @@ -99,6 +102,92 @@ int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext)
>  	return r;
>  }
>  
> +unsigned int kvm_sve_max_vl;
> +
> +int kvm_arm_init_arch_resources(void)
> +{
> +	if (system_supports_sve()) {
> +		kvm_sve_max_vl = sve_max_virtualisable_vl;
> +
> +		/*
> +		 * The get_sve_reg()/set_sve_reg() ioctl interface will need
> +		 * to be extended with multiple register slice support in
> +		 * order to support vector lengths greater than
> +		 * SVE_VL_ARCH_MAX:
> +		 */
> +		if (WARN_ON(kvm_sve_max_vl > SVE_VL_ARCH_MAX))
> +			kvm_sve_max_vl = SVE_VL_ARCH_MAX;
> +
> +		/*
> +		 * Don't even try to make use of vector lengths that
> +		 * aren't available on all CPUs, for now:
> +		 */
> +		if (kvm_sve_max_vl < sve_max_vl)
> +			pr_warn("KVM: SVE vector length for guests limited to %u bytes\n",
> +				kvm_sve_max_vl);
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Finalize vcpu's maximum SVE vector length, allocating
> + * vcpu->arch.sve_state as necessary.
> + */
> +static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
> +{
> +	void *buf;
> +	unsigned int vl;
> +
> +	vl = vcpu->arch.sve_max_vl;
> +
> +	/*
> +	 * Resposibility for these properties is shared between
> +	 * kvm_arm_init_arch_resources(), kvm_vcpu_enable_sve() and
> +	 * set_sve_vls().  Double-check here just to be sure:
> +	 */
> +	if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl ||
> +		    vl > SVE_VL_ARCH_MAX))
> +		return -EIO;
> +
> +	buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	vcpu->arch.sve_state = buf;
> +	vcpu->arch.flags |= KVM_ARM64_VCPU_SVE_FINALIZED;
> +	return 0;
> +}
> +
> +int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what)
> +{
> +	switch (what) {
> +	case KVM_ARM_VCPU_SVE:
> +		if (!vcpu_has_sve(vcpu))
> +			return -EINVAL;
> +
> +		if (kvm_arm_vcpu_sve_finalized(vcpu))
> +			return -EPERM;
> +
> +		return kvm_vcpu_finalize_sve(vcpu);
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu)
> +{
> +	if (vcpu_has_sve(vcpu) && !kvm_arm_vcpu_sve_finalized(vcpu))
> +		return false;
> +
> +	return true;
> +}
> +
> +void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
> +{
> +	kfree(vcpu->arch.sve_state);
> +}
> +
>  /**
>   * kvm_reset_vcpu - sets core registers and sys_regs to reset value
>   * @vcpu: The VCPU pointer
> -- 
> 2.1.4
>

Thanks,
drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-04 20:31     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 20:31 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> allow userspace to set and query the set of vector lengths visible
> to the guest.
> 
> In the future, multiple register slices per SVE register may be
> visible through the ioctl interface.  Once the set of slices has
> been determined we would not be able to allow the vector length set
> to be changed any more, in order to avoid userspace seeing
> inconsistent sets of registers.  For this reason, this patch adds
> support for explicit finalization of the SVE configuration via the
> KVM_ARM_VCPU_FINALIZE ioctl.
> 
> Finalization is the proper place to allocate the SVE register state
> storage in vcpu->arch.sve_state, so this patch adds that as
> appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> was previously a no-op on arm64.
> 
> To simplify the logic for determining what vector lengths can be
> supported, some code is added to KVM init to work this out, in the
> kvm_arm_init_arch_resources() hook.
> 
> The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> Subsequent patches will allow SVE to be turned on for guest vcpus,
> making it visible.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * [Julien Thierry] Delete overzealous BUILD_BUG_ON() checks.
>    It also turns out that these could cause kernel build failures in
>    some configurations, even though the checked condition is compile-
>    time constant.
> 
>    Because of the way the affected functions are called, the checks
>    are superfluous, so the simplest option is simply to get rid of
>    them.
> 
>  * [Julien Thierry] Free vcpu->arch.sve_state (if any) in
>    kvm_arch_vcpu_uninit() (which is currently a no-op).
> 
>    This was accidentally lost during a previous rebase.
> 
>  * Add kvm_arm_init_arch_resources() hook, and use it to probe SVE
>    configuration for KVM, to avoid duplicating the logic elsewhere.
>    We only need to do this once.
> 
>  * Move sve_state buffer allocation to kvm_arm_vcpu_finalize().
> 
>    As well as making the code more straightforward, this avoids the
>    need to allocate memory in kvm_reset_vcpu(), the meat of which is
>    non-preemptible since commit 358b28f09f0a ("arm/arm64: KVM: Allow a
>    VCPU to fully reset itself").
> 
>    The refactoring means that if this has not been done by the time
>    we hit KVM_RUN, then this allocation will happen on the
>    kvm_arm_first_run_init() path, where preemption remains enabled.
> 
>  * Add a couple of comments in {get,set}_sve_reg() to make the handling
>    of the KVM_REG_ARM64_SVE_VLS special case a little clearer.
> 
>  * Move mis-split rework to avoid put_user() being the correct size
>    by accident in KVM_GET_REG_LIST to KVM: arm64: Enumerate SVE register
>    indices for KVM_GET_REG_LIST.
> 
>  * Fix wrong WARN_ON() check sense when checking whether the
>    implementation may needs move SVE register slices than KVM can
>    support.
> 
>  * Fix erroneous setting of vcpu->arch.sve_max_vl based on stale loop
>    control veriable vq.
> 
>  * Move definition of KVM_ARM_VCPU_SVE from KVM: arm64/sve: Allow
>    userspace to enable SVE for vcpus.
> 
>  * Migrate to explicit finalization of the SVE configuration, using
>    KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
> ---
>  arch/arm64/include/asm/kvm_host.h |  15 +++--
>  arch/arm64/include/uapi/asm/kvm.h |   5 ++
>  arch/arm64/kvm/guest.c            | 114 +++++++++++++++++++++++++++++++++++++-
>  arch/arm64/kvm/reset.c            |  89 +++++++++++++++++++++++++++++
>  4 files changed, 215 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 98658f7..5475cc4 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -23,7 +23,6 @@
>  #define __ARM64_KVM_HOST_H__
>  
>  #include <linux/bitmap.h>
> -#include <linux/errno.h>
>  #include <linux/types.h>
>  #include <linux/jump_label.h>
>  #include <linux/kvm_types.h>
> @@ -50,6 +49,7 @@
>  
>  #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
>  
> +/* Will be incremented when KVM_ARM_VCPU_SVE is fully implemented: */
>  #define KVM_VCPU_MAX_FEATURES 4
>  
>  #define KVM_REQ_SLEEP \
> @@ -59,10 +59,12 @@
>  
>  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
>  
> -static inline int kvm_arm_init_arch_resources(void) { return 0; }
> +extern unsigned int kvm_sve_max_vl;
> +int kvm_arm_init_arch_resources(void);
>  
>  int __attribute_const__ kvm_target_cpu(void);
>  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> +void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu);
>  int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext);
>  void __extended_idmap_trampoline(phys_addr_t boot_pgd, phys_addr_t idmap_start);
>  
> @@ -353,6 +355,7 @@ struct kvm_vcpu_arch {
>  #define KVM_ARM64_HOST_SVE_IN_USE	(1 << 3) /* backup for host TIF_SVE */
>  #define KVM_ARM64_HOST_SVE_ENABLED	(1 << 4) /* SVE enabled for EL0 */
>  #define KVM_ARM64_GUEST_HAS_SVE		(1 << 5) /* SVE exposed to guest */
> +#define KVM_ARM64_VCPU_SVE_FINALIZED	(1 << 6) /* SVE config completed */
>  
>  #define vcpu_has_sve(vcpu) (system_supports_sve() && \
>  			    ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))
> @@ -525,7 +528,6 @@ static inline bool kvm_arch_requires_vhe(void)
>  
>  static inline void kvm_arch_hardware_unsetup(void) {}
>  static inline void kvm_arch_sync_events(struct kvm *kvm) {}
> -static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {}
>  static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
>  static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {}
>  
> @@ -626,7 +628,10 @@ void kvm_arch_free_vm(struct kvm *kvm);
>  
>  int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type);
>  
> -#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
> -#define kvm_arm_vcpu_is_finalized(vcpu) true
> +int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what);
> +bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
> +
> +#define kvm_arm_vcpu_sve_finalized(vcpu) \
> +	((vcpu)->arch.flags & KVM_ARM64_VCPU_SVE_FINALIZED)
>  
>  #endif /* __ARM64_KVM_HOST_H__ */
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index ced760c..6963b7e 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -102,6 +102,7 @@ struct kvm_regs {
>  #define KVM_ARM_VCPU_EL1_32BIT		1 /* CPU running a 32bit VM */
>  #define KVM_ARM_VCPU_PSCI_0_2		2 /* CPU uses PSCI v0.2 */
>  #define KVM_ARM_VCPU_PMU_V3		3 /* Support guest PMUv3 */
> +#define KVM_ARM_VCPU_SVE		4 /* enable SVE for this CPU */
>  
>  struct kvm_vcpu_init {
>  	__u32 target;
> @@ -243,6 +244,10 @@ struct kvm_vcpu_events {
>  					 ((n) << 5) | (i))
>  #define KVM_REG_ARM64_SVE_FFR(i)	KVM_REG_ARM64_SVE_PREG(16, i)
>  
> +/* Vector lengths pseudo-register: */
> +#define KVM_REG_ARM64_SVE_VLS		(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
> +					 KVM_REG_SIZE_U512 | 0xffff)
> +
>  /* Device Control API: ARM VGIC */
>  #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
>  #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 2aa80a5..086ab05 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -206,6 +206,73 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	return err;
>  }
>  
> +#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64)
> +#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64)
> +
> +static bool vq_present(
> +	const u64 (*const vqs)[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)],
> +	unsigned int vq)
> +{
> +	return (*vqs)[vq_word(vq)] & vq_mask(vq);
> +}
> +
> +static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> +{
> +	unsigned int max_vq, vq;
> +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> +
> +	if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl)))
> +		return -EINVAL;
> +
> +	memset(vqs, 0, sizeof(vqs));
> +
> +	max_vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
> +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> +		if (sve_vq_available(vq))
> +			vqs[vq_word(vq)] |= vq_mask(vq);
> +
> +	if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs)))
> +		return -EFAULT;
> +
> +	return 0;
> +}
> +
> +static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> +{
> +	unsigned int max_vq, vq;
> +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> +
> +	if (kvm_arm_vcpu_sve_finalized(vcpu))
> +		return -EPERM; /* too late! */
> +
> +	if (WARN_ON(vcpu->arch.sve_state))
> +		return -EINVAL;
> +
> +	if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs)))
> +		return -EFAULT;
> +
> +	max_vq = 0;
> +	for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq)
> +		if (vq_present(&vqs, vq))
> +			max_vq = vq;
> +
> +	if (max_vq > sve_vq_from_vl(kvm_sve_max_vl))
> +		return -EINVAL;
> +
> +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> +		if (vq_present(&vqs, vq) != sve_vq_available(vq))
> +			return -EINVAL;
> +
> +	/* Can't run with no vector lengths at all: */
> +	if (max_vq < SVE_VQ_MIN)
> +		return -EINVAL;
> +
> +	/* vcpu->arch.sve_state will be alloc'd by kvm_vcpu_finalize_sve() */
> +	vcpu->arch.sve_max_vl = sve_vl_from_vq(max_vq);
> +
> +	return 0;
> +}
> +
>  #define SVE_REG_SLICE_SHIFT	0
>  #define SVE_REG_SLICE_BITS	5
>  #define SVE_REG_ID_SHIFT	(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS)
> @@ -296,7 +363,19 @@ static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	struct sve_state_reg_region region;
>  	char __user *uptr = (char __user *)reg->addr;
>  
> -	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> +	if (!vcpu_has_sve(vcpu))
> +		return -ENOENT;
> +
> +	/* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */
> +	if (reg->id == KVM_REG_ARM64_SVE_VLS)
> +		return get_sve_vls(vcpu, reg);
> +
> +	/* Otherwise, reg is an architectural SVE register... */
> +
> +	if (!kvm_arm_vcpu_sve_finalized(vcpu))
> +		return -EPERM;
> +
> +	if (sve_reg_to_region(&region, vcpu, reg))
>  		return -ENOENT;
>  
>  	if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
> @@ -312,7 +391,19 @@ static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	struct sve_state_reg_region region;
>  	const char __user *uptr = (const char __user *)reg->addr;
>  
> -	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> +	if (!vcpu_has_sve(vcpu))
> +		return -ENOENT;
> +
> +	/* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */
> +	if (reg->id == KVM_REG_ARM64_SVE_VLS)
> +		return set_sve_vls(vcpu, reg);
> +
> +	/* Otherwise, reg is an architectural SVE register... */
> +
> +	if (!kvm_arm_vcpu_sve_finalized(vcpu))
> +		return -EPERM;
> +
> +	if (sve_reg_to_region(&region, vcpu, reg))
>  		return -ENOENT;
>  
>  	if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
> @@ -426,7 +517,11 @@ static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
>  	if (!vcpu_has_sve(vcpu))
>  		return 0;
>  
> -	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */);
> +	/* Policed by KVM_GET_REG_LIST: */
> +	WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
> +
> +	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */)
> +		+ 1; /* KVM_REG_ARM64_SVE_VLS */
>  }
>  
>  static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
> @@ -441,6 +536,19 @@ static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
>  	if (!vcpu_has_sve(vcpu))
>  		return 0;
>  
> +	/* Policed by KVM_GET_REG_LIST: */
> +	WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
> +
> +	/*
> +	 * Enumerate this first, so that userspace can save/restore in
> +	 * the order reported by KVM_GET_REG_LIST:
> +	 */
> +	reg = KVM_REG_ARM64_SVE_VLS;
> +	if (put_user(reg, uindices++))
> +		return -EFAULT;
> +
> +	++num_regs;
> +
>  	for (i = 0; i < slices; i++) {
>  		for (n = 0; n < SVE_NUM_ZREGS; n++) {
>  			reg = KVM_REG_ARM64_SVE_ZREG(n, i);
> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> index f16a5f8..e7f9c06 100644
> --- a/arch/arm64/kvm/reset.c
> +++ b/arch/arm64/kvm/reset.c
> @@ -23,11 +23,14 @@
>  #include <linux/kvm_host.h>
>  #include <linux/kvm.h>
>  #include <linux/hw_breakpoint.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
>  
>  #include <kvm/arm_arch_timer.h>
>  
>  #include <asm/cpufeature.h>
>  #include <asm/cputype.h>
> +#include <asm/fpsimd.h>
>  #include <asm/ptrace.h>
>  #include <asm/kvm_arm.h>
>  #include <asm/kvm_asm.h>
> @@ -99,6 +102,92 @@ int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext)
>  	return r;
>  }
>  
> +unsigned int kvm_sve_max_vl;
> +
> +int kvm_arm_init_arch_resources(void)
> +{
> +	if (system_supports_sve()) {
> +		kvm_sve_max_vl = sve_max_virtualisable_vl;
> +
> +		/*
> +		 * The get_sve_reg()/set_sve_reg() ioctl interface will need
> +		 * to be extended with multiple register slice support in
> +		 * order to support vector lengths greater than
> +		 * SVE_VL_ARCH_MAX:
> +		 */
> +		if (WARN_ON(kvm_sve_max_vl > SVE_VL_ARCH_MAX))
> +			kvm_sve_max_vl = SVE_VL_ARCH_MAX;
> +
> +		/*
> +		 * Don't even try to make use of vector lengths that
> +		 * aren't available on all CPUs, for now:
> +		 */
> +		if (kvm_sve_max_vl < sve_max_vl)
> +			pr_warn("KVM: SVE vector length for guests limited to %u bytes\n",
> +				kvm_sve_max_vl);
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Finalize vcpu's maximum SVE vector length, allocating
> + * vcpu->arch.sve_state as necessary.
> + */
> +static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
> +{
> +	void *buf;
> +	unsigned int vl;
> +
> +	vl = vcpu->arch.sve_max_vl;
> +
> +	/*
> +	 * Resposibility for these properties is shared between
> +	 * kvm_arm_init_arch_resources(), kvm_vcpu_enable_sve() and
> +	 * set_sve_vls().  Double-check here just to be sure:
> +	 */
> +	if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl ||
> +		    vl > SVE_VL_ARCH_MAX))
> +		return -EIO;
> +
> +	buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	vcpu->arch.sve_state = buf;
> +	vcpu->arch.flags |= KVM_ARM64_VCPU_SVE_FINALIZED;
> +	return 0;
> +}
> +
> +int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what)
> +{
> +	switch (what) {
> +	case KVM_ARM_VCPU_SVE:
> +		if (!vcpu_has_sve(vcpu))
> +			return -EINVAL;
> +
> +		if (kvm_arm_vcpu_sve_finalized(vcpu))
> +			return -EPERM;
> +
> +		return kvm_vcpu_finalize_sve(vcpu);

In the next patch I see that we already have KVM_ARM64_GUEST_HAS_SVE
set in vcpu->arch.flags at this point. So if this kvm_vcpu_finalize_sve()
call fails, shouldn't we unset KVM_ARM64_GUEST_HAS_SVE and anything
else used to indicate the vcpu has sve?

Thanks,
drew


> +	}
> +
> +	return -EINVAL;
> +}
> +
> +bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu)
> +{
> +	if (vcpu_has_sve(vcpu) && !kvm_arm_vcpu_sve_finalized(vcpu))
> +		return false;
> +
> +	return true;
> +}
> +
> +void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
> +{
> +	kfree(vcpu->arch.sve_state);
> +}
> +
>  /**
>   * kvm_reset_vcpu - sets core registers and sys_regs to reset value
>   * @vcpu: The VCPU pointer
> -- 
> 2.1.4
> 
> _______________________________________________
> kvmarm mailing list
> kvmarm@lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
@ 2019-04-04 20:31     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 20:31 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> allow userspace to set and query the set of vector lengths visible
> to the guest.
> 
> In the future, multiple register slices per SVE register may be
> visible through the ioctl interface.  Once the set of slices has
> been determined we would not be able to allow the vector length set
> to be changed any more, in order to avoid userspace seeing
> inconsistent sets of registers.  For this reason, this patch adds
> support for explicit finalization of the SVE configuration via the
> KVM_ARM_VCPU_FINALIZE ioctl.
> 
> Finalization is the proper place to allocate the SVE register state
> storage in vcpu->arch.sve_state, so this patch adds that as
> appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> was previously a no-op on arm64.
> 
> To simplify the logic for determining what vector lengths can be
> supported, some code is added to KVM init to work this out, in the
> kvm_arm_init_arch_resources() hook.
> 
> The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> Subsequent patches will allow SVE to be turned on for guest vcpus,
> making it visible.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * [Julien Thierry] Delete overzealous BUILD_BUG_ON() checks.
>    It also turns out that these could cause kernel build failures in
>    some configurations, even though the checked condition is compile-
>    time constant.
> 
>    Because of the way the affected functions are called, the checks
>    are superfluous, so the simplest option is simply to get rid of
>    them.
> 
>  * [Julien Thierry] Free vcpu->arch.sve_state (if any) in
>    kvm_arch_vcpu_uninit() (which is currently a no-op).
> 
>    This was accidentally lost during a previous rebase.
> 
>  * Add kvm_arm_init_arch_resources() hook, and use it to probe SVE
>    configuration for KVM, to avoid duplicating the logic elsewhere.
>    We only need to do this once.
> 
>  * Move sve_state buffer allocation to kvm_arm_vcpu_finalize().
> 
>    As well as making the code more straightforward, this avoids the
>    need to allocate memory in kvm_reset_vcpu(), the meat of which is
>    non-preemptible since commit 358b28f09f0a ("arm/arm64: KVM: Allow a
>    VCPU to fully reset itself").
> 
>    The refactoring means that if this has not been done by the time
>    we hit KVM_RUN, then this allocation will happen on the
>    kvm_arm_first_run_init() path, where preemption remains enabled.
> 
>  * Add a couple of comments in {get,set}_sve_reg() to make the handling
>    of the KVM_REG_ARM64_SVE_VLS special case a little clearer.
> 
>  * Move mis-split rework to avoid put_user() being the correct size
>    by accident in KVM_GET_REG_LIST to KVM: arm64: Enumerate SVE register
>    indices for KVM_GET_REG_LIST.
> 
>  * Fix wrong WARN_ON() check sense when checking whether the
>    implementation may needs move SVE register slices than KVM can
>    support.
> 
>  * Fix erroneous setting of vcpu->arch.sve_max_vl based on stale loop
>    control veriable vq.
> 
>  * Move definition of KVM_ARM_VCPU_SVE from KVM: arm64/sve: Allow
>    userspace to enable SVE for vcpus.
> 
>  * Migrate to explicit finalization of the SVE configuration, using
>    KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
> ---
>  arch/arm64/include/asm/kvm_host.h |  15 +++--
>  arch/arm64/include/uapi/asm/kvm.h |   5 ++
>  arch/arm64/kvm/guest.c            | 114 +++++++++++++++++++++++++++++++++++++-
>  arch/arm64/kvm/reset.c            |  89 +++++++++++++++++++++++++++++
>  4 files changed, 215 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 98658f7..5475cc4 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -23,7 +23,6 @@
>  #define __ARM64_KVM_HOST_H__
>  
>  #include <linux/bitmap.h>
> -#include <linux/errno.h>
>  #include <linux/types.h>
>  #include <linux/jump_label.h>
>  #include <linux/kvm_types.h>
> @@ -50,6 +49,7 @@
>  
>  #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
>  
> +/* Will be incremented when KVM_ARM_VCPU_SVE is fully implemented: */
>  #define KVM_VCPU_MAX_FEATURES 4
>  
>  #define KVM_REQ_SLEEP \
> @@ -59,10 +59,12 @@
>  
>  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
>  
> -static inline int kvm_arm_init_arch_resources(void) { return 0; }
> +extern unsigned int kvm_sve_max_vl;
> +int kvm_arm_init_arch_resources(void);
>  
>  int __attribute_const__ kvm_target_cpu(void);
>  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
> +void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu);
>  int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext);
>  void __extended_idmap_trampoline(phys_addr_t boot_pgd, phys_addr_t idmap_start);
>  
> @@ -353,6 +355,7 @@ struct kvm_vcpu_arch {
>  #define KVM_ARM64_HOST_SVE_IN_USE	(1 << 3) /* backup for host TIF_SVE */
>  #define KVM_ARM64_HOST_SVE_ENABLED	(1 << 4) /* SVE enabled for EL0 */
>  #define KVM_ARM64_GUEST_HAS_SVE		(1 << 5) /* SVE exposed to guest */
> +#define KVM_ARM64_VCPU_SVE_FINALIZED	(1 << 6) /* SVE config completed */
>  
>  #define vcpu_has_sve(vcpu) (system_supports_sve() && \
>  			    ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))
> @@ -525,7 +528,6 @@ static inline bool kvm_arch_requires_vhe(void)
>  
>  static inline void kvm_arch_hardware_unsetup(void) {}
>  static inline void kvm_arch_sync_events(struct kvm *kvm) {}
> -static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {}
>  static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
>  static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {}
>  
> @@ -626,7 +628,10 @@ void kvm_arch_free_vm(struct kvm *kvm);
>  
>  int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type);
>  
> -#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
> -#define kvm_arm_vcpu_is_finalized(vcpu) true
> +int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what);
> +bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
> +
> +#define kvm_arm_vcpu_sve_finalized(vcpu) \
> +	((vcpu)->arch.flags & KVM_ARM64_VCPU_SVE_FINALIZED)
>  
>  #endif /* __ARM64_KVM_HOST_H__ */
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index ced760c..6963b7e 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -102,6 +102,7 @@ struct kvm_regs {
>  #define KVM_ARM_VCPU_EL1_32BIT		1 /* CPU running a 32bit VM */
>  #define KVM_ARM_VCPU_PSCI_0_2		2 /* CPU uses PSCI v0.2 */
>  #define KVM_ARM_VCPU_PMU_V3		3 /* Support guest PMUv3 */
> +#define KVM_ARM_VCPU_SVE		4 /* enable SVE for this CPU */
>  
>  struct kvm_vcpu_init {
>  	__u32 target;
> @@ -243,6 +244,10 @@ struct kvm_vcpu_events {
>  					 ((n) << 5) | (i))
>  #define KVM_REG_ARM64_SVE_FFR(i)	KVM_REG_ARM64_SVE_PREG(16, i)
>  
> +/* Vector lengths pseudo-register: */
> +#define KVM_REG_ARM64_SVE_VLS		(KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
> +					 KVM_REG_SIZE_U512 | 0xffff)
> +
>  /* Device Control API: ARM VGIC */
>  #define KVM_DEV_ARM_VGIC_GRP_ADDR	0
>  #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS	1
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 2aa80a5..086ab05 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -206,6 +206,73 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	return err;
>  }
>  
> +#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64)
> +#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64)
> +
> +static bool vq_present(
> +	const u64 (*const vqs)[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)],
> +	unsigned int vq)
> +{
> +	return (*vqs)[vq_word(vq)] & vq_mask(vq);
> +}
> +
> +static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> +{
> +	unsigned int max_vq, vq;
> +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> +
> +	if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl)))
> +		return -EINVAL;
> +
> +	memset(vqs, 0, sizeof(vqs));
> +
> +	max_vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
> +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> +		if (sve_vq_available(vq))
> +			vqs[vq_word(vq)] |= vq_mask(vq);
> +
> +	if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs)))
> +		return -EFAULT;
> +
> +	return 0;
> +}
> +
> +static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> +{
> +	unsigned int max_vq, vq;
> +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> +
> +	if (kvm_arm_vcpu_sve_finalized(vcpu))
> +		return -EPERM; /* too late! */
> +
> +	if (WARN_ON(vcpu->arch.sve_state))
> +		return -EINVAL;
> +
> +	if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs)))
> +		return -EFAULT;
> +
> +	max_vq = 0;
> +	for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq)
> +		if (vq_present(&vqs, vq))
> +			max_vq = vq;
> +
> +	if (max_vq > sve_vq_from_vl(kvm_sve_max_vl))
> +		return -EINVAL;
> +
> +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> +		if (vq_present(&vqs, vq) != sve_vq_available(vq))
> +			return -EINVAL;
> +
> +	/* Can't run with no vector lengths at all: */
> +	if (max_vq < SVE_VQ_MIN)
> +		return -EINVAL;
> +
> +	/* vcpu->arch.sve_state will be alloc'd by kvm_vcpu_finalize_sve() */
> +	vcpu->arch.sve_max_vl = sve_vl_from_vq(max_vq);
> +
> +	return 0;
> +}
> +
>  #define SVE_REG_SLICE_SHIFT	0
>  #define SVE_REG_SLICE_BITS	5
>  #define SVE_REG_ID_SHIFT	(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS)
> @@ -296,7 +363,19 @@ static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	struct sve_state_reg_region region;
>  	char __user *uptr = (char __user *)reg->addr;
>  
> -	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> +	if (!vcpu_has_sve(vcpu))
> +		return -ENOENT;
> +
> +	/* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */
> +	if (reg->id == KVM_REG_ARM64_SVE_VLS)
> +		return get_sve_vls(vcpu, reg);
> +
> +	/* Otherwise, reg is an architectural SVE register... */
> +
> +	if (!kvm_arm_vcpu_sve_finalized(vcpu))
> +		return -EPERM;
> +
> +	if (sve_reg_to_region(&region, vcpu, reg))
>  		return -ENOENT;
>  
>  	if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset,
> @@ -312,7 +391,19 @@ static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	struct sve_state_reg_region region;
>  	const char __user *uptr = (const char __user *)reg->addr;
>  
> -	if (!vcpu_has_sve(vcpu) || sve_reg_to_region(&region, vcpu, reg))
> +	if (!vcpu_has_sve(vcpu))
> +		return -ENOENT;
> +
> +	/* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */
> +	if (reg->id == KVM_REG_ARM64_SVE_VLS)
> +		return set_sve_vls(vcpu, reg);
> +
> +	/* Otherwise, reg is an architectural SVE register... */
> +
> +	if (!kvm_arm_vcpu_sve_finalized(vcpu))
> +		return -EPERM;
> +
> +	if (sve_reg_to_region(&region, vcpu, reg))
>  		return -ENOENT;
>  
>  	if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr,
> @@ -426,7 +517,11 @@ static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
>  	if (!vcpu_has_sve(vcpu))
>  		return 0;
>  
> -	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */);
> +	/* Policed by KVM_GET_REG_LIST: */
> +	WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
> +
> +	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */)
> +		+ 1; /* KVM_REG_ARM64_SVE_VLS */
>  }
>  
>  static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
> @@ -441,6 +536,19 @@ static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
>  	if (!vcpu_has_sve(vcpu))
>  		return 0;
>  
> +	/* Policed by KVM_GET_REG_LIST: */
> +	WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
> +
> +	/*
> +	 * Enumerate this first, so that userspace can save/restore in
> +	 * the order reported by KVM_GET_REG_LIST:
> +	 */
> +	reg = KVM_REG_ARM64_SVE_VLS;
> +	if (put_user(reg, uindices++))
> +		return -EFAULT;
> +
> +	++num_regs;
> +
>  	for (i = 0; i < slices; i++) {
>  		for (n = 0; n < SVE_NUM_ZREGS; n++) {
>  			reg = KVM_REG_ARM64_SVE_ZREG(n, i);
> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> index f16a5f8..e7f9c06 100644
> --- a/arch/arm64/kvm/reset.c
> +++ b/arch/arm64/kvm/reset.c
> @@ -23,11 +23,14 @@
>  #include <linux/kvm_host.h>
>  #include <linux/kvm.h>
>  #include <linux/hw_breakpoint.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
>  
>  #include <kvm/arm_arch_timer.h>
>  
>  #include <asm/cpufeature.h>
>  #include <asm/cputype.h>
> +#include <asm/fpsimd.h>
>  #include <asm/ptrace.h>
>  #include <asm/kvm_arm.h>
>  #include <asm/kvm_asm.h>
> @@ -99,6 +102,92 @@ int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext)
>  	return r;
>  }
>  
> +unsigned int kvm_sve_max_vl;
> +
> +int kvm_arm_init_arch_resources(void)
> +{
> +	if (system_supports_sve()) {
> +		kvm_sve_max_vl = sve_max_virtualisable_vl;
> +
> +		/*
> +		 * The get_sve_reg()/set_sve_reg() ioctl interface will need
> +		 * to be extended with multiple register slice support in
> +		 * order to support vector lengths greater than
> +		 * SVE_VL_ARCH_MAX:
> +		 */
> +		if (WARN_ON(kvm_sve_max_vl > SVE_VL_ARCH_MAX))
> +			kvm_sve_max_vl = SVE_VL_ARCH_MAX;
> +
> +		/*
> +		 * Don't even try to make use of vector lengths that
> +		 * aren't available on all CPUs, for now:
> +		 */
> +		if (kvm_sve_max_vl < sve_max_vl)
> +			pr_warn("KVM: SVE vector length for guests limited to %u bytes\n",
> +				kvm_sve_max_vl);
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Finalize vcpu's maximum SVE vector length, allocating
> + * vcpu->arch.sve_state as necessary.
> + */
> +static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
> +{
> +	void *buf;
> +	unsigned int vl;
> +
> +	vl = vcpu->arch.sve_max_vl;
> +
> +	/*
> +	 * Resposibility for these properties is shared between
> +	 * kvm_arm_init_arch_resources(), kvm_vcpu_enable_sve() and
> +	 * set_sve_vls().  Double-check here just to be sure:
> +	 */
> +	if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl ||
> +		    vl > SVE_VL_ARCH_MAX))
> +		return -EIO;
> +
> +	buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	vcpu->arch.sve_state = buf;
> +	vcpu->arch.flags |= KVM_ARM64_VCPU_SVE_FINALIZED;
> +	return 0;
> +}
> +
> +int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what)
> +{
> +	switch (what) {
> +	case KVM_ARM_VCPU_SVE:
> +		if (!vcpu_has_sve(vcpu))
> +			return -EINVAL;
> +
> +		if (kvm_arm_vcpu_sve_finalized(vcpu))
> +			return -EPERM;
> +
> +		return kvm_vcpu_finalize_sve(vcpu);

In the next patch I see that we already have KVM_ARM64_GUEST_HAS_SVE
set in vcpu->arch.flags at this point. So if this kvm_vcpu_finalize_sve()
call fails, shouldn't we unset KVM_ARM64_GUEST_HAS_SVE and anything
else used to indicate the vcpu has sve?

Thanks,
drew


> +	}
> +
> +	return -EINVAL;
> +}
> +
> +bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu)
> +{
> +	if (vcpu_has_sve(vcpu) && !kvm_arm_vcpu_sve_finalized(vcpu))
> +		return false;
> +
> +	return true;
> +}
> +
> +void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
> +{
> +	kfree(vcpu->arch.sve_state);
> +}
> +
>  /**
>   * kvm_reset_vcpu - sets core registers and sys_regs to reset value
>   * @vcpu: The VCPU pointer
> -- 
> 2.1.4
> 
> _______________________________________________
> kvmarm mailing list
> kvmarm@lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 24/27] KVM: arm64/sve: Allow userspace to enable SVE for vcpus
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-04 20:36     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 20:36 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:49PM +0000, Dave Martin wrote:
> Now that all the pieces are in place, this patch offers a new flag
> KVM_ARM_VCPU_SVE that userspace can pass to KVM_ARM_VCPU_INIT to
> turn on SVE for the guest, on a per-vcpu basis.
> 
> As part of this, support for initialisation and reset of the SVE
> vector length set and registers is added in the appropriate places,
> as well as finally setting the KVM_ARM64_GUEST_HAS_SVE vcpu flag,
> to turn on the SVE support code.
> 
> Allocation of the SVE register storage in vcpu->arch.sve_state is
> deferred until the SVE configuration is finalized, by which time
> the size of the registers is known.
> 
> Setting the vector lengths supported by the vcpu is considered
> configuration of the emulated hardware rather than runtime
> configuration, so no support is offered for changing the vector
> lengths available to an existing vcpu across reset.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v6:
> 
>  * [Kristina Martšenko] Amend comments explaining the
>    kvm_arm_vcpu_sve_finalized() versus !kvm_arm_vcpu_sve_finalized()
>    cases in kvm_reset_vcpu().
> 
>    Actually, I've just deleted the comments, since if anything they're
>    more confusing than the code they're supposed to describe.
> 
> Changes since v5:
> 
>  * Refactored to make the code flow clearer and clarify responsiblity
>    for the various initialisation phases/checks.
> 
>    In place of the previous, confusingly dual-purpose kvm_reset_sve(),
>    enabling and resetting of SVE are split into separate functions and
>    called as appropriate from kvm_reset_vcpu().
> 
>    To avoid interactions with preempt_disable(), memory allocation is
>    done in the kvm_vcpu_first_fun_init() path instead.  To achieve
>    this, the SVE memory allocation is moved to kvm_arm_vcpu_finalize(),
>    which now takes on the role of actually doing deferred setup instead
>    of just setting a flag to indicate that the setup was done.
> 
>  * Add has_vhe() sanity-check into kvm_vcpu_enable_sve(), since it
>    makes more sense here than when resetting the vcpu.
> 
>  * When checking for SVE finalization in kvm_reset_vcpu(), call the new
>    SVE-specific function kvm_arm_vcpu_sve_finalized().  The new generic
>    check kvm_arm_vcpu_is_finalized() is unnecessarily broad here: using
>    the appropriate specific check makes the code more self-describing.
> 
>  * Definition of KVM_ARM_VCPU_SVE moved to KVM: arm64/sve: Add pseudo-
>    register for the guest's vector lengths (which needs it for the
>    KVM_ARM_VCPU_FINALIZE ioctl).
> ---
>  arch/arm64/include/asm/kvm_host.h |  3 +--
>  arch/arm64/kvm/reset.c            | 43 ++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 43 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 5475cc4..9d57cf8 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -49,8 +49,7 @@
>  
>  #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
>  
> -/* Will be incremented when KVM_ARM_VCPU_SVE is fully implemented: */
> -#define KVM_VCPU_MAX_FEATURES 4
> +#define KVM_VCPU_MAX_FEATURES 5
>  
>  #define KVM_REQ_SLEEP \
>  	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> index e7f9c06..32c5ac0 100644
> --- a/arch/arm64/kvm/reset.c
> +++ b/arch/arm64/kvm/reset.c
> @@ -20,10 +20,12 @@
>   */
>  
>  #include <linux/errno.h>
> +#include <linux/kernel.h>
>  #include <linux/kvm_host.h>
>  #include <linux/kvm.h>
>  #include <linux/hw_breakpoint.h>
>  #include <linux/slab.h>
> +#include <linux/string.h>
>  #include <linux/types.h>
>  
>  #include <kvm/arm_arch_timer.h>
> @@ -37,6 +39,7 @@
>  #include <asm/kvm_coproc.h>
>  #include <asm/kvm_emulate.h>
>  #include <asm/kvm_mmu.h>
> +#include <asm/virt.h>
>  
>  /* Maximum phys_shift supported for any VM on this host */
>  static u32 kvm_ipa_limit;
> @@ -130,6 +133,27 @@ int kvm_arm_init_arch_resources(void)
>  	return 0;
>  }
>  
> +static int kvm_vcpu_enable_sve(struct kvm_vcpu *vcpu)
> +{
> +	if (!system_supports_sve())
> +		return -EINVAL;
> +
> +	/* Verify that KVM startup enforced this when SVE was detected: */
> +	if (WARN_ON(!has_vhe()))
> +		return -EINVAL;
> +
> +	vcpu->arch.sve_max_vl = kvm_sve_max_vl;
> +
> +	/*
> +	 * Userspace can still customize the vector lengths by writing
> +	 * KVM_REG_ARM64_SVE_VLS.  Allocation is deferred until
> +	 * kvm_arm_vcpu_finalize(), which freezes the configuration.
> +	 */
> +	vcpu->arch.flags |= KVM_ARM64_GUEST_HAS_SVE;
> +
> +	return 0;
> +}
> +
>  /*
>   * Finalize vcpu's maximum SVE vector length, allocating
>   * vcpu->arch.sve_state as necessary.
> @@ -188,13 +212,20 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
>  	kfree(vcpu->arch.sve_state);
>  }
>  
> +static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
> +{
> +	if (vcpu_has_sve(vcpu))
> +		memset(vcpu->arch.sve_state, 0, vcpu_sve_state_size(vcpu));
> +}
> +
>  /**
>   * kvm_reset_vcpu - sets core registers and sys_regs to reset value
>   * @vcpu: The VCPU pointer
>   *
>   * This function finds the right table above and sets the registers on
>   * the virtual CPU struct to their architecturally defined reset
> - * values.
> + * values, except for registers whose reset is deferred until
> + * kvm_arm_vcpu_finalize().
>   *
>   * Note: This function can be called from two paths: The KVM_ARM_VCPU_INIT
>   * ioctl or as part of handling a request issued by another VCPU in the PSCI
> @@ -217,6 +248,16 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
>  	if (loaded)
>  		kvm_arch_vcpu_put(vcpu);
>  
> +	if (!kvm_arm_vcpu_sve_finalized(vcpu)) {
> +		if (test_bit(KVM_ARM_VCPU_SVE, vcpu->arch.features)) {
> +			ret = kvm_vcpu_enable_sve(vcpu);
> +			if (ret)
> +				goto out;
> +		}
> +	} else {
> +		kvm_vcpu_reset_sve(vcpu);
> +	}
> +
>  	switch (vcpu->arch.target) {
>  	default:
>  		if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) {
> -- 
> 2.1.4
>

Reviewed-by: Andrew Jones <drjones@redhat.com>
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v7 24/27] KVM: arm64/sve: Allow userspace to enable SVE for vcpus
@ 2019-04-04 20:36     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 20:36 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:49PM +0000, Dave Martin wrote:
> Now that all the pieces are in place, this patch offers a new flag
> KVM_ARM_VCPU_SVE that userspace can pass to KVM_ARM_VCPU_INIT to
> turn on SVE for the guest, on a per-vcpu basis.
> 
> As part of this, support for initialisation and reset of the SVE
> vector length set and registers is added in the appropriate places,
> as well as finally setting the KVM_ARM64_GUEST_HAS_SVE vcpu flag,
> to turn on the SVE support code.
> 
> Allocation of the SVE register storage in vcpu->arch.sve_state is
> deferred until the SVE configuration is finalized, by which time
> the size of the registers is known.
> 
> Setting the vector lengths supported by the vcpu is considered
> configuration of the emulated hardware rather than runtime
> configuration, so no support is offered for changing the vector
> lengths available to an existing vcpu across reset.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v6:
> 
>  * [Kristina Martšenko] Amend comments explaining the
>    kvm_arm_vcpu_sve_finalized() versus !kvm_arm_vcpu_sve_finalized()
>    cases in kvm_reset_vcpu().
> 
>    Actually, I've just deleted the comments, since if anything they're
>    more confusing than the code they're supposed to describe.
> 
> Changes since v5:
> 
>  * Refactored to make the code flow clearer and clarify responsiblity
>    for the various initialisation phases/checks.
> 
>    In place of the previous, confusingly dual-purpose kvm_reset_sve(),
>    enabling and resetting of SVE are split into separate functions and
>    called as appropriate from kvm_reset_vcpu().
> 
>    To avoid interactions with preempt_disable(), memory allocation is
>    done in the kvm_vcpu_first_fun_init() path instead.  To achieve
>    this, the SVE memory allocation is moved to kvm_arm_vcpu_finalize(),
>    which now takes on the role of actually doing deferred setup instead
>    of just setting a flag to indicate that the setup was done.
> 
>  * Add has_vhe() sanity-check into kvm_vcpu_enable_sve(), since it
>    makes more sense here than when resetting the vcpu.
> 
>  * When checking for SVE finalization in kvm_reset_vcpu(), call the new
>    SVE-specific function kvm_arm_vcpu_sve_finalized().  The new generic
>    check kvm_arm_vcpu_is_finalized() is unnecessarily broad here: using
>    the appropriate specific check makes the code more self-describing.
> 
>  * Definition of KVM_ARM_VCPU_SVE moved to KVM: arm64/sve: Add pseudo-
>    register for the guest's vector lengths (which needs it for the
>    KVM_ARM_VCPU_FINALIZE ioctl).
> ---
>  arch/arm64/include/asm/kvm_host.h |  3 +--
>  arch/arm64/kvm/reset.c            | 43 ++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 43 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 5475cc4..9d57cf8 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -49,8 +49,7 @@
>  
>  #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
>  
> -/* Will be incremented when KVM_ARM_VCPU_SVE is fully implemented: */
> -#define KVM_VCPU_MAX_FEATURES 4
> +#define KVM_VCPU_MAX_FEATURES 5
>  
>  #define KVM_REQ_SLEEP \
>  	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> index e7f9c06..32c5ac0 100644
> --- a/arch/arm64/kvm/reset.c
> +++ b/arch/arm64/kvm/reset.c
> @@ -20,10 +20,12 @@
>   */
>  
>  #include <linux/errno.h>
> +#include <linux/kernel.h>
>  #include <linux/kvm_host.h>
>  #include <linux/kvm.h>
>  #include <linux/hw_breakpoint.h>
>  #include <linux/slab.h>
> +#include <linux/string.h>
>  #include <linux/types.h>
>  
>  #include <kvm/arm_arch_timer.h>
> @@ -37,6 +39,7 @@
>  #include <asm/kvm_coproc.h>
>  #include <asm/kvm_emulate.h>
>  #include <asm/kvm_mmu.h>
> +#include <asm/virt.h>
>  
>  /* Maximum phys_shift supported for any VM on this host */
>  static u32 kvm_ipa_limit;
> @@ -130,6 +133,27 @@ int kvm_arm_init_arch_resources(void)
>  	return 0;
>  }
>  
> +static int kvm_vcpu_enable_sve(struct kvm_vcpu *vcpu)
> +{
> +	if (!system_supports_sve())
> +		return -EINVAL;
> +
> +	/* Verify that KVM startup enforced this when SVE was detected: */
> +	if (WARN_ON(!has_vhe()))
> +		return -EINVAL;
> +
> +	vcpu->arch.sve_max_vl = kvm_sve_max_vl;
> +
> +	/*
> +	 * Userspace can still customize the vector lengths by writing
> +	 * KVM_REG_ARM64_SVE_VLS.  Allocation is deferred until
> +	 * kvm_arm_vcpu_finalize(), which freezes the configuration.
> +	 */
> +	vcpu->arch.flags |= KVM_ARM64_GUEST_HAS_SVE;
> +
> +	return 0;
> +}
> +
>  /*
>   * Finalize vcpu's maximum SVE vector length, allocating
>   * vcpu->arch.sve_state as necessary.
> @@ -188,13 +212,20 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
>  	kfree(vcpu->arch.sve_state);
>  }
>  
> +static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu)
> +{
> +	if (vcpu_has_sve(vcpu))
> +		memset(vcpu->arch.sve_state, 0, vcpu_sve_state_size(vcpu));
> +}
> +
>  /**
>   * kvm_reset_vcpu - sets core registers and sys_regs to reset value
>   * @vcpu: The VCPU pointer
>   *
>   * This function finds the right table above and sets the registers on
>   * the virtual CPU struct to their architecturally defined reset
> - * values.
> + * values, except for registers whose reset is deferred until
> + * kvm_arm_vcpu_finalize().
>   *
>   * Note: This function can be called from two paths: The KVM_ARM_VCPU_INIT
>   * ioctl or as part of handling a request issued by another VCPU in the PSCI
> @@ -217,6 +248,16 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
>  	if (loaded)
>  		kvm_arch_vcpu_put(vcpu);
>  
> +	if (!kvm_arm_vcpu_sve_finalized(vcpu)) {
> +		if (test_bit(KVM_ARM_VCPU_SVE, vcpu->arch.features)) {
> +			ret = kvm_vcpu_enable_sve(vcpu);
> +			if (ret)
> +				goto out;
> +		}
> +	} else {
> +		kvm_vcpu_reset_sve(vcpu);
> +	}
> +
>  	switch (vcpu->arch.target) {
>  	default:
>  		if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) {
> -- 
> 2.1.4
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 25/27] KVM: arm64: Add a capability to advertise SVE support
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-04 20:39     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 20:39 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:50PM +0000, Dave Martin wrote:
> To provide a uniform way to check for KVM SVE support amongst other
> features, this patch adds a suitable capability KVM_CAP_ARM_SVE,
> and reports it as present when SVE is available.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * [Julien Thierry] Strip out has_vhe() sanity-check, which wasn't in
>    the most logical place, and anyway doesn't really belong in this
>    patch.
> 
>    Moved to KVM: arm64/sve: Allow userspace to enable SVE for vcpus
>    instead.
> ---
>  arch/arm64/kvm/reset.c   | 3 +++
>  include/uapi/linux/kvm.h | 1 +
>  2 files changed, 4 insertions(+)
> 
> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> index 32c5ac0..f13378d 100644
> --- a/arch/arm64/kvm/reset.c
> +++ b/arch/arm64/kvm/reset.c
> @@ -98,6 +98,9 @@ int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext)
>  	case KVM_CAP_ARM_VM_IPA_SIZE:
>  		r = kvm_ipa_limit;
>  		break;
> +	case KVM_CAP_ARM_SVE:
> +		r = system_supports_sve();
> +		break;
>  	default:
>  		r = 0;
>  	}
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index c3b8e7a..1d56444 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -988,6 +988,7 @@ struct kvm_ppc_resize_hpt {
>  #define KVM_CAP_ARM_VM_IPA_SIZE 165
>  #define KVM_CAP_MANUAL_DIRTY_LOG_PROTECT 166
>  #define KVM_CAP_HYPERV_CPUID 167
> +#define KVM_CAP_ARM_SVE 168
>  
>  #ifdef KVM_CAP_IRQ_ROUTING
>  
> -- 
> 2.1.4
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v7 25/27] KVM: arm64: Add a capability to advertise SVE support
@ 2019-04-04 20:39     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 20:39 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:50PM +0000, Dave Martin wrote:
> To provide a uniform way to check for KVM SVE support amongst other
> features, this patch adds a suitable capability KVM_CAP_ARM_SVE,
> and reports it as present when SVE is available.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * [Julien Thierry] Strip out has_vhe() sanity-check, which wasn't in
>    the most logical place, and anyway doesn't really belong in this
>    patch.
> 
>    Moved to KVM: arm64/sve: Allow userspace to enable SVE for vcpus
>    instead.
> ---
>  arch/arm64/kvm/reset.c   | 3 +++
>  include/uapi/linux/kvm.h | 1 +
>  2 files changed, 4 insertions(+)
> 
> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> index 32c5ac0..f13378d 100644
> --- a/arch/arm64/kvm/reset.c
> +++ b/arch/arm64/kvm/reset.c
> @@ -98,6 +98,9 @@ int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext)
>  	case KVM_CAP_ARM_VM_IPA_SIZE:
>  		r = kvm_ipa_limit;
>  		break;
> +	case KVM_CAP_ARM_SVE:
> +		r = system_supports_sve();
> +		break;
>  	default:
>  		r = 0;
>  	}
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index c3b8e7a..1d56444 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -988,6 +988,7 @@ struct kvm_ppc_resize_hpt {
>  #define KVM_CAP_ARM_VM_IPA_SIZE 165
>  #define KVM_CAP_MANUAL_DIRTY_LOG_PROTECT 166
>  #define KVM_CAP_HYPERV_CPUID 167
> +#define KVM_CAP_ARM_SVE 168
>  
>  #ifdef KVM_CAP_IRQ_ROUTING
>  
> -- 
> 2.1.4
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 27/27] KVM: arm64/sve: Document KVM API extensions for SVE
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-04 21:09     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 21:09 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:52PM +0000, Dave Martin wrote:
> This patch adds sections to the KVM API documentation describing
> the extensions for supporting the Scalable Vector Extension (SVE)
> in guests.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> 
> ---
> 
> Changes since v5:
> 
>  * Document KVM_ARM_VCPU_FINALIZE and its interactions with SVE.
> ---
>  Documentation/virtual/kvm/api.txt | 132 +++++++++++++++++++++++++++++++++++++-
>  1 file changed, 129 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index cd920dd..68509de 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -1873,6 +1873,7 @@ Parameters: struct kvm_one_reg (in)
>  Returns: 0 on success, negative value on failure
>  Errors:
>    ENOENT:   no such register
> +  EPERM:    register access forbidden for architecture-dependent reasons
>    EINVAL:   other errors, such as bad size encoding for a known register
>  
>  struct kvm_one_reg {
> @@ -2127,13 +2128,20 @@ Specifically:
>    0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
>    0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
>    0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
> -  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]
> -  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]
> +  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]    (*)
> +  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]    (*)
>      ...
> -  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]
> +  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]   (*)
>    0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
>    0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
>  
> +(*) These encodings are not accepted for SVE-enabled vcpus.  See
> +    KVM_ARM_VCPU_INIT.
> +
> +    The equivalent register content can be accessed via bits [127:0] of
> +    the corresponding SVE Zn registers instead for vcpus that have SVE
> +    enabled (see below).
> +
>  arm64 CCSIDR registers are demultiplexed by CSSELR value:
>    0x6020 0000 0011 00 <csselr:8>
>  
> @@ -2143,6 +2151,61 @@ arm64 system registers have the following id bit patterns:
>  arm64 firmware pseudo-registers have the following bit pattern:
>    0x6030 0000 0014 <regno:16>
>  
> +arm64 SVE registers have the following bit patterns:
> +  0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> +  0x6050 0000 0015 04 <n:4> <slice:5>   Pn bits[256*slice + 255 : 256*slice]
> +  0x6050 0000 0015 060 <slice:5>        FFR bits[256*slice + 255 : 256*slice]
> +  0x6060 0000 0015 ffff                 KVM_REG_ARM64_SVE_VLS pseudo-register
> +
> +Access to slices beyond the maximum vector length configured for the
> +vcpu (i.e., where 16 * slice >= max_vq (**)) will fail with ENOENT.

I've been doing pretty well keeping track of the 16's, 128's, VL's and
VQ's, but this example lost me. Also, should it be >= or just > ?

> +
> +These registers are only accessible on vcpus for which SVE is enabled.
> +See KVM_ARM_VCPU_INIT for details.
> +
> +In addition, except for KVM_REG_ARM64_SVE_VLS, these registers are not
> +accessible until the vcpu's SVE configuration has been finalized
> +using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).  See KVM_ARM_VCPU_INIT
> +and KVM_ARM_VCPU_FINALIZE for more information about this procedure.
> +
> +KVM_REG_ARM64_SVE_VLS is a pseudo-register that allows the set of vector
> +lengths supported by the vcpu to be discovered and configured by
> +userspace.  When transferred to or from user memory via KVM_GET_ONE_REG
> +or KVM_SET_ONE_REG, the value of this register is of type __u64[8], and
> +encodes the set of vector lengths as follows:
> +
> +__u64 vector_lengths[8];
> +
> +if (vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX &&
> +    ((vector_lengths[(vq - 1) / 64] >> ((vq - 1) % 64)) & 1))
> +	/* Vector length vq * 16 bytes supported */
> +else
> +	/* Vector length vq * 16 bytes not supported */
> +
> +(**) The maximum value vq for which the above condition is true is
> +max_vq.  This is the maximum vector length available to the guest on
> +this vcpu, and determines which register slices are visible through
> +this ioctl interface.
> +
> +(See Documentation/arm64/sve.txt for an explanation of the "vq"
> +nomenclature.)
> +
> +KVM_REG_ARM64_SVE_VLS is only accessible after KVM_ARM_VCPU_INIT.
> +KVM_ARM_VCPU_INIT initialises it to the best set of vector lengths that
> +the host supports.
> +
> +Userspace may subsequently modify it if desired until the vcpu's SVE
> +configuration is finalized using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
> +
> +Apart from simply removing all vector lengths from the host set that
> +exceed some value, support for arbitrarily chosen sets of vector lengths
> +is hardware-dependent and may not be available.  Attempting to configure
> +an invalid set of vector lengths via KVM_SET_ONE_REG will fail with
> +EINVAL.
> +
> +After the vcpu's SVE configuration is finalized, further attempts to
> +write this register will fail with EPERM.
> +
>  
>  MIPS registers are mapped using the lower 32 bits.  The upper 16 of that is
>  the register group type:
> @@ -2197,6 +2260,7 @@ Parameters: struct kvm_one_reg (in and out)
>  Returns: 0 on success, negative value on failure
>  Errors:
>    ENOENT:   no such register
> +  EPERM:    register access forbidden for architecture-dependent reasons
>    EINVAL:   other errors, such as bad size encoding for a known register
>  
>  This ioctl allows to receive the value of a single register implemented
> @@ -2690,6 +2754,33 @@ Possible features:
>  	- KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
>  	  Depends on KVM_CAP_ARM_PMU_V3.
>  
> +	- KVM_ARM_VCPU_SVE: Enables SVE for the CPU (arm64 only).
> +	  Depends on KVM_CAP_ARM_SVE.
> +	  Requires KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> +
> +	   * After KVM_ARM_VCPU_INIT:
> +
> +	      - KVM_REG_ARM64_SVE_VLS may be read using KVM_GET_ONE_REG: the
> +	        initial value of this pseudo-register indicates the best set of
> +	        vector lengths possible for a vcpu on this host.
> +
> +	   * Before KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> +
> +	      - KVM_RUN and KVM_GET_REG_LIST are not available;
> +
> +	      - KVM_GET_ONE_REG and KVM_SET_ONE_REG cannot be used to access
> +	        the scalable archietctural SVE registers
> +	        KVM_REG_ARM64_SVE_ZREG(), KVM_REG_ARM64_SVE_PREG() or
> +	        KVM_REG_ARM64_SVE_FFR;
> +
> +	      - KVM_REG_ARM64_SVE_VLS may optionally be written using
> +	        KVM_SET_ONE_REG, to modify the set of vector lengths available
> +	        for the vcpu.
> +
> +	   * After KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> +
> +	      - the KVM_REG_ARM64_SVE_VLS pseudo-register is immutable, and can
> +	        no longer be written using KVM_SET_ONE_REG.
>  
>  4.83 KVM_ARM_PREFERRED_TARGET
>  
> @@ -3904,6 +3995,41 @@ number of valid entries in the 'entries' array, which is then filled.
>  'index' and 'flags' fields in 'struct kvm_cpuid_entry2' are currently reserved,
>  userspace should not expect to get any particular value there.
>  
> +4.119 KVM_ARM_VCPU_FINALIZE
> +
> +Capability: KVM_CAP_ARM_SVE

The KVM_ARM_VCPU_FINALIZE vcpu ioctl isn't SVE specific, so it shouldn't
depend on the SVE cap. It should have it's own cap, or maybe it should
just be an KVM_ARM_VCPU_SVE_FINALIZE ioctl instead, i.e. not general.

> +Architectures: arm, arm64
> +Type: vcpu ioctl
> +Parameters: int feature (in)

This was called 'what' in the code.

> +Returns: 0 on success, -1 on error
> +Errors:
> +  EPERM:     feature not enabled, needs configuration, or already finalized
> +  EINVAL:    unknown feature
> +
> +Recognised values for feature:
> +  arm64      KVM_ARM_VCPU_SVE
> +
> +Finalizes the configuration of the specified vcpu feature.
> +
> +The vcpu must already have been initialised, enabling the affected feature, by
> +means of a successful KVM_ARM_VCPU_INIT call with the appropriate flag set in
> +features[].
> +
> +For affected vcpu features, this is a mandatory step that must be performed
> +before the vcpu is fully usable.
> +
> +Between KVM_ARM_VCPU_INIT and KVM_ARM_VCPU_FINALIZE, the feature may be
> +configured by use of ioctls such as KVM_SET_ONE_REG.  The exact configuration
> +that should be performaned and how to do it are feature-dependent.
> +
> +Other calls that depend on a particular feature being finalized, such as
> +KVM_RUN, KVM_GET_REG_LIST, KVM_GET_ONE_REG and KVM_SET_ONE_REG, will fail with
> +-EPERM unless the feature has already been finalized by means of a
> +KVM_ARM_VCPU_FINALIZE call.
> +
> +See KVM_ARM_VCPU_INIT for details of vcpu features that require finalization
> +using this ioctl.
> +
>  5. The kvm_run structure
>  ------------------------
>

I'm still not sure about EPERM vs. ENOEXEC.

Thanks,
drew

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

* Re: [PATCH v7 27/27] KVM: arm64/sve: Document KVM API extensions for SVE
@ 2019-04-04 21:09     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 21:09 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:52PM +0000, Dave Martin wrote:
> This patch adds sections to the KVM API documentation describing
> the extensions for supporting the Scalable Vector Extension (SVE)
> in guests.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> 
> ---
> 
> Changes since v5:
> 
>  * Document KVM_ARM_VCPU_FINALIZE and its interactions with SVE.
> ---
>  Documentation/virtual/kvm/api.txt | 132 +++++++++++++++++++++++++++++++++++++-
>  1 file changed, 129 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index cd920dd..68509de 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -1873,6 +1873,7 @@ Parameters: struct kvm_one_reg (in)
>  Returns: 0 on success, negative value on failure
>  Errors:
>    ENOENT:   no such register
> +  EPERM:    register access forbidden for architecture-dependent reasons
>    EINVAL:   other errors, such as bad size encoding for a known register
>  
>  struct kvm_one_reg {
> @@ -2127,13 +2128,20 @@ Specifically:
>    0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
>    0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
>    0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
> -  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]
> -  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]
> +  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]    (*)
> +  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]    (*)
>      ...
> -  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]
> +  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]   (*)
>    0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
>    0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
>  
> +(*) These encodings are not accepted for SVE-enabled vcpus.  See
> +    KVM_ARM_VCPU_INIT.
> +
> +    The equivalent register content can be accessed via bits [127:0] of
> +    the corresponding SVE Zn registers instead for vcpus that have SVE
> +    enabled (see below).
> +
>  arm64 CCSIDR registers are demultiplexed by CSSELR value:
>    0x6020 0000 0011 00 <csselr:8>
>  
> @@ -2143,6 +2151,61 @@ arm64 system registers have the following id bit patterns:
>  arm64 firmware pseudo-registers have the following bit pattern:
>    0x6030 0000 0014 <regno:16>
>  
> +arm64 SVE registers have the following bit patterns:
> +  0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> +  0x6050 0000 0015 04 <n:4> <slice:5>   Pn bits[256*slice + 255 : 256*slice]
> +  0x6050 0000 0015 060 <slice:5>        FFR bits[256*slice + 255 : 256*slice]
> +  0x6060 0000 0015 ffff                 KVM_REG_ARM64_SVE_VLS pseudo-register
> +
> +Access to slices beyond the maximum vector length configured for the
> +vcpu (i.e., where 16 * slice >= max_vq (**)) will fail with ENOENT.

I've been doing pretty well keeping track of the 16's, 128's, VL's and
VQ's, but this example lost me. Also, should it be >= or just > ?

> +
> +These registers are only accessible on vcpus for which SVE is enabled.
> +See KVM_ARM_VCPU_INIT for details.
> +
> +In addition, except for KVM_REG_ARM64_SVE_VLS, these registers are not
> +accessible until the vcpu's SVE configuration has been finalized
> +using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).  See KVM_ARM_VCPU_INIT
> +and KVM_ARM_VCPU_FINALIZE for more information about this procedure.
> +
> +KVM_REG_ARM64_SVE_VLS is a pseudo-register that allows the set of vector
> +lengths supported by the vcpu to be discovered and configured by
> +userspace.  When transferred to or from user memory via KVM_GET_ONE_REG
> +or KVM_SET_ONE_REG, the value of this register is of type __u64[8], and
> +encodes the set of vector lengths as follows:
> +
> +__u64 vector_lengths[8];
> +
> +if (vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX &&
> +    ((vector_lengths[(vq - 1) / 64] >> ((vq - 1) % 64)) & 1))
> +	/* Vector length vq * 16 bytes supported */
> +else
> +	/* Vector length vq * 16 bytes not supported */
> +
> +(**) The maximum value vq for which the above condition is true is
> +max_vq.  This is the maximum vector length available to the guest on
> +this vcpu, and determines which register slices are visible through
> +this ioctl interface.
> +
> +(See Documentation/arm64/sve.txt for an explanation of the "vq"
> +nomenclature.)
> +
> +KVM_REG_ARM64_SVE_VLS is only accessible after KVM_ARM_VCPU_INIT.
> +KVM_ARM_VCPU_INIT initialises it to the best set of vector lengths that
> +the host supports.
> +
> +Userspace may subsequently modify it if desired until the vcpu's SVE
> +configuration is finalized using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
> +
> +Apart from simply removing all vector lengths from the host set that
> +exceed some value, support for arbitrarily chosen sets of vector lengths
> +is hardware-dependent and may not be available.  Attempting to configure
> +an invalid set of vector lengths via KVM_SET_ONE_REG will fail with
> +EINVAL.
> +
> +After the vcpu's SVE configuration is finalized, further attempts to
> +write this register will fail with EPERM.
> +
>  
>  MIPS registers are mapped using the lower 32 bits.  The upper 16 of that is
>  the register group type:
> @@ -2197,6 +2260,7 @@ Parameters: struct kvm_one_reg (in and out)
>  Returns: 0 on success, negative value on failure
>  Errors:
>    ENOENT:   no such register
> +  EPERM:    register access forbidden for architecture-dependent reasons
>    EINVAL:   other errors, such as bad size encoding for a known register
>  
>  This ioctl allows to receive the value of a single register implemented
> @@ -2690,6 +2754,33 @@ Possible features:
>  	- KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
>  	  Depends on KVM_CAP_ARM_PMU_V3.
>  
> +	- KVM_ARM_VCPU_SVE: Enables SVE for the CPU (arm64 only).
> +	  Depends on KVM_CAP_ARM_SVE.
> +	  Requires KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> +
> +	   * After KVM_ARM_VCPU_INIT:
> +
> +	      - KVM_REG_ARM64_SVE_VLS may be read using KVM_GET_ONE_REG: the
> +	        initial value of this pseudo-register indicates the best set of
> +	        vector lengths possible for a vcpu on this host.
> +
> +	   * Before KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> +
> +	      - KVM_RUN and KVM_GET_REG_LIST are not available;
> +
> +	      - KVM_GET_ONE_REG and KVM_SET_ONE_REG cannot be used to access
> +	        the scalable archietctural SVE registers
> +	        KVM_REG_ARM64_SVE_ZREG(), KVM_REG_ARM64_SVE_PREG() or
> +	        KVM_REG_ARM64_SVE_FFR;
> +
> +	      - KVM_REG_ARM64_SVE_VLS may optionally be written using
> +	        KVM_SET_ONE_REG, to modify the set of vector lengths available
> +	        for the vcpu.
> +
> +	   * After KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> +
> +	      - the KVM_REG_ARM64_SVE_VLS pseudo-register is immutable, and can
> +	        no longer be written using KVM_SET_ONE_REG.
>  
>  4.83 KVM_ARM_PREFERRED_TARGET
>  
> @@ -3904,6 +3995,41 @@ number of valid entries in the 'entries' array, which is then filled.
>  'index' and 'flags' fields in 'struct kvm_cpuid_entry2' are currently reserved,
>  userspace should not expect to get any particular value there.
>  
> +4.119 KVM_ARM_VCPU_FINALIZE
> +
> +Capability: KVM_CAP_ARM_SVE

The KVM_ARM_VCPU_FINALIZE vcpu ioctl isn't SVE specific, so it shouldn't
depend on the SVE cap. It should have it's own cap, or maybe it should
just be an KVM_ARM_VCPU_SVE_FINALIZE ioctl instead, i.e. not general.

> +Architectures: arm, arm64
> +Type: vcpu ioctl
> +Parameters: int feature (in)

This was called 'what' in the code.

> +Returns: 0 on success, -1 on error
> +Errors:
> +  EPERM:     feature not enabled, needs configuration, or already finalized
> +  EINVAL:    unknown feature
> +
> +Recognised values for feature:
> +  arm64      KVM_ARM_VCPU_SVE
> +
> +Finalizes the configuration of the specified vcpu feature.
> +
> +The vcpu must already have been initialised, enabling the affected feature, by
> +means of a successful KVM_ARM_VCPU_INIT call with the appropriate flag set in
> +features[].
> +
> +For affected vcpu features, this is a mandatory step that must be performed
> +before the vcpu is fully usable.
> +
> +Between KVM_ARM_VCPU_INIT and KVM_ARM_VCPU_FINALIZE, the feature may be
> +configured by use of ioctls such as KVM_SET_ONE_REG.  The exact configuration
> +that should be performaned and how to do it are feature-dependent.
> +
> +Other calls that depend on a particular feature being finalized, such as
> +KVM_RUN, KVM_GET_REG_LIST, KVM_GET_ONE_REG and KVM_SET_ONE_REG, will fail with
> +-EPERM unless the feature has already been finalized by means of a
> +KVM_ARM_VCPU_FINALIZE call.
> +
> +See KVM_ARM_VCPU_INIT for details of vcpu features that require finalization
> +using this ioctl.
> +
>  5. The kvm_run structure
>  ------------------------
>

I'm still not sure about EPERM vs. ENOEXEC.

Thanks,
drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 14/27] KVM: Allow 2048-bit register access via ioctl interface
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-04 21:11     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 21:11 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:39PM +0000, Dave Martin wrote:
> The Arm SVE architecture defines registers that are up to 2048 bits
> in size (with some possibility of further future expansion).
> 
> In order to avoid the need for an excessively large number of
> ioctls when saving and restoring a vcpu's registers, this patch
> adds a #define to make support for individual 2048-bit registers
> through the KVM_{GET,SET}_ONE_REG ioctl interface official.  This
> will allow each SVE register to be accessed in a single call.
> 
> There are sufficient spare bits in the register id size field for
> this change, so there is no ABI impact, providing that
> KVM_GET_REG_LIST does not enumerate any 2048-bit register unless
> userspace explicitly opts in to the relevant architecture-specific
> features.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> ---
>  include/uapi/linux/kvm.h | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 6d4ea4b..dc77a5a 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -1145,6 +1145,7 @@ struct kvm_dirty_tlb {
>  #define KVM_REG_SIZE_U256	0x0050000000000000ULL
>  #define KVM_REG_SIZE_U512	0x0060000000000000ULL
>  #define KVM_REG_SIZE_U1024	0x0070000000000000ULL
> +#define KVM_REG_SIZE_U2048	0x0080000000000000ULL
>  
>  struct kvm_reg_list {
>  	__u64 n; /* number of regs */
> -- 
> 2.1.4
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v7 14/27] KVM: Allow 2048-bit register access via ioctl interface
@ 2019-04-04 21:11     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 21:11 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:39PM +0000, Dave Martin wrote:
> The Arm SVE architecture defines registers that are up to 2048 bits
> in size (with some possibility of further future expansion).
> 
> In order to avoid the need for an excessively large number of
> ioctls when saving and restoring a vcpu's registers, this patch
> adds a #define to make support for individual 2048-bit registers
> through the KVM_{GET,SET}_ONE_REG ioctl interface official.  This
> will allow each SVE register to be accessed in a single call.
> 
> There are sufficient spare bits in the register id size field for
> this change, so there is no ABI impact, providing that
> KVM_GET_REG_LIST does not enumerate any 2048-bit register unless
> userspace explicitly opts in to the relevant architecture-specific
> features.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> ---
>  include/uapi/linux/kvm.h | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 6d4ea4b..dc77a5a 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -1145,6 +1145,7 @@ struct kvm_dirty_tlb {
>  #define KVM_REG_SIZE_U256	0x0050000000000000ULL
>  #define KVM_REG_SIZE_U512	0x0060000000000000ULL
>  #define KVM_REG_SIZE_U1024	0x0070000000000000ULL
> +#define KVM_REG_SIZE_U2048	0x0080000000000000ULL
>  
>  struct kvm_reg_list {
>  	__u64 n; /* number of regs */
> -- 
> 2.1.4
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 10/27] KVM: arm64: Propagate vcpu into read_id_reg()
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-04 21:15     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 21:15 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:35PM +0000, Dave Martin wrote:
> Architecture features that are conditionally visible to the guest
> will require run-time checks in the ID register accessor functions.
> In particular, read_id_reg() will need to perform checks in order
> to generate the correct emulated value for certain ID register
> fields such as ID_AA64PFR0_EL1.SVE for example.
> 
> This patch propagates vcpu into read_id_reg() so that future
> patches can add run-time checks on the guest configuration here.
> 
> For now, there is no functional change.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> ---
>  arch/arm64/kvm/sys_regs.c | 23 +++++++++++++----------
>  1 file changed, 13 insertions(+), 10 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v7 10/27] KVM: arm64: Propagate vcpu into read_id_reg()
@ 2019-04-04 21:15     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 21:15 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:35PM +0000, Dave Martin wrote:
> Architecture features that are conditionally visible to the guest
> will require run-time checks in the ID register accessor functions.
> In particular, read_id_reg() will need to perform checks in order
> to generate the correct emulated value for certain ID register
> fields such as ID_AA64PFR0_EL1.SVE for example.
> 
> This patch propagates vcpu into read_id_reg() so that future
> patches can add run-time checks on the guest configuration here.
> 
> For now, there is no functional change.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> ---
>  arch/arm64/kvm/sys_regs.c | 23 +++++++++++++----------
>  1 file changed, 13 insertions(+), 10 deletions(-)
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 09/27] KVM: arm64: Add a vcpu flag to control SVE visibility for the guest
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-04 21:15     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 21:15 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:34PM +0000, Dave Martin wrote:
> Since SVE will be enabled or disabled on a per-vcpu basis, a flag
> is needed in order to track which vcpus have it enabled.
> 
> This patch adds a suitable flag and a helper for checking it.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> ---
>  arch/arm64/include/asm/kvm_host.h | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 6d10100..ad4f7f0 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -328,6 +328,10 @@ struct kvm_vcpu_arch {
>  #define KVM_ARM64_FP_HOST		(1 << 2) /* host FP regs loaded */
>  #define KVM_ARM64_HOST_SVE_IN_USE	(1 << 3) /* backup for host TIF_SVE */
>  #define KVM_ARM64_HOST_SVE_ENABLED	(1 << 4) /* SVE enabled for EL0 */
> +#define KVM_ARM64_GUEST_HAS_SVE		(1 << 5) /* SVE exposed to guest */
> +
> +#define vcpu_has_sve(vcpu) (system_supports_sve() && \
> +			    ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))
>  
>  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
>  
> -- 
> 2.1.4
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v7 09/27] KVM: arm64: Add a vcpu flag to control SVE visibility for the guest
@ 2019-04-04 21:15     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 21:15 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:34PM +0000, Dave Martin wrote:
> Since SVE will be enabled or disabled on a per-vcpu basis, a flag
> is needed in order to track which vcpus have it enabled.
> 
> This patch adds a suitable flag and a helper for checking it.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> ---
>  arch/arm64/include/asm/kvm_host.h | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 6d10100..ad4f7f0 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -328,6 +328,10 @@ struct kvm_vcpu_arch {
>  #define KVM_ARM64_FP_HOST		(1 << 2) /* host FP regs loaded */
>  #define KVM_ARM64_HOST_SVE_IN_USE	(1 << 3) /* backup for host TIF_SVE */
>  #define KVM_ARM64_HOST_SVE_ENABLED	(1 << 4) /* SVE enabled for EL0 */
> +#define KVM_ARM64_GUEST_HAS_SVE		(1 << 5) /* SVE exposed to guest */
> +
> +#define vcpu_has_sve(vcpu) (system_supports_sve() && \
> +			    ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))
>  
>  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
>  
> -- 
> 2.1.4
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 07/27] arm64/sve: Check SVE virtualisability
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-04 21:21     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 21:21 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:32PM +0000, Dave Martin wrote:
> Due to the way the effective SVE vector length is controlled and
> trapped at different exception levels, certain mismatches in the
> sets of vector lengths supported by different physical CPUs in the
> system may prevent straightforward virtualisation of SVE at parity
> with the host.
> 
> This patch analyses the extent to which SVE can be virtualised
> safely without interfering with migration of vcpus between physical
> CPUs, and rejects late secondary CPUs that would erode the
> situation further.
> 
> It is left up to KVM to decide what to do with this information.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> QUESTION: The final structure of this code makes it quite natural to
> clamp the vector length for KVM guests to the maximum value supportable
> across all CPUs; such a value is guaranteed to exist, but may be
> surprisingly small on a given hardware platform.
> 
> Should we be stricter and actually refuse to support KVM at all on such
> hardware?  This may help to force people to fix Linux (or the
> architecture) if/when this issue comes up.

Blocking KVM would be too harsh, since the users of the host may not
care about guests with SVE, but still care about guests.

> 
> For now, I stick with pr_warn() and make do with a limited SVE vector
> length for guests.

I think that's probably the best we can do.

> 
> Changes since v5:
> 
>  * pr_info() about the presence of unvirtualisable vector lengths in
>    sve_setup() upgrade to pr_warn(), for consistency with
>    sve_verify_vq_map().
> ---
>  arch/arm64/include/asm/fpsimd.h |  1 +
>  arch/arm64/kernel/cpufeature.c  |  2 +-
>  arch/arm64/kernel/fpsimd.c      | 86 ++++++++++++++++++++++++++++++++++-------
>  3 files changed, 73 insertions(+), 16 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
> index dd1ad39..964adc9 100644
> --- a/arch/arm64/include/asm/fpsimd.h
> +++ b/arch/arm64/include/asm/fpsimd.h
> @@ -87,6 +87,7 @@ extern void sve_kernel_enable(const struct arm64_cpu_capabilities *__unused);
>  extern u64 read_zcr_features(void);
>  
>  extern int __ro_after_init sve_max_vl;
> +extern int __ro_after_init sve_max_virtualisable_vl;
>  
>  #ifdef CONFIG_ARM64_SVE
>  
> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index 4061de1..7f8cc51 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -1863,7 +1863,7 @@ static void verify_sve_features(void)
>  	unsigned int len = zcr & ZCR_ELx_LEN_MASK;
>  
>  	if (len < safe_len || sve_verify_vq_map()) {
> -		pr_crit("CPU%d: SVE: required vector length(s) missing\n",
> +		pr_crit("CPU%d: SVE: vector length support mismatch\n",
>  			smp_processor_id());
>  		cpu_die_early();
>  	}
> diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
> index f59ea67..b219796a 100644
> --- a/arch/arm64/kernel/fpsimd.c
> +++ b/arch/arm64/kernel/fpsimd.c
> @@ -18,6 +18,7 @@
>   */
>  
>  #include <linux/bitmap.h>
> +#include <linux/bitops.h>
>  #include <linux/bottom_half.h>
>  #include <linux/bug.h>
>  #include <linux/cache.h>
> @@ -48,6 +49,7 @@
>  #include <asm/sigcontext.h>
>  #include <asm/sysreg.h>
>  #include <asm/traps.h>
> +#include <asm/virt.h>
>  
>  #define FPEXC_IOF	(1 << 0)
>  #define FPEXC_DZF	(1 << 1)
> @@ -130,14 +132,18 @@ static int sve_default_vl = -1;
>  
>  /* Maximum supported vector length across all CPUs (initially poisoned) */
>  int __ro_after_init sve_max_vl = SVE_VL_MIN;
> +int __ro_after_init sve_max_virtualisable_vl = SVE_VL_MIN;
>  /* Set of available vector lengths, as vq_to_bit(vq): */
>  static __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
> +/* Set of vector lengths present on at least one cpu: */
> +static __ro_after_init DECLARE_BITMAP(sve_vq_partial_map, SVE_VQ_MAX);
>  static void __percpu *efi_sve_state;
>  
>  #else /* ! CONFIG_ARM64_SVE */
>  
>  /* Dummy declaration for code that will be optimised out: */
>  extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
> +extern __ro_after_init DECLARE_BITMAP(sve_vq_partial_map, SVE_VQ_MAX);
>  extern void __percpu *efi_sve_state;
>  
>  #endif /* ! CONFIG_ARM64_SVE */
> @@ -623,12 +629,6 @@ int sve_get_current_vl(void)
>  	return sve_prctl_status(0);
>  }
>  
> -/*
> - * Bitmap for temporary storage of the per-CPU set of supported vector lengths
> - * during secondary boot.
> - */
> -static DECLARE_BITMAP(sve_secondary_vq_map, SVE_VQ_MAX);
> -
>  static void sve_probe_vqs(DECLARE_BITMAP(map, SVE_VQ_MAX))
>  {
>  	unsigned int vq, vl;
> @@ -654,6 +654,7 @@ static void sve_probe_vqs(DECLARE_BITMAP(map, SVE_VQ_MAX))
>  void __init sve_init_vq_map(void)
>  {
>  	sve_probe_vqs(sve_vq_map);
> +	bitmap_copy(sve_vq_partial_map, sve_vq_map, SVE_VQ_MAX);
>  }
>  
>  /*
> @@ -663,8 +664,11 @@ void __init sve_init_vq_map(void)
>   */
>  void sve_update_vq_map(void)
>  {
> -	sve_probe_vqs(sve_secondary_vq_map);
> -	bitmap_and(sve_vq_map, sve_vq_map, sve_secondary_vq_map, SVE_VQ_MAX);
> +	DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
> +
> +	sve_probe_vqs(tmp_map);
> +	bitmap_and(sve_vq_map, sve_vq_map, tmp_map, SVE_VQ_MAX);
> +	bitmap_or(sve_vq_partial_map, sve_vq_partial_map, tmp_map, SVE_VQ_MAX);
>  }
>  
>  /*
> @@ -673,18 +677,48 @@ void sve_update_vq_map(void)
>   */
>  int sve_verify_vq_map(void)
>  {
> -	int ret = 0;
> +	DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
> +	unsigned long b;
>  
> -	sve_probe_vqs(sve_secondary_vq_map);
> -	bitmap_andnot(sve_secondary_vq_map, sve_vq_map, sve_secondary_vq_map,
> -		      SVE_VQ_MAX);
> -	if (!bitmap_empty(sve_secondary_vq_map, SVE_VQ_MAX)) {
> +	sve_probe_vqs(tmp_map);
> +
> +	bitmap_complement(tmp_map, tmp_map, SVE_VQ_MAX);
> +	if (bitmap_intersects(tmp_map, sve_vq_map, SVE_VQ_MAX)) {
>  		pr_warn("SVE: cpu%d: Required vector length(s) missing\n",
>  			smp_processor_id());
> -		ret = -EINVAL;
> +		return -EINVAL;
>  	}
>  
> -	return ret;
> +	if (!IS_ENABLED(CONFIG_KVM) || !is_hyp_mode_available())
> +		return 0;
> +
> +	/*
> +	 * For KVM, it is necessary to ensure that this CPU doesn't
> +	 * support any vector length that guests may have probed as
> +	 * unsupported.
> +	 */
> +
> +	/* Recover the set of supported VQs: */
> +	bitmap_complement(tmp_map, tmp_map, SVE_VQ_MAX);
> +	/* Find VQs supported that are not globally supported: */
> +	bitmap_andnot(tmp_map, tmp_map, sve_vq_map, SVE_VQ_MAX);
> +
> +	/* Find the lowest such VQ, if any: */
> +	b = find_last_bit(tmp_map, SVE_VQ_MAX);
> +	if (b >= SVE_VQ_MAX)
> +		return 0; /* no mismatches */
> +
> +	/*
> +	 * Mismatches above sve_max_virtualisable_vl are fine, since
> +	 * no guest is allowed to configure ZCR_EL2.LEN to exceed this:
> +	 */
> +	if (sve_vl_from_vq(bit_to_vq(b)) <= sve_max_virtualisable_vl) {
> +		pr_warn("SVE: cpu%d: Unsupported vector length(s) present\n",
> +			smp_processor_id());
> +		return -EINVAL;
> +	}
> +
> +	return 0;
>  }
>  
>  static void __init sve_efi_setup(void)
> @@ -751,6 +785,8 @@ u64 read_zcr_features(void)
>  void __init sve_setup(void)
>  {
>  	u64 zcr;
> +	DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
> +	unsigned long b;
>  
>  	if (!system_supports_sve())
>  		return;
> @@ -779,11 +815,31 @@ void __init sve_setup(void)
>  	 */
>  	sve_default_vl = find_supported_vector_length(64);
>  
> +	bitmap_andnot(tmp_map, sve_vq_partial_map, sve_vq_map,
> +		      SVE_VQ_MAX);
> +
> +	b = find_last_bit(tmp_map, SVE_VQ_MAX);
> +	if (b >= SVE_VQ_MAX)
> +		/* No non-virtualisable VLs found */
> +		sve_max_virtualisable_vl = SVE_VQ_MAX;
> +	else if (WARN_ON(b == SVE_VQ_MAX - 1))
> +		/* No virtualisable VLs?  This is architecturally forbidden. */
> +		sve_max_virtualisable_vl = SVE_VQ_MIN;
> +	else /* b + 1 < SVE_VQ_MAX */
> +		sve_max_virtualisable_vl = sve_vl_from_vq(bit_to_vq(b + 1));
> +
> +	if (sve_max_virtualisable_vl > sve_max_vl)
> +		sve_max_virtualisable_vl = sve_max_vl;
> +
>  	pr_info("SVE: maximum available vector length %u bytes per vector\n",
>  		sve_max_vl);
>  	pr_info("SVE: default vector length %u bytes per vector\n",
>  		sve_default_vl);
>  
> +	/* KVM decides whether to support mismatched systems. Just warn here: */
> +	if (sve_max_virtualisable_vl < sve_max_vl)
> +		pr_warn("SVE: unvirtualisable vector lengths present\n");
> +
>  	sve_efi_setup();
>  }
>  
> -- 
> 2.1.4
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v7 07/27] arm64/sve: Check SVE virtualisability
@ 2019-04-04 21:21     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 21:21 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:32PM +0000, Dave Martin wrote:
> Due to the way the effective SVE vector length is controlled and
> trapped at different exception levels, certain mismatches in the
> sets of vector lengths supported by different physical CPUs in the
> system may prevent straightforward virtualisation of SVE at parity
> with the host.
> 
> This patch analyses the extent to which SVE can be virtualised
> safely without interfering with migration of vcpus between physical
> CPUs, and rejects late secondary CPUs that would erode the
> situation further.
> 
> It is left up to KVM to decide what to do with this information.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> QUESTION: The final structure of this code makes it quite natural to
> clamp the vector length for KVM guests to the maximum value supportable
> across all CPUs; such a value is guaranteed to exist, but may be
> surprisingly small on a given hardware platform.
> 
> Should we be stricter and actually refuse to support KVM at all on such
> hardware?  This may help to force people to fix Linux (or the
> architecture) if/when this issue comes up.

Blocking KVM would be too harsh, since the users of the host may not
care about guests with SVE, but still care about guests.

> 
> For now, I stick with pr_warn() and make do with a limited SVE vector
> length for guests.

I think that's probably the best we can do.

> 
> Changes since v5:
> 
>  * pr_info() about the presence of unvirtualisable vector lengths in
>    sve_setup() upgrade to pr_warn(), for consistency with
>    sve_verify_vq_map().
> ---
>  arch/arm64/include/asm/fpsimd.h |  1 +
>  arch/arm64/kernel/cpufeature.c  |  2 +-
>  arch/arm64/kernel/fpsimd.c      | 86 ++++++++++++++++++++++++++++++++++-------
>  3 files changed, 73 insertions(+), 16 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
> index dd1ad39..964adc9 100644
> --- a/arch/arm64/include/asm/fpsimd.h
> +++ b/arch/arm64/include/asm/fpsimd.h
> @@ -87,6 +87,7 @@ extern void sve_kernel_enable(const struct arm64_cpu_capabilities *__unused);
>  extern u64 read_zcr_features(void);
>  
>  extern int __ro_after_init sve_max_vl;
> +extern int __ro_after_init sve_max_virtualisable_vl;
>  
>  #ifdef CONFIG_ARM64_SVE
>  
> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index 4061de1..7f8cc51 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -1863,7 +1863,7 @@ static void verify_sve_features(void)
>  	unsigned int len = zcr & ZCR_ELx_LEN_MASK;
>  
>  	if (len < safe_len || sve_verify_vq_map()) {
> -		pr_crit("CPU%d: SVE: required vector length(s) missing\n",
> +		pr_crit("CPU%d: SVE: vector length support mismatch\n",
>  			smp_processor_id());
>  		cpu_die_early();
>  	}
> diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
> index f59ea67..b219796a 100644
> --- a/arch/arm64/kernel/fpsimd.c
> +++ b/arch/arm64/kernel/fpsimd.c
> @@ -18,6 +18,7 @@
>   */
>  
>  #include <linux/bitmap.h>
> +#include <linux/bitops.h>
>  #include <linux/bottom_half.h>
>  #include <linux/bug.h>
>  #include <linux/cache.h>
> @@ -48,6 +49,7 @@
>  #include <asm/sigcontext.h>
>  #include <asm/sysreg.h>
>  #include <asm/traps.h>
> +#include <asm/virt.h>
>  
>  #define FPEXC_IOF	(1 << 0)
>  #define FPEXC_DZF	(1 << 1)
> @@ -130,14 +132,18 @@ static int sve_default_vl = -1;
>  
>  /* Maximum supported vector length across all CPUs (initially poisoned) */
>  int __ro_after_init sve_max_vl = SVE_VL_MIN;
> +int __ro_after_init sve_max_virtualisable_vl = SVE_VL_MIN;
>  /* Set of available vector lengths, as vq_to_bit(vq): */
>  static __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
> +/* Set of vector lengths present on at least one cpu: */
> +static __ro_after_init DECLARE_BITMAP(sve_vq_partial_map, SVE_VQ_MAX);
>  static void __percpu *efi_sve_state;
>  
>  #else /* ! CONFIG_ARM64_SVE */
>  
>  /* Dummy declaration for code that will be optimised out: */
>  extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
> +extern __ro_after_init DECLARE_BITMAP(sve_vq_partial_map, SVE_VQ_MAX);
>  extern void __percpu *efi_sve_state;
>  
>  #endif /* ! CONFIG_ARM64_SVE */
> @@ -623,12 +629,6 @@ int sve_get_current_vl(void)
>  	return sve_prctl_status(0);
>  }
>  
> -/*
> - * Bitmap for temporary storage of the per-CPU set of supported vector lengths
> - * during secondary boot.
> - */
> -static DECLARE_BITMAP(sve_secondary_vq_map, SVE_VQ_MAX);
> -
>  static void sve_probe_vqs(DECLARE_BITMAP(map, SVE_VQ_MAX))
>  {
>  	unsigned int vq, vl;
> @@ -654,6 +654,7 @@ static void sve_probe_vqs(DECLARE_BITMAP(map, SVE_VQ_MAX))
>  void __init sve_init_vq_map(void)
>  {
>  	sve_probe_vqs(sve_vq_map);
> +	bitmap_copy(sve_vq_partial_map, sve_vq_map, SVE_VQ_MAX);
>  }
>  
>  /*
> @@ -663,8 +664,11 @@ void __init sve_init_vq_map(void)
>   */
>  void sve_update_vq_map(void)
>  {
> -	sve_probe_vqs(sve_secondary_vq_map);
> -	bitmap_and(sve_vq_map, sve_vq_map, sve_secondary_vq_map, SVE_VQ_MAX);
> +	DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
> +
> +	sve_probe_vqs(tmp_map);
> +	bitmap_and(sve_vq_map, sve_vq_map, tmp_map, SVE_VQ_MAX);
> +	bitmap_or(sve_vq_partial_map, sve_vq_partial_map, tmp_map, SVE_VQ_MAX);
>  }
>  
>  /*
> @@ -673,18 +677,48 @@ void sve_update_vq_map(void)
>   */
>  int sve_verify_vq_map(void)
>  {
> -	int ret = 0;
> +	DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
> +	unsigned long b;
>  
> -	sve_probe_vqs(sve_secondary_vq_map);
> -	bitmap_andnot(sve_secondary_vq_map, sve_vq_map, sve_secondary_vq_map,
> -		      SVE_VQ_MAX);
> -	if (!bitmap_empty(sve_secondary_vq_map, SVE_VQ_MAX)) {
> +	sve_probe_vqs(tmp_map);
> +
> +	bitmap_complement(tmp_map, tmp_map, SVE_VQ_MAX);
> +	if (bitmap_intersects(tmp_map, sve_vq_map, SVE_VQ_MAX)) {
>  		pr_warn("SVE: cpu%d: Required vector length(s) missing\n",
>  			smp_processor_id());
> -		ret = -EINVAL;
> +		return -EINVAL;
>  	}
>  
> -	return ret;
> +	if (!IS_ENABLED(CONFIG_KVM) || !is_hyp_mode_available())
> +		return 0;
> +
> +	/*
> +	 * For KVM, it is necessary to ensure that this CPU doesn't
> +	 * support any vector length that guests may have probed as
> +	 * unsupported.
> +	 */
> +
> +	/* Recover the set of supported VQs: */
> +	bitmap_complement(tmp_map, tmp_map, SVE_VQ_MAX);
> +	/* Find VQs supported that are not globally supported: */
> +	bitmap_andnot(tmp_map, tmp_map, sve_vq_map, SVE_VQ_MAX);
> +
> +	/* Find the lowest such VQ, if any: */
> +	b = find_last_bit(tmp_map, SVE_VQ_MAX);
> +	if (b >= SVE_VQ_MAX)
> +		return 0; /* no mismatches */
> +
> +	/*
> +	 * Mismatches above sve_max_virtualisable_vl are fine, since
> +	 * no guest is allowed to configure ZCR_EL2.LEN to exceed this:
> +	 */
> +	if (sve_vl_from_vq(bit_to_vq(b)) <= sve_max_virtualisable_vl) {
> +		pr_warn("SVE: cpu%d: Unsupported vector length(s) present\n",
> +			smp_processor_id());
> +		return -EINVAL;
> +	}
> +
> +	return 0;
>  }
>  
>  static void __init sve_efi_setup(void)
> @@ -751,6 +785,8 @@ u64 read_zcr_features(void)
>  void __init sve_setup(void)
>  {
>  	u64 zcr;
> +	DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
> +	unsigned long b;
>  
>  	if (!system_supports_sve())
>  		return;
> @@ -779,11 +815,31 @@ void __init sve_setup(void)
>  	 */
>  	sve_default_vl = find_supported_vector_length(64);
>  
> +	bitmap_andnot(tmp_map, sve_vq_partial_map, sve_vq_map,
> +		      SVE_VQ_MAX);
> +
> +	b = find_last_bit(tmp_map, SVE_VQ_MAX);
> +	if (b >= SVE_VQ_MAX)
> +		/* No non-virtualisable VLs found */
> +		sve_max_virtualisable_vl = SVE_VQ_MAX;
> +	else if (WARN_ON(b == SVE_VQ_MAX - 1))
> +		/* No virtualisable VLs?  This is architecturally forbidden. */
> +		sve_max_virtualisable_vl = SVE_VQ_MIN;
> +	else /* b + 1 < SVE_VQ_MAX */
> +		sve_max_virtualisable_vl = sve_vl_from_vq(bit_to_vq(b + 1));
> +
> +	if (sve_max_virtualisable_vl > sve_max_vl)
> +		sve_max_virtualisable_vl = sve_max_vl;
> +
>  	pr_info("SVE: maximum available vector length %u bytes per vector\n",
>  		sve_max_vl);
>  	pr_info("SVE: default vector length %u bytes per vector\n",
>  		sve_default_vl);
>  
> +	/* KVM decides whether to support mismatched systems. Just warn here: */
> +	if (sve_max_virtualisable_vl < sve_max_vl)
> +		pr_warn("SVE: unvirtualisable vector lengths present\n");
> +
>  	sve_efi_setup();
>  }
>  
> -- 
> 2.1.4
>

Reviewed-by: Andrew Jones <drjones@redhat.com>

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 06/27] arm64/sve: Clarify role of the VQ map maintenance functions
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-04 21:21     ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 21:21 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:31PM +0000, Dave Martin wrote:
> The roles of sve_init_vq_map(), sve_update_vq_map() and
> sve_verify_vq_map() are highly non-obvious to anyone who has not dug
> through cpufeatures.c in detail.
> 
> Since the way these functions interact with each other is more
> important here than a full understanding of the cpufeatures code, this
> patch adds comments to make the functions' roles clearer.
> 
> No functional change.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * [Julien Thierry] This patch is useful for explaining the previous
>    patch (as per the v5 ordering), and is anyway non-functional.
>    Swapped it with the previous patch to provide a more logical reading
>    order for the series.
> ---
>  arch/arm64/kernel/fpsimd.c | 10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
> index 62c37f0..f59ea67 100644
> --- a/arch/arm64/kernel/fpsimd.c
> +++ b/arch/arm64/kernel/fpsimd.c
> @@ -647,6 +647,10 @@ static void sve_probe_vqs(DECLARE_BITMAP(map, SVE_VQ_MAX))
>  	}
>  }
>  
> +/*
> + * Initialise the set of known supported VQs for the boot CPU.
> + * This is called during kernel boot, before secondary CPUs are brought up.
> + */
>  void __init sve_init_vq_map(void)
>  {
>  	sve_probe_vqs(sve_vq_map);
> @@ -655,6 +659,7 @@ void __init sve_init_vq_map(void)
>  /*
>   * If we haven't committed to the set of supported VQs yet, filter out
>   * those not supported by the current CPU.
> + * This function is called during the bring-up of early secondary CPUs only.
>   */
>  void sve_update_vq_map(void)
>  {
> @@ -662,7 +667,10 @@ void sve_update_vq_map(void)
>  	bitmap_and(sve_vq_map, sve_vq_map, sve_secondary_vq_map, SVE_VQ_MAX);
>  }
>  
> -/* Check whether the current CPU supports all VQs in the committed set */
> +/*
> + * Check whether the current CPU supports all VQs in the committed set.
> + * This function is called during the bring-up of late secondary CPUs only.
> + */
>  int sve_verify_vq_map(void)
>  {
>  	int ret = 0;
> -- 
> 2.1.4

Reviewed-by: Andrew Jones <drjones@redhat.com>

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

* Re: [PATCH v7 06/27] arm64/sve: Clarify role of the VQ map maintenance functions
@ 2019-04-04 21:21     ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-04 21:21 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:31PM +0000, Dave Martin wrote:
> The roles of sve_init_vq_map(), sve_update_vq_map() and
> sve_verify_vq_map() are highly non-obvious to anyone who has not dug
> through cpufeatures.c in detail.
> 
> Since the way these functions interact with each other is more
> important here than a full understanding of the cpufeatures code, this
> patch adds comments to make the functions' roles clearer.
> 
> No functional change.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> ---
> 
> Changes since v5:
> 
>  * [Julien Thierry] This patch is useful for explaining the previous
>    patch (as per the v5 ordering), and is anyway non-functional.
>    Swapped it with the previous patch to provide a more logical reading
>    order for the series.
> ---
>  arch/arm64/kernel/fpsimd.c | 10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
> index 62c37f0..f59ea67 100644
> --- a/arch/arm64/kernel/fpsimd.c
> +++ b/arch/arm64/kernel/fpsimd.c
> @@ -647,6 +647,10 @@ static void sve_probe_vqs(DECLARE_BITMAP(map, SVE_VQ_MAX))
>  	}
>  }
>  
> +/*
> + * Initialise the set of known supported VQs for the boot CPU.
> + * This is called during kernel boot, before secondary CPUs are brought up.
> + */
>  void __init sve_init_vq_map(void)
>  {
>  	sve_probe_vqs(sve_vq_map);
> @@ -655,6 +659,7 @@ void __init sve_init_vq_map(void)
>  /*
>   * If we haven't committed to the set of supported VQs yet, filter out
>   * those not supported by the current CPU.
> + * This function is called during the bring-up of early secondary CPUs only.
>   */
>  void sve_update_vq_map(void)
>  {
> @@ -662,7 +667,10 @@ void sve_update_vq_map(void)
>  	bitmap_and(sve_vq_map, sve_vq_map, sve_secondary_vq_map, SVE_VQ_MAX);
>  }
>  
> -/* Check whether the current CPU supports all VQs in the committed set */
> +/*
> + * Check whether the current CPU supports all VQs in the committed set.
> + * This function is called during the bring-up of late secondary CPUs only.
> + */
>  int sve_verify_vq_map(void)
>  {
>  	int ret = 0;
> -- 
> 2.1.4

Reviewed-by: Andrew Jones <drjones@redhat.com>

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 07/27] arm64/sve: Check SVE virtualisability
  2019-04-04 21:21     ` Andrew Jones
@ 2019-04-05  9:35       ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05  9:35 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 11:21:04PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:32PM +0000, Dave Martin wrote:
> > Due to the way the effective SVE vector length is controlled and
> > trapped at different exception levels, certain mismatches in the
> > sets of vector lengths supported by different physical CPUs in the
> > system may prevent straightforward virtualisation of SVE at parity
> > with the host.
> > 
> > This patch analyses the extent to which SVE can be virtualised
> > safely without interfering with migration of vcpus between physical
> > CPUs, and rejects late secondary CPUs that would erode the
> > situation further.
> > 
> > It is left up to KVM to decide what to do with this information.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > 
> > ---
> > 
> > QUESTION: The final structure of this code makes it quite natural to
> > clamp the vector length for KVM guests to the maximum value supportable
> > across all CPUs; such a value is guaranteed to exist, but may be
> > surprisingly small on a given hardware platform.
> > 
> > Should we be stricter and actually refuse to support KVM at all on such
> > hardware?  This may help to force people to fix Linux (or the
> > architecture) if/when this issue comes up.
> 
> Blocking KVM would be too harsh, since the users of the host may not
> care about guests with SVE, but still care about guests.
> 
> > 
> > For now, I stick with pr_warn() and make do with a limited SVE vector
> > length for guests.
> 
> I think that's probably the best we can do.

Agreed.  Since it fell out quite nicely this way in the code, this was
my preferred option.

[...]

> Reviewed-by: Andrew Jones <drjones@redhat.com>

Thanks

---Dave

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

* Re: [PATCH v7 07/27] arm64/sve: Check SVE virtualisability
@ 2019-04-05  9:35       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05  9:35 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 11:21:04PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:32PM +0000, Dave Martin wrote:
> > Due to the way the effective SVE vector length is controlled and
> > trapped at different exception levels, certain mismatches in the
> > sets of vector lengths supported by different physical CPUs in the
> > system may prevent straightforward virtualisation of SVE at parity
> > with the host.
> > 
> > This patch analyses the extent to which SVE can be virtualised
> > safely without interfering with migration of vcpus between physical
> > CPUs, and rejects late secondary CPUs that would erode the
> > situation further.
> > 
> > It is left up to KVM to decide what to do with this information.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > 
> > ---
> > 
> > QUESTION: The final structure of this code makes it quite natural to
> > clamp the vector length for KVM guests to the maximum value supportable
> > across all CPUs; such a value is guaranteed to exist, but may be
> > surprisingly small on a given hardware platform.
> > 
> > Should we be stricter and actually refuse to support KVM at all on such
> > hardware?  This may help to force people to fix Linux (or the
> > architecture) if/when this issue comes up.
> 
> Blocking KVM would be too harsh, since the users of the host may not
> care about guests with SVE, but still care about guests.
> 
> > 
> > For now, I stick with pr_warn() and make do with a limited SVE vector
> > length for guests.
> 
> I think that's probably the best we can do.

Agreed.  Since it fell out quite nicely this way in the code, this was
my preferred option.

[...]

> Reviewed-by: Andrew Jones <drjones@redhat.com>

Thanks

---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 19/27] KVM: arm64: Enumerate SVE register indices for KVM_GET_REG_LIST
  2019-04-04 14:08     ` Andrew Jones
@ 2019-04-05  9:35       ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05  9:35 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 04:08:32PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:44PM +0000, Dave Martin wrote:
> > This patch includes the SVE register IDs in the list returned by
> > KVM_GET_REG_LIST, as appropriate.
> > 
> > On a non-SVE-enabled vcpu, no new IDs are added.
> > 
> > On an SVE-enabled vcpu, IDs for the FPSIMD V-registers are removed
> > from the list, since userspace is required to access the Z-
> > registers instead in order to access the V-register content.  For
> > the variably-sized SVE registers, the appropriate set of slice IDs
> > are enumerated, depending on the maximum vector length for the
> > vcpu.
> > 
> > As it currently stands, the SVE architecture never requires more
> > than one slice to exist per register, so this patch adds no
> > explicit support for enumerating multiple slices.  The code can be
> > extended straightforwardly to support this in the future, if
> > needed.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > 
> > ---
> > 
> > Changes since v6:
> > 
> >  * [Julien Thierry] Add a #define to replace the magic "slices = 1",
> >    and add a comment explaining to maintainers what needs to happen if
> >    this is updated in the future.
> > 
> > Changes since v5:
> > 
> > (Dropped Julien Thierry's Reviewed-by due to non-trivial rebasing)
> > 
> >  * Move mis-split reword to prevent put_user()s being accidentally the
> >    correct size from KVM: arm64/sve: Add pseudo-register for the guest's
> >    vector lengths.
> > ---
> >  arch/arm64/kvm/guest.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 63 insertions(+)
> > 
> > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > index 736d8cb..2aa80a5 100644
> > --- a/arch/arm64/kvm/guest.c
> > +++ b/arch/arm64/kvm/guest.c
> > @@ -222,6 +222,13 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >  #define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0))
> >  #define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0))
> >  
> > +/*
> > + * number of register slices required to cover each whole SVE register on vcpu
> 
> s/number/Number/

Not a sentence -> no capital letter.

Due to the adjacent note it does look a little odd though.  I'm happy to
change it.

> s/on vcpu//

Agreed, I can drop that.

> > + * NOTE: If you are tempted to modify this, you must also to rework
> 
> s/to rework/rework/

Ack

> > + * sve_reg_to_region() to match:
> > + */
> > +#define vcpu_sve_slices(vcpu) 1
> > +
> >  /* Bounds of a single SVE register slice within vcpu->arch.sve_state */
> >  struct sve_state_reg_region {
> >  	unsigned int koffset;	/* offset into sve_state in kernel memory */
> > @@ -411,6 +418,56 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >  	return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0;
> >  }
> >  
> > +static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
> > +{
> > +	/* Only the first slice ever exists, for now */
> 
> I'd move this comment up into the one above vcpu_sve_slices(),
> and then nothing needs to change here when more slices come.
> 
> > +	const unsigned int slices = vcpu_sve_slices(vcpu);
> > +
> > +	if (!vcpu_has_sve(vcpu))
> > +		return 0;
> > +
> > +	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */);
> > +}
> > +
> > +static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
> > +				u64 __user *uindices)
> > +{
> > +	/* Only the first slice ever exists, for now */
> 
> Same comment as above.

Fair point: this was to explain the magic "1" that was previously here,
but the comments are a bit redundant here now: better to move the
comments where the 1 itself went.

> > +	const unsigned int slices = vcpu_sve_slices(vcpu);
> > +	u64 reg;
> > +	unsigned int i, n;
> > +	int num_regs = 0;
> > +
> > +	if (!vcpu_has_sve(vcpu))
> > +		return 0;
> > +
> > +	for (i = 0; i < slices; i++) {
> > +		for (n = 0; n < SVE_NUM_ZREGS; n++) {
> > +			reg = KVM_REG_ARM64_SVE_ZREG(n, i);
> > +			if (put_user(reg, uindices++))
> > +				return -EFAULT;
> > +
> > +			num_regs++;
> > +		}
> > +
> > +		for (n = 0; n < SVE_NUM_PREGS; n++) {
> > +			reg = KVM_REG_ARM64_SVE_PREG(n, i);
> > +			if (put_user(reg, uindices++))
> > +				return -EFAULT;
> > +
> > +			num_regs++;
> > +		}
> > +
> > +		reg = KVM_REG_ARM64_SVE_FFR(i);
> > +		if (put_user(reg, uindices++))
> > +			return -EFAULT;
> > +
> > +		num_regs++;
> > +	}
> 
> nit: the extra blank lines above the num_regs++'s give the code an odd
>      look (to me)

There's no guaranteed fall-through onto the increments: the blank line
was there to highlight the fact that we may jump out using a return
instead.

But I'm happy enough to change it if you have a strong preference or
you feel the code is equally clear without.

> 
> > +
> > +	return num_regs;
> > +}
> > +
> >  /**
> >   * kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG
> >   *
> > @@ -421,6 +478,7 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
> >  	unsigned long res = 0;
> >  
> >  	res += num_core_regs(vcpu);
> > +	res += num_sve_regs(vcpu);
> >  	res += kvm_arm_num_sys_reg_descs(vcpu);
> >  	res += kvm_arm_get_fw_num_regs(vcpu);
> >  	res += NUM_TIMER_REGS;
> > @@ -442,6 +500,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
> >  		return ret;
> >  	uindices += ret;
> >  
> > +	ret = copy_sve_reg_indices(vcpu, uindices);
> > +	if (ret)
> > +		return ret;
> > +	uindices += ret;
> 
> I know this if ret vs. if ret < 0 is being addressed already.

Yes, Marc's patch in kvmarm/next should fix that.

Cheers
---Dave

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

* Re: [PATCH v7 19/27] KVM: arm64: Enumerate SVE register indices for KVM_GET_REG_LIST
@ 2019-04-05  9:35       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05  9:35 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 04:08:32PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:44PM +0000, Dave Martin wrote:
> > This patch includes the SVE register IDs in the list returned by
> > KVM_GET_REG_LIST, as appropriate.
> > 
> > On a non-SVE-enabled vcpu, no new IDs are added.
> > 
> > On an SVE-enabled vcpu, IDs for the FPSIMD V-registers are removed
> > from the list, since userspace is required to access the Z-
> > registers instead in order to access the V-register content.  For
> > the variably-sized SVE registers, the appropriate set of slice IDs
> > are enumerated, depending on the maximum vector length for the
> > vcpu.
> > 
> > As it currently stands, the SVE architecture never requires more
> > than one slice to exist per register, so this patch adds no
> > explicit support for enumerating multiple slices.  The code can be
> > extended straightforwardly to support this in the future, if
> > needed.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > 
> > ---
> > 
> > Changes since v6:
> > 
> >  * [Julien Thierry] Add a #define to replace the magic "slices = 1",
> >    and add a comment explaining to maintainers what needs to happen if
> >    this is updated in the future.
> > 
> > Changes since v5:
> > 
> > (Dropped Julien Thierry's Reviewed-by due to non-trivial rebasing)
> > 
> >  * Move mis-split reword to prevent put_user()s being accidentally the
> >    correct size from KVM: arm64/sve: Add pseudo-register for the guest's
> >    vector lengths.
> > ---
> >  arch/arm64/kvm/guest.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 63 insertions(+)
> > 
> > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > index 736d8cb..2aa80a5 100644
> > --- a/arch/arm64/kvm/guest.c
> > +++ b/arch/arm64/kvm/guest.c
> > @@ -222,6 +222,13 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >  #define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0))
> >  #define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0))
> >  
> > +/*
> > + * number of register slices required to cover each whole SVE register on vcpu
> 
> s/number/Number/

Not a sentence -> no capital letter.

Due to the adjacent note it does look a little odd though.  I'm happy to
change it.

> s/on vcpu//

Agreed, I can drop that.

> > + * NOTE: If you are tempted to modify this, you must also to rework
> 
> s/to rework/rework/

Ack

> > + * sve_reg_to_region() to match:
> > + */
> > +#define vcpu_sve_slices(vcpu) 1
> > +
> >  /* Bounds of a single SVE register slice within vcpu->arch.sve_state */
> >  struct sve_state_reg_region {
> >  	unsigned int koffset;	/* offset into sve_state in kernel memory */
> > @@ -411,6 +418,56 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >  	return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0;
> >  }
> >  
> > +static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
> > +{
> > +	/* Only the first slice ever exists, for now */
> 
> I'd move this comment up into the one above vcpu_sve_slices(),
> and then nothing needs to change here when more slices come.
> 
> > +	const unsigned int slices = vcpu_sve_slices(vcpu);
> > +
> > +	if (!vcpu_has_sve(vcpu))
> > +		return 0;
> > +
> > +	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */);
> > +}
> > +
> > +static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
> > +				u64 __user *uindices)
> > +{
> > +	/* Only the first slice ever exists, for now */
> 
> Same comment as above.

Fair point: this was to explain the magic "1" that was previously here,
but the comments are a bit redundant here now: better to move the
comments where the 1 itself went.

> > +	const unsigned int slices = vcpu_sve_slices(vcpu);
> > +	u64 reg;
> > +	unsigned int i, n;
> > +	int num_regs = 0;
> > +
> > +	if (!vcpu_has_sve(vcpu))
> > +		return 0;
> > +
> > +	for (i = 0; i < slices; i++) {
> > +		for (n = 0; n < SVE_NUM_ZREGS; n++) {
> > +			reg = KVM_REG_ARM64_SVE_ZREG(n, i);
> > +			if (put_user(reg, uindices++))
> > +				return -EFAULT;
> > +
> > +			num_regs++;
> > +		}
> > +
> > +		for (n = 0; n < SVE_NUM_PREGS; n++) {
> > +			reg = KVM_REG_ARM64_SVE_PREG(n, i);
> > +			if (put_user(reg, uindices++))
> > +				return -EFAULT;
> > +
> > +			num_regs++;
> > +		}
> > +
> > +		reg = KVM_REG_ARM64_SVE_FFR(i);
> > +		if (put_user(reg, uindices++))
> > +			return -EFAULT;
> > +
> > +		num_regs++;
> > +	}
> 
> nit: the extra blank lines above the num_regs++'s give the code an odd
>      look (to me)

There's no guaranteed fall-through onto the increments: the blank line
was there to highlight the fact that we may jump out using a return
instead.

But I'm happy enough to change it if you have a strong preference or
you feel the code is equally clear without.

> 
> > +
> > +	return num_regs;
> > +}
> > +
> >  /**
> >   * kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG
> >   *
> > @@ -421,6 +478,7 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
> >  	unsigned long res = 0;
> >  
> >  	res += num_core_regs(vcpu);
> > +	res += num_sve_regs(vcpu);
> >  	res += kvm_arm_num_sys_reg_descs(vcpu);
> >  	res += kvm_arm_get_fw_num_regs(vcpu);
> >  	res += NUM_TIMER_REGS;
> > @@ -442,6 +500,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
> >  		return ret;
> >  	uindices += ret;
> >  
> > +	ret = copy_sve_reg_indices(vcpu, uindices);
> > +	if (ret)
> > +		return ret;
> > +	uindices += ret;
> 
> I know this if ret vs. if ret < 0 is being addressed already.

Yes, Marc's patch in kvmarm/next should fix that.

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 20/27] arm64/sve: In-kernel vector length availability query interface
  2019-04-04 14:20     ` Andrew Jones
@ 2019-04-05  9:35       ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05  9:35 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 04:20:34PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:45PM +0000, Dave Martin wrote:
> > KVM will need to interrogate the set of SVE vector lengths
> > available on the system.
> > 
> > This patch exposes the relevant bits to the kernel, along with a
> > sve_vq_available() helper to check whether a particular vector
> > length is supported.
> > 
> > __vq_to_bit() and __bit_to_vq() are not intended for use outside
> > these functions: now that these are exposed outside fpsimd.c, they
> > are prefixed with __ in order to provide an extra hint that they
> > are not intended for general-purpose use.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > ---
> >  arch/arm64/include/asm/fpsimd.h | 29 +++++++++++++++++++++++++++++
> >  arch/arm64/kernel/fpsimd.c      | 35 ++++++++---------------------------
> >  2 files changed, 37 insertions(+), 27 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
> > index df7a143..ad6d2e4 100644
> > --- a/arch/arm64/include/asm/fpsimd.h
> > +++ b/arch/arm64/include/asm/fpsimd.h
> > @@ -24,10 +24,13 @@
> >  
> >  #ifndef __ASSEMBLY__
> >  
> > +#include <linux/bitmap.h>
> >  #include <linux/build_bug.h>
> > +#include <linux/bug.h>
> >  #include <linux/cache.h>
> >  #include <linux/init.h>
> >  #include <linux/stddef.h>
> > +#include <linux/types.h>
> >  
> >  #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
> >  /* Masks for extracting the FPSR and FPCR from the FPSCR */
> > @@ -89,6 +92,32 @@ extern u64 read_zcr_features(void);
> >  
> >  extern int __ro_after_init sve_max_vl;
> >  extern int __ro_after_init sve_max_virtualisable_vl;
> > +/* Set of available vector lengths, as vq_to_bit(vq): */
> 
> s/as/for use with/ ?

Not exactly.  Does the following work for you:

/*
 * Set of available vector lengths
 * Vector length vq is encoded as bit __vq_to_bit(vq):
 */

> s/vq_to_bit/__vq_to_bit/

Ack: that got renamed when I moved it to fpsimd.h, bit I clearly didn't
update the comment as I pasted it across.

> 
> > +extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
> > +
> > +/*
> > + * Helpers to translate bit indices in sve_vq_map to VQ values (and
> > + * vice versa).  This allows find_next_bit() to be used to find the
> > + * _maximum_ VQ not exceeding a certain value.
> > + */
> > +static inline unsigned int __vq_to_bit(unsigned int vq)
> > +{
> 
> Why not have the same WARN_ON and clamping here as we do
> in __bit_to_vq. Here a vq > SVE_VQ_MAX will wrap around
> to a super high bit.
> 
> > +	return SVE_VQ_MAX - vq;
> > +}
> > +
> > +static inline unsigned int __bit_to_vq(unsigned int bit)
> > +{
> > +	if (WARN_ON(bit >= SVE_VQ_MAX))
> > +		bit = SVE_VQ_MAX - 1;
> > +
> > +	return SVE_VQ_MAX - bit;
> > +}
> > +
> > +/* Ensure vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX before calling this function */
> 
> Are we avoiding putting these tests and WARN_ONs in this function to
> keep it fast?

These are intended as backend for use only by fpsimd.c and this header,
so peppering them with WARN_ON() felt excessive.  I don't expect a lot
of new calls to these (or any, probably).

I don't recall why I kept the WARN_ON() just in __bit_to_vq(), except
that the way that gets called is a bit more complex in some places.

Are you happy to replace these with comments?  e.g.:

/* Only valid when vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX */
__vq_to_bit()

/* Only valid when bit < SVE_VQ_MAX */
__bit_to_vq()


OTOH, these are not used on fast paths, so maybe having both as
WARN_ON() would be better.  Part of the problem is knowing what to clamp
to: these are generally used in conjunction with looping or bitmap find
operations, so the caller may be making assumptions about the return
value that may wrong when the value is clamped.

Alternatively, these could be BUG() -- but that seems heavy.

What do you think?

[...]

Cheers
---Dave

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

* Re: [PATCH v7 20/27] arm64/sve: In-kernel vector length availability query interface
@ 2019-04-05  9:35       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05  9:35 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 04:20:34PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:45PM +0000, Dave Martin wrote:
> > KVM will need to interrogate the set of SVE vector lengths
> > available on the system.
> > 
> > This patch exposes the relevant bits to the kernel, along with a
> > sve_vq_available() helper to check whether a particular vector
> > length is supported.
> > 
> > __vq_to_bit() and __bit_to_vq() are not intended for use outside
> > these functions: now that these are exposed outside fpsimd.c, they
> > are prefixed with __ in order to provide an extra hint that they
> > are not intended for general-purpose use.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > ---
> >  arch/arm64/include/asm/fpsimd.h | 29 +++++++++++++++++++++++++++++
> >  arch/arm64/kernel/fpsimd.c      | 35 ++++++++---------------------------
> >  2 files changed, 37 insertions(+), 27 deletions(-)
> > 
> > diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
> > index df7a143..ad6d2e4 100644
> > --- a/arch/arm64/include/asm/fpsimd.h
> > +++ b/arch/arm64/include/asm/fpsimd.h
> > @@ -24,10 +24,13 @@
> >  
> >  #ifndef __ASSEMBLY__
> >  
> > +#include <linux/bitmap.h>
> >  #include <linux/build_bug.h>
> > +#include <linux/bug.h>
> >  #include <linux/cache.h>
> >  #include <linux/init.h>
> >  #include <linux/stddef.h>
> > +#include <linux/types.h>
> >  
> >  #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
> >  /* Masks for extracting the FPSR and FPCR from the FPSCR */
> > @@ -89,6 +92,32 @@ extern u64 read_zcr_features(void);
> >  
> >  extern int __ro_after_init sve_max_vl;
> >  extern int __ro_after_init sve_max_virtualisable_vl;
> > +/* Set of available vector lengths, as vq_to_bit(vq): */
> 
> s/as/for use with/ ?

Not exactly.  Does the following work for you:

/*
 * Set of available vector lengths
 * Vector length vq is encoded as bit __vq_to_bit(vq):
 */

> s/vq_to_bit/__vq_to_bit/

Ack: that got renamed when I moved it to fpsimd.h, bit I clearly didn't
update the comment as I pasted it across.

> 
> > +extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
> > +
> > +/*
> > + * Helpers to translate bit indices in sve_vq_map to VQ values (and
> > + * vice versa).  This allows find_next_bit() to be used to find the
> > + * _maximum_ VQ not exceeding a certain value.
> > + */
> > +static inline unsigned int __vq_to_bit(unsigned int vq)
> > +{
> 
> Why not have the same WARN_ON and clamping here as we do
> in __bit_to_vq. Here a vq > SVE_VQ_MAX will wrap around
> to a super high bit.
> 
> > +	return SVE_VQ_MAX - vq;
> > +}
> > +
> > +static inline unsigned int __bit_to_vq(unsigned int bit)
> > +{
> > +	if (WARN_ON(bit >= SVE_VQ_MAX))
> > +		bit = SVE_VQ_MAX - 1;
> > +
> > +	return SVE_VQ_MAX - bit;
> > +}
> > +
> > +/* Ensure vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX before calling this function */
> 
> Are we avoiding putting these tests and WARN_ONs in this function to
> keep it fast?

These are intended as backend for use only by fpsimd.c and this header,
so peppering them with WARN_ON() felt excessive.  I don't expect a lot
of new calls to these (or any, probably).

I don't recall why I kept the WARN_ON() just in __bit_to_vq(), except
that the way that gets called is a bit more complex in some places.

Are you happy to replace these with comments?  e.g.:

/* Only valid when vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX */
__vq_to_bit()

/* Only valid when bit < SVE_VQ_MAX */
__bit_to_vq()


OTOH, these are not used on fast paths, so maybe having both as
WARN_ON() would be better.  Part of the problem is knowing what to clamp
to: these are generally used in conjunction with looping or bitmap find
operations, so the caller may be making assumptions about the return
value that may wrong when the value is clamped.

Alternatively, these could be BUG() -- but that seems heavy.

What do you think?

[...]

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
  2019-04-04 20:18     ` Andrew Jones
@ 2019-04-05  9:36       ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05  9:36 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 10:18:54PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> > This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> > allow userspace to set and query the set of vector lengths visible
> > to the guest.
> > 
> > In the future, multiple register slices per SVE register may be
> > visible through the ioctl interface.  Once the set of slices has
> > been determined we would not be able to allow the vector length set
> > to be changed any more, in order to avoid userspace seeing
> > inconsistent sets of registers.  For this reason, this patch adds
> > support for explicit finalization of the SVE configuration via the
> > KVM_ARM_VCPU_FINALIZE ioctl.
> > 
> > Finalization is the proper place to allocate the SVE register state
> > storage in vcpu->arch.sve_state, so this patch adds that as
> > appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> > was previously a no-op on arm64.
> > 
> > To simplify the logic for determining what vector lengths can be
> > supported, some code is added to KVM init to work this out, in the
> > kvm_arm_init_arch_resources() hook.
> > 
> > The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> > Subsequent patches will allow SVE to be turned on for guest vcpus,
> > making it visible.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > 
> > ---

[...]

> > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > index 2aa80a5..086ab05 100644
> > --- a/arch/arm64/kvm/guest.c
> > +++ b/arch/arm64/kvm/guest.c
> > @@ -206,6 +206,73 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >  	return err;
> >  }
> >  
> > +#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64)
> > +#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64)
> > +
> > +static bool vq_present(
> > +	const u64 (*const vqs)[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)],
> > +	unsigned int vq)
> > +{
> > +	return (*vqs)[vq_word(vq)] & vq_mask(vq);
> > +}
> > +
> > +static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > +{
> > +	unsigned int max_vq, vq;
> > +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> > +
> > +	if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl)))
> > +		return -EINVAL;
> > +
> > +	memset(vqs, 0, sizeof(vqs));
> > +
> > +	max_vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
> > +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > +		if (sve_vq_available(vq))
> > +			vqs[vq_word(vq)] |= vq_mask(vq);
> > +
> > +	if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs)))
> > +		return -EFAULT;
> > +
> > +	return 0;
> > +}
> > +
> > +static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > +{
> > +	unsigned int max_vq, vq;
> > +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> 
> There are three of these long 'DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)'.
> A macro is probably warranted.

Fair point.  These are a bit cumbersome.  How about:

#define SVE_VLS_WORDS DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)

Annoyingly, this is virtually identical to a Linux bitmap: the base type
is u64 instead of unsigned long; otherwise there's no intentional
difference.

(Aside: do you know why the KVM API insists on everything being u64?
This makes sense for non-native types (like guest registers), but not
for native things like host userspace addresses etc.)

> > +
> > +	if (kvm_arm_vcpu_sve_finalized(vcpu))
> > +		return -EPERM; /* too late! */
> > +
> > +	if (WARN_ON(vcpu->arch.sve_state))
> > +		return -EINVAL;
> > +
> > +	if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs)))
> > +		return -EFAULT;
> > +
> > +	max_vq = 0;
> > +	for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq)
> > +		if (vq_present(&vqs, vq))
> > +			max_vq = vq;
> > +
> > +	if (max_vq > sve_vq_from_vl(kvm_sve_max_vl))
> > +		return -EINVAL;
> > +
> > +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > +		if (vq_present(&vqs, vq) != sve_vq_available(vq))
> > +			return -EINVAL;
> 
> What about supporting the optional non-power-of-2 vector lengths? For
> example, if the maximum VL is 512, then in addition to 512, 128, and
> 256 there could be a 384. If we plan to start a guest on a machine
> that has all four and then migrate it to a machine that only has
> 128,256,512 we would want to set the VL set to 128,256,512, even on
> the machine that supports 384. If I understand the above test correctly,
> then that wouldn't work.

This is exactly what the code is trying to forbid, though it may not be
obvious here why.

The trouble is, we can't correctly emulate a vcpu supporting
{128,256,512} on hardware that also supports 384-bit vectors: the
architecture says that the vector length you get is determined by
rounding ZCR_EL1.LEN down to the next vector length actually
supported.

So, the guest would expect writing ZCR_EL1.LEN = 2 to give a vector
length of 256 bits, whereas on this hardware the actual resulting
vector length would be 384 bits.

sve_probe_vqs() relies on this property to detect the set of available
vector lengths.  Simple, bare-metal guests might also just set
ZCR_ELx.LEN = 0x1ff to just get the max available.


The architecture says categorically that the set of vector lengths
supported is a fixed property of the (emulated) hardware -- we can't
having this changing under the guest's feet.

Fixing this would require an archietctural way to filter out individual
vector lengths from the supported set, not just a way to clamp the
maximum (which is all ZCR_EL2.LEN gives us).

The general expectation is that sanely designed cluster will be
"homogeneous enough" and won't trigger this check -- it's here
just in case.


I attempt to capture this in api.txt, leaving the door open in case the
architecture gives a way to support this in future:

  | KVM_REG_ARM64_SVE_VLS
  | 
  | [...]
  | 
  | Apart from simply removing all vector lengths from the host set
  | that exceed some value, support for arbitrarily chosen sets of
  | vector lengths is hardware-dependent and may not be available.
  | Attempting to configure an invalid set of vector lengths via
  | KVM_SET_ONE_REG will fail with EINVAL.

Is this enough, or do you think more explanation is needed somewhere?

[...]

Chees
---DavE

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

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
@ 2019-04-05  9:36       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05  9:36 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 10:18:54PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> > This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> > allow userspace to set and query the set of vector lengths visible
> > to the guest.
> > 
> > In the future, multiple register slices per SVE register may be
> > visible through the ioctl interface.  Once the set of slices has
> > been determined we would not be able to allow the vector length set
> > to be changed any more, in order to avoid userspace seeing
> > inconsistent sets of registers.  For this reason, this patch adds
> > support for explicit finalization of the SVE configuration via the
> > KVM_ARM_VCPU_FINALIZE ioctl.
> > 
> > Finalization is the proper place to allocate the SVE register state
> > storage in vcpu->arch.sve_state, so this patch adds that as
> > appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> > was previously a no-op on arm64.
> > 
> > To simplify the logic for determining what vector lengths can be
> > supported, some code is added to KVM init to work this out, in the
> > kvm_arm_init_arch_resources() hook.
> > 
> > The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> > Subsequent patches will allow SVE to be turned on for guest vcpus,
> > making it visible.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > 
> > ---

[...]

> > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > index 2aa80a5..086ab05 100644
> > --- a/arch/arm64/kvm/guest.c
> > +++ b/arch/arm64/kvm/guest.c
> > @@ -206,6 +206,73 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> >  	return err;
> >  }
> >  
> > +#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64)
> > +#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64)
> > +
> > +static bool vq_present(
> > +	const u64 (*const vqs)[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)],
> > +	unsigned int vq)
> > +{
> > +	return (*vqs)[vq_word(vq)] & vq_mask(vq);
> > +}
> > +
> > +static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > +{
> > +	unsigned int max_vq, vq;
> > +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> > +
> > +	if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl)))
> > +		return -EINVAL;
> > +
> > +	memset(vqs, 0, sizeof(vqs));
> > +
> > +	max_vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
> > +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > +		if (sve_vq_available(vq))
> > +			vqs[vq_word(vq)] |= vq_mask(vq);
> > +
> > +	if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs)))
> > +		return -EFAULT;
> > +
> > +	return 0;
> > +}
> > +
> > +static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > +{
> > +	unsigned int max_vq, vq;
> > +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> 
> There are three of these long 'DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)'.
> A macro is probably warranted.

Fair point.  These are a bit cumbersome.  How about:

#define SVE_VLS_WORDS DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)

Annoyingly, this is virtually identical to a Linux bitmap: the base type
is u64 instead of unsigned long; otherwise there's no intentional
difference.

(Aside: do you know why the KVM API insists on everything being u64?
This makes sense for non-native types (like guest registers), but not
for native things like host userspace addresses etc.)

> > +
> > +	if (kvm_arm_vcpu_sve_finalized(vcpu))
> > +		return -EPERM; /* too late! */
> > +
> > +	if (WARN_ON(vcpu->arch.sve_state))
> > +		return -EINVAL;
> > +
> > +	if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs)))
> > +		return -EFAULT;
> > +
> > +	max_vq = 0;
> > +	for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq)
> > +		if (vq_present(&vqs, vq))
> > +			max_vq = vq;
> > +
> > +	if (max_vq > sve_vq_from_vl(kvm_sve_max_vl))
> > +		return -EINVAL;
> > +
> > +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > +		if (vq_present(&vqs, vq) != sve_vq_available(vq))
> > +			return -EINVAL;
> 
> What about supporting the optional non-power-of-2 vector lengths? For
> example, if the maximum VL is 512, then in addition to 512, 128, and
> 256 there could be a 384. If we plan to start a guest on a machine
> that has all four and then migrate it to a machine that only has
> 128,256,512 we would want to set the VL set to 128,256,512, even on
> the machine that supports 384. If I understand the above test correctly,
> then that wouldn't work.

This is exactly what the code is trying to forbid, though it may not be
obvious here why.

The trouble is, we can't correctly emulate a vcpu supporting
{128,256,512} on hardware that also supports 384-bit vectors: the
architecture says that the vector length you get is determined by
rounding ZCR_EL1.LEN down to the next vector length actually
supported.

So, the guest would expect writing ZCR_EL1.LEN = 2 to give a vector
length of 256 bits, whereas on this hardware the actual resulting
vector length would be 384 bits.

sve_probe_vqs() relies on this property to detect the set of available
vector lengths.  Simple, bare-metal guests might also just set
ZCR_ELx.LEN = 0x1ff to just get the max available.


The architecture says categorically that the set of vector lengths
supported is a fixed property of the (emulated) hardware -- we can't
having this changing under the guest's feet.

Fixing this would require an archietctural way to filter out individual
vector lengths from the supported set, not just a way to clamp the
maximum (which is all ZCR_EL2.LEN gives us).

The general expectation is that sanely designed cluster will be
"homogeneous enough" and won't trigger this check -- it's here
just in case.


I attempt to capture this in api.txt, leaving the door open in case the
architecture gives a way to support this in future:

  | KVM_REG_ARM64_SVE_VLS
  | 
  | [...]
  | 
  | Apart from simply removing all vector lengths from the host set
  | that exceed some value, support for arbitrarily chosen sets of
  | vector lengths is hardware-dependent and may not be available.
  | Attempting to configure an invalid set of vector lengths via
  | KVM_SET_ONE_REG will fail with EINVAL.

Is this enough, or do you think more explanation is needed somewhere?

[...]

Chees
---DavE

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
  2019-04-04 20:31     ` Andrew Jones
@ 2019-04-05  9:36       ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05  9:36 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 10:31:09PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> > This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> > allow userspace to set and query the set of vector lengths visible
> > to the guest.
> > 
> > In the future, multiple register slices per SVE register may be
> > visible through the ioctl interface.  Once the set of slices has
> > been determined we would not be able to allow the vector length set
> > to be changed any more, in order to avoid userspace seeing
> > inconsistent sets of registers.  For this reason, this patch adds
> > support for explicit finalization of the SVE configuration via the
> > KVM_ARM_VCPU_FINALIZE ioctl.
> > 
> > Finalization is the proper place to allocate the SVE register state
> > storage in vcpu->arch.sve_state, so this patch adds that as
> > appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> > was previously a no-op on arm64.
> > 
> > To simplify the logic for determining what vector lengths can be
> > supported, some code is added to KVM init to work this out, in the
> > kvm_arm_init_arch_resources() hook.
> > 
> > The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> > Subsequent patches will allow SVE to be turned on for guest vcpus,
> > making it visible.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

[...]

> > diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c

[...]

> > +/*
> > + * Finalize vcpu's maximum SVE vector length, allocating
> > + * vcpu->arch.sve_state as necessary.
> > + */
> > +static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
> > +{
> > +	void *buf;
> > +	unsigned int vl;
> > +
> > +	vl = vcpu->arch.sve_max_vl;
> > +
> > +	/*
> > +	 * Resposibility for these properties is shared between
> > +	 * kvm_arm_init_arch_resources(), kvm_vcpu_enable_sve() and
> > +	 * set_sve_vls().  Double-check here just to be sure:
> > +	 */
> > +	if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl ||
> > +		    vl > SVE_VL_ARCH_MAX))
> > +		return -EIO;
> > +
> > +	buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL);
> > +	if (!buf)
> > +		return -ENOMEM;
> > +
> > +	vcpu->arch.sve_state = buf;
> > +	vcpu->arch.flags |= KVM_ARM64_VCPU_SVE_FINALIZED;
> > +	return 0;
> > +}
> > +
> > +int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what)
> > +{
> > +	switch (what) {
> > +	case KVM_ARM_VCPU_SVE:
> > +		if (!vcpu_has_sve(vcpu))
> > +			return -EINVAL;
> > +
> > +		if (kvm_arm_vcpu_sve_finalized(vcpu))
> > +			return -EPERM;
> > +
> > +		return kvm_vcpu_finalize_sve(vcpu);
> 
> In the next patch I see that we already have KVM_ARM64_GUEST_HAS_SVE
> set in vcpu->arch.flags at this point. So if this kvm_vcpu_finalize_sve()
> call fails, shouldn't we unset KVM_ARM64_GUEST_HAS_SVE and anything
> else used to indicate the vcpu has sve?

If this fails, either userspace did the wrong thing, or there was some
fatal error (like the ENOMEM case).  Either way, the vcpu is not runnable
and userspace is expected to bail out.

Further, KVM_ARM_VCPU_INIT fixes the set of features requested by
userspace: we shouldn't change the set of features under userspace's
feet and try to limp on somehow.  We have no means for userspace to find
out that some features went away in the meantime...

So, what would you be trying to achieve with this change?

[...]

Cheers
---Dave

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

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
@ 2019-04-05  9:36       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05  9:36 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 10:31:09PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> > This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> > allow userspace to set and query the set of vector lengths visible
> > to the guest.
> > 
> > In the future, multiple register slices per SVE register may be
> > visible through the ioctl interface.  Once the set of slices has
> > been determined we would not be able to allow the vector length set
> > to be changed any more, in order to avoid userspace seeing
> > inconsistent sets of registers.  For this reason, this patch adds
> > support for explicit finalization of the SVE configuration via the
> > KVM_ARM_VCPU_FINALIZE ioctl.
> > 
> > Finalization is the proper place to allocate the SVE register state
> > storage in vcpu->arch.sve_state, so this patch adds that as
> > appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> > was previously a no-op on arm64.
> > 
> > To simplify the logic for determining what vector lengths can be
> > supported, some code is added to KVM init to work this out, in the
> > kvm_arm_init_arch_resources() hook.
> > 
> > The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> > Subsequent patches will allow SVE to be turned on for guest vcpus,
> > making it visible.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

[...]

> > diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c

[...]

> > +/*
> > + * Finalize vcpu's maximum SVE vector length, allocating
> > + * vcpu->arch.sve_state as necessary.
> > + */
> > +static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
> > +{
> > +	void *buf;
> > +	unsigned int vl;
> > +
> > +	vl = vcpu->arch.sve_max_vl;
> > +
> > +	/*
> > +	 * Resposibility for these properties is shared between
> > +	 * kvm_arm_init_arch_resources(), kvm_vcpu_enable_sve() and
> > +	 * set_sve_vls().  Double-check here just to be sure:
> > +	 */
> > +	if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl ||
> > +		    vl > SVE_VL_ARCH_MAX))
> > +		return -EIO;
> > +
> > +	buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL);
> > +	if (!buf)
> > +		return -ENOMEM;
> > +
> > +	vcpu->arch.sve_state = buf;
> > +	vcpu->arch.flags |= KVM_ARM64_VCPU_SVE_FINALIZED;
> > +	return 0;
> > +}
> > +
> > +int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what)
> > +{
> > +	switch (what) {
> > +	case KVM_ARM_VCPU_SVE:
> > +		if (!vcpu_has_sve(vcpu))
> > +			return -EINVAL;
> > +
> > +		if (kvm_arm_vcpu_sve_finalized(vcpu))
> > +			return -EPERM;
> > +
> > +		return kvm_vcpu_finalize_sve(vcpu);
> 
> In the next patch I see that we already have KVM_ARM64_GUEST_HAS_SVE
> set in vcpu->arch.flags at this point. So if this kvm_vcpu_finalize_sve()
> call fails, shouldn't we unset KVM_ARM64_GUEST_HAS_SVE and anything
> else used to indicate the vcpu has sve?

If this fails, either userspace did the wrong thing, or there was some
fatal error (like the ENOMEM case).  Either way, the vcpu is not runnable
and userspace is expected to bail out.

Further, KVM_ARM_VCPU_INIT fixes the set of features requested by
userspace: we shouldn't change the set of features under userspace's
feet and try to limp on somehow.  We have no means for userspace to find
out that some features went away in the meantime...

So, what would you be trying to achieve with this change?

[...]

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 27/27] KVM: arm64/sve: Document KVM API extensions for SVE
  2019-04-04 21:09     ` Andrew Jones
@ 2019-04-05  9:36       ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05  9:36 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 11:09:21PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:52PM +0000, Dave Martin wrote:
> > This patch adds sections to the KVM API documentation describing
> > the extensions for supporting the Scalable Vector Extension (SVE)
> > in guests.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > 
> > ---
> > 
> > Changes since v5:
> > 
> >  * Document KVM_ARM_VCPU_FINALIZE and its interactions with SVE.
> > ---
> >  Documentation/virtual/kvm/api.txt | 132 +++++++++++++++++++++++++++++++++++++-
> >  1 file changed, 129 insertions(+), 3 deletions(-)
> > 
> > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> > index cd920dd..68509de 100644
> > --- a/Documentation/virtual/kvm/api.txt
> > +++ b/Documentation/virtual/kvm/api.txt
> > @@ -1873,6 +1873,7 @@ Parameters: struct kvm_one_reg (in)
> >  Returns: 0 on success, negative value on failure
> >  Errors:
> >    ENOENT:   no such register
> > +  EPERM:    register access forbidden for architecture-dependent reasons
> >    EINVAL:   other errors, such as bad size encoding for a known register
> >  
> >  struct kvm_one_reg {
> > @@ -2127,13 +2128,20 @@ Specifically:
> >    0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
> >    0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
> >    0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
> > -  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]
> > -  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]
> > +  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]    (*)
> > +  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]    (*)
> >      ...
> > -  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]
> > +  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]   (*)
> >    0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
> >    0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
> >  
> > +(*) These encodings are not accepted for SVE-enabled vcpus.  See
> > +    KVM_ARM_VCPU_INIT.
> > +
> > +    The equivalent register content can be accessed via bits [127:0] of
> > +    the corresponding SVE Zn registers instead for vcpus that have SVE
> > +    enabled (see below).
> > +
> >  arm64 CCSIDR registers are demultiplexed by CSSELR value:
> >    0x6020 0000 0011 00 <csselr:8>
> >  
> > @@ -2143,6 +2151,61 @@ arm64 system registers have the following id bit patterns:
> >  arm64 firmware pseudo-registers have the following bit pattern:
> >    0x6030 0000 0014 <regno:16>
> >  
> > +arm64 SVE registers have the following bit patterns:
> > +  0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> > +  0x6050 0000 0015 04 <n:4> <slice:5>   Pn bits[256*slice + 255 : 256*slice]
> > +  0x6050 0000 0015 060 <slice:5>        FFR bits[256*slice + 255 : 256*slice]
> > +  0x6060 0000 0015 ffff                 KVM_REG_ARM64_SVE_VLS pseudo-register
> > +
> > +Access to slices beyond the maximum vector length configured for the
> > +vcpu (i.e., where 16 * slice >= max_vq (**)) will fail with ENOENT.
> 
> I've been doing pretty well keeping track of the 16's, 128's, VL's and
> VQ's, but this example lost me. Also, should it be >= or just > ?

It should be >=.  It's analogous to not being allowed to derefence an
array index that is >= the size of the array.

Also, the 16 here is not the number of bytes per quadword (as it often
does with all things SVE), but the number of quadwords per 2048-bit
KVM register slice.

To make matters worse (**) resembles some weird C syntax.

Maybe this would be less confusing written as

    Access to register IDs where 2048 * slice >= 128 * max_vq will fail
    with ENOENT.  max_vq is the vcpu's maximum supported vector length
    in 128-bit quadwords: see (**) below.

Does that help at all?

> 
> > +
> > +These registers are only accessible on vcpus for which SVE is enabled.
> > +See KVM_ARM_VCPU_INIT for details.
> > +
> > +In addition, except for KVM_REG_ARM64_SVE_VLS, these registers are not
> > +accessible until the vcpu's SVE configuration has been finalized
> > +using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).  See KVM_ARM_VCPU_INIT
> > +and KVM_ARM_VCPU_FINALIZE for more information about this procedure.
> > +
> > +KVM_REG_ARM64_SVE_VLS is a pseudo-register that allows the set of vector
> > +lengths supported by the vcpu to be discovered and configured by
> > +userspace.  When transferred to or from user memory via KVM_GET_ONE_REG
> > +or KVM_SET_ONE_REG, the value of this register is of type __u64[8], and
> > +encodes the set of vector lengths as follows:
> > +
> > +__u64 vector_lengths[8];
> > +
> > +if (vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX &&
> > +    ((vector_lengths[(vq - 1) / 64] >> ((vq - 1) % 64)) & 1))
> > +	/* Vector length vq * 16 bytes supported */
> > +else
> > +	/* Vector length vq * 16 bytes not supported */
> > +
> > +(**) The maximum value vq for which the above condition is true is
> > +max_vq.  This is the maximum vector length available to the guest on
> > +this vcpu, and determines which register slices are visible through
> > +this ioctl interface.
> > +
> > +(See Documentation/arm64/sve.txt for an explanation of the "vq"
> > +nomenclature.)
> > +
> > +KVM_REG_ARM64_SVE_VLS is only accessible after KVM_ARM_VCPU_INIT.
> > +KVM_ARM_VCPU_INIT initialises it to the best set of vector lengths that
> > +the host supports.
> > +
> > +Userspace may subsequently modify it if desired until the vcpu's SVE
> > +configuration is finalized using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
> > +
> > +Apart from simply removing all vector lengths from the host set that
> > +exceed some value, support for arbitrarily chosen sets of vector lengths
> > +is hardware-dependent and may not be available.  Attempting to configure
> > +an invalid set of vector lengths via KVM_SET_ONE_REG will fail with
> > +EINVAL.
> > +
> > +After the vcpu's SVE configuration is finalized, further attempts to
> > +write this register will fail with EPERM.
> > +
> >  
> >  MIPS registers are mapped using the lower 32 bits.  The upper 16 of that is
> >  the register group type:
> > @@ -2197,6 +2260,7 @@ Parameters: struct kvm_one_reg (in and out)
> >  Returns: 0 on success, negative value on failure
> >  Errors:
> >    ENOENT:   no such register
> > +  EPERM:    register access forbidden for architecture-dependent reasons
> >    EINVAL:   other errors, such as bad size encoding for a known register
> >  
> >  This ioctl allows to receive the value of a single register implemented
> > @@ -2690,6 +2754,33 @@ Possible features:
> >  	- KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
> >  	  Depends on KVM_CAP_ARM_PMU_V3.
> >  
> > +	- KVM_ARM_VCPU_SVE: Enables SVE for the CPU (arm64 only).
> > +	  Depends on KVM_CAP_ARM_SVE.
> > +	  Requires KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > +
> > +	   * After KVM_ARM_VCPU_INIT:
> > +
> > +	      - KVM_REG_ARM64_SVE_VLS may be read using KVM_GET_ONE_REG: the
> > +	        initial value of this pseudo-register indicates the best set of
> > +	        vector lengths possible for a vcpu on this host.
> > +
> > +	   * Before KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > +
> > +	      - KVM_RUN and KVM_GET_REG_LIST are not available;
> > +
> > +	      - KVM_GET_ONE_REG and KVM_SET_ONE_REG cannot be used to access
> > +	        the scalable archietctural SVE registers
> > +	        KVM_REG_ARM64_SVE_ZREG(), KVM_REG_ARM64_SVE_PREG() or
> > +	        KVM_REG_ARM64_SVE_FFR;
> > +
> > +	      - KVM_REG_ARM64_SVE_VLS may optionally be written using
> > +	        KVM_SET_ONE_REG, to modify the set of vector lengths available
> > +	        for the vcpu.
> > +
> > +	   * After KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > +
> > +	      - the KVM_REG_ARM64_SVE_VLS pseudo-register is immutable, and can
> > +	        no longer be written using KVM_SET_ONE_REG.
> >  
> >  4.83 KVM_ARM_PREFERRED_TARGET
> >  
> > @@ -3904,6 +3995,41 @@ number of valid entries in the 'entries' array, which is then filled.
> >  'index' and 'flags' fields in 'struct kvm_cpuid_entry2' are currently reserved,
> >  userspace should not expect to get any particular value there.
> >  
> > +4.119 KVM_ARM_VCPU_FINALIZE
> > +
> > +Capability: KVM_CAP_ARM_SVE
> 
> The KVM_ARM_VCPU_FINALIZE vcpu ioctl isn't SVE specific, so it shouldn't
> depend on the SVE cap. It should have it's own cap, or maybe it should
> just be an KVM_ARM_VCPU_SVE_FINALIZE ioctl instead, i.e. not general.

This one's a bit annoying.  This would ideally read

Capability: KVM_CAP_ARM_SVE, or any other capability that advertises the
availability of a feature that requires KVM_ARM_VCPU_FINALIZE to be used.

(which sounds vague).

We could add a specific cap for KVM_ARM_VCPU_FINALIZE, but that seemed
overkill.  Or document KVM_ARM_VCPU_FINALIZE as unconditionally
supported, but make the individual feature values cap-dependent.  This
works because the symptom of missing support is the same (EINVAL)
ragardless of whether it is the specific feature or
KVM_ARM_VCPU_FINALIZE that is unsupported.

Thoughts?

> > +Architectures: arm, arm64
> > +Type: vcpu ioctl
> > +Parameters: int feature (in)
> 
> This was called 'what' in the code.

Indeed it is.  I wanted to avoid the implication that this paramter
exactly maps onto the KVM_ARM_VCPU_INIT features.  But "what" seemed
a bit too vague for the documentation.

Mind you, if lseek() can have a "whence" parameter, perhaps "what" is
also acceptable.

OTOH I don't mind changing the name in the code to "feature" if you
think that's preferable.

Thoughts?

> 
> > +Returns: 0 on success, -1 on error
> > +Errors:
> > +  EPERM:     feature not enabled, needs configuration, or already finalized
> > +  EINVAL:    unknown feature
> > +
> > +Recognised values for feature:
> > +  arm64      KVM_ARM_VCPU_SVE
> > +
> > +Finalizes the configuration of the specified vcpu feature.
> > +
> > +The vcpu must already have been initialised, enabling the affected feature, by
> > +means of a successful KVM_ARM_VCPU_INIT call with the appropriate flag set in
> > +features[].
> > +
> > +For affected vcpu features, this is a mandatory step that must be performed
> > +before the vcpu is fully usable.
> > +
> > +Between KVM_ARM_VCPU_INIT and KVM_ARM_VCPU_FINALIZE, the feature may be
> > +configured by use of ioctls such as KVM_SET_ONE_REG.  The exact configuration
> > +that should be performaned and how to do it are feature-dependent.
> > +
> > +Other calls that depend on a particular feature being finalized, such as
> > +KVM_RUN, KVM_GET_REG_LIST, KVM_GET_ONE_REG and KVM_SET_ONE_REG, will fail with
> > +-EPERM unless the feature has already been finalized by means of a
> > +KVM_ARM_VCPU_FINALIZE call.
> > +
> > +See KVM_ARM_VCPU_INIT for details of vcpu features that require finalization
> > +using this ioctl.
> > +
> >  5. The kvm_run structure
> >  ------------------------
> >
> 
> I'm still not sure about EPERM vs. ENOEXEC.

There is no need to distinguish the two: this is just a generic "vcpu in
wrong state for this to work" error.  I can't think of another subsystem
that uses ENOEXEC for this meaning, but it's established in KVM.

If you can't see a reason why we would need these to be distinct
errors (?) then I'm happy for this to be ENOEXEC for all cases.

Cheers
---Dave

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

* Re: [PATCH v7 27/27] KVM: arm64/sve: Document KVM API extensions for SVE
@ 2019-04-05  9:36       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05  9:36 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Thu, Apr 04, 2019 at 11:09:21PM +0200, Andrew Jones wrote:
> On Fri, Mar 29, 2019 at 01:00:52PM +0000, Dave Martin wrote:
> > This patch adds sections to the KVM API documentation describing
> > the extensions for supporting the Scalable Vector Extension (SVE)
> > in guests.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > 
> > ---
> > 
> > Changes since v5:
> > 
> >  * Document KVM_ARM_VCPU_FINALIZE and its interactions with SVE.
> > ---
> >  Documentation/virtual/kvm/api.txt | 132 +++++++++++++++++++++++++++++++++++++-
> >  1 file changed, 129 insertions(+), 3 deletions(-)
> > 
> > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> > index cd920dd..68509de 100644
> > --- a/Documentation/virtual/kvm/api.txt
> > +++ b/Documentation/virtual/kvm/api.txt
> > @@ -1873,6 +1873,7 @@ Parameters: struct kvm_one_reg (in)
> >  Returns: 0 on success, negative value on failure
> >  Errors:
> >    ENOENT:   no such register
> > +  EPERM:    register access forbidden for architecture-dependent reasons
> >    EINVAL:   other errors, such as bad size encoding for a known register
> >  
> >  struct kvm_one_reg {
> > @@ -2127,13 +2128,20 @@ Specifically:
> >    0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
> >    0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
> >    0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
> > -  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]
> > -  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]
> > +  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]    (*)
> > +  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]    (*)
> >      ...
> > -  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]
> > +  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]   (*)
> >    0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
> >    0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
> >  
> > +(*) These encodings are not accepted for SVE-enabled vcpus.  See
> > +    KVM_ARM_VCPU_INIT.
> > +
> > +    The equivalent register content can be accessed via bits [127:0] of
> > +    the corresponding SVE Zn registers instead for vcpus that have SVE
> > +    enabled (see below).
> > +
> >  arm64 CCSIDR registers are demultiplexed by CSSELR value:
> >    0x6020 0000 0011 00 <csselr:8>
> >  
> > @@ -2143,6 +2151,61 @@ arm64 system registers have the following id bit patterns:
> >  arm64 firmware pseudo-registers have the following bit pattern:
> >    0x6030 0000 0014 <regno:16>
> >  
> > +arm64 SVE registers have the following bit patterns:
> > +  0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> > +  0x6050 0000 0015 04 <n:4> <slice:5>   Pn bits[256*slice + 255 : 256*slice]
> > +  0x6050 0000 0015 060 <slice:5>        FFR bits[256*slice + 255 : 256*slice]
> > +  0x6060 0000 0015 ffff                 KVM_REG_ARM64_SVE_VLS pseudo-register
> > +
> > +Access to slices beyond the maximum vector length configured for the
> > +vcpu (i.e., where 16 * slice >= max_vq (**)) will fail with ENOENT.
> 
> I've been doing pretty well keeping track of the 16's, 128's, VL's and
> VQ's, but this example lost me. Also, should it be >= or just > ?

It should be >=.  It's analogous to not being allowed to derefence an
array index that is >= the size of the array.

Also, the 16 here is not the number of bytes per quadword (as it often
does with all things SVE), but the number of quadwords per 2048-bit
KVM register slice.

To make matters worse (**) resembles some weird C syntax.

Maybe this would be less confusing written as

    Access to register IDs where 2048 * slice >= 128 * max_vq will fail
    with ENOENT.  max_vq is the vcpu's maximum supported vector length
    in 128-bit quadwords: see (**) below.

Does that help at all?

> 
> > +
> > +These registers are only accessible on vcpus for which SVE is enabled.
> > +See KVM_ARM_VCPU_INIT for details.
> > +
> > +In addition, except for KVM_REG_ARM64_SVE_VLS, these registers are not
> > +accessible until the vcpu's SVE configuration has been finalized
> > +using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).  See KVM_ARM_VCPU_INIT
> > +and KVM_ARM_VCPU_FINALIZE for more information about this procedure.
> > +
> > +KVM_REG_ARM64_SVE_VLS is a pseudo-register that allows the set of vector
> > +lengths supported by the vcpu to be discovered and configured by
> > +userspace.  When transferred to or from user memory via KVM_GET_ONE_REG
> > +or KVM_SET_ONE_REG, the value of this register is of type __u64[8], and
> > +encodes the set of vector lengths as follows:
> > +
> > +__u64 vector_lengths[8];
> > +
> > +if (vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX &&
> > +    ((vector_lengths[(vq - 1) / 64] >> ((vq - 1) % 64)) & 1))
> > +	/* Vector length vq * 16 bytes supported */
> > +else
> > +	/* Vector length vq * 16 bytes not supported */
> > +
> > +(**) The maximum value vq for which the above condition is true is
> > +max_vq.  This is the maximum vector length available to the guest on
> > +this vcpu, and determines which register slices are visible through
> > +this ioctl interface.
> > +
> > +(See Documentation/arm64/sve.txt for an explanation of the "vq"
> > +nomenclature.)
> > +
> > +KVM_REG_ARM64_SVE_VLS is only accessible after KVM_ARM_VCPU_INIT.
> > +KVM_ARM_VCPU_INIT initialises it to the best set of vector lengths that
> > +the host supports.
> > +
> > +Userspace may subsequently modify it if desired until the vcpu's SVE
> > +configuration is finalized using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
> > +
> > +Apart from simply removing all vector lengths from the host set that
> > +exceed some value, support for arbitrarily chosen sets of vector lengths
> > +is hardware-dependent and may not be available.  Attempting to configure
> > +an invalid set of vector lengths via KVM_SET_ONE_REG will fail with
> > +EINVAL.
> > +
> > +After the vcpu's SVE configuration is finalized, further attempts to
> > +write this register will fail with EPERM.
> > +
> >  
> >  MIPS registers are mapped using the lower 32 bits.  The upper 16 of that is
> >  the register group type:
> > @@ -2197,6 +2260,7 @@ Parameters: struct kvm_one_reg (in and out)
> >  Returns: 0 on success, negative value on failure
> >  Errors:
> >    ENOENT:   no such register
> > +  EPERM:    register access forbidden for architecture-dependent reasons
> >    EINVAL:   other errors, such as bad size encoding for a known register
> >  
> >  This ioctl allows to receive the value of a single register implemented
> > @@ -2690,6 +2754,33 @@ Possible features:
> >  	- KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
> >  	  Depends on KVM_CAP_ARM_PMU_V3.
> >  
> > +	- KVM_ARM_VCPU_SVE: Enables SVE for the CPU (arm64 only).
> > +	  Depends on KVM_CAP_ARM_SVE.
> > +	  Requires KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > +
> > +	   * After KVM_ARM_VCPU_INIT:
> > +
> > +	      - KVM_REG_ARM64_SVE_VLS may be read using KVM_GET_ONE_REG: the
> > +	        initial value of this pseudo-register indicates the best set of
> > +	        vector lengths possible for a vcpu on this host.
> > +
> > +	   * Before KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > +
> > +	      - KVM_RUN and KVM_GET_REG_LIST are not available;
> > +
> > +	      - KVM_GET_ONE_REG and KVM_SET_ONE_REG cannot be used to access
> > +	        the scalable archietctural SVE registers
> > +	        KVM_REG_ARM64_SVE_ZREG(), KVM_REG_ARM64_SVE_PREG() or
> > +	        KVM_REG_ARM64_SVE_FFR;
> > +
> > +	      - KVM_REG_ARM64_SVE_VLS may optionally be written using
> > +	        KVM_SET_ONE_REG, to modify the set of vector lengths available
> > +	        for the vcpu.
> > +
> > +	   * After KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > +
> > +	      - the KVM_REG_ARM64_SVE_VLS pseudo-register is immutable, and can
> > +	        no longer be written using KVM_SET_ONE_REG.
> >  
> >  4.83 KVM_ARM_PREFERRED_TARGET
> >  
> > @@ -3904,6 +3995,41 @@ number of valid entries in the 'entries' array, which is then filled.
> >  'index' and 'flags' fields in 'struct kvm_cpuid_entry2' are currently reserved,
> >  userspace should not expect to get any particular value there.
> >  
> > +4.119 KVM_ARM_VCPU_FINALIZE
> > +
> > +Capability: KVM_CAP_ARM_SVE
> 
> The KVM_ARM_VCPU_FINALIZE vcpu ioctl isn't SVE specific, so it shouldn't
> depend on the SVE cap. It should have it's own cap, or maybe it should
> just be an KVM_ARM_VCPU_SVE_FINALIZE ioctl instead, i.e. not general.

This one's a bit annoying.  This would ideally read

Capability: KVM_CAP_ARM_SVE, or any other capability that advertises the
availability of a feature that requires KVM_ARM_VCPU_FINALIZE to be used.

(which sounds vague).

We could add a specific cap for KVM_ARM_VCPU_FINALIZE, but that seemed
overkill.  Or document KVM_ARM_VCPU_FINALIZE as unconditionally
supported, but make the individual feature values cap-dependent.  This
works because the symptom of missing support is the same (EINVAL)
ragardless of whether it is the specific feature or
KVM_ARM_VCPU_FINALIZE that is unsupported.

Thoughts?

> > +Architectures: arm, arm64
> > +Type: vcpu ioctl
> > +Parameters: int feature (in)
> 
> This was called 'what' in the code.

Indeed it is.  I wanted to avoid the implication that this paramter
exactly maps onto the KVM_ARM_VCPU_INIT features.  But "what" seemed
a bit too vague for the documentation.

Mind you, if lseek() can have a "whence" parameter, perhaps "what" is
also acceptable.

OTOH I don't mind changing the name in the code to "feature" if you
think that's preferable.

Thoughts?

> 
> > +Returns: 0 on success, -1 on error
> > +Errors:
> > +  EPERM:     feature not enabled, needs configuration, or already finalized
> > +  EINVAL:    unknown feature
> > +
> > +Recognised values for feature:
> > +  arm64      KVM_ARM_VCPU_SVE
> > +
> > +Finalizes the configuration of the specified vcpu feature.
> > +
> > +The vcpu must already have been initialised, enabling the affected feature, by
> > +means of a successful KVM_ARM_VCPU_INIT call with the appropriate flag set in
> > +features[].
> > +
> > +For affected vcpu features, this is a mandatory step that must be performed
> > +before the vcpu is fully usable.
> > +
> > +Between KVM_ARM_VCPU_INIT and KVM_ARM_VCPU_FINALIZE, the feature may be
> > +configured by use of ioctls such as KVM_SET_ONE_REG.  The exact configuration
> > +that should be performaned and how to do it are feature-dependent.
> > +
> > +Other calls that depend on a particular feature being finalized, such as
> > +KVM_RUN, KVM_GET_REG_LIST, KVM_GET_ONE_REG and KVM_SET_ONE_REG, will fail with
> > +-EPERM unless the feature has already been finalized by means of a
> > +KVM_ARM_VCPU_FINALIZE call.
> > +
> > +See KVM_ARM_VCPU_INIT for details of vcpu features that require finalization
> > +using this ioctl.
> > +
> >  5. The kvm_run structure
> >  ------------------------
> >
> 
> I'm still not sure about EPERM vs. ENOEXEC.

There is no need to distinguish the two: this is just a generic "vcpu in
wrong state for this to work" error.  I can't think of another subsystem
that uses ENOEXEC for this meaning, but it's established in KVM.

If you can't see a reason why we would need these to be distinct
errors (?) then I'm happy for this to be ENOEXEC for all cases.

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 21/27] KVM: arm/arm64: Add hook for arch-specific KVM initialisation
  2019-04-04 16:33         ` Andrew Jones
@ 2019-04-05  9:36           ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05  9:36 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	Dave Martin, linux-arm-kernel

On Thu, Apr 04, 2019 at 06:33:08PM +0200, Andrew Jones wrote:
> On Thu, Apr 04, 2019 at 03:53:55PM +0100, Dave Martin wrote:
> > On Thu, Apr 04, 2019 at 04:25:28PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:46PM +0000, Dave Martin wrote:

[...]

> > > > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > > > index 99c3738..c69e137 100644
> > > > --- a/virt/kvm/arm/arm.c
> > > > +++ b/virt/kvm/arm/arm.c
> > > > @@ -1664,6 +1664,10 @@ int kvm_arch_init(void *opaque)
> > > >  	if (err)
> > > >  		return err;
> > > >  
> > > > +	err = kvm_arm_init_arch_resources();
> > > > +	if (err)
> > > > +		return err;
> > > > +
> > > >  	if (!in_hyp_mode) {
> > > >  		err = init_hyp_mode();
> > > >  		if (err)
> > > > -- 
> > > > 2.1.4
> > > >
> > > 
> > > It's not clear to me from the commit message why init_common_resources()
> > > won't work for this. Maybe it'll be more clear as I continue the review.
> > 
> > init_common_resources() is for stuff common to arm and arm64.
> 
> Well currently init_common_resources() only calls kvm_set_ipa_limit(),
> which isn't implemented for arm. So if there was a plan to only use
> that function for init that actually does something on both, it doesn't.

Hmmm, perhaps I was wishfully interpreting the word "common" to mean
what I would like it to mean...

> > kvm_arm_init_arch_resources() is intended for stuff specific to the
> > particular arch backend.
> 
> I'm not sure we need that yet. We just need an arm setup sve stub like
> arm's kvm_set_ipa_limit() stub. OTOH, if we have to keep adding stubs
> to arm we should probably have something like
> kvm_arm_init_arch_resources() instead, and kvm_set_ipa_limit() should
> be moved inside the arm64 one and the arm ipa limit stub can go. Then
> since init_common_resources() would no longer be used, it could just
> be deleted.

OK, for simplicity I may call the sve setup directly as you suggest, and
make an arm stub for it: that feels a bit weird, but there is precedent.

If we end up accumulating a lot of these, we can revisit it and maybe
invent something like kvm_arm_init_arch_resources() at that point.

Does that sound reasonable?

Cheers
---Dave

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

* Re: [PATCH v7 21/27] KVM: arm/arm64: Add hook for arch-specific KVM initialisation
@ 2019-04-05  9:36           ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05  9:36 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	Dave Martin, linux-arm-kernel

On Thu, Apr 04, 2019 at 06:33:08PM +0200, Andrew Jones wrote:
> On Thu, Apr 04, 2019 at 03:53:55PM +0100, Dave Martin wrote:
> > On Thu, Apr 04, 2019 at 04:25:28PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:46PM +0000, Dave Martin wrote:

[...]

> > > > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > > > index 99c3738..c69e137 100644
> > > > --- a/virt/kvm/arm/arm.c
> > > > +++ b/virt/kvm/arm/arm.c
> > > > @@ -1664,6 +1664,10 @@ int kvm_arch_init(void *opaque)
> > > >  	if (err)
> > > >  		return err;
> > > >  
> > > > +	err = kvm_arm_init_arch_resources();
> > > > +	if (err)
> > > > +		return err;
> > > > +
> > > >  	if (!in_hyp_mode) {
> > > >  		err = init_hyp_mode();
> > > >  		if (err)
> > > > -- 
> > > > 2.1.4
> > > >
> > > 
> > > It's not clear to me from the commit message why init_common_resources()
> > > won't work for this. Maybe it'll be more clear as I continue the review.
> > 
> > init_common_resources() is for stuff common to arm and arm64.
> 
> Well currently init_common_resources() only calls kvm_set_ipa_limit(),
> which isn't implemented for arm. So if there was a plan to only use
> that function for init that actually does something on both, it doesn't.

Hmmm, perhaps I was wishfully interpreting the word "common" to mean
what I would like it to mean...

> > kvm_arm_init_arch_resources() is intended for stuff specific to the
> > particular arch backend.
> 
> I'm not sure we need that yet. We just need an arm setup sve stub like
> arm's kvm_set_ipa_limit() stub. OTOH, if we have to keep adding stubs
> to arm we should probably have something like
> kvm_arm_init_arch_resources() instead, and kvm_set_ipa_limit() should
> be moved inside the arm64 one and the arm ipa limit stub can go. Then
> since init_common_resources() would no longer be used, it could just
> be deleted.

OK, for simplicity I may call the sve setup directly as you suggest, and
make an arm stub for it: that feels a bit weird, but there is precedent.

If we end up accumulating a lot of these, we can revisit it and maybe
invent something like kvm_arm_init_arch_resources() at that point.

Does that sound reasonable?

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 19/27] KVM: arm64: Enumerate SVE register indices for KVM_GET_REG_LIST
  2019-04-05  9:35       ` Dave Martin
@ 2019-04-05  9:45         ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-05  9:45 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 10:35:45AM +0100, Dave Martin wrote:
> On Thu, Apr 04, 2019 at 04:08:32PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:44PM +0000, Dave Martin wrote:
> > > This patch includes the SVE register IDs in the list returned by
> > > KVM_GET_REG_LIST, as appropriate.
> > > 
> > > On a non-SVE-enabled vcpu, no new IDs are added.
> > > 
> > > On an SVE-enabled vcpu, IDs for the FPSIMD V-registers are removed
> > > from the list, since userspace is required to access the Z-
> > > registers instead in order to access the V-register content.  For
> > > the variably-sized SVE registers, the appropriate set of slice IDs
> > > are enumerated, depending on the maximum vector length for the
> > > vcpu.
> > > 
> > > As it currently stands, the SVE architecture never requires more
> > > than one slice to exist per register, so this patch adds no
> > > explicit support for enumerating multiple slices.  The code can be
> > > extended straightforwardly to support this in the future, if
> > > needed.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > 
> > > ---
> > > 
> > > Changes since v6:
> > > 
> > >  * [Julien Thierry] Add a #define to replace the magic "slices = 1",
> > >    and add a comment explaining to maintainers what needs to happen if
> > >    this is updated in the future.
> > > 
> > > Changes since v5:
> > > 
> > > (Dropped Julien Thierry's Reviewed-by due to non-trivial rebasing)
> > > 
> > >  * Move mis-split reword to prevent put_user()s being accidentally the
> > >    correct size from KVM: arm64/sve: Add pseudo-register for the guest's
> > >    vector lengths.
> > > ---
> > >  arch/arm64/kvm/guest.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++
> > >  1 file changed, 63 insertions(+)
> > > 
> > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > index 736d8cb..2aa80a5 100644
> > > --- a/arch/arm64/kvm/guest.c
> > > +++ b/arch/arm64/kvm/guest.c
> > > @@ -222,6 +222,13 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >  #define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0))
> > >  #define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0))
> > >  
> > > +/*
> > > + * number of register slices required to cover each whole SVE register on vcpu
> > 
> > s/number/Number/
> 
> Not a sentence -> no capital letter.
> 
> Due to the adjacent note it does look a little odd though.  I'm happy to
> change it.
> 
> > s/on vcpu//
> 
> Agreed, I can drop that.
> 
> > > + * NOTE: If you are tempted to modify this, you must also to rework
> > 
> > s/to rework/rework/
> 
> Ack
> 
> > > + * sve_reg_to_region() to match:
> > > + */
> > > +#define vcpu_sve_slices(vcpu) 1
> > > +
> > >  /* Bounds of a single SVE register slice within vcpu->arch.sve_state */
> > >  struct sve_state_reg_region {
> > >  	unsigned int koffset;	/* offset into sve_state in kernel memory */
> > > @@ -411,6 +418,56 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >  	return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0;
> > >  }
> > >  
> > > +static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
> > > +{
> > > +	/* Only the first slice ever exists, for now */
> > 
> > I'd move this comment up into the one above vcpu_sve_slices(),
> > and then nothing needs to change here when more slices come.
> > 
> > > +	const unsigned int slices = vcpu_sve_slices(vcpu);
> > > +
> > > +	if (!vcpu_has_sve(vcpu))
> > > +		return 0;
> > > +
> > > +	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */);
> > > +}
> > > +
> > > +static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
> > > +				u64 __user *uindices)
> > > +{
> > > +	/* Only the first slice ever exists, for now */
> > 
> > Same comment as above.
> 
> Fair point: this was to explain the magic "1" that was previously here,
> but the comments are a bit redundant here now: better to move the
> comments where the 1 itself went.
> 
> > > +	const unsigned int slices = vcpu_sve_slices(vcpu);
> > > +	u64 reg;
> > > +	unsigned int i, n;
> > > +	int num_regs = 0;
> > > +
> > > +	if (!vcpu_has_sve(vcpu))
> > > +		return 0;
> > > +
> > > +	for (i = 0; i < slices; i++) {
> > > +		for (n = 0; n < SVE_NUM_ZREGS; n++) {
> > > +			reg = KVM_REG_ARM64_SVE_ZREG(n, i);
> > > +			if (put_user(reg, uindices++))
> > > +				return -EFAULT;
> > > +
> > > +			num_regs++;
> > > +		}
> > > +
> > > +		for (n = 0; n < SVE_NUM_PREGS; n++) {
> > > +			reg = KVM_REG_ARM64_SVE_PREG(n, i);
> > > +			if (put_user(reg, uindices++))
> > > +				return -EFAULT;
> > > +
> > > +			num_regs++;
> > > +		}
> > > +
> > > +		reg = KVM_REG_ARM64_SVE_FFR(i);
> > > +		if (put_user(reg, uindices++))
> > > +			return -EFAULT;
> > > +
> > > +		num_regs++;
> > > +	}
> > 
> > nit: the extra blank lines above the num_regs++'s give the code an odd
> >      look (to me)
> 
> There's no guaranteed fall-through onto the increments: the blank line
> was there to highlight the fact that we may jump out using a return
> instead.
> 
> But I'm happy enough to change it if you have a strong preference or
> you feel the code is equally clear without.

It's just a nit, so I don't have a strong preference :)

> 
> > 
> > > +
> > > +	return num_regs;
> > > +}
> > > +
> > >  /**
> > >   * kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG
> > >   *
> > > @@ -421,6 +478,7 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
> > >  	unsigned long res = 0;
> > >  
> > >  	res += num_core_regs(vcpu);
> > > +	res += num_sve_regs(vcpu);
> > >  	res += kvm_arm_num_sys_reg_descs(vcpu);
> > >  	res += kvm_arm_get_fw_num_regs(vcpu);
> > >  	res += NUM_TIMER_REGS;
> > > @@ -442,6 +500,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
> > >  		return ret;
> > >  	uindices += ret;
> > >  
> > > +	ret = copy_sve_reg_indices(vcpu, uindices);
> > > +	if (ret)
> > > +		return ret;
> > > +	uindices += ret;
> > 
> > I know this if ret vs. if ret < 0 is being addressed already.
> 
> Yes, Marc's patch in kvmarm/next should fix that.
> 
> Cheers
> ---Dave

Thanks,
drew

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

* Re: [PATCH v7 19/27] KVM: arm64: Enumerate SVE register indices for KVM_GET_REG_LIST
@ 2019-04-05  9:45         ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-05  9:45 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 10:35:45AM +0100, Dave Martin wrote:
> On Thu, Apr 04, 2019 at 04:08:32PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:44PM +0000, Dave Martin wrote:
> > > This patch includes the SVE register IDs in the list returned by
> > > KVM_GET_REG_LIST, as appropriate.
> > > 
> > > On a non-SVE-enabled vcpu, no new IDs are added.
> > > 
> > > On an SVE-enabled vcpu, IDs for the FPSIMD V-registers are removed
> > > from the list, since userspace is required to access the Z-
> > > registers instead in order to access the V-register content.  For
> > > the variably-sized SVE registers, the appropriate set of slice IDs
> > > are enumerated, depending on the maximum vector length for the
> > > vcpu.
> > > 
> > > As it currently stands, the SVE architecture never requires more
> > > than one slice to exist per register, so this patch adds no
> > > explicit support for enumerating multiple slices.  The code can be
> > > extended straightforwardly to support this in the future, if
> > > needed.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > 
> > > ---
> > > 
> > > Changes since v6:
> > > 
> > >  * [Julien Thierry] Add a #define to replace the magic "slices = 1",
> > >    and add a comment explaining to maintainers what needs to happen if
> > >    this is updated in the future.
> > > 
> > > Changes since v5:
> > > 
> > > (Dropped Julien Thierry's Reviewed-by due to non-trivial rebasing)
> > > 
> > >  * Move mis-split reword to prevent put_user()s being accidentally the
> > >    correct size from KVM: arm64/sve: Add pseudo-register for the guest's
> > >    vector lengths.
> > > ---
> > >  arch/arm64/kvm/guest.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++
> > >  1 file changed, 63 insertions(+)
> > > 
> > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > index 736d8cb..2aa80a5 100644
> > > --- a/arch/arm64/kvm/guest.c
> > > +++ b/arch/arm64/kvm/guest.c
> > > @@ -222,6 +222,13 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >  #define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0))
> > >  #define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0))
> > >  
> > > +/*
> > > + * number of register slices required to cover each whole SVE register on vcpu
> > 
> > s/number/Number/
> 
> Not a sentence -> no capital letter.
> 
> Due to the adjacent note it does look a little odd though.  I'm happy to
> change it.
> 
> > s/on vcpu//
> 
> Agreed, I can drop that.
> 
> > > + * NOTE: If you are tempted to modify this, you must also to rework
> > 
> > s/to rework/rework/
> 
> Ack
> 
> > > + * sve_reg_to_region() to match:
> > > + */
> > > +#define vcpu_sve_slices(vcpu) 1
> > > +
> > >  /* Bounds of a single SVE register slice within vcpu->arch.sve_state */
> > >  struct sve_state_reg_region {
> > >  	unsigned int koffset;	/* offset into sve_state in kernel memory */
> > > @@ -411,6 +418,56 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >  	return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0;
> > >  }
> > >  
> > > +static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
> > > +{
> > > +	/* Only the first slice ever exists, for now */
> > 
> > I'd move this comment up into the one above vcpu_sve_slices(),
> > and then nothing needs to change here when more slices come.
> > 
> > > +	const unsigned int slices = vcpu_sve_slices(vcpu);
> > > +
> > > +	if (!vcpu_has_sve(vcpu))
> > > +		return 0;
> > > +
> > > +	return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */);
> > > +}
> > > +
> > > +static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
> > > +				u64 __user *uindices)
> > > +{
> > > +	/* Only the first slice ever exists, for now */
> > 
> > Same comment as above.
> 
> Fair point: this was to explain the magic "1" that was previously here,
> but the comments are a bit redundant here now: better to move the
> comments where the 1 itself went.
> 
> > > +	const unsigned int slices = vcpu_sve_slices(vcpu);
> > > +	u64 reg;
> > > +	unsigned int i, n;
> > > +	int num_regs = 0;
> > > +
> > > +	if (!vcpu_has_sve(vcpu))
> > > +		return 0;
> > > +
> > > +	for (i = 0; i < slices; i++) {
> > > +		for (n = 0; n < SVE_NUM_ZREGS; n++) {
> > > +			reg = KVM_REG_ARM64_SVE_ZREG(n, i);
> > > +			if (put_user(reg, uindices++))
> > > +				return -EFAULT;
> > > +
> > > +			num_regs++;
> > > +		}
> > > +
> > > +		for (n = 0; n < SVE_NUM_PREGS; n++) {
> > > +			reg = KVM_REG_ARM64_SVE_PREG(n, i);
> > > +			if (put_user(reg, uindices++))
> > > +				return -EFAULT;
> > > +
> > > +			num_regs++;
> > > +		}
> > > +
> > > +		reg = KVM_REG_ARM64_SVE_FFR(i);
> > > +		if (put_user(reg, uindices++))
> > > +			return -EFAULT;
> > > +
> > > +		num_regs++;
> > > +	}
> > 
> > nit: the extra blank lines above the num_regs++'s give the code an odd
> >      look (to me)
> 
> There's no guaranteed fall-through onto the increments: the blank line
> was there to highlight the fact that we may jump out using a return
> instead.
> 
> But I'm happy enough to change it if you have a strong preference or
> you feel the code is equally clear without.

It's just a nit, so I don't have a strong preference :)

> 
> > 
> > > +
> > > +	return num_regs;
> > > +}
> > > +
> > >  /**
> > >   * kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG
> > >   *
> > > @@ -421,6 +478,7 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
> > >  	unsigned long res = 0;
> > >  
> > >  	res += num_core_regs(vcpu);
> > > +	res += num_sve_regs(vcpu);
> > >  	res += kvm_arm_num_sys_reg_descs(vcpu);
> > >  	res += kvm_arm_get_fw_num_regs(vcpu);
> > >  	res += NUM_TIMER_REGS;
> > > @@ -442,6 +500,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
> > >  		return ret;
> > >  	uindices += ret;
> > >  
> > > +	ret = copy_sve_reg_indices(vcpu, uindices);
> > > +	if (ret)
> > > +		return ret;
> > > +	uindices += ret;
> > 
> > I know this if ret vs. if ret < 0 is being addressed already.
> 
> Yes, Marc's patch in kvmarm/next should fix that.
> 
> Cheers
> ---Dave

Thanks,
drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 20/27] arm64/sve: In-kernel vector length availability query interface
  2019-04-05  9:35       ` Dave Martin
@ 2019-04-05  9:54         ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-05  9:54 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 10:35:55AM +0100, Dave Martin wrote:
> On Thu, Apr 04, 2019 at 04:20:34PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:45PM +0000, Dave Martin wrote:
> > > KVM will need to interrogate the set of SVE vector lengths
> > > available on the system.
> > > 
> > > This patch exposes the relevant bits to the kernel, along with a
> > > sve_vq_available() helper to check whether a particular vector
> > > length is supported.
> > > 
> > > __vq_to_bit() and __bit_to_vq() are not intended for use outside
> > > these functions: now that these are exposed outside fpsimd.c, they
> > > are prefixed with __ in order to provide an extra hint that they
> > > are not intended for general-purpose use.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > ---
> > >  arch/arm64/include/asm/fpsimd.h | 29 +++++++++++++++++++++++++++++
> > >  arch/arm64/kernel/fpsimd.c      | 35 ++++++++---------------------------
> > >  2 files changed, 37 insertions(+), 27 deletions(-)
> > > 
> > > diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
> > > index df7a143..ad6d2e4 100644
> > > --- a/arch/arm64/include/asm/fpsimd.h
> > > +++ b/arch/arm64/include/asm/fpsimd.h
> > > @@ -24,10 +24,13 @@
> > >  
> > >  #ifndef __ASSEMBLY__
> > >  
> > > +#include <linux/bitmap.h>
> > >  #include <linux/build_bug.h>
> > > +#include <linux/bug.h>
> > >  #include <linux/cache.h>
> > >  #include <linux/init.h>
> > >  #include <linux/stddef.h>
> > > +#include <linux/types.h>
> > >  
> > >  #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
> > >  /* Masks for extracting the FPSR and FPCR from the FPSCR */
> > > @@ -89,6 +92,32 @@ extern u64 read_zcr_features(void);
> > >  
> > >  extern int __ro_after_init sve_max_vl;
> > >  extern int __ro_after_init sve_max_virtualisable_vl;
> > > +/* Set of available vector lengths, as vq_to_bit(vq): */
> > 
> > s/as/for use with/ ?
> 
> Not exactly.  Does the following work for you:
> 
> /*
>  * Set of available vector lengths
>  * Vector length vq is encoded as bit __vq_to_bit(vq):
>  */

Yes. That reads much better.

> 
> > s/vq_to_bit/__vq_to_bit/
> 
> Ack: that got renamed when I moved it to fpsimd.h, bit I clearly didn't
> update the comment as I pasted it across.
> 
> > 
> > > +extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
> > > +
> > > +/*
> > > + * Helpers to translate bit indices in sve_vq_map to VQ values (and
> > > + * vice versa).  This allows find_next_bit() to be used to find the
> > > + * _maximum_ VQ not exceeding a certain value.
> > > + */
> > > +static inline unsigned int __vq_to_bit(unsigned int vq)
> > > +{
> > 
> > Why not have the same WARN_ON and clamping here as we do
> > in __bit_to_vq. Here a vq > SVE_VQ_MAX will wrap around
> > to a super high bit.
> > 
> > > +	return SVE_VQ_MAX - vq;
> > > +}
> > > +
> > > +static inline unsigned int __bit_to_vq(unsigned int bit)
> > > +{
> > > +	if (WARN_ON(bit >= SVE_VQ_MAX))
> > > +		bit = SVE_VQ_MAX - 1;
> > > +
> > > +	return SVE_VQ_MAX - bit;
> > > +}
> > > +
> > > +/* Ensure vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX before calling this function */
> > 
> > Are we avoiding putting these tests and WARN_ONs in this function to
> > keep it fast?
> 
> These are intended as backend for use only by fpsimd.c and this header,
> so peppering them with WARN_ON() felt excessive.  I don't expect a lot
> of new calls to these (or any, probably).
> 
> I don't recall why I kept the WARN_ON() just in __bit_to_vq(), except
> that the way that gets called is a bit more complex in some places.
> 
> Are you happy to replace these with comments?  e.g.:
> 
> /* Only valid when vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX */
> __vq_to_bit()
> 
> /* Only valid when bit < SVE_VQ_MAX */
> __bit_to_vq()
> 
> 
> OTOH, these are not used on fast paths, so maybe having both as
> WARN_ON() would be better.  Part of the problem is knowing what to clamp
> to: these are generally used in conjunction with looping or bitmap find
> operations, so the caller may be making assumptions about the return
> value that may wrong when the value is clamped.
> 
> Alternatively, these could be BUG() -- but that seems heavy.
> 
> What do you think?

I like the idea of having WARN_ON's to enforce the constraints. I
wouldn't be completely opposed to not having anything other than
the comments, though, as there is a limit to how defensive we should
be. I'll abstain from this vote.

Thanks,
drew

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

* Re: [PATCH v7 20/27] arm64/sve: In-kernel vector length availability query interface
@ 2019-04-05  9:54         ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-05  9:54 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 10:35:55AM +0100, Dave Martin wrote:
> On Thu, Apr 04, 2019 at 04:20:34PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:45PM +0000, Dave Martin wrote:
> > > KVM will need to interrogate the set of SVE vector lengths
> > > available on the system.
> > > 
> > > This patch exposes the relevant bits to the kernel, along with a
> > > sve_vq_available() helper to check whether a particular vector
> > > length is supported.
> > > 
> > > __vq_to_bit() and __bit_to_vq() are not intended for use outside
> > > these functions: now that these are exposed outside fpsimd.c, they
> > > are prefixed with __ in order to provide an extra hint that they
> > > are not intended for general-purpose use.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > ---
> > >  arch/arm64/include/asm/fpsimd.h | 29 +++++++++++++++++++++++++++++
> > >  arch/arm64/kernel/fpsimd.c      | 35 ++++++++---------------------------
> > >  2 files changed, 37 insertions(+), 27 deletions(-)
> > > 
> > > diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
> > > index df7a143..ad6d2e4 100644
> > > --- a/arch/arm64/include/asm/fpsimd.h
> > > +++ b/arch/arm64/include/asm/fpsimd.h
> > > @@ -24,10 +24,13 @@
> > >  
> > >  #ifndef __ASSEMBLY__
> > >  
> > > +#include <linux/bitmap.h>
> > >  #include <linux/build_bug.h>
> > > +#include <linux/bug.h>
> > >  #include <linux/cache.h>
> > >  #include <linux/init.h>
> > >  #include <linux/stddef.h>
> > > +#include <linux/types.h>
> > >  
> > >  #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
> > >  /* Masks for extracting the FPSR and FPCR from the FPSCR */
> > > @@ -89,6 +92,32 @@ extern u64 read_zcr_features(void);
> > >  
> > >  extern int __ro_after_init sve_max_vl;
> > >  extern int __ro_after_init sve_max_virtualisable_vl;
> > > +/* Set of available vector lengths, as vq_to_bit(vq): */
> > 
> > s/as/for use with/ ?
> 
> Not exactly.  Does the following work for you:
> 
> /*
>  * Set of available vector lengths
>  * Vector length vq is encoded as bit __vq_to_bit(vq):
>  */

Yes. That reads much better.

> 
> > s/vq_to_bit/__vq_to_bit/
> 
> Ack: that got renamed when I moved it to fpsimd.h, bit I clearly didn't
> update the comment as I pasted it across.
> 
> > 
> > > +extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
> > > +
> > > +/*
> > > + * Helpers to translate bit indices in sve_vq_map to VQ values (and
> > > + * vice versa).  This allows find_next_bit() to be used to find the
> > > + * _maximum_ VQ not exceeding a certain value.
> > > + */
> > > +static inline unsigned int __vq_to_bit(unsigned int vq)
> > > +{
> > 
> > Why not have the same WARN_ON and clamping here as we do
> > in __bit_to_vq. Here a vq > SVE_VQ_MAX will wrap around
> > to a super high bit.
> > 
> > > +	return SVE_VQ_MAX - vq;
> > > +}
> > > +
> > > +static inline unsigned int __bit_to_vq(unsigned int bit)
> > > +{
> > > +	if (WARN_ON(bit >= SVE_VQ_MAX))
> > > +		bit = SVE_VQ_MAX - 1;
> > > +
> > > +	return SVE_VQ_MAX - bit;
> > > +}
> > > +
> > > +/* Ensure vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX before calling this function */
> > 
> > Are we avoiding putting these tests and WARN_ONs in this function to
> > keep it fast?
> 
> These are intended as backend for use only by fpsimd.c and this header,
> so peppering them with WARN_ON() felt excessive.  I don't expect a lot
> of new calls to these (or any, probably).
> 
> I don't recall why I kept the WARN_ON() just in __bit_to_vq(), except
> that the way that gets called is a bit more complex in some places.
> 
> Are you happy to replace these with comments?  e.g.:
> 
> /* Only valid when vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX */
> __vq_to_bit()
> 
> /* Only valid when bit < SVE_VQ_MAX */
> __bit_to_vq()
> 
> 
> OTOH, these are not used on fast paths, so maybe having both as
> WARN_ON() would be better.  Part of the problem is knowing what to clamp
> to: these are generally used in conjunction with looping or bitmap find
> operations, so the caller may be making assumptions about the return
> value that may wrong when the value is clamped.
> 
> Alternatively, these could be BUG() -- but that seems heavy.
> 
> What do you think?

I like the idea of having WARN_ON's to enforce the constraints. I
wouldn't be completely opposed to not having anything other than
the comments, though, as there is a limit to how defensive we should
be. I'll abstain from this vote.

Thanks,
drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
  2019-04-05  9:36       ` Dave Martin
@ 2019-04-05 10:14         ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-05 10:14 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 10:36:03AM +0100, Dave Martin wrote:
> On Thu, Apr 04, 2019 at 10:18:54PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> > > This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> > > allow userspace to set and query the set of vector lengths visible
> > > to the guest.
> > > 
> > > In the future, multiple register slices per SVE register may be
> > > visible through the ioctl interface.  Once the set of slices has
> > > been determined we would not be able to allow the vector length set
> > > to be changed any more, in order to avoid userspace seeing
> > > inconsistent sets of registers.  For this reason, this patch adds
> > > support for explicit finalization of the SVE configuration via the
> > > KVM_ARM_VCPU_FINALIZE ioctl.
> > > 
> > > Finalization is the proper place to allocate the SVE register state
> > > storage in vcpu->arch.sve_state, so this patch adds that as
> > > appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> > > was previously a no-op on arm64.
> > > 
> > > To simplify the logic for determining what vector lengths can be
> > > supported, some code is added to KVM init to work this out, in the
> > > kvm_arm_init_arch_resources() hook.
> > > 
> > > The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> > > Subsequent patches will allow SVE to be turned on for guest vcpus,
> > > making it visible.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > 
> > > ---
> 
> [...]
> 
> > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > index 2aa80a5..086ab05 100644
> > > --- a/arch/arm64/kvm/guest.c
> > > +++ b/arch/arm64/kvm/guest.c
> > > @@ -206,6 +206,73 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >  	return err;
> > >  }
> > >  
> > > +#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64)
> > > +#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64)
> > > +
> > > +static bool vq_present(
> > > +	const u64 (*const vqs)[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)],
> > > +	unsigned int vq)
> > > +{
> > > +	return (*vqs)[vq_word(vq)] & vq_mask(vq);
> > > +}
> > > +
> > > +static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > +{
> > > +	unsigned int max_vq, vq;
> > > +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> > > +
> > > +	if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl)))
> > > +		return -EINVAL;
> > > +
> > > +	memset(vqs, 0, sizeof(vqs));
> > > +
> > > +	max_vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
> > > +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > > +		if (sve_vq_available(vq))
> > > +			vqs[vq_word(vq)] |= vq_mask(vq);
> > > +
> > > +	if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs)))
> > > +		return -EFAULT;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > +{
> > > +	unsigned int max_vq, vq;
> > > +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> > 
> > There are three of these long 'DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)'.
> > A macro is probably warranted.
> 
> Fair point.  These are a bit cumbersome.  How about:
> 
> #define SVE_VLS_WORDS DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)
> 
> Annoyingly, this is virtually identical to a Linux bitmap: the base type
> is u64 instead of unsigned long; otherwise there's no intentional
> difference.

Yeah, I noticed it was a reinvented bitmap, but I liked that it was,
because, for the userspace api, removing the bitmap abstractions
ensures we know what is what and where exactly it is.

> 
> (Aside: do you know why the KVM API insists on everything being u64?
> This makes sense for non-native types (like guest registers), but not
> for native things like host userspace addresses etc.)

Would that work when the kernel is 64-bit and the userspace is 32? I
personally like the interfaces being explicit with type size, as it
removes the brain burden of translating long and int when moving arch
to arch and kernel to userspace.

> 
> > > +
> > > +	if (kvm_arm_vcpu_sve_finalized(vcpu))
> > > +		return -EPERM; /* too late! */
> > > +
> > > +	if (WARN_ON(vcpu->arch.sve_state))
> > > +		return -EINVAL;
> > > +
> > > +	if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs)))
> > > +		return -EFAULT;
> > > +
> > > +	max_vq = 0;
> > > +	for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq)
> > > +		if (vq_present(&vqs, vq))
> > > +			max_vq = vq;
> > > +
> > > +	if (max_vq > sve_vq_from_vl(kvm_sve_max_vl))
> > > +		return -EINVAL;
> > > +
> > > +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > > +		if (vq_present(&vqs, vq) != sve_vq_available(vq))
> > > +			return -EINVAL;
> > 
> > What about supporting the optional non-power-of-2 vector lengths? For
> > example, if the maximum VL is 512, then in addition to 512, 128, and
> > 256 there could be a 384. If we plan to start a guest on a machine
> > that has all four and then migrate it to a machine that only has
> > 128,256,512 we would want to set the VL set to 128,256,512, even on
> > the machine that supports 384. If I understand the above test correctly,
> > then that wouldn't work.
> 
> This is exactly what the code is trying to forbid, though it may not be
> obvious here why.
> 
> The trouble is, we can't correctly emulate a vcpu supporting
> {128,256,512} on hardware that also supports 384-bit vectors: the
> architecture says that the vector length you get is determined by
> rounding ZCR_EL1.LEN down to the next vector length actually
> supported.
> 
> So, the guest would expect writing ZCR_EL1.LEN = 2 to give a vector
> length of 256 bits, whereas on this hardware the actual resulting
> vector length would be 384 bits.

Oh, I see.

> 
> sve_probe_vqs() relies on this property to detect the set of available
> vector lengths.  Simple, bare-metal guests might also just set
> ZCR_ELx.LEN = 0x1ff to just get the max available.
> 
> 
> The architecture says categorically that the set of vector lengths
> supported is a fixed property of the (emulated) hardware -- we can't
> having this changing under the guest's feet.
> 
> Fixing this would require an archietctural way to filter out individual
> vector lengths from the supported set, not just a way to clamp the
> maximum (which is all ZCR_EL2.LEN gives us).
> 
> The general expectation is that sanely designed cluster will be
> "homogeneous enough" and won't trigger this check -- it's here
> just in case.

Data centers evolve as they expand and hardware is replaced. I wouldn't
expect them to stay homogeneous for long, not without keeping them that
way at substantial cost. This isn't the first thing that is forcing Arm
virt data centers to be homogeneous (we still use qemu's '-cpu host'),
but it's disappointing to have yet another one.

> 
> 
> I attempt to capture this in api.txt, leaving the door open in case the
> architecture gives a way to support this in future:
> 
>   | KVM_REG_ARM64_SVE_VLS
>   | 
>   | [...]
>   | 
>   | Apart from simply removing all vector lengths from the host set
>   | that exceed some value, support for arbitrarily chosen sets of
>   | vector lengths is hardware-dependent and may not be available.
>   | Attempting to configure an invalid set of vector lengths via
>   | KVM_SET_ONE_REG will fail with EINVAL.
> 
> Is this enough, or do you think more explanation is needed somewhere?

I saw that before, so I guess more is needed :) What you wrote above about
how we can only shorten the list due to how zcr_el1.len works was the
missing piece for me. Maybe that should be integrated into the text
somehow.

Thanks,
drew

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

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
@ 2019-04-05 10:14         ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-05 10:14 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 10:36:03AM +0100, Dave Martin wrote:
> On Thu, Apr 04, 2019 at 10:18:54PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> > > This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> > > allow userspace to set and query the set of vector lengths visible
> > > to the guest.
> > > 
> > > In the future, multiple register slices per SVE register may be
> > > visible through the ioctl interface.  Once the set of slices has
> > > been determined we would not be able to allow the vector length set
> > > to be changed any more, in order to avoid userspace seeing
> > > inconsistent sets of registers.  For this reason, this patch adds
> > > support for explicit finalization of the SVE configuration via the
> > > KVM_ARM_VCPU_FINALIZE ioctl.
> > > 
> > > Finalization is the proper place to allocate the SVE register state
> > > storage in vcpu->arch.sve_state, so this patch adds that as
> > > appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> > > was previously a no-op on arm64.
> > > 
> > > To simplify the logic for determining what vector lengths can be
> > > supported, some code is added to KVM init to work this out, in the
> > > kvm_arm_init_arch_resources() hook.
> > > 
> > > The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> > > Subsequent patches will allow SVE to be turned on for guest vcpus,
> > > making it visible.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > 
> > > ---
> 
> [...]
> 
> > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > index 2aa80a5..086ab05 100644
> > > --- a/arch/arm64/kvm/guest.c
> > > +++ b/arch/arm64/kvm/guest.c
> > > @@ -206,6 +206,73 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > >  	return err;
> > >  }
> > >  
> > > +#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64)
> > > +#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64)
> > > +
> > > +static bool vq_present(
> > > +	const u64 (*const vqs)[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)],
> > > +	unsigned int vq)
> > > +{
> > > +	return (*vqs)[vq_word(vq)] & vq_mask(vq);
> > > +}
> > > +
> > > +static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > +{
> > > +	unsigned int max_vq, vq;
> > > +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> > > +
> > > +	if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl)))
> > > +		return -EINVAL;
> > > +
> > > +	memset(vqs, 0, sizeof(vqs));
> > > +
> > > +	max_vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
> > > +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > > +		if (sve_vq_available(vq))
> > > +			vqs[vq_word(vq)] |= vq_mask(vq);
> > > +
> > > +	if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs)))
> > > +		return -EFAULT;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > +{
> > > +	unsigned int max_vq, vq;
> > > +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> > 
> > There are three of these long 'DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)'.
> > A macro is probably warranted.
> 
> Fair point.  These are a bit cumbersome.  How about:
> 
> #define SVE_VLS_WORDS DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)
> 
> Annoyingly, this is virtually identical to a Linux bitmap: the base type
> is u64 instead of unsigned long; otherwise there's no intentional
> difference.

Yeah, I noticed it was a reinvented bitmap, but I liked that it was,
because, for the userspace api, removing the bitmap abstractions
ensures we know what is what and where exactly it is.

> 
> (Aside: do you know why the KVM API insists on everything being u64?
> This makes sense for non-native types (like guest registers), but not
> for native things like host userspace addresses etc.)

Would that work when the kernel is 64-bit and the userspace is 32? I
personally like the interfaces being explicit with type size, as it
removes the brain burden of translating long and int when moving arch
to arch and kernel to userspace.

> 
> > > +
> > > +	if (kvm_arm_vcpu_sve_finalized(vcpu))
> > > +		return -EPERM; /* too late! */
> > > +
> > > +	if (WARN_ON(vcpu->arch.sve_state))
> > > +		return -EINVAL;
> > > +
> > > +	if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs)))
> > > +		return -EFAULT;
> > > +
> > > +	max_vq = 0;
> > > +	for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq)
> > > +		if (vq_present(&vqs, vq))
> > > +			max_vq = vq;
> > > +
> > > +	if (max_vq > sve_vq_from_vl(kvm_sve_max_vl))
> > > +		return -EINVAL;
> > > +
> > > +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > > +		if (vq_present(&vqs, vq) != sve_vq_available(vq))
> > > +			return -EINVAL;
> > 
> > What about supporting the optional non-power-of-2 vector lengths? For
> > example, if the maximum VL is 512, then in addition to 512, 128, and
> > 256 there could be a 384. If we plan to start a guest on a machine
> > that has all four and then migrate it to a machine that only has
> > 128,256,512 we would want to set the VL set to 128,256,512, even on
> > the machine that supports 384. If I understand the above test correctly,
> > then that wouldn't work.
> 
> This is exactly what the code is trying to forbid, though it may not be
> obvious here why.
> 
> The trouble is, we can't correctly emulate a vcpu supporting
> {128,256,512} on hardware that also supports 384-bit vectors: the
> architecture says that the vector length you get is determined by
> rounding ZCR_EL1.LEN down to the next vector length actually
> supported.
> 
> So, the guest would expect writing ZCR_EL1.LEN = 2 to give a vector
> length of 256 bits, whereas on this hardware the actual resulting
> vector length would be 384 bits.

Oh, I see.

> 
> sve_probe_vqs() relies on this property to detect the set of available
> vector lengths.  Simple, bare-metal guests might also just set
> ZCR_ELx.LEN = 0x1ff to just get the max available.
> 
> 
> The architecture says categorically that the set of vector lengths
> supported is a fixed property of the (emulated) hardware -- we can't
> having this changing under the guest's feet.
> 
> Fixing this would require an archietctural way to filter out individual
> vector lengths from the supported set, not just a way to clamp the
> maximum (which is all ZCR_EL2.LEN gives us).
> 
> The general expectation is that sanely designed cluster will be
> "homogeneous enough" and won't trigger this check -- it's here
> just in case.

Data centers evolve as they expand and hardware is replaced. I wouldn't
expect them to stay homogeneous for long, not without keeping them that
way at substantial cost. This isn't the first thing that is forcing Arm
virt data centers to be homogeneous (we still use qemu's '-cpu host'),
but it's disappointing to have yet another one.

> 
> 
> I attempt to capture this in api.txt, leaving the door open in case the
> architecture gives a way to support this in future:
> 
>   | KVM_REG_ARM64_SVE_VLS
>   | 
>   | [...]
>   | 
>   | Apart from simply removing all vector lengths from the host set
>   | that exceed some value, support for arbitrarily chosen sets of
>   | vector lengths is hardware-dependent and may not be available.
>   | Attempting to configure an invalid set of vector lengths via
>   | KVM_SET_ONE_REG will fail with EINVAL.
> 
> Is this enough, or do you think more explanation is needed somewhere?

I saw that before, so I guess more is needed :) What you wrote above about
how we can only shorten the list due to how zcr_el1.len works was the
missing piece for me. Maybe that should be integrated into the text
somehow.

Thanks,
drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
  2019-04-05  9:36       ` Dave Martin
@ 2019-04-05 10:22         ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-05 10:22 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 10:36:10AM +0100, Dave Martin wrote:
> On Thu, Apr 04, 2019 at 10:31:09PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> > > This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> > > allow userspace to set and query the set of vector lengths visible
> > > to the guest.
> > > 
> > > In the future, multiple register slices per SVE register may be
> > > visible through the ioctl interface.  Once the set of slices has
> > > been determined we would not be able to allow the vector length set
> > > to be changed any more, in order to avoid userspace seeing
> > > inconsistent sets of registers.  For this reason, this patch adds
> > > support for explicit finalization of the SVE configuration via the
> > > KVM_ARM_VCPU_FINALIZE ioctl.
> > > 
> > > Finalization is the proper place to allocate the SVE register state
> > > storage in vcpu->arch.sve_state, so this patch adds that as
> > > appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> > > was previously a no-op on arm64.
> > > 
> > > To simplify the logic for determining what vector lengths can be
> > > supported, some code is added to KVM init to work this out, in the
> > > kvm_arm_init_arch_resources() hook.
> > > 
> > > The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> > > Subsequent patches will allow SVE to be turned on for guest vcpus,
> > > making it visible.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> [...]
> 
> > > diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> 
> [...]
> 
> > > +/*
> > > + * Finalize vcpu's maximum SVE vector length, allocating
> > > + * vcpu->arch.sve_state as necessary.
> > > + */
> > > +static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
> > > +{
> > > +	void *buf;
> > > +	unsigned int vl;
> > > +
> > > +	vl = vcpu->arch.sve_max_vl;
> > > +
> > > +	/*
> > > +	 * Resposibility for these properties is shared between
> > > +	 * kvm_arm_init_arch_resources(), kvm_vcpu_enable_sve() and
> > > +	 * set_sve_vls().  Double-check here just to be sure:
> > > +	 */
> > > +	if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl ||
> > > +		    vl > SVE_VL_ARCH_MAX))
> > > +		return -EIO;
> > > +
> > > +	buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL);
> > > +	if (!buf)
> > > +		return -ENOMEM;
> > > +
> > > +	vcpu->arch.sve_state = buf;
> > > +	vcpu->arch.flags |= KVM_ARM64_VCPU_SVE_FINALIZED;
> > > +	return 0;
> > > +}
> > > +
> > > +int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what)
> > > +{
> > > +	switch (what) {
> > > +	case KVM_ARM_VCPU_SVE:
> > > +		if (!vcpu_has_sve(vcpu))
> > > +			return -EINVAL;
> > > +
> > > +		if (kvm_arm_vcpu_sve_finalized(vcpu))
> > > +			return -EPERM;
> > > +
> > > +		return kvm_vcpu_finalize_sve(vcpu);
> > 
> > In the next patch I see that we already have KVM_ARM64_GUEST_HAS_SVE
> > set in vcpu->arch.flags at this point. So if this kvm_vcpu_finalize_sve()
> > call fails, shouldn't we unset KVM_ARM64_GUEST_HAS_SVE and anything
> > else used to indicate the vcpu has sve?
> 
> If this fails, either userspace did the wrong thing, or there was some
> fatal error (like the ENOMEM case).  Either way, the vcpu is not runnable
> and userspace is expected to bail out.
> 
> Further, KVM_ARM_VCPU_INIT fixes the set of features requested by
> userspace: we shouldn't change the set of features under userspace's
> feet and try to limp on somehow.  We have no means for userspace to find
> out that some features went away in the meantime...
> 
> So, what would you be trying to achieve with this change?

Being able to do additional vcpu ioctls with only partially initialized
sve (sve_state is still null, but we otherwise believe the vcpu has sve).
That sounds risky. Although I see we only set KVM_ARM64_VCPU_SVE_FINALIZED
when everything, like the memory allocation, succeeds, so we're probably
fine. Indeed having KVM_ARM64_GUEST_HAS_SVE and not KVM_ARM64_VCPU_SVE_FINALIZED
is likely the safest vcpu state for a vcpu that failed to finalize sve.

Thanks,
drew

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

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
@ 2019-04-05 10:22         ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-05 10:22 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 10:36:10AM +0100, Dave Martin wrote:
> On Thu, Apr 04, 2019 at 10:31:09PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> > > This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> > > allow userspace to set and query the set of vector lengths visible
> > > to the guest.
> > > 
> > > In the future, multiple register slices per SVE register may be
> > > visible through the ioctl interface.  Once the set of slices has
> > > been determined we would not be able to allow the vector length set
> > > to be changed any more, in order to avoid userspace seeing
> > > inconsistent sets of registers.  For this reason, this patch adds
> > > support for explicit finalization of the SVE configuration via the
> > > KVM_ARM_VCPU_FINALIZE ioctl.
> > > 
> > > Finalization is the proper place to allocate the SVE register state
> > > storage in vcpu->arch.sve_state, so this patch adds that as
> > > appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> > > was previously a no-op on arm64.
> > > 
> > > To simplify the logic for determining what vector lengths can be
> > > supported, some code is added to KVM init to work this out, in the
> > > kvm_arm_init_arch_resources() hook.
> > > 
> > > The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> > > Subsequent patches will allow SVE to be turned on for guest vcpus,
> > > making it visible.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> 
> [...]
> 
> > > diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> 
> [...]
> 
> > > +/*
> > > + * Finalize vcpu's maximum SVE vector length, allocating
> > > + * vcpu->arch.sve_state as necessary.
> > > + */
> > > +static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
> > > +{
> > > +	void *buf;
> > > +	unsigned int vl;
> > > +
> > > +	vl = vcpu->arch.sve_max_vl;
> > > +
> > > +	/*
> > > +	 * Resposibility for these properties is shared between
> > > +	 * kvm_arm_init_arch_resources(), kvm_vcpu_enable_sve() and
> > > +	 * set_sve_vls().  Double-check here just to be sure:
> > > +	 */
> > > +	if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl ||
> > > +		    vl > SVE_VL_ARCH_MAX))
> > > +		return -EIO;
> > > +
> > > +	buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL);
> > > +	if (!buf)
> > > +		return -ENOMEM;
> > > +
> > > +	vcpu->arch.sve_state = buf;
> > > +	vcpu->arch.flags |= KVM_ARM64_VCPU_SVE_FINALIZED;
> > > +	return 0;
> > > +}
> > > +
> > > +int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what)
> > > +{
> > > +	switch (what) {
> > > +	case KVM_ARM_VCPU_SVE:
> > > +		if (!vcpu_has_sve(vcpu))
> > > +			return -EINVAL;
> > > +
> > > +		if (kvm_arm_vcpu_sve_finalized(vcpu))
> > > +			return -EPERM;
> > > +
> > > +		return kvm_vcpu_finalize_sve(vcpu);
> > 
> > In the next patch I see that we already have KVM_ARM64_GUEST_HAS_SVE
> > set in vcpu->arch.flags at this point. So if this kvm_vcpu_finalize_sve()
> > call fails, shouldn't we unset KVM_ARM64_GUEST_HAS_SVE and anything
> > else used to indicate the vcpu has sve?
> 
> If this fails, either userspace did the wrong thing, or there was some
> fatal error (like the ENOMEM case).  Either way, the vcpu is not runnable
> and userspace is expected to bail out.
> 
> Further, KVM_ARM_VCPU_INIT fixes the set of features requested by
> userspace: we shouldn't change the set of features under userspace's
> feet and try to limp on somehow.  We have no means for userspace to find
> out that some features went away in the meantime...
> 
> So, what would you be trying to achieve with this change?

Being able to do additional vcpu ioctls with only partially initialized
sve (sve_state is still null, but we otherwise believe the vcpu has sve).
That sounds risky. Although I see we only set KVM_ARM64_VCPU_SVE_FINALIZED
when everything, like the memory allocation, succeeds, so we're probably
fine. Indeed having KVM_ARM64_GUEST_HAS_SVE and not KVM_ARM64_VCPU_SVE_FINALIZED
is likely the safest vcpu state for a vcpu that failed to finalize sve.

Thanks,
drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 27/27] KVM: arm64/sve: Document KVM API extensions for SVE
  2019-04-05  9:36       ` Dave Martin
@ 2019-04-05 10:39         ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-05 10:39 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 10:36:17AM +0100, Dave Martin wrote:
> On Thu, Apr 04, 2019 at 11:09:21PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:52PM +0000, Dave Martin wrote:
> > > This patch adds sections to the KVM API documentation describing
> > > the extensions for supporting the Scalable Vector Extension (SVE)
> > > in guests.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > 
> > > ---
> > > 
> > > Changes since v5:
> > > 
> > >  * Document KVM_ARM_VCPU_FINALIZE and its interactions with SVE.
> > > ---
> > >  Documentation/virtual/kvm/api.txt | 132 +++++++++++++++++++++++++++++++++++++-
> > >  1 file changed, 129 insertions(+), 3 deletions(-)
> > > 
> > > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> > > index cd920dd..68509de 100644
> > > --- a/Documentation/virtual/kvm/api.txt
> > > +++ b/Documentation/virtual/kvm/api.txt
> > > @@ -1873,6 +1873,7 @@ Parameters: struct kvm_one_reg (in)
> > >  Returns: 0 on success, negative value on failure
> > >  Errors:
> > >    ENOENT:   no such register
> > > +  EPERM:    register access forbidden for architecture-dependent reasons
> > >    EINVAL:   other errors, such as bad size encoding for a known register
> > >  
> > >  struct kvm_one_reg {
> > > @@ -2127,13 +2128,20 @@ Specifically:
> > >    0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
> > >    0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
> > >    0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
> > > -  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]
> > > -  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]
> > > +  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]    (*)
> > > +  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]    (*)
> > >      ...
> > > -  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]
> > > +  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]   (*)
> > >    0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
> > >    0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
> > >  
> > > +(*) These encodings are not accepted for SVE-enabled vcpus.  See
> > > +    KVM_ARM_VCPU_INIT.
> > > +
> > > +    The equivalent register content can be accessed via bits [127:0] of
> > > +    the corresponding SVE Zn registers instead for vcpus that have SVE
> > > +    enabled (see below).
> > > +
> > >  arm64 CCSIDR registers are demultiplexed by CSSELR value:
> > >    0x6020 0000 0011 00 <csselr:8>
> > >  
> > > @@ -2143,6 +2151,61 @@ arm64 system registers have the following id bit patterns:
> > >  arm64 firmware pseudo-registers have the following bit pattern:
> > >    0x6030 0000 0014 <regno:16>
> > >  
> > > +arm64 SVE registers have the following bit patterns:
> > > +  0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> > > +  0x6050 0000 0015 04 <n:4> <slice:5>   Pn bits[256*slice + 255 : 256*slice]
> > > +  0x6050 0000 0015 060 <slice:5>        FFR bits[256*slice + 255 : 256*slice]
> > > +  0x6060 0000 0015 ffff                 KVM_REG_ARM64_SVE_VLS pseudo-register
> > > +
> > > +Access to slices beyond the maximum vector length configured for the
> > > +vcpu (i.e., where 16 * slice >= max_vq (**)) will fail with ENOENT.
> > 
> > I've been doing pretty well keeping track of the 16's, 128's, VL's and
> > VQ's, but this example lost me. Also, should it be >= or just > ?
> 
> It should be >=.  It's analogous to not being allowed to derefence an
> array index that is >= the size of the array.
> 
> Also, the 16 here is not the number of bytes per quadword (as it often
> does with all things SVE), but the number of quadwords per 2048-bit
> KVM register slice.
> 
> To make matters worse (**) resembles some weird C syntax.
> 
> Maybe this would be less confusing written as
> 
>     Access to register IDs where 2048 * slice >= 128 * max_vq will fail
>     with ENOENT.  max_vq is the vcpu's maximum supported vector length
>     in 128-bit quadwords: see (**) below.
> 
> Does that help at all?

Yes. Thanks.

> 
> > 
> > > +
> > > +These registers are only accessible on vcpus for which SVE is enabled.
> > > +See KVM_ARM_VCPU_INIT for details.
> > > +
> > > +In addition, except for KVM_REG_ARM64_SVE_VLS, these registers are not
> > > +accessible until the vcpu's SVE configuration has been finalized
> > > +using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).  See KVM_ARM_VCPU_INIT
> > > +and KVM_ARM_VCPU_FINALIZE for more information about this procedure.
> > > +
> > > +KVM_REG_ARM64_SVE_VLS is a pseudo-register that allows the set of vector
> > > +lengths supported by the vcpu to be discovered and configured by
> > > +userspace.  When transferred to or from user memory via KVM_GET_ONE_REG
> > > +or KVM_SET_ONE_REG, the value of this register is of type __u64[8], and
> > > +encodes the set of vector lengths as follows:
> > > +
> > > +__u64 vector_lengths[8];
> > > +
> > > +if (vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX &&
> > > +    ((vector_lengths[(vq - 1) / 64] >> ((vq - 1) % 64)) & 1))
> > > +	/* Vector length vq * 16 bytes supported */
> > > +else
> > > +	/* Vector length vq * 16 bytes not supported */
> > > +
> > > +(**) The maximum value vq for which the above condition is true is
> > > +max_vq.  This is the maximum vector length available to the guest on
> > > +this vcpu, and determines which register slices are visible through
> > > +this ioctl interface.
> > > +
> > > +(See Documentation/arm64/sve.txt for an explanation of the "vq"
> > > +nomenclature.)
> > > +
> > > +KVM_REG_ARM64_SVE_VLS is only accessible after KVM_ARM_VCPU_INIT.
> > > +KVM_ARM_VCPU_INIT initialises it to the best set of vector lengths that
> > > +the host supports.
> > > +
> > > +Userspace may subsequently modify it if desired until the vcpu's SVE
> > > +configuration is finalized using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
> > > +
> > > +Apart from simply removing all vector lengths from the host set that
> > > +exceed some value, support for arbitrarily chosen sets of vector lengths
> > > +is hardware-dependent and may not be available.  Attempting to configure
> > > +an invalid set of vector lengths via KVM_SET_ONE_REG will fail with
> > > +EINVAL.
> > > +
> > > +After the vcpu's SVE configuration is finalized, further attempts to
> > > +write this register will fail with EPERM.
> > > +
> > >  
> > >  MIPS registers are mapped using the lower 32 bits.  The upper 16 of that is
> > >  the register group type:
> > > @@ -2197,6 +2260,7 @@ Parameters: struct kvm_one_reg (in and out)
> > >  Returns: 0 on success, negative value on failure
> > >  Errors:
> > >    ENOENT:   no such register
> > > +  EPERM:    register access forbidden for architecture-dependent reasons
> > >    EINVAL:   other errors, such as bad size encoding for a known register
> > >  
> > >  This ioctl allows to receive the value of a single register implemented
> > > @@ -2690,6 +2754,33 @@ Possible features:
> > >  	- KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
> > >  	  Depends on KVM_CAP_ARM_PMU_V3.
> > >  
> > > +	- KVM_ARM_VCPU_SVE: Enables SVE for the CPU (arm64 only).
> > > +	  Depends on KVM_CAP_ARM_SVE.
> > > +	  Requires KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > > +
> > > +	   * After KVM_ARM_VCPU_INIT:
> > > +
> > > +	      - KVM_REG_ARM64_SVE_VLS may be read using KVM_GET_ONE_REG: the
> > > +	        initial value of this pseudo-register indicates the best set of
> > > +	        vector lengths possible for a vcpu on this host.
> > > +
> > > +	   * Before KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > > +
> > > +	      - KVM_RUN and KVM_GET_REG_LIST are not available;
> > > +
> > > +	      - KVM_GET_ONE_REG and KVM_SET_ONE_REG cannot be used to access
> > > +	        the scalable archietctural SVE registers
> > > +	        KVM_REG_ARM64_SVE_ZREG(), KVM_REG_ARM64_SVE_PREG() or
> > > +	        KVM_REG_ARM64_SVE_FFR;
> > > +
> > > +	      - KVM_REG_ARM64_SVE_VLS may optionally be written using
> > > +	        KVM_SET_ONE_REG, to modify the set of vector lengths available
> > > +	        for the vcpu.
> > > +
> > > +	   * After KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > > +
> > > +	      - the KVM_REG_ARM64_SVE_VLS pseudo-register is immutable, and can
> > > +	        no longer be written using KVM_SET_ONE_REG.
> > >  
> > >  4.83 KVM_ARM_PREFERRED_TARGET
> > >  
> > > @@ -3904,6 +3995,41 @@ number of valid entries in the 'entries' array, which is then filled.
> > >  'index' and 'flags' fields in 'struct kvm_cpuid_entry2' are currently reserved,
> > >  userspace should not expect to get any particular value there.
> > >  
> > > +4.119 KVM_ARM_VCPU_FINALIZE
> > > +
> > > +Capability: KVM_CAP_ARM_SVE
> > 
> > The KVM_ARM_VCPU_FINALIZE vcpu ioctl isn't SVE specific, so it shouldn't
> > depend on the SVE cap. It should have it's own cap, or maybe it should
> > just be an KVM_ARM_VCPU_SVE_FINALIZE ioctl instead, i.e. not general.
> 
> This one's a bit annoying.  This would ideally read
> 
> Capability: KVM_CAP_ARM_SVE, or any other capability that advertises the
> availability of a feature that requires KVM_ARM_VCPU_FINALIZE to be used.
> 
> (which sounds vague).
> 
> We could add a specific cap for KVM_ARM_VCPU_FINALIZE, but that seemed
> overkill.  Or document KVM_ARM_VCPU_FINALIZE as unconditionally
> supported, but make the individual feature values cap-dependent.  This
> works because the symptom of missing support is the same (EINVAL)
> ragardless of whether it is the specific feature or
> KVM_ARM_VCPU_FINALIZE that is unsupported.
> 
> Thoughts?
> 

I like that unconditionally supported idea.

> > > +Architectures: arm, arm64
> > > +Type: vcpu ioctl
> > > +Parameters: int feature (in)
> > 
> > This was called 'what' in the code.
> 
> Indeed it is.  I wanted to avoid the implication that this paramter
> exactly maps onto the KVM_ARM_VCPU_INIT features.  But "what" seemed
> a bit too vague for the documentation.
> 
> Mind you, if lseek() can have a "whence" parameter, perhaps "what" is
> also acceptable.
> 
> OTOH I don't mind changing the name in the code to "feature" if you
> think that's preferable.
> 
> Thoughts?

I prefer them to be the same, and I think both are fine.

> 
> > 
> > > +Returns: 0 on success, -1 on error
> > > +Errors:
> > > +  EPERM:     feature not enabled, needs configuration, or already finalized
> > > +  EINVAL:    unknown feature
> > > +
> > > +Recognised values for feature:
> > > +  arm64      KVM_ARM_VCPU_SVE
> > > +
> > > +Finalizes the configuration of the specified vcpu feature.
> > > +
> > > +The vcpu must already have been initialised, enabling the affected feature, by
> > > +means of a successful KVM_ARM_VCPU_INIT call with the appropriate flag set in
> > > +features[].
> > > +
> > > +For affected vcpu features, this is a mandatory step that must be performed
> > > +before the vcpu is fully usable.
> > > +
> > > +Between KVM_ARM_VCPU_INIT and KVM_ARM_VCPU_FINALIZE, the feature may be
> > > +configured by use of ioctls such as KVM_SET_ONE_REG.  The exact configuration
> > > +that should be performaned and how to do it are feature-dependent.
> > > +
> > > +Other calls that depend on a particular feature being finalized, such as
> > > +KVM_RUN, KVM_GET_REG_LIST, KVM_GET_ONE_REG and KVM_SET_ONE_REG, will fail with
> > > +-EPERM unless the feature has already been finalized by means of a
> > > +KVM_ARM_VCPU_FINALIZE call.
> > > +
> > > +See KVM_ARM_VCPU_INIT for details of vcpu features that require finalization
> > > +using this ioctl.
> > > +
> > >  5. The kvm_run structure
> > >  ------------------------
> > >
> > 
> > I'm still not sure about EPERM vs. ENOEXEC.
> 
> There is no need to distinguish the two: this is just a generic "vcpu in
> wrong state for this to work" error.  I can't think of another subsystem
> that uses ENOEXEC for this meaning, but it's established in KVM.
> 
> If you can't see a reason why we would need these to be distinct
> errors (?) then I'm happy for this to be ENOEXEC for all cases.
> 

I do see some value in keeping them distinct. I think it's just the use
of EPERM specifically that bothers me, but I don't have that strong of
an opinion against its use either. So I'll just shut up :)

Thanks,
drew

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

* Re: [PATCH v7 27/27] KVM: arm64/sve: Document KVM API extensions for SVE
@ 2019-04-05 10:39         ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-05 10:39 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 10:36:17AM +0100, Dave Martin wrote:
> On Thu, Apr 04, 2019 at 11:09:21PM +0200, Andrew Jones wrote:
> > On Fri, Mar 29, 2019 at 01:00:52PM +0000, Dave Martin wrote:
> > > This patch adds sections to the KVM API documentation describing
> > > the extensions for supporting the Scalable Vector Extension (SVE)
> > > in guests.
> > > 
> > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > 
> > > ---
> > > 
> > > Changes since v5:
> > > 
> > >  * Document KVM_ARM_VCPU_FINALIZE and its interactions with SVE.
> > > ---
> > >  Documentation/virtual/kvm/api.txt | 132 +++++++++++++++++++++++++++++++++++++-
> > >  1 file changed, 129 insertions(+), 3 deletions(-)
> > > 
> > > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> > > index cd920dd..68509de 100644
> > > --- a/Documentation/virtual/kvm/api.txt
> > > +++ b/Documentation/virtual/kvm/api.txt
> > > @@ -1873,6 +1873,7 @@ Parameters: struct kvm_one_reg (in)
> > >  Returns: 0 on success, negative value on failure
> > >  Errors:
> > >    ENOENT:   no such register
> > > +  EPERM:    register access forbidden for architecture-dependent reasons
> > >    EINVAL:   other errors, such as bad size encoding for a known register
> > >  
> > >  struct kvm_one_reg {
> > > @@ -2127,13 +2128,20 @@ Specifically:
> > >    0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
> > >    0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
> > >    0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
> > > -  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]
> > > -  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]
> > > +  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]    (*)
> > > +  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]    (*)
> > >      ...
> > > -  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]
> > > +  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]   (*)
> > >    0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
> > >    0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
> > >  
> > > +(*) These encodings are not accepted for SVE-enabled vcpus.  See
> > > +    KVM_ARM_VCPU_INIT.
> > > +
> > > +    The equivalent register content can be accessed via bits [127:0] of
> > > +    the corresponding SVE Zn registers instead for vcpus that have SVE
> > > +    enabled (see below).
> > > +
> > >  arm64 CCSIDR registers are demultiplexed by CSSELR value:
> > >    0x6020 0000 0011 00 <csselr:8>
> > >  
> > > @@ -2143,6 +2151,61 @@ arm64 system registers have the following id bit patterns:
> > >  arm64 firmware pseudo-registers have the following bit pattern:
> > >    0x6030 0000 0014 <regno:16>
> > >  
> > > +arm64 SVE registers have the following bit patterns:
> > > +  0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> > > +  0x6050 0000 0015 04 <n:4> <slice:5>   Pn bits[256*slice + 255 : 256*slice]
> > > +  0x6050 0000 0015 060 <slice:5>        FFR bits[256*slice + 255 : 256*slice]
> > > +  0x6060 0000 0015 ffff                 KVM_REG_ARM64_SVE_VLS pseudo-register
> > > +
> > > +Access to slices beyond the maximum vector length configured for the
> > > +vcpu (i.e., where 16 * slice >= max_vq (**)) will fail with ENOENT.
> > 
> > I've been doing pretty well keeping track of the 16's, 128's, VL's and
> > VQ's, but this example lost me. Also, should it be >= or just > ?
> 
> It should be >=.  It's analogous to not being allowed to derefence an
> array index that is >= the size of the array.
> 
> Also, the 16 here is not the number of bytes per quadword (as it often
> does with all things SVE), but the number of quadwords per 2048-bit
> KVM register slice.
> 
> To make matters worse (**) resembles some weird C syntax.
> 
> Maybe this would be less confusing written as
> 
>     Access to register IDs where 2048 * slice >= 128 * max_vq will fail
>     with ENOENT.  max_vq is the vcpu's maximum supported vector length
>     in 128-bit quadwords: see (**) below.
> 
> Does that help at all?

Yes. Thanks.

> 
> > 
> > > +
> > > +These registers are only accessible on vcpus for which SVE is enabled.
> > > +See KVM_ARM_VCPU_INIT for details.
> > > +
> > > +In addition, except for KVM_REG_ARM64_SVE_VLS, these registers are not
> > > +accessible until the vcpu's SVE configuration has been finalized
> > > +using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).  See KVM_ARM_VCPU_INIT
> > > +and KVM_ARM_VCPU_FINALIZE for more information about this procedure.
> > > +
> > > +KVM_REG_ARM64_SVE_VLS is a pseudo-register that allows the set of vector
> > > +lengths supported by the vcpu to be discovered and configured by
> > > +userspace.  When transferred to or from user memory via KVM_GET_ONE_REG
> > > +or KVM_SET_ONE_REG, the value of this register is of type __u64[8], and
> > > +encodes the set of vector lengths as follows:
> > > +
> > > +__u64 vector_lengths[8];
> > > +
> > > +if (vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX &&
> > > +    ((vector_lengths[(vq - 1) / 64] >> ((vq - 1) % 64)) & 1))
> > > +	/* Vector length vq * 16 bytes supported */
> > > +else
> > > +	/* Vector length vq * 16 bytes not supported */
> > > +
> > > +(**) The maximum value vq for which the above condition is true is
> > > +max_vq.  This is the maximum vector length available to the guest on
> > > +this vcpu, and determines which register slices are visible through
> > > +this ioctl interface.
> > > +
> > > +(See Documentation/arm64/sve.txt for an explanation of the "vq"
> > > +nomenclature.)
> > > +
> > > +KVM_REG_ARM64_SVE_VLS is only accessible after KVM_ARM_VCPU_INIT.
> > > +KVM_ARM_VCPU_INIT initialises it to the best set of vector lengths that
> > > +the host supports.
> > > +
> > > +Userspace may subsequently modify it if desired until the vcpu's SVE
> > > +configuration is finalized using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
> > > +
> > > +Apart from simply removing all vector lengths from the host set that
> > > +exceed some value, support for arbitrarily chosen sets of vector lengths
> > > +is hardware-dependent and may not be available.  Attempting to configure
> > > +an invalid set of vector lengths via KVM_SET_ONE_REG will fail with
> > > +EINVAL.
> > > +
> > > +After the vcpu's SVE configuration is finalized, further attempts to
> > > +write this register will fail with EPERM.
> > > +
> > >  
> > >  MIPS registers are mapped using the lower 32 bits.  The upper 16 of that is
> > >  the register group type:
> > > @@ -2197,6 +2260,7 @@ Parameters: struct kvm_one_reg (in and out)
> > >  Returns: 0 on success, negative value on failure
> > >  Errors:
> > >    ENOENT:   no such register
> > > +  EPERM:    register access forbidden for architecture-dependent reasons
> > >    EINVAL:   other errors, such as bad size encoding for a known register
> > >  
> > >  This ioctl allows to receive the value of a single register implemented
> > > @@ -2690,6 +2754,33 @@ Possible features:
> > >  	- KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
> > >  	  Depends on KVM_CAP_ARM_PMU_V3.
> > >  
> > > +	- KVM_ARM_VCPU_SVE: Enables SVE for the CPU (arm64 only).
> > > +	  Depends on KVM_CAP_ARM_SVE.
> > > +	  Requires KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > > +
> > > +	   * After KVM_ARM_VCPU_INIT:
> > > +
> > > +	      - KVM_REG_ARM64_SVE_VLS may be read using KVM_GET_ONE_REG: the
> > > +	        initial value of this pseudo-register indicates the best set of
> > > +	        vector lengths possible for a vcpu on this host.
> > > +
> > > +	   * Before KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > > +
> > > +	      - KVM_RUN and KVM_GET_REG_LIST are not available;
> > > +
> > > +	      - KVM_GET_ONE_REG and KVM_SET_ONE_REG cannot be used to access
> > > +	        the scalable archietctural SVE registers
> > > +	        KVM_REG_ARM64_SVE_ZREG(), KVM_REG_ARM64_SVE_PREG() or
> > > +	        KVM_REG_ARM64_SVE_FFR;
> > > +
> > > +	      - KVM_REG_ARM64_SVE_VLS may optionally be written using
> > > +	        KVM_SET_ONE_REG, to modify the set of vector lengths available
> > > +	        for the vcpu.
> > > +
> > > +	   * After KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > > +
> > > +	      - the KVM_REG_ARM64_SVE_VLS pseudo-register is immutable, and can
> > > +	        no longer be written using KVM_SET_ONE_REG.
> > >  
> > >  4.83 KVM_ARM_PREFERRED_TARGET
> > >  
> > > @@ -3904,6 +3995,41 @@ number of valid entries in the 'entries' array, which is then filled.
> > >  'index' and 'flags' fields in 'struct kvm_cpuid_entry2' are currently reserved,
> > >  userspace should not expect to get any particular value there.
> > >  
> > > +4.119 KVM_ARM_VCPU_FINALIZE
> > > +
> > > +Capability: KVM_CAP_ARM_SVE
> > 
> > The KVM_ARM_VCPU_FINALIZE vcpu ioctl isn't SVE specific, so it shouldn't
> > depend on the SVE cap. It should have it's own cap, or maybe it should
> > just be an KVM_ARM_VCPU_SVE_FINALIZE ioctl instead, i.e. not general.
> 
> This one's a bit annoying.  This would ideally read
> 
> Capability: KVM_CAP_ARM_SVE, or any other capability that advertises the
> availability of a feature that requires KVM_ARM_VCPU_FINALIZE to be used.
> 
> (which sounds vague).
> 
> We could add a specific cap for KVM_ARM_VCPU_FINALIZE, but that seemed
> overkill.  Or document KVM_ARM_VCPU_FINALIZE as unconditionally
> supported, but make the individual feature values cap-dependent.  This
> works because the symptom of missing support is the same (EINVAL)
> ragardless of whether it is the specific feature or
> KVM_ARM_VCPU_FINALIZE that is unsupported.
> 
> Thoughts?
> 

I like that unconditionally supported idea.

> > > +Architectures: arm, arm64
> > > +Type: vcpu ioctl
> > > +Parameters: int feature (in)
> > 
> > This was called 'what' in the code.
> 
> Indeed it is.  I wanted to avoid the implication that this paramter
> exactly maps onto the KVM_ARM_VCPU_INIT features.  But "what" seemed
> a bit too vague for the documentation.
> 
> Mind you, if lseek() can have a "whence" parameter, perhaps "what" is
> also acceptable.
> 
> OTOH I don't mind changing the name in the code to "feature" if you
> think that's preferable.
> 
> Thoughts?

I prefer them to be the same, and I think both are fine.

> 
> > 
> > > +Returns: 0 on success, -1 on error
> > > +Errors:
> > > +  EPERM:     feature not enabled, needs configuration, or already finalized
> > > +  EINVAL:    unknown feature
> > > +
> > > +Recognised values for feature:
> > > +  arm64      KVM_ARM_VCPU_SVE
> > > +
> > > +Finalizes the configuration of the specified vcpu feature.
> > > +
> > > +The vcpu must already have been initialised, enabling the affected feature, by
> > > +means of a successful KVM_ARM_VCPU_INIT call with the appropriate flag set in
> > > +features[].
> > > +
> > > +For affected vcpu features, this is a mandatory step that must be performed
> > > +before the vcpu is fully usable.
> > > +
> > > +Between KVM_ARM_VCPU_INIT and KVM_ARM_VCPU_FINALIZE, the feature may be
> > > +configured by use of ioctls such as KVM_SET_ONE_REG.  The exact configuration
> > > +that should be performaned and how to do it are feature-dependent.
> > > +
> > > +Other calls that depend on a particular feature being finalized, such as
> > > +KVM_RUN, KVM_GET_REG_LIST, KVM_GET_ONE_REG and KVM_SET_ONE_REG, will fail with
> > > +-EPERM unless the feature has already been finalized by means of a
> > > +KVM_ARM_VCPU_FINALIZE call.
> > > +
> > > +See KVM_ARM_VCPU_INIT for details of vcpu features that require finalization
> > > +using this ioctl.
> > > +
> > >  5. The kvm_run structure
> > >  ------------------------
> > >
> > 
> > I'm still not sure about EPERM vs. ENOEXEC.
> 
> There is no need to distinguish the two: this is just a generic "vcpu in
> wrong state for this to work" error.  I can't think of another subsystem
> that uses ENOEXEC for this meaning, but it's established in KVM.
> 
> If you can't see a reason why we would need these to be distinct
> errors (?) then I'm happy for this to be ENOEXEC for all cases.
> 

I do see some value in keeping them distinct. I think it's just the use
of EPERM specifically that bothers me, but I don't have that strong of
an opinion against its use either. So I'll just shut up :)

Thanks,
drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 21/27] KVM: arm/arm64: Add hook for arch-specific KVM initialisation
  2019-04-05  9:36           ` Dave Martin
@ 2019-04-05 10:40             ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-05 10:40 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 10:36:24AM +0100, Dave Martin wrote:
> On Thu, Apr 04, 2019 at 06:33:08PM +0200, Andrew Jones wrote:
> > On Thu, Apr 04, 2019 at 03:53:55PM +0100, Dave Martin wrote:
> > > On Thu, Apr 04, 2019 at 04:25:28PM +0200, Andrew Jones wrote:
> > > > On Fri, Mar 29, 2019 at 01:00:46PM +0000, Dave Martin wrote:
> 
> [...]
> 
> > > > > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > > > > index 99c3738..c69e137 100644
> > > > > --- a/virt/kvm/arm/arm.c
> > > > > +++ b/virt/kvm/arm/arm.c
> > > > > @@ -1664,6 +1664,10 @@ int kvm_arch_init(void *opaque)
> > > > >  	if (err)
> > > > >  		return err;
> > > > >  
> > > > > +	err = kvm_arm_init_arch_resources();
> > > > > +	if (err)
> > > > > +		return err;
> > > > > +
> > > > >  	if (!in_hyp_mode) {
> > > > >  		err = init_hyp_mode();
> > > > >  		if (err)
> > > > > -- 
> > > > > 2.1.4
> > > > >
> > > > 
> > > > It's not clear to me from the commit message why init_common_resources()
> > > > won't work for this. Maybe it'll be more clear as I continue the review.
> > > 
> > > init_common_resources() is for stuff common to arm and arm64.
> > 
> > Well currently init_common_resources() only calls kvm_set_ipa_limit(),
> > which isn't implemented for arm. So if there was a plan to only use
> > that function for init that actually does something on both, it doesn't.
> 
> Hmmm, perhaps I was wishfully interpreting the word "common" to mean
> what I would like it to mean...
> 
> > > kvm_arm_init_arch_resources() is intended for stuff specific to the
> > > particular arch backend.
> > 
> > I'm not sure we need that yet. We just need an arm setup sve stub like
> > arm's kvm_set_ipa_limit() stub. OTOH, if we have to keep adding stubs
> > to arm we should probably have something like
> > kvm_arm_init_arch_resources() instead, and kvm_set_ipa_limit() should
> > be moved inside the arm64 one and the arm ipa limit stub can go. Then
> > since init_common_resources() would no longer be used, it could just
> > be deleted.
> 
> OK, for simplicity I may call the sve setup directly as you suggest, and
> make an arm stub for it: that feels a bit weird, but there is precedent.
> 
> If we end up accumulating a lot of these, we can revisit it and maybe
> invent something like kvm_arm_init_arch_resources() at that point.
> 
> Does that sound reasonable?

Yup. Sounds good to me.

Thanks,
drew

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

* Re: [PATCH v7 21/27] KVM: arm/arm64: Add hook for arch-specific KVM initialisation
@ 2019-04-05 10:40             ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-05 10:40 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 10:36:24AM +0100, Dave Martin wrote:
> On Thu, Apr 04, 2019 at 06:33:08PM +0200, Andrew Jones wrote:
> > On Thu, Apr 04, 2019 at 03:53:55PM +0100, Dave Martin wrote:
> > > On Thu, Apr 04, 2019 at 04:25:28PM +0200, Andrew Jones wrote:
> > > > On Fri, Mar 29, 2019 at 01:00:46PM +0000, Dave Martin wrote:
> 
> [...]
> 
> > > > > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > > > > index 99c3738..c69e137 100644
> > > > > --- a/virt/kvm/arm/arm.c
> > > > > +++ b/virt/kvm/arm/arm.c
> > > > > @@ -1664,6 +1664,10 @@ int kvm_arch_init(void *opaque)
> > > > >  	if (err)
> > > > >  		return err;
> > > > >  
> > > > > +	err = kvm_arm_init_arch_resources();
> > > > > +	if (err)
> > > > > +		return err;
> > > > > +
> > > > >  	if (!in_hyp_mode) {
> > > > >  		err = init_hyp_mode();
> > > > >  		if (err)
> > > > > -- 
> > > > > 2.1.4
> > > > >
> > > > 
> > > > It's not clear to me from the commit message why init_common_resources()
> > > > won't work for this. Maybe it'll be more clear as I continue the review.
> > > 
> > > init_common_resources() is for stuff common to arm and arm64.
> > 
> > Well currently init_common_resources() only calls kvm_set_ipa_limit(),
> > which isn't implemented for arm. So if there was a plan to only use
> > that function for init that actually does something on both, it doesn't.
> 
> Hmmm, perhaps I was wishfully interpreting the word "common" to mean
> what I would like it to mean...
> 
> > > kvm_arm_init_arch_resources() is intended for stuff specific to the
> > > particular arch backend.
> > 
> > I'm not sure we need that yet. We just need an arm setup sve stub like
> > arm's kvm_set_ipa_limit() stub. OTOH, if we have to keep adding stubs
> > to arm we should probably have something like
> > kvm_arm_init_arch_resources() instead, and kvm_set_ipa_limit() should
> > be moved inside the arm64 one and the arm ipa limit stub can go. Then
> > since init_common_resources() would no longer be used, it could just
> > be deleted.
> 
> OK, for simplicity I may call the sve setup directly as you suggest, and
> make an arm stub for it: that feels a bit weird, but there is precedent.
> 
> If we end up accumulating a lot of these, we can revisit it and maybe
> invent something like kvm_arm_init_arch_resources() at that point.
> 
> Does that sound reasonable?

Yup. Sounds good to me.

Thanks,
drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 19/27] KVM: arm64: Enumerate SVE register indices for KVM_GET_REG_LIST
  2019-04-05  9:45         ` Andrew Jones
@ 2019-04-05 11:11           ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05 11:11 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 11:45:56AM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 10:35:45AM +0100, Dave Martin wrote:
> > On Thu, Apr 04, 2019 at 04:08:32PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:44PM +0000, Dave Martin wrote:
> > > > This patch includes the SVE register IDs in the list returned by
> > > > KVM_GET_REG_LIST, as appropriate.
> > > > 
> > > > On a non-SVE-enabled vcpu, no new IDs are added.
> > > > 
> > > > On an SVE-enabled vcpu, IDs for the FPSIMD V-registers are removed
> > > > from the list, since userspace is required to access the Z-
> > > > registers instead in order to access the V-register content.  For
> > > > the variably-sized SVE registers, the appropriate set of slice IDs
> > > > are enumerated, depending on the maximum vector length for the
> > > > vcpu.
> > > > 
> > > > As it currently stands, the SVE architecture never requires more
> > > > than one slice to exist per register, so this patch adds no
> > > > explicit support for enumerating multiple slices.  The code can be
> > > > extended straightforwardly to support this in the future, if
> > > > needed.
> > > > 
> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > > 
> > > > ---

[...]

> > > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c

[...]

> > > > +static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
> > > > +				u64 __user *uindices)
> > > > +{
> > > > +	/* Only the first slice ever exists, for now */

[...]

> > > > +	const unsigned int slices = vcpu_sve_slices(vcpu);
> > > > +	u64 reg;
> > > > +	unsigned int i, n;
> > > > +	int num_regs = 0;
> > > > +
> > > > +	if (!vcpu_has_sve(vcpu))
> > > > +		return 0;
> > > > +
> > > > +	for (i = 0; i < slices; i++) {
> > > > +		for (n = 0; n < SVE_NUM_ZREGS; n++) {
> > > > +			reg = KVM_REG_ARM64_SVE_ZREG(n, i);
> > > > +			if (put_user(reg, uindices++))
> > > > +				return -EFAULT;
> > > > +
> > > > +			num_regs++;
> > > > +		}
> > > > +
> > > > +		for (n = 0; n < SVE_NUM_PREGS; n++) {
> > > > +			reg = KVM_REG_ARM64_SVE_PREG(n, i);
> > > > +			if (put_user(reg, uindices++))
> > > > +				return -EFAULT;
> > > > +
> > > > +			num_regs++;
> > > > +		}
> > > > +
> > > > +		reg = KVM_REG_ARM64_SVE_FFR(i);
> > > > +		if (put_user(reg, uindices++))
> > > > +			return -EFAULT;
> > > > +
> > > > +		num_regs++;
> > > > +	}
> > > 
> > > nit: the extra blank lines above the num_regs++'s give the code an odd
> > >      look (to me)
> > 
> > There's no guaranteed fall-through onto the increments: the blank line
> > was there to highlight the fact that we may jump out using a return
> > instead.
> > 
> > But I'm happy enough to change it if you have a strong preference or
> > you feel the code is equally clear without.
> 
> It's just a nit, so I don't have a strong preference :)

OK, well given that you mentioned it and there are other tweaks to make
on top of this patch anyway, I'll go ahead and make the change.

This saves a few lines, if nothing else.

Cheers
---Dave

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

* Re: [PATCH v7 19/27] KVM: arm64: Enumerate SVE register indices for KVM_GET_REG_LIST
@ 2019-04-05 11:11           ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05 11:11 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 11:45:56AM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 10:35:45AM +0100, Dave Martin wrote:
> > On Thu, Apr 04, 2019 at 04:08:32PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:44PM +0000, Dave Martin wrote:
> > > > This patch includes the SVE register IDs in the list returned by
> > > > KVM_GET_REG_LIST, as appropriate.
> > > > 
> > > > On a non-SVE-enabled vcpu, no new IDs are added.
> > > > 
> > > > On an SVE-enabled vcpu, IDs for the FPSIMD V-registers are removed
> > > > from the list, since userspace is required to access the Z-
> > > > registers instead in order to access the V-register content.  For
> > > > the variably-sized SVE registers, the appropriate set of slice IDs
> > > > are enumerated, depending on the maximum vector length for the
> > > > vcpu.
> > > > 
> > > > As it currently stands, the SVE architecture never requires more
> > > > than one slice to exist per register, so this patch adds no
> > > > explicit support for enumerating multiple slices.  The code can be
> > > > extended straightforwardly to support this in the future, if
> > > > needed.
> > > > 
> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > > 
> > > > ---

[...]

> > > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c

[...]

> > > > +static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
> > > > +				u64 __user *uindices)
> > > > +{
> > > > +	/* Only the first slice ever exists, for now */

[...]

> > > > +	const unsigned int slices = vcpu_sve_slices(vcpu);
> > > > +	u64 reg;
> > > > +	unsigned int i, n;
> > > > +	int num_regs = 0;
> > > > +
> > > > +	if (!vcpu_has_sve(vcpu))
> > > > +		return 0;
> > > > +
> > > > +	for (i = 0; i < slices; i++) {
> > > > +		for (n = 0; n < SVE_NUM_ZREGS; n++) {
> > > > +			reg = KVM_REG_ARM64_SVE_ZREG(n, i);
> > > > +			if (put_user(reg, uindices++))
> > > > +				return -EFAULT;
> > > > +
> > > > +			num_regs++;
> > > > +		}
> > > > +
> > > > +		for (n = 0; n < SVE_NUM_PREGS; n++) {
> > > > +			reg = KVM_REG_ARM64_SVE_PREG(n, i);
> > > > +			if (put_user(reg, uindices++))
> > > > +				return -EFAULT;
> > > > +
> > > > +			num_regs++;
> > > > +		}
> > > > +
> > > > +		reg = KVM_REG_ARM64_SVE_FFR(i);
> > > > +		if (put_user(reg, uindices++))
> > > > +			return -EFAULT;
> > > > +
> > > > +		num_regs++;
> > > > +	}
> > > 
> > > nit: the extra blank lines above the num_regs++'s give the code an odd
> > >      look (to me)
> > 
> > There's no guaranteed fall-through onto the increments: the blank line
> > was there to highlight the fact that we may jump out using a return
> > instead.
> > 
> > But I'm happy enough to change it if you have a strong preference or
> > you feel the code is equally clear without.
> 
> It's just a nit, so I don't have a strong preference :)

OK, well given that you mentioned it and there are other tweaks to make
on top of this patch anyway, I'll go ahead and make the change.

This saves a few lines, if nothing else.

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 20/27] arm64/sve: In-kernel vector length availability query interface
  2019-04-05  9:54         ` Andrew Jones
@ 2019-04-05 11:13           ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05 11:13 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 11:54:07AM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 10:35:55AM +0100, Dave Martin wrote:
> > On Thu, Apr 04, 2019 at 04:20:34PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:45PM +0000, Dave Martin wrote:
> > > > KVM will need to interrogate the set of SVE vector lengths
> > > > available on the system.
> > > > 
> > > > This patch exposes the relevant bits to the kernel, along with a
> > > > sve_vq_available() helper to check whether a particular vector
> > > > length is supported.
> > > > 
> > > > __vq_to_bit() and __bit_to_vq() are not intended for use outside
> > > > these functions: now that these are exposed outside fpsimd.c, they
> > > > are prefixed with __ in order to provide an extra hint that they
> > > > are not intended for general-purpose use.
> > > > 
> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > > ---
> > > >  arch/arm64/include/asm/fpsimd.h | 29 +++++++++++++++++++++++++++++
> > > >  arch/arm64/kernel/fpsimd.c      | 35 ++++++++---------------------------
> > > >  2 files changed, 37 insertions(+), 27 deletions(-)
> > > > 
> > > > diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h

[...]

> > > > +/* Set of available vector lengths, as vq_to_bit(vq): */
> > > 
> > > s/as/for use with/ ?
> > 
> > Not exactly.  Does the following work for you:
> > 
> > /*
> >  * Set of available vector lengths
> >  * Vector length vq is encoded as bit __vq_to_bit(vq):
> >  */
> 
> Yes. That reads much better.

OK

> > > s/vq_to_bit/__vq_to_bit/
> > 
> > Ack: that got renamed when I moved it to fpsimd.h, bit I clearly didn't
> > update the comment as I pasted it across.
> > 
> > > 
> > > > +extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
> > > > +
> > > > +/*
> > > > + * Helpers to translate bit indices in sve_vq_map to VQ values (and
> > > > + * vice versa).  This allows find_next_bit() to be used to find the
> > > > + * _maximum_ VQ not exceeding a certain value.
> > > > + */
> > > > +static inline unsigned int __vq_to_bit(unsigned int vq)
> > > > +{
> > > 
> > > Why not have the same WARN_ON and clamping here as we do
> > > in __bit_to_vq. Here a vq > SVE_VQ_MAX will wrap around
> > > to a super high bit.
> > > 
> > > > +	return SVE_VQ_MAX - vq;
> > > > +}
> > > > +
> > > > +static inline unsigned int __bit_to_vq(unsigned int bit)
> > > > +{
> > > > +	if (WARN_ON(bit >= SVE_VQ_MAX))
> > > > +		bit = SVE_VQ_MAX - 1;
> > > > +
> > > > +	return SVE_VQ_MAX - bit;
> > > > +}
> > > > +
> > > > +/* Ensure vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX before calling this function */
> > > 
> > > Are we avoiding putting these tests and WARN_ONs in this function to
> > > keep it fast?
> > 
> > These are intended as backend for use only by fpsimd.c and this header,
> > so peppering them with WARN_ON() felt excessive.  I don't expect a lot
> > of new calls to these (or any, probably).
> > 
> > I don't recall why I kept the WARN_ON() just in __bit_to_vq(), except
> > that the way that gets called is a bit more complex in some places.
> > 
> > Are you happy to replace these with comments?  e.g.:
> > 
> > /* Only valid when vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX */
> > __vq_to_bit()
> > 
> > /* Only valid when bit < SVE_VQ_MAX */
> > __bit_to_vq()
> > 
> > 
> > OTOH, these are not used on fast paths, so maybe having both as
> > WARN_ON() would be better.  Part of the problem is knowing what to clamp
> > to: these are generally used in conjunction with looping or bitmap find
> > operations, so the caller may be making assumptions about the return
> > value that may wrong when the value is clamped.
> > 
> > Alternatively, these could be BUG() -- but that seems heavy.
> > 
> > What do you think?
> 
> I like the idea of having WARN_ON's to enforce the constraints. I
> wouldn't be completely opposed to not having anything other than
> the comments, though, as there is a limit to how defensive we should
> be. I'll abstain from this vote.

I'll have a think about whether there's anything non-toxic that we can
return in the error cases.  If not, I may demote these to comments:
returning an actual error code for this sort of things feels like a
step too far.

Otherwise we can have WARNs.

Cheers
---Dave

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

* Re: [PATCH v7 20/27] arm64/sve: In-kernel vector length availability query interface
@ 2019-04-05 11:13           ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05 11:13 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 11:54:07AM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 10:35:55AM +0100, Dave Martin wrote:
> > On Thu, Apr 04, 2019 at 04:20:34PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:45PM +0000, Dave Martin wrote:
> > > > KVM will need to interrogate the set of SVE vector lengths
> > > > available on the system.
> > > > 
> > > > This patch exposes the relevant bits to the kernel, along with a
> > > > sve_vq_available() helper to check whether a particular vector
> > > > length is supported.
> > > > 
> > > > __vq_to_bit() and __bit_to_vq() are not intended for use outside
> > > > these functions: now that these are exposed outside fpsimd.c, they
> > > > are prefixed with __ in order to provide an extra hint that they
> > > > are not intended for general-purpose use.
> > > > 
> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > > ---
> > > >  arch/arm64/include/asm/fpsimd.h | 29 +++++++++++++++++++++++++++++
> > > >  arch/arm64/kernel/fpsimd.c      | 35 ++++++++---------------------------
> > > >  2 files changed, 37 insertions(+), 27 deletions(-)
> > > > 
> > > > diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h

[...]

> > > > +/* Set of available vector lengths, as vq_to_bit(vq): */
> > > 
> > > s/as/for use with/ ?
> > 
> > Not exactly.  Does the following work for you:
> > 
> > /*
> >  * Set of available vector lengths
> >  * Vector length vq is encoded as bit __vq_to_bit(vq):
> >  */
> 
> Yes. That reads much better.

OK

> > > s/vq_to_bit/__vq_to_bit/
> > 
> > Ack: that got renamed when I moved it to fpsimd.h, bit I clearly didn't
> > update the comment as I pasted it across.
> > 
> > > 
> > > > +extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
> > > > +
> > > > +/*
> > > > + * Helpers to translate bit indices in sve_vq_map to VQ values (and
> > > > + * vice versa).  This allows find_next_bit() to be used to find the
> > > > + * _maximum_ VQ not exceeding a certain value.
> > > > + */
> > > > +static inline unsigned int __vq_to_bit(unsigned int vq)
> > > > +{
> > > 
> > > Why not have the same WARN_ON and clamping here as we do
> > > in __bit_to_vq. Here a vq > SVE_VQ_MAX will wrap around
> > > to a super high bit.
> > > 
> > > > +	return SVE_VQ_MAX - vq;
> > > > +}
> > > > +
> > > > +static inline unsigned int __bit_to_vq(unsigned int bit)
> > > > +{
> > > > +	if (WARN_ON(bit >= SVE_VQ_MAX))
> > > > +		bit = SVE_VQ_MAX - 1;
> > > > +
> > > > +	return SVE_VQ_MAX - bit;
> > > > +}
> > > > +
> > > > +/* Ensure vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX before calling this function */
> > > 
> > > Are we avoiding putting these tests and WARN_ONs in this function to
> > > keep it fast?
> > 
> > These are intended as backend for use only by fpsimd.c and this header,
> > so peppering them with WARN_ON() felt excessive.  I don't expect a lot
> > of new calls to these (or any, probably).
> > 
> > I don't recall why I kept the WARN_ON() just in __bit_to_vq(), except
> > that the way that gets called is a bit more complex in some places.
> > 
> > Are you happy to replace these with comments?  e.g.:
> > 
> > /* Only valid when vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX */
> > __vq_to_bit()
> > 
> > /* Only valid when bit < SVE_VQ_MAX */
> > __bit_to_vq()
> > 
> > 
> > OTOH, these are not used on fast paths, so maybe having both as
> > WARN_ON() would be better.  Part of the problem is knowing what to clamp
> > to: these are generally used in conjunction with looping or bitmap find
> > operations, so the caller may be making assumptions about the return
> > value that may wrong when the value is clamped.
> > 
> > Alternatively, these could be BUG() -- but that seems heavy.
> > 
> > What do you think?
> 
> I like the idea of having WARN_ON's to enforce the constraints. I
> wouldn't be completely opposed to not having anything other than
> the comments, though, as there is a limit to how defensive we should
> be. I'll abstain from this vote.

I'll have a think about whether there's anything non-toxic that we can
return in the error cases.  If not, I may demote these to comments:
returning an actual error code for this sort of things feels like a
step too far.

Otherwise we can have WARNs.

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 21/27] KVM: arm/arm64: Add hook for arch-specific KVM initialisation
  2019-04-05 10:40             ` Andrew Jones
@ 2019-04-05 11:14               ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05 11:14 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 12:40:57PM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 10:36:24AM +0100, Dave Martin wrote:
> > On Thu, Apr 04, 2019 at 06:33:08PM +0200, Andrew Jones wrote:
> > > On Thu, Apr 04, 2019 at 03:53:55PM +0100, Dave Martin wrote:
> > > > On Thu, Apr 04, 2019 at 04:25:28PM +0200, Andrew Jones wrote:
> > > > > On Fri, Mar 29, 2019 at 01:00:46PM +0000, Dave Martin wrote:
> > 
> > [...]
> > 
> > > > > > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > > > > > index 99c3738..c69e137 100644
> > > > > > --- a/virt/kvm/arm/arm.c
> > > > > > +++ b/virt/kvm/arm/arm.c
> > > > > > @@ -1664,6 +1664,10 @@ int kvm_arch_init(void *opaque)
> > > > > >  	if (err)
> > > > > >  		return err;
> > > > > >  
> > > > > > +	err = kvm_arm_init_arch_resources();
> > > > > > +	if (err)
> > > > > > +		return err;
> > > > > > +
> > > > > >  	if (!in_hyp_mode) {
> > > > > >  		err = init_hyp_mode();
> > > > > >  		if (err)
> > > > > > -- 
> > > > > > 2.1.4
> > > > > >
> > > > > 
> > > > > It's not clear to me from the commit message why init_common_resources()
> > > > > won't work for this. Maybe it'll be more clear as I continue the review.
> > > > 
> > > > init_common_resources() is for stuff common to arm and arm64.
> > > 
> > > Well currently init_common_resources() only calls kvm_set_ipa_limit(),
> > > which isn't implemented for arm. So if there was a plan to only use
> > > that function for init that actually does something on both, it doesn't.
> > 
> > Hmmm, perhaps I was wishfully interpreting the word "common" to mean
> > what I would like it to mean...
> > 
> > > > kvm_arm_init_arch_resources() is intended for stuff specific to the
> > > > particular arch backend.
> > > 
> > > I'm not sure we need that yet. We just need an arm setup sve stub like
> > > arm's kvm_set_ipa_limit() stub. OTOH, if we have to keep adding stubs
> > > to arm we should probably have something like
> > > kvm_arm_init_arch_resources() instead, and kvm_set_ipa_limit() should
> > > be moved inside the arm64 one and the arm ipa limit stub can go. Then
> > > since init_common_resources() would no longer be used, it could just
> > > be deleted.
> > 
> > OK, for simplicity I may call the sve setup directly as you suggest, and
> > make an arm stub for it: that feels a bit weird, but there is precedent.
> > 
> > If we end up accumulating a lot of these, we can revisit it and maybe
> > invent something like kvm_arm_init_arch_resources() at that point.
> > 
> > Does that sound reasonable?
> 
> Yup. Sounds good to me.

OK, can do

Cheers
---Dave

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

* Re: [PATCH v7 21/27] KVM: arm/arm64: Add hook for arch-specific KVM initialisation
@ 2019-04-05 11:14               ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05 11:14 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 12:40:57PM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 10:36:24AM +0100, Dave Martin wrote:
> > On Thu, Apr 04, 2019 at 06:33:08PM +0200, Andrew Jones wrote:
> > > On Thu, Apr 04, 2019 at 03:53:55PM +0100, Dave Martin wrote:
> > > > On Thu, Apr 04, 2019 at 04:25:28PM +0200, Andrew Jones wrote:
> > > > > On Fri, Mar 29, 2019 at 01:00:46PM +0000, Dave Martin wrote:
> > 
> > [...]
> > 
> > > > > > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > > > > > index 99c3738..c69e137 100644
> > > > > > --- a/virt/kvm/arm/arm.c
> > > > > > +++ b/virt/kvm/arm/arm.c
> > > > > > @@ -1664,6 +1664,10 @@ int kvm_arch_init(void *opaque)
> > > > > >  	if (err)
> > > > > >  		return err;
> > > > > >  
> > > > > > +	err = kvm_arm_init_arch_resources();
> > > > > > +	if (err)
> > > > > > +		return err;
> > > > > > +
> > > > > >  	if (!in_hyp_mode) {
> > > > > >  		err = init_hyp_mode();
> > > > > >  		if (err)
> > > > > > -- 
> > > > > > 2.1.4
> > > > > >
> > > > > 
> > > > > It's not clear to me from the commit message why init_common_resources()
> > > > > won't work for this. Maybe it'll be more clear as I continue the review.
> > > > 
> > > > init_common_resources() is for stuff common to arm and arm64.
> > > 
> > > Well currently init_common_resources() only calls kvm_set_ipa_limit(),
> > > which isn't implemented for arm. So if there was a plan to only use
> > > that function for init that actually does something on both, it doesn't.
> > 
> > Hmmm, perhaps I was wishfully interpreting the word "common" to mean
> > what I would like it to mean...
> > 
> > > > kvm_arm_init_arch_resources() is intended for stuff specific to the
> > > > particular arch backend.
> > > 
> > > I'm not sure we need that yet. We just need an arm setup sve stub like
> > > arm's kvm_set_ipa_limit() stub. OTOH, if we have to keep adding stubs
> > > to arm we should probably have something like
> > > kvm_arm_init_arch_resources() instead, and kvm_set_ipa_limit() should
> > > be moved inside the arm64 one and the arm ipa limit stub can go. Then
> > > since init_common_resources() would no longer be used, it could just
> > > be deleted.
> > 
> > OK, for simplicity I may call the sve setup directly as you suggest, and
> > make an arm stub for it: that feels a bit weird, but there is precedent.
> > 
> > If we end up accumulating a lot of these, we can revisit it and maybe
> > invent something like kvm_arm_init_arch_resources() at that point.
> > 
> > Does that sound reasonable?
> 
> Yup. Sounds good to me.

OK, can do

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
  2019-04-05 10:14         ` Andrew Jones
@ 2019-04-05 12:54           ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05 12:54 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 12:14:51PM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 10:36:03AM +0100, Dave Martin wrote:
> > On Thu, Apr 04, 2019 at 10:18:54PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> > > > This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> > > > allow userspace to set and query the set of vector lengths visible
> > > > to the guest.
> > > > 
> > > > In the future, multiple register slices per SVE register may be
> > > > visible through the ioctl interface.  Once the set of slices has
> > > > been determined we would not be able to allow the vector length set
> > > > to be changed any more, in order to avoid userspace seeing
> > > > inconsistent sets of registers.  For this reason, this patch adds
> > > > support for explicit finalization of the SVE configuration via the
> > > > KVM_ARM_VCPU_FINALIZE ioctl.
> > > > 
> > > > Finalization is the proper place to allocate the SVE register state
> > > > storage in vcpu->arch.sve_state, so this patch adds that as
> > > > appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> > > > was previously a no-op on arm64.
> > > > 
> > > > To simplify the logic for determining what vector lengths can be
> > > > supported, some code is added to KVM init to work this out, in the
> > > > kvm_arm_init_arch_resources() hook.
> > > > 
> > > > The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> > > > Subsequent patches will allow SVE to be turned on for guest vcpus,
> > > > making it visible.
> > > > 
> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > > 
> > > > ---
> > 
> > [...]
> > 
> > > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > > index 2aa80a5..086ab05 100644
> > > > --- a/arch/arm64/kvm/guest.c
> > > > +++ b/arch/arm64/kvm/guest.c
> > > > @@ -206,6 +206,73 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >  	return err;
> > > >  }
> > > >  
> > > > +#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64)
> > > > +#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64)
> > > > +
> > > > +static bool vq_present(
> > > > +	const u64 (*const vqs)[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)],
> > > > +	unsigned int vq)
> > > > +{
> > > > +	return (*vqs)[vq_word(vq)] & vq_mask(vq);
> > > > +}
> > > > +
> > > > +static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > > +{
> > > > +	unsigned int max_vq, vq;
> > > > +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> > > > +
> > > > +	if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl)))
> > > > +		return -EINVAL;
> > > > +
> > > > +	memset(vqs, 0, sizeof(vqs));
> > > > +
> > > > +	max_vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
> > > > +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > > > +		if (sve_vq_available(vq))
> > > > +			vqs[vq_word(vq)] |= vq_mask(vq);
> > > > +
> > > > +	if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs)))
> > > > +		return -EFAULT;
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > > +{
> > > > +	unsigned int max_vq, vq;
> > > > +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> > > 
> > > There are three of these long 'DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)'.
> > > A macro is probably warranted.
> > 
> > Fair point.  These are a bit cumbersome.  How about:
> > 
> > #define SVE_VLS_WORDS DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)
> > 
> > Annoyingly, this is virtually identical to a Linux bitmap: the base type
> > is u64 instead of unsigned long; otherwise there's no intentional
> > difference.
> 
> Yeah, I noticed it was a reinvented bitmap, but I liked that it was,
> because, for the userspace api, removing the bitmap abstractions
> ensures we know what is what and where exactly it is.

Agreed.  I thought of using the bitmap API inside the kernel, but even
if this is arm64-specific code, it made me uneasy: the compiler doesn't
necessarily think that u64 and unsigned long are the same type even if
they're both 64-bit, so there's the potential for weird optimisations to
happen.

> > (Aside: do you know why the KVM API insists on everything being u64?
> > This makes sense for non-native types (like guest registers), but not
> > for native things like host userspace addresses etc.)
> 
> Would that work when the kernel is 64-bit and the userspace is 32? I
> personally like the interfaces being explicit with type size, as it
> removes the brain burden of translating long and int when moving arch
> to arch and kernel to userspace.

Ah yes, the joys of compat.  And ioctl.  Ignore me.

> > > > +
> > > > +	if (kvm_arm_vcpu_sve_finalized(vcpu))
> > > > +		return -EPERM; /* too late! */
> > > > +
> > > > +	if (WARN_ON(vcpu->arch.sve_state))
> > > > +		return -EINVAL;
> > > > +
> > > > +	if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs)))
> > > > +		return -EFAULT;
> > > > +
> > > > +	max_vq = 0;
> > > > +	for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq)
> > > > +		if (vq_present(&vqs, vq))
> > > > +			max_vq = vq;
> > > > +
> > > > +	if (max_vq > sve_vq_from_vl(kvm_sve_max_vl))
> > > > +		return -EINVAL;
> > > > +
> > > > +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > > > +		if (vq_present(&vqs, vq) != sve_vq_available(vq))
> > > > +			return -EINVAL;
> > > 
> > > What about supporting the optional non-power-of-2 vector lengths? For
> > > example, if the maximum VL is 512, then in addition to 512, 128, and
> > > 256 there could be a 384. If we plan to start a guest on a machine
> > > that has all four and then migrate it to a machine that only has
> > > 128,256,512 we would want to set the VL set to 128,256,512, even on
> > > the machine that supports 384. If I understand the above test correctly,
> > > then that wouldn't work.
> > 
> > This is exactly what the code is trying to forbid, though it may not be
> > obvious here why.
> > 
> > The trouble is, we can't correctly emulate a vcpu supporting
> > {128,256,512} on hardware that also supports 384-bit vectors: the
> > architecture says that the vector length you get is determined by
> > rounding ZCR_EL1.LEN down to the next vector length actually
> > supported.
> > 
> > So, the guest would expect writing ZCR_EL1.LEN = 2 to give a vector
> > length of 256 bits, whereas on this hardware the actual resulting
> > vector length would be 384 bits.
> 
> Oh, I see.
> 
> > 
> > sve_probe_vqs() relies on this property to detect the set of available
> > vector lengths.  Simple, bare-metal guests might also just set
> > ZCR_ELx.LEN = 0x1ff to just get the max available.
> > 
> > 
> > The architecture says categorically that the set of vector lengths
> > supported is a fixed property of the (emulated) hardware -- we can't
> > having this changing under the guest's feet.
> > 
> > Fixing this would require an archietctural way to filter out individual
> > vector lengths from the supported set, not just a way to clamp the
> > maximum (which is all ZCR_EL2.LEN gives us).
> > 
> > The general expectation is that sanely designed cluster will be
> > "homogeneous enough" and won't trigger this check -- it's here
> > just in case.
> 
> Data centers evolve as they expand and hardware is replaced. I wouldn't
> expect them to stay homogeneous for long, not without keeping them that
> way at substantial cost. This isn't the first thing that is forcing Arm
> virt data centers to be homogeneous (we still use qemu's '-cpu host'),
> but it's disappointing to have yet another one.

This may or may not be a problem in practive, since I suspect
implementations that support non-power-of-two vector lengths may be in
the minority anyway.

The ARM Fast Model and probably QEMU can do it, but people are less
likely to try to build a high-performance cluster out of those...

> > I attempt to capture this in api.txt, leaving the door open in case the
> > architecture gives a way to support this in future:
> > 
> >   | KVM_REG_ARM64_SVE_VLS
> >   | 
> >   | [...]
> >   | 
> >   | Apart from simply removing all vector lengths from the host set
> >   | that exceed some value, support for arbitrarily chosen sets of
> >   | vector lengths is hardware-dependent and may not be available.
> >   | Attempting to configure an invalid set of vector lengths via
> >   | KVM_SET_ONE_REG will fail with EINVAL.
> > 
> > Is this enough, or do you think more explanation is needed somewhere?
> 
> I saw that before, so I guess more is needed :) What you wrote above about
> how we can only shorten the list due to how zcr_el1.len works was the
> missing piece for me. Maybe that should be integrated into the text
> somehow.

If you think the above is enough for ABI documentation purposes, I will
aim to drop the following comment into set_sve_vls():

	/*
	 * Vector lengths supported by the host can't currently be
	 * hidden from the guest individually: instead we can only set a
	 * maxmium via ZCR_EL2.LEN.  So, make sure the available vector
	 * length match the set requested exactly up to the requested
	 * maximum:
	 */
	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
		if (vq_present(&vqs, vq) != sve_vq_available(vq))
			return -EINVAL;

Do you think that's enough?

Cheers
---Dave

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

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
@ 2019-04-05 12:54           ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05 12:54 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 12:14:51PM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 10:36:03AM +0100, Dave Martin wrote:
> > On Thu, Apr 04, 2019 at 10:18:54PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> > > > This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> > > > allow userspace to set and query the set of vector lengths visible
> > > > to the guest.
> > > > 
> > > > In the future, multiple register slices per SVE register may be
> > > > visible through the ioctl interface.  Once the set of slices has
> > > > been determined we would not be able to allow the vector length set
> > > > to be changed any more, in order to avoid userspace seeing
> > > > inconsistent sets of registers.  For this reason, this patch adds
> > > > support for explicit finalization of the SVE configuration via the
> > > > KVM_ARM_VCPU_FINALIZE ioctl.
> > > > 
> > > > Finalization is the proper place to allocate the SVE register state
> > > > storage in vcpu->arch.sve_state, so this patch adds that as
> > > > appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> > > > was previously a no-op on arm64.
> > > > 
> > > > To simplify the logic for determining what vector lengths can be
> > > > supported, some code is added to KVM init to work this out, in the
> > > > kvm_arm_init_arch_resources() hook.
> > > > 
> > > > The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> > > > Subsequent patches will allow SVE to be turned on for guest vcpus,
> > > > making it visible.
> > > > 
> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > > 
> > > > ---
> > 
> > [...]
> > 
> > > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > > index 2aa80a5..086ab05 100644
> > > > --- a/arch/arm64/kvm/guest.c
> > > > +++ b/arch/arm64/kvm/guest.c
> > > > @@ -206,6 +206,73 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > >  	return err;
> > > >  }
> > > >  
> > > > +#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64)
> > > > +#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64)
> > > > +
> > > > +static bool vq_present(
> > > > +	const u64 (*const vqs)[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)],
> > > > +	unsigned int vq)
> > > > +{
> > > > +	return (*vqs)[vq_word(vq)] & vq_mask(vq);
> > > > +}
> > > > +
> > > > +static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > > +{
> > > > +	unsigned int max_vq, vq;
> > > > +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> > > > +
> > > > +	if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl)))
> > > > +		return -EINVAL;
> > > > +
> > > > +	memset(vqs, 0, sizeof(vqs));
> > > > +
> > > > +	max_vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
> > > > +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > > > +		if (sve_vq_available(vq))
> > > > +			vqs[vq_word(vq)] |= vq_mask(vq);
> > > > +
> > > > +	if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs)))
> > > > +		return -EFAULT;
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > > +{
> > > > +	unsigned int max_vq, vq;
> > > > +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> > > 
> > > There are three of these long 'DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)'.
> > > A macro is probably warranted.
> > 
> > Fair point.  These are a bit cumbersome.  How about:
> > 
> > #define SVE_VLS_WORDS DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)
> > 
> > Annoyingly, this is virtually identical to a Linux bitmap: the base type
> > is u64 instead of unsigned long; otherwise there's no intentional
> > difference.
> 
> Yeah, I noticed it was a reinvented bitmap, but I liked that it was,
> because, for the userspace api, removing the bitmap abstractions
> ensures we know what is what and where exactly it is.

Agreed.  I thought of using the bitmap API inside the kernel, but even
if this is arm64-specific code, it made me uneasy: the compiler doesn't
necessarily think that u64 and unsigned long are the same type even if
they're both 64-bit, so there's the potential for weird optimisations to
happen.

> > (Aside: do you know why the KVM API insists on everything being u64?
> > This makes sense for non-native types (like guest registers), but not
> > for native things like host userspace addresses etc.)
> 
> Would that work when the kernel is 64-bit and the userspace is 32? I
> personally like the interfaces being explicit with type size, as it
> removes the brain burden of translating long and int when moving arch
> to arch and kernel to userspace.

Ah yes, the joys of compat.  And ioctl.  Ignore me.

> > > > +
> > > > +	if (kvm_arm_vcpu_sve_finalized(vcpu))
> > > > +		return -EPERM; /* too late! */
> > > > +
> > > > +	if (WARN_ON(vcpu->arch.sve_state))
> > > > +		return -EINVAL;
> > > > +
> > > > +	if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs)))
> > > > +		return -EFAULT;
> > > > +
> > > > +	max_vq = 0;
> > > > +	for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq)
> > > > +		if (vq_present(&vqs, vq))
> > > > +			max_vq = vq;
> > > > +
> > > > +	if (max_vq > sve_vq_from_vl(kvm_sve_max_vl))
> > > > +		return -EINVAL;
> > > > +
> > > > +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > > > +		if (vq_present(&vqs, vq) != sve_vq_available(vq))
> > > > +			return -EINVAL;
> > > 
> > > What about supporting the optional non-power-of-2 vector lengths? For
> > > example, if the maximum VL is 512, then in addition to 512, 128, and
> > > 256 there could be a 384. If we plan to start a guest on a machine
> > > that has all four and then migrate it to a machine that only has
> > > 128,256,512 we would want to set the VL set to 128,256,512, even on
> > > the machine that supports 384. If I understand the above test correctly,
> > > then that wouldn't work.
> > 
> > This is exactly what the code is trying to forbid, though it may not be
> > obvious here why.
> > 
> > The trouble is, we can't correctly emulate a vcpu supporting
> > {128,256,512} on hardware that also supports 384-bit vectors: the
> > architecture says that the vector length you get is determined by
> > rounding ZCR_EL1.LEN down to the next vector length actually
> > supported.
> > 
> > So, the guest would expect writing ZCR_EL1.LEN = 2 to give a vector
> > length of 256 bits, whereas on this hardware the actual resulting
> > vector length would be 384 bits.
> 
> Oh, I see.
> 
> > 
> > sve_probe_vqs() relies on this property to detect the set of available
> > vector lengths.  Simple, bare-metal guests might also just set
> > ZCR_ELx.LEN = 0x1ff to just get the max available.
> > 
> > 
> > The architecture says categorically that the set of vector lengths
> > supported is a fixed property of the (emulated) hardware -- we can't
> > having this changing under the guest's feet.
> > 
> > Fixing this would require an archietctural way to filter out individual
> > vector lengths from the supported set, not just a way to clamp the
> > maximum (which is all ZCR_EL2.LEN gives us).
> > 
> > The general expectation is that sanely designed cluster will be
> > "homogeneous enough" and won't trigger this check -- it's here
> > just in case.
> 
> Data centers evolve as they expand and hardware is replaced. I wouldn't
> expect them to stay homogeneous for long, not without keeping them that
> way at substantial cost. This isn't the first thing that is forcing Arm
> virt data centers to be homogeneous (we still use qemu's '-cpu host'),
> but it's disappointing to have yet another one.

This may or may not be a problem in practive, since I suspect
implementations that support non-power-of-two vector lengths may be in
the minority anyway.

The ARM Fast Model and probably QEMU can do it, but people are less
likely to try to build a high-performance cluster out of those...

> > I attempt to capture this in api.txt, leaving the door open in case the
> > architecture gives a way to support this in future:
> > 
> >   | KVM_REG_ARM64_SVE_VLS
> >   | 
> >   | [...]
> >   | 
> >   | Apart from simply removing all vector lengths from the host set
> >   | that exceed some value, support for arbitrarily chosen sets of
> >   | vector lengths is hardware-dependent and may not be available.
> >   | Attempting to configure an invalid set of vector lengths via
> >   | KVM_SET_ONE_REG will fail with EINVAL.
> > 
> > Is this enough, or do you think more explanation is needed somewhere?
> 
> I saw that before, so I guess more is needed :) What you wrote above about
> how we can only shorten the list due to how zcr_el1.len works was the
> missing piece for me. Maybe that should be integrated into the text
> somehow.

If you think the above is enough for ABI documentation purposes, I will
aim to drop the following comment into set_sve_vls():

	/*
	 * Vector lengths supported by the host can't currently be
	 * hidden from the guest individually: instead we can only set a
	 * maxmium via ZCR_EL2.LEN.  So, make sure the available vector
	 * length match the set requested exactly up to the requested
	 * maximum:
	 */
	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
		if (vq_present(&vqs, vq) != sve_vq_available(vq))
			return -EINVAL;

Do you think that's enough?

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 27/27] KVM: arm64/sve: Document KVM API extensions for SVE
  2019-04-05 10:39         ` Andrew Jones
@ 2019-04-05 13:00           ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05 13:00 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 12:39:37PM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 10:36:17AM +0100, Dave Martin wrote:
> > On Thu, Apr 04, 2019 at 11:09:21PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:52PM +0000, Dave Martin wrote:
> > > > This patch adds sections to the KVM API documentation describing
> > > > the extensions for supporting the Scalable Vector Extension (SVE)
> > > > in guests.
> > > > 
> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > 
> > > > ---
> > > > 
> > > > Changes since v5:
> > > > 
> > > >  * Document KVM_ARM_VCPU_FINALIZE and its interactions with SVE.
> > > > ---
> > > >  Documentation/virtual/kvm/api.txt | 132 +++++++++++++++++++++++++++++++++++++-
> > > >  1 file changed, 129 insertions(+), 3 deletions(-)
> > > > 
> > > > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> > > > index cd920dd..68509de 100644
> > > > --- a/Documentation/virtual/kvm/api.txt
> > > > +++ b/Documentation/virtual/kvm/api.txt
> > > > @@ -1873,6 +1873,7 @@ Parameters: struct kvm_one_reg (in)
> > > >  Returns: 0 on success, negative value on failure
> > > >  Errors:
> > > >    ENOENT:   no such register
> > > > +  EPERM:    register access forbidden for architecture-dependent reasons
> > > >    EINVAL:   other errors, such as bad size encoding for a known register
> > > >  
> > > >  struct kvm_one_reg {
> > > > @@ -2127,13 +2128,20 @@ Specifically:
> > > >    0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
> > > >    0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
> > > >    0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
> > > > -  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]
> > > > -  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]
> > > > +  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]    (*)
> > > > +  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]    (*)
> > > >      ...
> > > > -  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]
> > > > +  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]   (*)
> > > >    0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
> > > >    0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
> > > >  
> > > > +(*) These encodings are not accepted for SVE-enabled vcpus.  See
> > > > +    KVM_ARM_VCPU_INIT.
> > > > +
> > > > +    The equivalent register content can be accessed via bits [127:0] of
> > > > +    the corresponding SVE Zn registers instead for vcpus that have SVE
> > > > +    enabled (see below).
> > > > +
> > > >  arm64 CCSIDR registers are demultiplexed by CSSELR value:
> > > >    0x6020 0000 0011 00 <csselr:8>
> > > >  
> > > > @@ -2143,6 +2151,61 @@ arm64 system registers have the following id bit patterns:
> > > >  arm64 firmware pseudo-registers have the following bit pattern:
> > > >    0x6030 0000 0014 <regno:16>
> > > >  
> > > > +arm64 SVE registers have the following bit patterns:
> > > > +  0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> > > > +  0x6050 0000 0015 04 <n:4> <slice:5>   Pn bits[256*slice + 255 : 256*slice]
> > > > +  0x6050 0000 0015 060 <slice:5>        FFR bits[256*slice + 255 : 256*slice]
> > > > +  0x6060 0000 0015 ffff                 KVM_REG_ARM64_SVE_VLS pseudo-register
> > > > +
> > > > +Access to slices beyond the maximum vector length configured for the
> > > > +vcpu (i.e., where 16 * slice >= max_vq (**)) will fail with ENOENT.
> > > 
> > > I've been doing pretty well keeping track of the 16's, 128's, VL's and
> > > VQ's, but this example lost me. Also, should it be >= or just > ?
> > 
> > It should be >=.  It's analogous to not being allowed to derefence an
> > array index that is >= the size of the array.
> > 
> > Also, the 16 here is not the number of bytes per quadword (as it often
> > does with all things SVE), but the number of quadwords per 2048-bit
> > KVM register slice.
> > 
> > To make matters worse (**) resembles some weird C syntax.
> > 
> > Maybe this would be less confusing written as
> > 
> >     Access to register IDs where 2048 * slice >= 128 * max_vq will fail
> >     with ENOENT.  max_vq is the vcpu's maximum supported vector length
> >     in 128-bit quadwords: see (**) below.
> > 
> > Does that help at all?
> 
> Yes. Thanks.

OK, I'll do that.

> 
> > 
> > > 
> > > > +
> > > > +These registers are only accessible on vcpus for which SVE is enabled.
> > > > +See KVM_ARM_VCPU_INIT for details.
> > > > +
> > > > +In addition, except for KVM_REG_ARM64_SVE_VLS, these registers are not
> > > > +accessible until the vcpu's SVE configuration has been finalized
> > > > +using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).  See KVM_ARM_VCPU_INIT
> > > > +and KVM_ARM_VCPU_FINALIZE for more information about this procedure.
> > > > +
> > > > +KVM_REG_ARM64_SVE_VLS is a pseudo-register that allows the set of vector
> > > > +lengths supported by the vcpu to be discovered and configured by
> > > > +userspace.  When transferred to or from user memory via KVM_GET_ONE_REG
> > > > +or KVM_SET_ONE_REG, the value of this register is of type __u64[8], and
> > > > +encodes the set of vector lengths as follows:
> > > > +
> > > > +__u64 vector_lengths[8];
> > > > +
> > > > +if (vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX &&
> > > > +    ((vector_lengths[(vq - 1) / 64] >> ((vq - 1) % 64)) & 1))
> > > > +	/* Vector length vq * 16 bytes supported */
> > > > +else
> > > > +	/* Vector length vq * 16 bytes not supported */
> > > > +
> > > > +(**) The maximum value vq for which the above condition is true is
> > > > +max_vq.  This is the maximum vector length available to the guest on
> > > > +this vcpu, and determines which register slices are visible through
> > > > +this ioctl interface.
> > > > +
> > > > +(See Documentation/arm64/sve.txt for an explanation of the "vq"
> > > > +nomenclature.)
> > > > +
> > > > +KVM_REG_ARM64_SVE_VLS is only accessible after KVM_ARM_VCPU_INIT.
> > > > +KVM_ARM_VCPU_INIT initialises it to the best set of vector lengths that
> > > > +the host supports.
> > > > +
> > > > +Userspace may subsequently modify it if desired until the vcpu's SVE
> > > > +configuration is finalized using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
> > > > +
> > > > +Apart from simply removing all vector lengths from the host set that
> > > > +exceed some value, support for arbitrarily chosen sets of vector lengths
> > > > +is hardware-dependent and may not be available.  Attempting to configure
> > > > +an invalid set of vector lengths via KVM_SET_ONE_REG will fail with
> > > > +EINVAL.
> > > > +
> > > > +After the vcpu's SVE configuration is finalized, further attempts to
> > > > +write this register will fail with EPERM.
> > > > +
> > > >  
> > > >  MIPS registers are mapped using the lower 32 bits.  The upper 16 of that is
> > > >  the register group type:
> > > > @@ -2197,6 +2260,7 @@ Parameters: struct kvm_one_reg (in and out)
> > > >  Returns: 0 on success, negative value on failure
> > > >  Errors:
> > > >    ENOENT:   no such register
> > > > +  EPERM:    register access forbidden for architecture-dependent reasons
> > > >    EINVAL:   other errors, such as bad size encoding for a known register
> > > >  
> > > >  This ioctl allows to receive the value of a single register implemented
> > > > @@ -2690,6 +2754,33 @@ Possible features:
> > > >  	- KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
> > > >  	  Depends on KVM_CAP_ARM_PMU_V3.
> > > >  
> > > > +	- KVM_ARM_VCPU_SVE: Enables SVE for the CPU (arm64 only).
> > > > +	  Depends on KVM_CAP_ARM_SVE.
> > > > +	  Requires KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > > > +
> > > > +	   * After KVM_ARM_VCPU_INIT:
> > > > +
> > > > +	      - KVM_REG_ARM64_SVE_VLS may be read using KVM_GET_ONE_REG: the
> > > > +	        initial value of this pseudo-register indicates the best set of
> > > > +	        vector lengths possible for a vcpu on this host.
> > > > +
> > > > +	   * Before KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > > > +
> > > > +	      - KVM_RUN and KVM_GET_REG_LIST are not available;
> > > > +
> > > > +	      - KVM_GET_ONE_REG and KVM_SET_ONE_REG cannot be used to access
> > > > +	        the scalable archietctural SVE registers
> > > > +	        KVM_REG_ARM64_SVE_ZREG(), KVM_REG_ARM64_SVE_PREG() or
> > > > +	        KVM_REG_ARM64_SVE_FFR;
> > > > +
> > > > +	      - KVM_REG_ARM64_SVE_VLS may optionally be written using
> > > > +	        KVM_SET_ONE_REG, to modify the set of vector lengths available
> > > > +	        for the vcpu.
> > > > +
> > > > +	   * After KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > > > +
> > > > +	      - the KVM_REG_ARM64_SVE_VLS pseudo-register is immutable, and can
> > > > +	        no longer be written using KVM_SET_ONE_REG.
> > > >  
> > > >  4.83 KVM_ARM_PREFERRED_TARGET
> > > >  
> > > > @@ -3904,6 +3995,41 @@ number of valid entries in the 'entries' array, which is then filled.
> > > >  'index' and 'flags' fields in 'struct kvm_cpuid_entry2' are currently reserved,
> > > >  userspace should not expect to get any particular value there.
> > > >  
> > > > +4.119 KVM_ARM_VCPU_FINALIZE
> > > > +
> > > > +Capability: KVM_CAP_ARM_SVE
> > > 
> > > The KVM_ARM_VCPU_FINALIZE vcpu ioctl isn't SVE specific, so it shouldn't
> > > depend on the SVE cap. It should have it's own cap, or maybe it should
> > > just be an KVM_ARM_VCPU_SVE_FINALIZE ioctl instead, i.e. not general.
> > 
> > This one's a bit annoying.  This would ideally read
> > 
> > Capability: KVM_CAP_ARM_SVE, or any other capability that advertises the
> > availability of a feature that requires KVM_ARM_VCPU_FINALIZE to be used.
> > 
> > (which sounds vague).
> > 
> > We could add a specific cap for KVM_ARM_VCPU_FINALIZE, but that seemed
> > overkill.  Or document KVM_ARM_VCPU_FINALIZE as unconditionally
> > supported, but make the individual feature values cap-dependent.  This
> > works because the symptom of missing support is the same (EINVAL)
> > ragardless of whether it is the specific feature or
> > KVM_ARM_VCPU_FINALIZE that is unsupported.
> > 
> > Thoughts?
> > 
> 
> I like that unconditionally supported idea.

OK, I'll see how to write this up in the documentation.

> > > > +Architectures: arm, arm64
> > > > +Type: vcpu ioctl
> > > > +Parameters: int feature (in)
> > > 
> > > This was called 'what' in the code.
> > 
> > Indeed it is.  I wanted to avoid the implication that this paramter
> > exactly maps onto the KVM_ARM_VCPU_INIT features.  But "what" seemed
> > a bit too vague for the documentation.
> > 
> > Mind you, if lseek() can have a "whence" parameter, perhaps "what" is
> > also acceptable.
> > 
> > OTOH I don't mind changing the name in the code to "feature" if you
> > think that's preferable.
> > 
> > Thoughts?
> 
> I prefer them to be the same, and I think both are fine.

OK.  I'll go with "feature".

> > > > +Returns: 0 on success, -1 on error
> > > > +Errors:
> > > > +  EPERM:     feature not enabled, needs configuration, or already finalized
> > > > +  EINVAL:    unknown feature
> > > > +
> > > > +Recognised values for feature:
> > > > +  arm64      KVM_ARM_VCPU_SVE
> > > > +
> > > > +Finalizes the configuration of the specified vcpu feature.
> > > > +
> > > > +The vcpu must already have been initialised, enabling the affected feature, by
> > > > +means of a successful KVM_ARM_VCPU_INIT call with the appropriate flag set in
> > > > +features[].
> > > > +
> > > > +For affected vcpu features, this is a mandatory step that must be performed
> > > > +before the vcpu is fully usable.
> > > > +
> > > > +Between KVM_ARM_VCPU_INIT and KVM_ARM_VCPU_FINALIZE, the feature may be
> > > > +configured by use of ioctls such as KVM_SET_ONE_REG.  The exact configuration
> > > > +that should be performaned and how to do it are feature-dependent.
> > > > +
> > > > +Other calls that depend on a particular feature being finalized, such as
> > > > +KVM_RUN, KVM_GET_REG_LIST, KVM_GET_ONE_REG and KVM_SET_ONE_REG, will fail with
> > > > +-EPERM unless the feature has already been finalized by means of a
> > > > +KVM_ARM_VCPU_FINALIZE call.
> > > > +
> > > > +See KVM_ARM_VCPU_INIT for details of vcpu features that require finalization
> > > > +using this ioctl.
> > > > +
> > > >  5. The kvm_run structure
> > > >  ------------------------
> > > >
> > > 
> > > I'm still not sure about EPERM vs. ENOEXEC.
> > 
> > There is no need to distinguish the two: this is just a generic "vcpu in
> > wrong state for this to work" error.  I can't think of another subsystem
> > that uses ENOEXEC for this meaning, but it's established in KVM.
> > 
> > If you can't see a reason why we would need these to be distinct
> > errors (?) then I'm happy for this to be ENOEXEC for all cases.
> > 
> 
> I do see some value in keeping them distinct. I think it's just the use
> of EPERM specifically that bothers me, but I don't have that strong of
> an opinion against its use either. So I'll just shut up :)

In an earlier incarnation I had EBADFD, which does kind of mean the
right thing.

If there's not a clear way forward, I may leave this all as-is for now
(but I'll remove the explicit documentation for KVM_{GET,SET}_ONE_REG
error codes to give us more flexibility about this in the future, as
discussed).

Any objection?

Cheers
---Dave

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

* Re: [PATCH v7 27/27] KVM: arm64/sve: Document KVM API extensions for SVE
@ 2019-04-05 13:00           ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05 13:00 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 12:39:37PM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 10:36:17AM +0100, Dave Martin wrote:
> > On Thu, Apr 04, 2019 at 11:09:21PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:52PM +0000, Dave Martin wrote:
> > > > This patch adds sections to the KVM API documentation describing
> > > > the extensions for supporting the Scalable Vector Extension (SVE)
> > > > in guests.
> > > > 
> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > 
> > > > ---
> > > > 
> > > > Changes since v5:
> > > > 
> > > >  * Document KVM_ARM_VCPU_FINALIZE and its interactions with SVE.
> > > > ---
> > > >  Documentation/virtual/kvm/api.txt | 132 +++++++++++++++++++++++++++++++++++++-
> > > >  1 file changed, 129 insertions(+), 3 deletions(-)
> > > > 
> > > > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> > > > index cd920dd..68509de 100644
> > > > --- a/Documentation/virtual/kvm/api.txt
> > > > +++ b/Documentation/virtual/kvm/api.txt
> > > > @@ -1873,6 +1873,7 @@ Parameters: struct kvm_one_reg (in)
> > > >  Returns: 0 on success, negative value on failure
> > > >  Errors:
> > > >    ENOENT:   no such register
> > > > +  EPERM:    register access forbidden for architecture-dependent reasons
> > > >    EINVAL:   other errors, such as bad size encoding for a known register
> > > >  
> > > >  struct kvm_one_reg {
> > > > @@ -2127,13 +2128,20 @@ Specifically:
> > > >    0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
> > > >    0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
> > > >    0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
> > > > -  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]
> > > > -  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]
> > > > +  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]    (*)
> > > > +  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]    (*)
> > > >      ...
> > > > -  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]
> > > > +  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]   (*)
> > > >    0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
> > > >    0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
> > > >  
> > > > +(*) These encodings are not accepted for SVE-enabled vcpus.  See
> > > > +    KVM_ARM_VCPU_INIT.
> > > > +
> > > > +    The equivalent register content can be accessed via bits [127:0] of
> > > > +    the corresponding SVE Zn registers instead for vcpus that have SVE
> > > > +    enabled (see below).
> > > > +
> > > >  arm64 CCSIDR registers are demultiplexed by CSSELR value:
> > > >    0x6020 0000 0011 00 <csselr:8>
> > > >  
> > > > @@ -2143,6 +2151,61 @@ arm64 system registers have the following id bit patterns:
> > > >  arm64 firmware pseudo-registers have the following bit pattern:
> > > >    0x6030 0000 0014 <regno:16>
> > > >  
> > > > +arm64 SVE registers have the following bit patterns:
> > > > +  0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> > > > +  0x6050 0000 0015 04 <n:4> <slice:5>   Pn bits[256*slice + 255 : 256*slice]
> > > > +  0x6050 0000 0015 060 <slice:5>        FFR bits[256*slice + 255 : 256*slice]
> > > > +  0x6060 0000 0015 ffff                 KVM_REG_ARM64_SVE_VLS pseudo-register
> > > > +
> > > > +Access to slices beyond the maximum vector length configured for the
> > > > +vcpu (i.e., where 16 * slice >= max_vq (**)) will fail with ENOENT.
> > > 
> > > I've been doing pretty well keeping track of the 16's, 128's, VL's and
> > > VQ's, but this example lost me. Also, should it be >= or just > ?
> > 
> > It should be >=.  It's analogous to not being allowed to derefence an
> > array index that is >= the size of the array.
> > 
> > Also, the 16 here is not the number of bytes per quadword (as it often
> > does with all things SVE), but the number of quadwords per 2048-bit
> > KVM register slice.
> > 
> > To make matters worse (**) resembles some weird C syntax.
> > 
> > Maybe this would be less confusing written as
> > 
> >     Access to register IDs where 2048 * slice >= 128 * max_vq will fail
> >     with ENOENT.  max_vq is the vcpu's maximum supported vector length
> >     in 128-bit quadwords: see (**) below.
> > 
> > Does that help at all?
> 
> Yes. Thanks.

OK, I'll do that.

> 
> > 
> > > 
> > > > +
> > > > +These registers are only accessible on vcpus for which SVE is enabled.
> > > > +See KVM_ARM_VCPU_INIT for details.
> > > > +
> > > > +In addition, except for KVM_REG_ARM64_SVE_VLS, these registers are not
> > > > +accessible until the vcpu's SVE configuration has been finalized
> > > > +using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).  See KVM_ARM_VCPU_INIT
> > > > +and KVM_ARM_VCPU_FINALIZE for more information about this procedure.
> > > > +
> > > > +KVM_REG_ARM64_SVE_VLS is a pseudo-register that allows the set of vector
> > > > +lengths supported by the vcpu to be discovered and configured by
> > > > +userspace.  When transferred to or from user memory via KVM_GET_ONE_REG
> > > > +or KVM_SET_ONE_REG, the value of this register is of type __u64[8], and
> > > > +encodes the set of vector lengths as follows:
> > > > +
> > > > +__u64 vector_lengths[8];
> > > > +
> > > > +if (vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX &&
> > > > +    ((vector_lengths[(vq - 1) / 64] >> ((vq - 1) % 64)) & 1))
> > > > +	/* Vector length vq * 16 bytes supported */
> > > > +else
> > > > +	/* Vector length vq * 16 bytes not supported */
> > > > +
> > > > +(**) The maximum value vq for which the above condition is true is
> > > > +max_vq.  This is the maximum vector length available to the guest on
> > > > +this vcpu, and determines which register slices are visible through
> > > > +this ioctl interface.
> > > > +
> > > > +(See Documentation/arm64/sve.txt for an explanation of the "vq"
> > > > +nomenclature.)
> > > > +
> > > > +KVM_REG_ARM64_SVE_VLS is only accessible after KVM_ARM_VCPU_INIT.
> > > > +KVM_ARM_VCPU_INIT initialises it to the best set of vector lengths that
> > > > +the host supports.
> > > > +
> > > > +Userspace may subsequently modify it if desired until the vcpu's SVE
> > > > +configuration is finalized using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
> > > > +
> > > > +Apart from simply removing all vector lengths from the host set that
> > > > +exceed some value, support for arbitrarily chosen sets of vector lengths
> > > > +is hardware-dependent and may not be available.  Attempting to configure
> > > > +an invalid set of vector lengths via KVM_SET_ONE_REG will fail with
> > > > +EINVAL.
> > > > +
> > > > +After the vcpu's SVE configuration is finalized, further attempts to
> > > > +write this register will fail with EPERM.
> > > > +
> > > >  
> > > >  MIPS registers are mapped using the lower 32 bits.  The upper 16 of that is
> > > >  the register group type:
> > > > @@ -2197,6 +2260,7 @@ Parameters: struct kvm_one_reg (in and out)
> > > >  Returns: 0 on success, negative value on failure
> > > >  Errors:
> > > >    ENOENT:   no such register
> > > > +  EPERM:    register access forbidden for architecture-dependent reasons
> > > >    EINVAL:   other errors, such as bad size encoding for a known register
> > > >  
> > > >  This ioctl allows to receive the value of a single register implemented
> > > > @@ -2690,6 +2754,33 @@ Possible features:
> > > >  	- KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
> > > >  	  Depends on KVM_CAP_ARM_PMU_V3.
> > > >  
> > > > +	- KVM_ARM_VCPU_SVE: Enables SVE for the CPU (arm64 only).
> > > > +	  Depends on KVM_CAP_ARM_SVE.
> > > > +	  Requires KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > > > +
> > > > +	   * After KVM_ARM_VCPU_INIT:
> > > > +
> > > > +	      - KVM_REG_ARM64_SVE_VLS may be read using KVM_GET_ONE_REG: the
> > > > +	        initial value of this pseudo-register indicates the best set of
> > > > +	        vector lengths possible for a vcpu on this host.
> > > > +
> > > > +	   * Before KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > > > +
> > > > +	      - KVM_RUN and KVM_GET_REG_LIST are not available;
> > > > +
> > > > +	      - KVM_GET_ONE_REG and KVM_SET_ONE_REG cannot be used to access
> > > > +	        the scalable archietctural SVE registers
> > > > +	        KVM_REG_ARM64_SVE_ZREG(), KVM_REG_ARM64_SVE_PREG() or
> > > > +	        KVM_REG_ARM64_SVE_FFR;
> > > > +
> > > > +	      - KVM_REG_ARM64_SVE_VLS may optionally be written using
> > > > +	        KVM_SET_ONE_REG, to modify the set of vector lengths available
> > > > +	        for the vcpu.
> > > > +
> > > > +	   * After KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > > > +
> > > > +	      - the KVM_REG_ARM64_SVE_VLS pseudo-register is immutable, and can
> > > > +	        no longer be written using KVM_SET_ONE_REG.
> > > >  
> > > >  4.83 KVM_ARM_PREFERRED_TARGET
> > > >  
> > > > @@ -3904,6 +3995,41 @@ number of valid entries in the 'entries' array, which is then filled.
> > > >  'index' and 'flags' fields in 'struct kvm_cpuid_entry2' are currently reserved,
> > > >  userspace should not expect to get any particular value there.
> > > >  
> > > > +4.119 KVM_ARM_VCPU_FINALIZE
> > > > +
> > > > +Capability: KVM_CAP_ARM_SVE
> > > 
> > > The KVM_ARM_VCPU_FINALIZE vcpu ioctl isn't SVE specific, so it shouldn't
> > > depend on the SVE cap. It should have it's own cap, or maybe it should
> > > just be an KVM_ARM_VCPU_SVE_FINALIZE ioctl instead, i.e. not general.
> > 
> > This one's a bit annoying.  This would ideally read
> > 
> > Capability: KVM_CAP_ARM_SVE, or any other capability that advertises the
> > availability of a feature that requires KVM_ARM_VCPU_FINALIZE to be used.
> > 
> > (which sounds vague).
> > 
> > We could add a specific cap for KVM_ARM_VCPU_FINALIZE, but that seemed
> > overkill.  Or document KVM_ARM_VCPU_FINALIZE as unconditionally
> > supported, but make the individual feature values cap-dependent.  This
> > works because the symptom of missing support is the same (EINVAL)
> > ragardless of whether it is the specific feature or
> > KVM_ARM_VCPU_FINALIZE that is unsupported.
> > 
> > Thoughts?
> > 
> 
> I like that unconditionally supported idea.

OK, I'll see how to write this up in the documentation.

> > > > +Architectures: arm, arm64
> > > > +Type: vcpu ioctl
> > > > +Parameters: int feature (in)
> > > 
> > > This was called 'what' in the code.
> > 
> > Indeed it is.  I wanted to avoid the implication that this paramter
> > exactly maps onto the KVM_ARM_VCPU_INIT features.  But "what" seemed
> > a bit too vague for the documentation.
> > 
> > Mind you, if lseek() can have a "whence" parameter, perhaps "what" is
> > also acceptable.
> > 
> > OTOH I don't mind changing the name in the code to "feature" if you
> > think that's preferable.
> > 
> > Thoughts?
> 
> I prefer them to be the same, and I think both are fine.

OK.  I'll go with "feature".

> > > > +Returns: 0 on success, -1 on error
> > > > +Errors:
> > > > +  EPERM:     feature not enabled, needs configuration, or already finalized
> > > > +  EINVAL:    unknown feature
> > > > +
> > > > +Recognised values for feature:
> > > > +  arm64      KVM_ARM_VCPU_SVE
> > > > +
> > > > +Finalizes the configuration of the specified vcpu feature.
> > > > +
> > > > +The vcpu must already have been initialised, enabling the affected feature, by
> > > > +means of a successful KVM_ARM_VCPU_INIT call with the appropriate flag set in
> > > > +features[].
> > > > +
> > > > +For affected vcpu features, this is a mandatory step that must be performed
> > > > +before the vcpu is fully usable.
> > > > +
> > > > +Between KVM_ARM_VCPU_INIT and KVM_ARM_VCPU_FINALIZE, the feature may be
> > > > +configured by use of ioctls such as KVM_SET_ONE_REG.  The exact configuration
> > > > +that should be performaned and how to do it are feature-dependent.
> > > > +
> > > > +Other calls that depend on a particular feature being finalized, such as
> > > > +KVM_RUN, KVM_GET_REG_LIST, KVM_GET_ONE_REG and KVM_SET_ONE_REG, will fail with
> > > > +-EPERM unless the feature has already been finalized by means of a
> > > > +KVM_ARM_VCPU_FINALIZE call.
> > > > +
> > > > +See KVM_ARM_VCPU_INIT for details of vcpu features that require finalization
> > > > +using this ioctl.
> > > > +
> > > >  5. The kvm_run structure
> > > >  ------------------------
> > > >
> > > 
> > > I'm still not sure about EPERM vs. ENOEXEC.
> > 
> > There is no need to distinguish the two: this is just a generic "vcpu in
> > wrong state for this to work" error.  I can't think of another subsystem
> > that uses ENOEXEC for this meaning, but it's established in KVM.
> > 
> > If you can't see a reason why we would need these to be distinct
> > errors (?) then I'm happy for this to be ENOEXEC for all cases.
> > 
> 
> I do see some value in keeping them distinct. I think it's just the use
> of EPERM specifically that bothers me, but I don't have that strong of
> an opinion against its use either. So I'll just shut up :)

In an earlier incarnation I had EBADFD, which does kind of mean the
right thing.

If there's not a clear way forward, I may leave this all as-is for now
(but I'll remove the explicit documentation for KVM_{GET,SET}_ONE_REG
error codes to give us more flexibility about this in the future, as
discussed).

Any objection?

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
  2019-04-05 10:22         ` Andrew Jones
@ 2019-04-05 14:06           ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05 14:06 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 12:22:04PM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 10:36:10AM +0100, Dave Martin wrote:
> > On Thu, Apr 04, 2019 at 10:31:09PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> > > > This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> > > > allow userspace to set and query the set of vector lengths visible
> > > > to the guest.
> > > > 
> > > > In the future, multiple register slices per SVE register may be
> > > > visible through the ioctl interface.  Once the set of slices has
> > > > been determined we would not be able to allow the vector length set
> > > > to be changed any more, in order to avoid userspace seeing
> > > > inconsistent sets of registers.  For this reason, this patch adds
> > > > support for explicit finalization of the SVE configuration via the
> > > > KVM_ARM_VCPU_FINALIZE ioctl.
> > > > 
> > > > Finalization is the proper place to allocate the SVE register state
> > > > storage in vcpu->arch.sve_state, so this patch adds that as
> > > > appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> > > > was previously a no-op on arm64.
> > > > 
> > > > To simplify the logic for determining what vector lengths can be
> > > > supported, some code is added to KVM init to work this out, in the
> > > > kvm_arm_init_arch_resources() hook.
> > > > 
> > > > The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> > > > Subsequent patches will allow SVE to be turned on for guest vcpus,
> > > > making it visible.
> > > > 
> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > 
> > [...]
> > 
> > > > diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> > 
> > [...]
> > 
> > > > +/*
> > > > + * Finalize vcpu's maximum SVE vector length, allocating
> > > > + * vcpu->arch.sve_state as necessary.
> > > > + */
> > > > +static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
> > > > +{
> > > > +	void *buf;
> > > > +	unsigned int vl;
> > > > +
> > > > +	vl = vcpu->arch.sve_max_vl;
> > > > +
> > > > +	/*
> > > > +	 * Resposibility for these properties is shared between
> > > > +	 * kvm_arm_init_arch_resources(), kvm_vcpu_enable_sve() and
> > > > +	 * set_sve_vls().  Double-check here just to be sure:
> > > > +	 */
> > > > +	if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl ||
> > > > +		    vl > SVE_VL_ARCH_MAX))
> > > > +		return -EIO;
> > > > +
> > > > +	buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL);
> > > > +	if (!buf)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	vcpu->arch.sve_state = buf;
> > > > +	vcpu->arch.flags |= KVM_ARM64_VCPU_SVE_FINALIZED;
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what)
> > > > +{
> > > > +	switch (what) {
> > > > +	case KVM_ARM_VCPU_SVE:
> > > > +		if (!vcpu_has_sve(vcpu))
> > > > +			return -EINVAL;
> > > > +
> > > > +		if (kvm_arm_vcpu_sve_finalized(vcpu))
> > > > +			return -EPERM;
> > > > +
> > > > +		return kvm_vcpu_finalize_sve(vcpu);
> > > 
> > > In the next patch I see that we already have KVM_ARM64_GUEST_HAS_SVE
> > > set in vcpu->arch.flags at this point. So if this kvm_vcpu_finalize_sve()
> > > call fails, shouldn't we unset KVM_ARM64_GUEST_HAS_SVE and anything
> > > else used to indicate the vcpu has sve?
> > 
> > If this fails, either userspace did the wrong thing, or there was some
> > fatal error (like the ENOMEM case).  Either way, the vcpu is not runnable
> > and userspace is expected to bail out.
> > 
> > Further, KVM_ARM_VCPU_INIT fixes the set of features requested by
> > userspace: we shouldn't change the set of features under userspace's
> > feet and try to limp on somehow.  We have no means for userspace to find
> > out that some features went away in the meantime...
> > 
> > So, what would you be trying to achieve with this change?
> 
> Being able to do additional vcpu ioctls with only partially initialized
> sve (sve_state is still null, but we otherwise believe the vcpu has sve).
> That sounds risky. Although I see we only set KVM_ARM64_VCPU_SVE_FINALIZED
> when everything, like the memory allocation, succeeds, so we're probably
> fine. Indeed having KVM_ARM64_GUEST_HAS_SVE and not KVM_ARM64_VCPU_SVE_FINALIZED
> is likely the safest vcpu state for a vcpu that failed to finalize sve.

This was my rationale: every non-trivial operation that is affected by
SVE operation checks for kvm_arm_vcpu_sve_finalized(): accessing
KVM_REG_ARM64_SVE_VLS should be the only exception.

Of course, people might forget that in new code, but I think all the
major ABI code paths that are likely to exist for SVE are already there
now.

Does this sound OK, or do you still have concerns?

Clearing KVM_ARM64_GUEST_HAS_SVE could be done on finalization failure;
it just feels a bit weird.

Cheers
---Dave

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

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
@ 2019-04-05 14:06           ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05 14:06 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 12:22:04PM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 10:36:10AM +0100, Dave Martin wrote:
> > On Thu, Apr 04, 2019 at 10:31:09PM +0200, Andrew Jones wrote:
> > > On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> > > > This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> > > > allow userspace to set and query the set of vector lengths visible
> > > > to the guest.
> > > > 
> > > > In the future, multiple register slices per SVE register may be
> > > > visible through the ioctl interface.  Once the set of slices has
> > > > been determined we would not be able to allow the vector length set
> > > > to be changed any more, in order to avoid userspace seeing
> > > > inconsistent sets of registers.  For this reason, this patch adds
> > > > support for explicit finalization of the SVE configuration via the
> > > > KVM_ARM_VCPU_FINALIZE ioctl.
> > > > 
> > > > Finalization is the proper place to allocate the SVE register state
> > > > storage in vcpu->arch.sve_state, so this patch adds that as
> > > > appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> > > > was previously a no-op on arm64.
> > > > 
> > > > To simplify the logic for determining what vector lengths can be
> > > > supported, some code is added to KVM init to work this out, in the
> > > > kvm_arm_init_arch_resources() hook.
> > > > 
> > > > The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> > > > Subsequent patches will allow SVE to be turned on for guest vcpus,
> > > > making it visible.
> > > > 
> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > 
> > [...]
> > 
> > > > diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> > 
> > [...]
> > 
> > > > +/*
> > > > + * Finalize vcpu's maximum SVE vector length, allocating
> > > > + * vcpu->arch.sve_state as necessary.
> > > > + */
> > > > +static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
> > > > +{
> > > > +	void *buf;
> > > > +	unsigned int vl;
> > > > +
> > > > +	vl = vcpu->arch.sve_max_vl;
> > > > +
> > > > +	/*
> > > > +	 * Resposibility for these properties is shared between
> > > > +	 * kvm_arm_init_arch_resources(), kvm_vcpu_enable_sve() and
> > > > +	 * set_sve_vls().  Double-check here just to be sure:
> > > > +	 */
> > > > +	if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl ||
> > > > +		    vl > SVE_VL_ARCH_MAX))
> > > > +		return -EIO;
> > > > +
> > > > +	buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL);
> > > > +	if (!buf)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	vcpu->arch.sve_state = buf;
> > > > +	vcpu->arch.flags |= KVM_ARM64_VCPU_SVE_FINALIZED;
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what)
> > > > +{
> > > > +	switch (what) {
> > > > +	case KVM_ARM_VCPU_SVE:
> > > > +		if (!vcpu_has_sve(vcpu))
> > > > +			return -EINVAL;
> > > > +
> > > > +		if (kvm_arm_vcpu_sve_finalized(vcpu))
> > > > +			return -EPERM;
> > > > +
> > > > +		return kvm_vcpu_finalize_sve(vcpu);
> > > 
> > > In the next patch I see that we already have KVM_ARM64_GUEST_HAS_SVE
> > > set in vcpu->arch.flags at this point. So if this kvm_vcpu_finalize_sve()
> > > call fails, shouldn't we unset KVM_ARM64_GUEST_HAS_SVE and anything
> > > else used to indicate the vcpu has sve?
> > 
> > If this fails, either userspace did the wrong thing, or there was some
> > fatal error (like the ENOMEM case).  Either way, the vcpu is not runnable
> > and userspace is expected to bail out.
> > 
> > Further, KVM_ARM_VCPU_INIT fixes the set of features requested by
> > userspace: we shouldn't change the set of features under userspace's
> > feet and try to limp on somehow.  We have no means for userspace to find
> > out that some features went away in the meantime...
> > 
> > So, what would you be trying to achieve with this change?
> 
> Being able to do additional vcpu ioctls with only partially initialized
> sve (sve_state is still null, but we otherwise believe the vcpu has sve).
> That sounds risky. Although I see we only set KVM_ARM64_VCPU_SVE_FINALIZED
> when everything, like the memory allocation, succeeds, so we're probably
> fine. Indeed having KVM_ARM64_GUEST_HAS_SVE and not KVM_ARM64_VCPU_SVE_FINALIZED
> is likely the safest vcpu state for a vcpu that failed to finalize sve.

This was my rationale: every non-trivial operation that is affected by
SVE operation checks for kvm_arm_vcpu_sve_finalized(): accessing
KVM_REG_ARM64_SVE_VLS should be the only exception.

Of course, people might forget that in new code, but I think all the
major ABI code paths that are likely to exist for SVE are already there
now.

Does this sound OK, or do you still have concerns?

Clearing KVM_ARM64_GUEST_HAS_SVE could be done on finalization failure;
it just feels a bit weird.

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
  2019-04-05 12:54           ` Dave Martin
@ 2019-04-05 15:33             ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-05 15:33 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 01:54:13PM +0100, Dave Martin wrote:
> On Fri, Apr 05, 2019 at 12:14:51PM +0200, Andrew Jones wrote:
> > On Fri, Apr 05, 2019 at 10:36:03AM +0100, Dave Martin wrote:
> > > On Thu, Apr 04, 2019 at 10:18:54PM +0200, Andrew Jones wrote:
> > > > On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> > > > > This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> > > > > allow userspace to set and query the set of vector lengths visible
> > > > > to the guest.
> > > > > 
> > > > > In the future, multiple register slices per SVE register may be
> > > > > visible through the ioctl interface.  Once the set of slices has
> > > > > been determined we would not be able to allow the vector length set
> > > > > to be changed any more, in order to avoid userspace seeing
> > > > > inconsistent sets of registers.  For this reason, this patch adds
> > > > > support for explicit finalization of the SVE configuration via the
> > > > > KVM_ARM_VCPU_FINALIZE ioctl.
> > > > > 
> > > > > Finalization is the proper place to allocate the SVE register state
> > > > > storage in vcpu->arch.sve_state, so this patch adds that as
> > > > > appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> > > > > was previously a no-op on arm64.
> > > > > 
> > > > > To simplify the logic for determining what vector lengths can be
> > > > > supported, some code is added to KVM init to work this out, in the
> > > > > kvm_arm_init_arch_resources() hook.
> > > > > 
> > > > > The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> > > > > Subsequent patches will allow SVE to be turned on for guest vcpus,
> > > > > making it visible.
> > > > > 
> > > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > > > 
> > > > > ---
> > > 
> > > [...]
> > > 
> > > > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > > > index 2aa80a5..086ab05 100644
> > > > > --- a/arch/arm64/kvm/guest.c
> > > > > +++ b/arch/arm64/kvm/guest.c
> > > > > @@ -206,6 +206,73 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > > >  	return err;
> > > > >  }
> > > > >  
> > > > > +#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64)
> > > > > +#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64)
> > > > > +
> > > > > +static bool vq_present(
> > > > > +	const u64 (*const vqs)[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)],
> > > > > +	unsigned int vq)
> > > > > +{
> > > > > +	return (*vqs)[vq_word(vq)] & vq_mask(vq);
> > > > > +}
> > > > > +
> > > > > +static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > > > +{
> > > > > +	unsigned int max_vq, vq;
> > > > > +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> > > > > +
> > > > > +	if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl)))
> > > > > +		return -EINVAL;
> > > > > +
> > > > > +	memset(vqs, 0, sizeof(vqs));
> > > > > +
> > > > > +	max_vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
> > > > > +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > > > > +		if (sve_vq_available(vq))
> > > > > +			vqs[vq_word(vq)] |= vq_mask(vq);
> > > > > +
> > > > > +	if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs)))
> > > > > +		return -EFAULT;
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > > > +{
> > > > > +	unsigned int max_vq, vq;
> > > > > +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> > > > 
> > > > There are three of these long 'DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)'.
> > > > A macro is probably warranted.
> > > 
> > > Fair point.  These are a bit cumbersome.  How about:
> > > 
> > > #define SVE_VLS_WORDS DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)
> > > 
> > > Annoyingly, this is virtually identical to a Linux bitmap: the base type
> > > is u64 instead of unsigned long; otherwise there's no intentional
> > > difference.
> > 
> > Yeah, I noticed it was a reinvented bitmap, but I liked that it was,
> > because, for the userspace api, removing the bitmap abstractions
> > ensures we know what is what and where exactly it is.
> 
> Agreed.  I thought of using the bitmap API inside the kernel, but even
> if this is arm64-specific code, it made me uneasy: the compiler doesn't
> necessarily think that u64 and unsigned long are the same type even if
> they're both 64-bit, so there's the potential for weird optimisations to
> happen.
> 
> > > (Aside: do you know why the KVM API insists on everything being u64?
> > > This makes sense for non-native types (like guest registers), but not
> > > for native things like host userspace addresses etc.)
> > 
> > Would that work when the kernel is 64-bit and the userspace is 32? I
> > personally like the interfaces being explicit with type size, as it
> > removes the brain burden of translating long and int when moving arch
> > to arch and kernel to userspace.
> 
> Ah yes, the joys of compat.  And ioctl.  Ignore me.
> 
> > > > > +
> > > > > +	if (kvm_arm_vcpu_sve_finalized(vcpu))
> > > > > +		return -EPERM; /* too late! */
> > > > > +
> > > > > +	if (WARN_ON(vcpu->arch.sve_state))
> > > > > +		return -EINVAL;
> > > > > +
> > > > > +	if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs)))
> > > > > +		return -EFAULT;
> > > > > +
> > > > > +	max_vq = 0;
> > > > > +	for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq)
> > > > > +		if (vq_present(&vqs, vq))
> > > > > +			max_vq = vq;
> > > > > +
> > > > > +	if (max_vq > sve_vq_from_vl(kvm_sve_max_vl))
> > > > > +		return -EINVAL;
> > > > > +
> > > > > +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > > > > +		if (vq_present(&vqs, vq) != sve_vq_available(vq))
> > > > > +			return -EINVAL;
> > > > 
> > > > What about supporting the optional non-power-of-2 vector lengths? For
> > > > example, if the maximum VL is 512, then in addition to 512, 128, and
> > > > 256 there could be a 384. If we plan to start a guest on a machine
> > > > that has all four and then migrate it to a machine that only has
> > > > 128,256,512 we would want to set the VL set to 128,256,512, even on
> > > > the machine that supports 384. If I understand the above test correctly,
> > > > then that wouldn't work.
> > > 
> > > This is exactly what the code is trying to forbid, though it may not be
> > > obvious here why.
> > > 
> > > The trouble is, we can't correctly emulate a vcpu supporting
> > > {128,256,512} on hardware that also supports 384-bit vectors: the
> > > architecture says that the vector length you get is determined by
> > > rounding ZCR_EL1.LEN down to the next vector length actually
> > > supported.
> > > 
> > > So, the guest would expect writing ZCR_EL1.LEN = 2 to give a vector
> > > length of 256 bits, whereas on this hardware the actual resulting
> > > vector length would be 384 bits.
> > 
> > Oh, I see.
> > 
> > > 
> > > sve_probe_vqs() relies on this property to detect the set of available
> > > vector lengths.  Simple, bare-metal guests might also just set
> > > ZCR_ELx.LEN = 0x1ff to just get the max available.
> > > 
> > > 
> > > The architecture says categorically that the set of vector lengths
> > > supported is a fixed property of the (emulated) hardware -- we can't
> > > having this changing under the guest's feet.
> > > 
> > > Fixing this would require an archietctural way to filter out individual
> > > vector lengths from the supported set, not just a way to clamp the
> > > maximum (which is all ZCR_EL2.LEN gives us).
> > > 
> > > The general expectation is that sanely designed cluster will be
> > > "homogeneous enough" and won't trigger this check -- it's here
> > > just in case.
> > 
> > Data centers evolve as they expand and hardware is replaced. I wouldn't
> > expect them to stay homogeneous for long, not without keeping them that
> > way at substantial cost. This isn't the first thing that is forcing Arm
> > virt data centers to be homogeneous (we still use qemu's '-cpu host'),
> > but it's disappointing to have yet another one.
> 
> This may or may not be a problem in practive, since I suspect
> implementations that support non-power-of-two vector lengths may be in
> the minority anyway.
> 
> The ARM Fast Model and probably QEMU can do it, but people are less
> likely to try to build a high-performance cluster out of those...
> 
> > > I attempt to capture this in api.txt, leaving the door open in case the
> > > architecture gives a way to support this in future:
> > > 
> > >   | KVM_REG_ARM64_SVE_VLS
> > >   | 
> > >   | [...]
> > >   | 
> > >   | Apart from simply removing all vector lengths from the host set
> > >   | that exceed some value, support for arbitrarily chosen sets of
> > >   | vector lengths is hardware-dependent and may not be available.
> > >   | Attempting to configure an invalid set of vector lengths via
> > >   | KVM_SET_ONE_REG will fail with EINVAL.
> > > 
> > > Is this enough, or do you think more explanation is needed somewhere?
> > 
> > I saw that before, so I guess more is needed :) What you wrote above about
> > how we can only shorten the list due to how zcr_el1.len works was the
> > missing piece for me. Maybe that should be integrated into the text
> > somehow.
> 
> If you think the above is enough for ABI documentation purposes, I will
> aim to drop the following comment into set_sve_vls():
> 
> 	/*
> 	 * Vector lengths supported by the host can't currently be
> 	 * hidden from the guest individually: instead we can only set a
> 	 * maxmium via ZCR_EL2.LEN.  So, make sure the available vector
> 	 * length match the set requested exactly up to the requested
> 	 * maximum:
> 	 */
> 	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> 		if (vq_present(&vqs, vq) != sve_vq_available(vq))
> 			return -EINVAL;
> 
> Do you think that's enough?
>

That works for me, and I'm glad I now have it understood, because this
will be a key piece of the QEMU uesr interface to work out. I.e. we
need to be able to provide the user with the current host's VL list
up to the max virtualizable VL when queried, allow them to choose a max
from that list for a guest, and then commit to that VL sublist for the
guest. I'll dive into QEMU on Monday, hopefully I won't drown there.

drew

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

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
@ 2019-04-05 15:33             ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-05 15:33 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 01:54:13PM +0100, Dave Martin wrote:
> On Fri, Apr 05, 2019 at 12:14:51PM +0200, Andrew Jones wrote:
> > On Fri, Apr 05, 2019 at 10:36:03AM +0100, Dave Martin wrote:
> > > On Thu, Apr 04, 2019 at 10:18:54PM +0200, Andrew Jones wrote:
> > > > On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> > > > > This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> > > > > allow userspace to set and query the set of vector lengths visible
> > > > > to the guest.
> > > > > 
> > > > > In the future, multiple register slices per SVE register may be
> > > > > visible through the ioctl interface.  Once the set of slices has
> > > > > been determined we would not be able to allow the vector length set
> > > > > to be changed any more, in order to avoid userspace seeing
> > > > > inconsistent sets of registers.  For this reason, this patch adds
> > > > > support for explicit finalization of the SVE configuration via the
> > > > > KVM_ARM_VCPU_FINALIZE ioctl.
> > > > > 
> > > > > Finalization is the proper place to allocate the SVE register state
> > > > > storage in vcpu->arch.sve_state, so this patch adds that as
> > > > > appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> > > > > was previously a no-op on arm64.
> > > > > 
> > > > > To simplify the logic for determining what vector lengths can be
> > > > > supported, some code is added to KVM init to work this out, in the
> > > > > kvm_arm_init_arch_resources() hook.
> > > > > 
> > > > > The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> > > > > Subsequent patches will allow SVE to be turned on for guest vcpus,
> > > > > making it visible.
> > > > > 
> > > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > > > 
> > > > > ---
> > > 
> > > [...]
> > > 
> > > > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> > > > > index 2aa80a5..086ab05 100644
> > > > > --- a/arch/arm64/kvm/guest.c
> > > > > +++ b/arch/arm64/kvm/guest.c
> > > > > @@ -206,6 +206,73 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > > >  	return err;
> > > > >  }
> > > > >  
> > > > > +#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64)
> > > > > +#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64)
> > > > > +
> > > > > +static bool vq_present(
> > > > > +	const u64 (*const vqs)[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)],
> > > > > +	unsigned int vq)
> > > > > +{
> > > > > +	return (*vqs)[vq_word(vq)] & vq_mask(vq);
> > > > > +}
> > > > > +
> > > > > +static int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > > > +{
> > > > > +	unsigned int max_vq, vq;
> > > > > +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> > > > > +
> > > > > +	if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl)))
> > > > > +		return -EINVAL;
> > > > > +
> > > > > +	memset(vqs, 0, sizeof(vqs));
> > > > > +
> > > > > +	max_vq = sve_vq_from_vl(vcpu->arch.sve_max_vl);
> > > > > +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > > > > +		if (sve_vq_available(vq))
> > > > > +			vqs[vq_word(vq)] |= vq_mask(vq);
> > > > > +
> > > > > +	if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs)))
> > > > > +		return -EFAULT;
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> > > > > +{
> > > > > +	unsigned int max_vq, vq;
> > > > > +	u64 vqs[DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)];
> > > > 
> > > > There are three of these long 'DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)'.
> > > > A macro is probably warranted.
> > > 
> > > Fair point.  These are a bit cumbersome.  How about:
> > > 
> > > #define SVE_VLS_WORDS DIV_ROUND_UP(SVE_VQ_MAX - SVE_VQ_MIN + 1, 64)
> > > 
> > > Annoyingly, this is virtually identical to a Linux bitmap: the base type
> > > is u64 instead of unsigned long; otherwise there's no intentional
> > > difference.
> > 
> > Yeah, I noticed it was a reinvented bitmap, but I liked that it was,
> > because, for the userspace api, removing the bitmap abstractions
> > ensures we know what is what and where exactly it is.
> 
> Agreed.  I thought of using the bitmap API inside the kernel, but even
> if this is arm64-specific code, it made me uneasy: the compiler doesn't
> necessarily think that u64 and unsigned long are the same type even if
> they're both 64-bit, so there's the potential for weird optimisations to
> happen.
> 
> > > (Aside: do you know why the KVM API insists on everything being u64?
> > > This makes sense for non-native types (like guest registers), but not
> > > for native things like host userspace addresses etc.)
> > 
> > Would that work when the kernel is 64-bit and the userspace is 32? I
> > personally like the interfaces being explicit with type size, as it
> > removes the brain burden of translating long and int when moving arch
> > to arch and kernel to userspace.
> 
> Ah yes, the joys of compat.  And ioctl.  Ignore me.
> 
> > > > > +
> > > > > +	if (kvm_arm_vcpu_sve_finalized(vcpu))
> > > > > +		return -EPERM; /* too late! */
> > > > > +
> > > > > +	if (WARN_ON(vcpu->arch.sve_state))
> > > > > +		return -EINVAL;
> > > > > +
> > > > > +	if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs)))
> > > > > +		return -EFAULT;
> > > > > +
> > > > > +	max_vq = 0;
> > > > > +	for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq)
> > > > > +		if (vq_present(&vqs, vq))
> > > > > +			max_vq = vq;
> > > > > +
> > > > > +	if (max_vq > sve_vq_from_vl(kvm_sve_max_vl))
> > > > > +		return -EINVAL;
> > > > > +
> > > > > +	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > > > > +		if (vq_present(&vqs, vq) != sve_vq_available(vq))
> > > > > +			return -EINVAL;
> > > > 
> > > > What about supporting the optional non-power-of-2 vector lengths? For
> > > > example, if the maximum VL is 512, then in addition to 512, 128, and
> > > > 256 there could be a 384. If we plan to start a guest on a machine
> > > > that has all four and then migrate it to a machine that only has
> > > > 128,256,512 we would want to set the VL set to 128,256,512, even on
> > > > the machine that supports 384. If I understand the above test correctly,
> > > > then that wouldn't work.
> > > 
> > > This is exactly what the code is trying to forbid, though it may not be
> > > obvious here why.
> > > 
> > > The trouble is, we can't correctly emulate a vcpu supporting
> > > {128,256,512} on hardware that also supports 384-bit vectors: the
> > > architecture says that the vector length you get is determined by
> > > rounding ZCR_EL1.LEN down to the next vector length actually
> > > supported.
> > > 
> > > So, the guest would expect writing ZCR_EL1.LEN = 2 to give a vector
> > > length of 256 bits, whereas on this hardware the actual resulting
> > > vector length would be 384 bits.
> > 
> > Oh, I see.
> > 
> > > 
> > > sve_probe_vqs() relies on this property to detect the set of available
> > > vector lengths.  Simple, bare-metal guests might also just set
> > > ZCR_ELx.LEN = 0x1ff to just get the max available.
> > > 
> > > 
> > > The architecture says categorically that the set of vector lengths
> > > supported is a fixed property of the (emulated) hardware -- we can't
> > > having this changing under the guest's feet.
> > > 
> > > Fixing this would require an archietctural way to filter out individual
> > > vector lengths from the supported set, not just a way to clamp the
> > > maximum (which is all ZCR_EL2.LEN gives us).
> > > 
> > > The general expectation is that sanely designed cluster will be
> > > "homogeneous enough" and won't trigger this check -- it's here
> > > just in case.
> > 
> > Data centers evolve as they expand and hardware is replaced. I wouldn't
> > expect them to stay homogeneous for long, not without keeping them that
> > way at substantial cost. This isn't the first thing that is forcing Arm
> > virt data centers to be homogeneous (we still use qemu's '-cpu host'),
> > but it's disappointing to have yet another one.
> 
> This may or may not be a problem in practive, since I suspect
> implementations that support non-power-of-two vector lengths may be in
> the minority anyway.
> 
> The ARM Fast Model and probably QEMU can do it, but people are less
> likely to try to build a high-performance cluster out of those...
> 
> > > I attempt to capture this in api.txt, leaving the door open in case the
> > > architecture gives a way to support this in future:
> > > 
> > >   | KVM_REG_ARM64_SVE_VLS
> > >   | 
> > >   | [...]
> > >   | 
> > >   | Apart from simply removing all vector lengths from the host set
> > >   | that exceed some value, support for arbitrarily chosen sets of
> > >   | vector lengths is hardware-dependent and may not be available.
> > >   | Attempting to configure an invalid set of vector lengths via
> > >   | KVM_SET_ONE_REG will fail with EINVAL.
> > > 
> > > Is this enough, or do you think more explanation is needed somewhere?
> > 
> > I saw that before, so I guess more is needed :) What you wrote above about
> > how we can only shorten the list due to how zcr_el1.len works was the
> > missing piece for me. Maybe that should be integrated into the text
> > somehow.
> 
> If you think the above is enough for ABI documentation purposes, I will
> aim to drop the following comment into set_sve_vls():
> 
> 	/*
> 	 * Vector lengths supported by the host can't currently be
> 	 * hidden from the guest individually: instead we can only set a
> 	 * maxmium via ZCR_EL2.LEN.  So, make sure the available vector
> 	 * length match the set requested exactly up to the requested
> 	 * maximum:
> 	 */
> 	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> 		if (vq_present(&vqs, vq) != sve_vq_available(vq))
> 			return -EINVAL;
> 
> Do you think that's enough?
>

That works for me, and I'm glad I now have it understood, because this
will be a key piece of the QEMU uesr interface to work out. I.e. we
need to be able to provide the user with the current host's VL list
up to the max virtualizable VL when queried, allow them to choose a max
from that list for a guest, and then commit to that VL sublist for the
guest. I'll dive into QEMU on Monday, hopefully I won't drown there.

drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 27/27] KVM: arm64/sve: Document KVM API extensions for SVE
  2019-04-05 13:00           ` Dave Martin
@ 2019-04-05 15:38             ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-05 15:38 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 02:00:07PM +0100, Dave Martin wrote:
> On Fri, Apr 05, 2019 at 12:39:37PM +0200, Andrew Jones wrote:
> > On Fri, Apr 05, 2019 at 10:36:17AM +0100, Dave Martin wrote:
> > > On Thu, Apr 04, 2019 at 11:09:21PM +0200, Andrew Jones wrote:
> > > > On Fri, Mar 29, 2019 at 01:00:52PM +0000, Dave Martin wrote:
> > > > > This patch adds sections to the KVM API documentation describing
> > > > > the extensions for supporting the Scalable Vector Extension (SVE)
> > > > > in guests.
> > > > > 
> > > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > > 
> > > > > ---
> > > > > 
> > > > > Changes since v5:
> > > > > 
> > > > >  * Document KVM_ARM_VCPU_FINALIZE and its interactions with SVE.
> > > > > ---
> > > > >  Documentation/virtual/kvm/api.txt | 132 +++++++++++++++++++++++++++++++++++++-
> > > > >  1 file changed, 129 insertions(+), 3 deletions(-)
> > > > > 
> > > > > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> > > > > index cd920dd..68509de 100644
> > > > > --- a/Documentation/virtual/kvm/api.txt
> > > > > +++ b/Documentation/virtual/kvm/api.txt
> > > > > @@ -1873,6 +1873,7 @@ Parameters: struct kvm_one_reg (in)
> > > > >  Returns: 0 on success, negative value on failure
> > > > >  Errors:
> > > > >    ENOENT:   no such register
> > > > > +  EPERM:    register access forbidden for architecture-dependent reasons
> > > > >    EINVAL:   other errors, such as bad size encoding for a known register
> > > > >  
> > > > >  struct kvm_one_reg {
> > > > > @@ -2127,13 +2128,20 @@ Specifically:
> > > > >    0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
> > > > >    0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
> > > > >    0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
> > > > > -  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]
> > > > > -  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]
> > > > > +  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]    (*)
> > > > > +  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]    (*)
> > > > >      ...
> > > > > -  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]
> > > > > +  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]   (*)
> > > > >    0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
> > > > >    0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
> > > > >  
> > > > > +(*) These encodings are not accepted for SVE-enabled vcpus.  See
> > > > > +    KVM_ARM_VCPU_INIT.
> > > > > +
> > > > > +    The equivalent register content can be accessed via bits [127:0] of
> > > > > +    the corresponding SVE Zn registers instead for vcpus that have SVE
> > > > > +    enabled (see below).
> > > > > +
> > > > >  arm64 CCSIDR registers are demultiplexed by CSSELR value:
> > > > >    0x6020 0000 0011 00 <csselr:8>
> > > > >  
> > > > > @@ -2143,6 +2151,61 @@ arm64 system registers have the following id bit patterns:
> > > > >  arm64 firmware pseudo-registers have the following bit pattern:
> > > > >    0x6030 0000 0014 <regno:16>
> > > > >  
> > > > > +arm64 SVE registers have the following bit patterns:
> > > > > +  0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> > > > > +  0x6050 0000 0015 04 <n:4> <slice:5>   Pn bits[256*slice + 255 : 256*slice]
> > > > > +  0x6050 0000 0015 060 <slice:5>        FFR bits[256*slice + 255 : 256*slice]
> > > > > +  0x6060 0000 0015 ffff                 KVM_REG_ARM64_SVE_VLS pseudo-register
> > > > > +
> > > > > +Access to slices beyond the maximum vector length configured for the
> > > > > +vcpu (i.e., where 16 * slice >= max_vq (**)) will fail with ENOENT.
> > > > 
> > > > I've been doing pretty well keeping track of the 16's, 128's, VL's and
> > > > VQ's, but this example lost me. Also, should it be >= or just > ?
> > > 
> > > It should be >=.  It's analogous to not being allowed to derefence an
> > > array index that is >= the size of the array.
> > > 
> > > Also, the 16 here is not the number of bytes per quadword (as it often
> > > does with all things SVE), but the number of quadwords per 2048-bit
> > > KVM register slice.
> > > 
> > > To make matters worse (**) resembles some weird C syntax.
> > > 
> > > Maybe this would be less confusing written as
> > > 
> > >     Access to register IDs where 2048 * slice >= 128 * max_vq will fail
> > >     with ENOENT.  max_vq is the vcpu's maximum supported vector length
> > >     in 128-bit quadwords: see (**) below.
> > > 
> > > Does that help at all?
> > 
> > Yes. Thanks.
> 
> OK, I'll do that.
> 
> > 
> > > 
> > > > 
> > > > > +
> > > > > +These registers are only accessible on vcpus for which SVE is enabled.
> > > > > +See KVM_ARM_VCPU_INIT for details.
> > > > > +
> > > > > +In addition, except for KVM_REG_ARM64_SVE_VLS, these registers are not
> > > > > +accessible until the vcpu's SVE configuration has been finalized
> > > > > +using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).  See KVM_ARM_VCPU_INIT
> > > > > +and KVM_ARM_VCPU_FINALIZE for more information about this procedure.
> > > > > +
> > > > > +KVM_REG_ARM64_SVE_VLS is a pseudo-register that allows the set of vector
> > > > > +lengths supported by the vcpu to be discovered and configured by
> > > > > +userspace.  When transferred to or from user memory via KVM_GET_ONE_REG
> > > > > +or KVM_SET_ONE_REG, the value of this register is of type __u64[8], and
> > > > > +encodes the set of vector lengths as follows:
> > > > > +
> > > > > +__u64 vector_lengths[8];
> > > > > +
> > > > > +if (vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX &&
> > > > > +    ((vector_lengths[(vq - 1) / 64] >> ((vq - 1) % 64)) & 1))
> > > > > +	/* Vector length vq * 16 bytes supported */
> > > > > +else
> > > > > +	/* Vector length vq * 16 bytes not supported */
> > > > > +
> > > > > +(**) The maximum value vq for which the above condition is true is
> > > > > +max_vq.  This is the maximum vector length available to the guest on
> > > > > +this vcpu, and determines which register slices are visible through
> > > > > +this ioctl interface.
> > > > > +
> > > > > +(See Documentation/arm64/sve.txt for an explanation of the "vq"
> > > > > +nomenclature.)
> > > > > +
> > > > > +KVM_REG_ARM64_SVE_VLS is only accessible after KVM_ARM_VCPU_INIT.
> > > > > +KVM_ARM_VCPU_INIT initialises it to the best set of vector lengths that
> > > > > +the host supports.
> > > > > +
> > > > > +Userspace may subsequently modify it if desired until the vcpu's SVE
> > > > > +configuration is finalized using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
> > > > > +
> > > > > +Apart from simply removing all vector lengths from the host set that
> > > > > +exceed some value, support for arbitrarily chosen sets of vector lengths
> > > > > +is hardware-dependent and may not be available.  Attempting to configure
> > > > > +an invalid set of vector lengths via KVM_SET_ONE_REG will fail with
> > > > > +EINVAL.
> > > > > +
> > > > > +After the vcpu's SVE configuration is finalized, further attempts to
> > > > > +write this register will fail with EPERM.
> > > > > +
> > > > >  
> > > > >  MIPS registers are mapped using the lower 32 bits.  The upper 16 of that is
> > > > >  the register group type:
> > > > > @@ -2197,6 +2260,7 @@ Parameters: struct kvm_one_reg (in and out)
> > > > >  Returns: 0 on success, negative value on failure
> > > > >  Errors:
> > > > >    ENOENT:   no such register
> > > > > +  EPERM:    register access forbidden for architecture-dependent reasons
> > > > >    EINVAL:   other errors, such as bad size encoding for a known register
> > > > >  
> > > > >  This ioctl allows to receive the value of a single register implemented
> > > > > @@ -2690,6 +2754,33 @@ Possible features:
> > > > >  	- KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
> > > > >  	  Depends on KVM_CAP_ARM_PMU_V3.
> > > > >  
> > > > > +	- KVM_ARM_VCPU_SVE: Enables SVE for the CPU (arm64 only).
> > > > > +	  Depends on KVM_CAP_ARM_SVE.
> > > > > +	  Requires KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > > > > +
> > > > > +	   * After KVM_ARM_VCPU_INIT:
> > > > > +
> > > > > +	      - KVM_REG_ARM64_SVE_VLS may be read using KVM_GET_ONE_REG: the
> > > > > +	        initial value of this pseudo-register indicates the best set of
> > > > > +	        vector lengths possible for a vcpu on this host.
> > > > > +
> > > > > +	   * Before KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > > > > +
> > > > > +	      - KVM_RUN and KVM_GET_REG_LIST are not available;
> > > > > +
> > > > > +	      - KVM_GET_ONE_REG and KVM_SET_ONE_REG cannot be used to access
> > > > > +	        the scalable archietctural SVE registers
> > > > > +	        KVM_REG_ARM64_SVE_ZREG(), KVM_REG_ARM64_SVE_PREG() or
> > > > > +	        KVM_REG_ARM64_SVE_FFR;
> > > > > +
> > > > > +	      - KVM_REG_ARM64_SVE_VLS may optionally be written using
> > > > > +	        KVM_SET_ONE_REG, to modify the set of vector lengths available
> > > > > +	        for the vcpu.
> > > > > +
> > > > > +	   * After KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > > > > +
> > > > > +	      - the KVM_REG_ARM64_SVE_VLS pseudo-register is immutable, and can
> > > > > +	        no longer be written using KVM_SET_ONE_REG.
> > > > >  
> > > > >  4.83 KVM_ARM_PREFERRED_TARGET
> > > > >  
> > > > > @@ -3904,6 +3995,41 @@ number of valid entries in the 'entries' array, which is then filled.
> > > > >  'index' and 'flags' fields in 'struct kvm_cpuid_entry2' are currently reserved,
> > > > >  userspace should not expect to get any particular value there.
> > > > >  
> > > > > +4.119 KVM_ARM_VCPU_FINALIZE
> > > > > +
> > > > > +Capability: KVM_CAP_ARM_SVE
> > > > 
> > > > The KVM_ARM_VCPU_FINALIZE vcpu ioctl isn't SVE specific, so it shouldn't
> > > > depend on the SVE cap. It should have it's own cap, or maybe it should
> > > > just be an KVM_ARM_VCPU_SVE_FINALIZE ioctl instead, i.e. not general.
> > > 
> > > This one's a bit annoying.  This would ideally read
> > > 
> > > Capability: KVM_CAP_ARM_SVE, or any other capability that advertises the
> > > availability of a feature that requires KVM_ARM_VCPU_FINALIZE to be used.
> > > 
> > > (which sounds vague).
> > > 
> > > We could add a specific cap for KVM_ARM_VCPU_FINALIZE, but that seemed
> > > overkill.  Or document KVM_ARM_VCPU_FINALIZE as unconditionally
> > > supported, but make the individual feature values cap-dependent.  This
> > > works because the symptom of missing support is the same (EINVAL)
> > > ragardless of whether it is the specific feature or
> > > KVM_ARM_VCPU_FINALIZE that is unsupported.
> > > 
> > > Thoughts?
> > > 
> > 
> > I like that unconditionally supported idea.
> 
> OK, I'll see how to write this up in the documentation.
> 
> > > > > +Architectures: arm, arm64
> > > > > +Type: vcpu ioctl
> > > > > +Parameters: int feature (in)
> > > > 
> > > > This was called 'what' in the code.
> > > 
> > > Indeed it is.  I wanted to avoid the implication that this paramter
> > > exactly maps onto the KVM_ARM_VCPU_INIT features.  But "what" seemed
> > > a bit too vague for the documentation.
> > > 
> > > Mind you, if lseek() can have a "whence" parameter, perhaps "what" is
> > > also acceptable.
> > > 
> > > OTOH I don't mind changing the name in the code to "feature" if you
> > > think that's preferable.
> > > 
> > > Thoughts?
> > 
> > I prefer them to be the same, and I think both are fine.
> 
> OK.  I'll go with "feature".
> 
> > > > > +Returns: 0 on success, -1 on error
> > > > > +Errors:
> > > > > +  EPERM:     feature not enabled, needs configuration, or already finalized
> > > > > +  EINVAL:    unknown feature
> > > > > +
> > > > > +Recognised values for feature:
> > > > > +  arm64      KVM_ARM_VCPU_SVE
> > > > > +
> > > > > +Finalizes the configuration of the specified vcpu feature.
> > > > > +
> > > > > +The vcpu must already have been initialised, enabling the affected feature, by
> > > > > +means of a successful KVM_ARM_VCPU_INIT call with the appropriate flag set in
> > > > > +features[].
> > > > > +
> > > > > +For affected vcpu features, this is a mandatory step that must be performed
> > > > > +before the vcpu is fully usable.
> > > > > +
> > > > > +Between KVM_ARM_VCPU_INIT and KVM_ARM_VCPU_FINALIZE, the feature may be
> > > > > +configured by use of ioctls such as KVM_SET_ONE_REG.  The exact configuration
> > > > > +that should be performaned and how to do it are feature-dependent.
> > > > > +
> > > > > +Other calls that depend on a particular feature being finalized, such as
> > > > > +KVM_RUN, KVM_GET_REG_LIST, KVM_GET_ONE_REG and KVM_SET_ONE_REG, will fail with
> > > > > +-EPERM unless the feature has already been finalized by means of a
> > > > > +KVM_ARM_VCPU_FINALIZE call.
> > > > > +
> > > > > +See KVM_ARM_VCPU_INIT for details of vcpu features that require finalization
> > > > > +using this ioctl.
> > > > > +
> > > > >  5. The kvm_run structure
> > > > >  ------------------------
> > > > >
> > > > 
> > > > I'm still not sure about EPERM vs. ENOEXEC.
> > > 
> > > There is no need to distinguish the two: this is just a generic "vcpu in
> > > wrong state for this to work" error.  I can't think of another subsystem
> > > that uses ENOEXEC for this meaning, but it's established in KVM.
> > > 
> > > If you can't see a reason why we would need these to be distinct
> > > errors (?) then I'm happy for this to be ENOEXEC for all cases.
> > > 
> > 
> > I do see some value in keeping them distinct. I think it's just the use
> > of EPERM specifically that bothers me, but I don't have that strong of
> > an opinion against its use either. So I'll just shut up :)
> 
> In an earlier incarnation I had EBADFD, which does kind of mean the
> right thing.
> 
> If there's not a clear way forward, I may leave this all as-is for now
> (but I'll remove the explicit documentation for KVM_{GET,SET}_ONE_REG
> error codes to give us more flexibility about this in the future, as
> discussed).
> 
> Any objection?

Nope. Let's do that. EBADFD doesn't sound good, because we're using the FD
without trouble before and even after we attempt these ioctls. I think
EBADFD would indicate that no future ioctl (or read,write) should be
expected to work.

Thanks,
drew

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

* Re: [PATCH v7 27/27] KVM: arm64/sve: Document KVM API extensions for SVE
@ 2019-04-05 15:38             ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-05 15:38 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 02:00:07PM +0100, Dave Martin wrote:
> On Fri, Apr 05, 2019 at 12:39:37PM +0200, Andrew Jones wrote:
> > On Fri, Apr 05, 2019 at 10:36:17AM +0100, Dave Martin wrote:
> > > On Thu, Apr 04, 2019 at 11:09:21PM +0200, Andrew Jones wrote:
> > > > On Fri, Mar 29, 2019 at 01:00:52PM +0000, Dave Martin wrote:
> > > > > This patch adds sections to the KVM API documentation describing
> > > > > the extensions for supporting the Scalable Vector Extension (SVE)
> > > > > in guests.
> > > > > 
> > > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > > 
> > > > > ---
> > > > > 
> > > > > Changes since v5:
> > > > > 
> > > > >  * Document KVM_ARM_VCPU_FINALIZE and its interactions with SVE.
> > > > > ---
> > > > >  Documentation/virtual/kvm/api.txt | 132 +++++++++++++++++++++++++++++++++++++-
> > > > >  1 file changed, 129 insertions(+), 3 deletions(-)
> > > > > 
> > > > > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> > > > > index cd920dd..68509de 100644
> > > > > --- a/Documentation/virtual/kvm/api.txt
> > > > > +++ b/Documentation/virtual/kvm/api.txt
> > > > > @@ -1873,6 +1873,7 @@ Parameters: struct kvm_one_reg (in)
> > > > >  Returns: 0 on success, negative value on failure
> > > > >  Errors:
> > > > >    ENOENT:   no such register
> > > > > +  EPERM:    register access forbidden for architecture-dependent reasons
> > > > >    EINVAL:   other errors, such as bad size encoding for a known register
> > > > >  
> > > > >  struct kvm_one_reg {
> > > > > @@ -2127,13 +2128,20 @@ Specifically:
> > > > >    0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
> > > > >    0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
> > > > >    0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
> > > > > -  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]
> > > > > -  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]
> > > > > +  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]    (*)
> > > > > +  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]    (*)
> > > > >      ...
> > > > > -  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]
> > > > > +  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]   (*)
> > > > >    0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
> > > > >    0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
> > > > >  
> > > > > +(*) These encodings are not accepted for SVE-enabled vcpus.  See
> > > > > +    KVM_ARM_VCPU_INIT.
> > > > > +
> > > > > +    The equivalent register content can be accessed via bits [127:0] of
> > > > > +    the corresponding SVE Zn registers instead for vcpus that have SVE
> > > > > +    enabled (see below).
> > > > > +
> > > > >  arm64 CCSIDR registers are demultiplexed by CSSELR value:
> > > > >    0x6020 0000 0011 00 <csselr:8>
> > > > >  
> > > > > @@ -2143,6 +2151,61 @@ arm64 system registers have the following id bit patterns:
> > > > >  arm64 firmware pseudo-registers have the following bit pattern:
> > > > >    0x6030 0000 0014 <regno:16>
> > > > >  
> > > > > +arm64 SVE registers have the following bit patterns:
> > > > > +  0x6080 0000 0015 00 <n:5> <slice:5>   Zn bits[2048*slice + 2047 : 2048*slice]
> > > > > +  0x6050 0000 0015 04 <n:4> <slice:5>   Pn bits[256*slice + 255 : 256*slice]
> > > > > +  0x6050 0000 0015 060 <slice:5>        FFR bits[256*slice + 255 : 256*slice]
> > > > > +  0x6060 0000 0015 ffff                 KVM_REG_ARM64_SVE_VLS pseudo-register
> > > > > +
> > > > > +Access to slices beyond the maximum vector length configured for the
> > > > > +vcpu (i.e., where 16 * slice >= max_vq (**)) will fail with ENOENT.
> > > > 
> > > > I've been doing pretty well keeping track of the 16's, 128's, VL's and
> > > > VQ's, but this example lost me. Also, should it be >= or just > ?
> > > 
> > > It should be >=.  It's analogous to not being allowed to derefence an
> > > array index that is >= the size of the array.
> > > 
> > > Also, the 16 here is not the number of bytes per quadword (as it often
> > > does with all things SVE), but the number of quadwords per 2048-bit
> > > KVM register slice.
> > > 
> > > To make matters worse (**) resembles some weird C syntax.
> > > 
> > > Maybe this would be less confusing written as
> > > 
> > >     Access to register IDs where 2048 * slice >= 128 * max_vq will fail
> > >     with ENOENT.  max_vq is the vcpu's maximum supported vector length
> > >     in 128-bit quadwords: see (**) below.
> > > 
> > > Does that help at all?
> > 
> > Yes. Thanks.
> 
> OK, I'll do that.
> 
> > 
> > > 
> > > > 
> > > > > +
> > > > > +These registers are only accessible on vcpus for which SVE is enabled.
> > > > > +See KVM_ARM_VCPU_INIT for details.
> > > > > +
> > > > > +In addition, except for KVM_REG_ARM64_SVE_VLS, these registers are not
> > > > > +accessible until the vcpu's SVE configuration has been finalized
> > > > > +using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).  See KVM_ARM_VCPU_INIT
> > > > > +and KVM_ARM_VCPU_FINALIZE for more information about this procedure.
> > > > > +
> > > > > +KVM_REG_ARM64_SVE_VLS is a pseudo-register that allows the set of vector
> > > > > +lengths supported by the vcpu to be discovered and configured by
> > > > > +userspace.  When transferred to or from user memory via KVM_GET_ONE_REG
> > > > > +or KVM_SET_ONE_REG, the value of this register is of type __u64[8], and
> > > > > +encodes the set of vector lengths as follows:
> > > > > +
> > > > > +__u64 vector_lengths[8];
> > > > > +
> > > > > +if (vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX &&
> > > > > +    ((vector_lengths[(vq - 1) / 64] >> ((vq - 1) % 64)) & 1))
> > > > > +	/* Vector length vq * 16 bytes supported */
> > > > > +else
> > > > > +	/* Vector length vq * 16 bytes not supported */
> > > > > +
> > > > > +(**) The maximum value vq for which the above condition is true is
> > > > > +max_vq.  This is the maximum vector length available to the guest on
> > > > > +this vcpu, and determines which register slices are visible through
> > > > > +this ioctl interface.
> > > > > +
> > > > > +(See Documentation/arm64/sve.txt for an explanation of the "vq"
> > > > > +nomenclature.)
> > > > > +
> > > > > +KVM_REG_ARM64_SVE_VLS is only accessible after KVM_ARM_VCPU_INIT.
> > > > > +KVM_ARM_VCPU_INIT initialises it to the best set of vector lengths that
> > > > > +the host supports.
> > > > > +
> > > > > +Userspace may subsequently modify it if desired until the vcpu's SVE
> > > > > +configuration is finalized using KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE).
> > > > > +
> > > > > +Apart from simply removing all vector lengths from the host set that
> > > > > +exceed some value, support for arbitrarily chosen sets of vector lengths
> > > > > +is hardware-dependent and may not be available.  Attempting to configure
> > > > > +an invalid set of vector lengths via KVM_SET_ONE_REG will fail with
> > > > > +EINVAL.
> > > > > +
> > > > > +After the vcpu's SVE configuration is finalized, further attempts to
> > > > > +write this register will fail with EPERM.
> > > > > +
> > > > >  
> > > > >  MIPS registers are mapped using the lower 32 bits.  The upper 16 of that is
> > > > >  the register group type:
> > > > > @@ -2197,6 +2260,7 @@ Parameters: struct kvm_one_reg (in and out)
> > > > >  Returns: 0 on success, negative value on failure
> > > > >  Errors:
> > > > >    ENOENT:   no such register
> > > > > +  EPERM:    register access forbidden for architecture-dependent reasons
> > > > >    EINVAL:   other errors, such as bad size encoding for a known register
> > > > >  
> > > > >  This ioctl allows to receive the value of a single register implemented
> > > > > @@ -2690,6 +2754,33 @@ Possible features:
> > > > >  	- KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU.
> > > > >  	  Depends on KVM_CAP_ARM_PMU_V3.
> > > > >  
> > > > > +	- KVM_ARM_VCPU_SVE: Enables SVE for the CPU (arm64 only).
> > > > > +	  Depends on KVM_CAP_ARM_SVE.
> > > > > +	  Requires KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > > > > +
> > > > > +	   * After KVM_ARM_VCPU_INIT:
> > > > > +
> > > > > +	      - KVM_REG_ARM64_SVE_VLS may be read using KVM_GET_ONE_REG: the
> > > > > +	        initial value of this pseudo-register indicates the best set of
> > > > > +	        vector lengths possible for a vcpu on this host.
> > > > > +
> > > > > +	   * Before KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > > > > +
> > > > > +	      - KVM_RUN and KVM_GET_REG_LIST are not available;
> > > > > +
> > > > > +	      - KVM_GET_ONE_REG and KVM_SET_ONE_REG cannot be used to access
> > > > > +	        the scalable archietctural SVE registers
> > > > > +	        KVM_REG_ARM64_SVE_ZREG(), KVM_REG_ARM64_SVE_PREG() or
> > > > > +	        KVM_REG_ARM64_SVE_FFR;
> > > > > +
> > > > > +	      - KVM_REG_ARM64_SVE_VLS may optionally be written using
> > > > > +	        KVM_SET_ONE_REG, to modify the set of vector lengths available
> > > > > +	        for the vcpu.
> > > > > +
> > > > > +	   * After KVM_ARM_VCPU_FINALIZE(KVM_ARM_VCPU_SVE):
> > > > > +
> > > > > +	      - the KVM_REG_ARM64_SVE_VLS pseudo-register is immutable, and can
> > > > > +	        no longer be written using KVM_SET_ONE_REG.
> > > > >  
> > > > >  4.83 KVM_ARM_PREFERRED_TARGET
> > > > >  
> > > > > @@ -3904,6 +3995,41 @@ number of valid entries in the 'entries' array, which is then filled.
> > > > >  'index' and 'flags' fields in 'struct kvm_cpuid_entry2' are currently reserved,
> > > > >  userspace should not expect to get any particular value there.
> > > > >  
> > > > > +4.119 KVM_ARM_VCPU_FINALIZE
> > > > > +
> > > > > +Capability: KVM_CAP_ARM_SVE
> > > > 
> > > > The KVM_ARM_VCPU_FINALIZE vcpu ioctl isn't SVE specific, so it shouldn't
> > > > depend on the SVE cap. It should have it's own cap, or maybe it should
> > > > just be an KVM_ARM_VCPU_SVE_FINALIZE ioctl instead, i.e. not general.
> > > 
> > > This one's a bit annoying.  This would ideally read
> > > 
> > > Capability: KVM_CAP_ARM_SVE, or any other capability that advertises the
> > > availability of a feature that requires KVM_ARM_VCPU_FINALIZE to be used.
> > > 
> > > (which sounds vague).
> > > 
> > > We could add a specific cap for KVM_ARM_VCPU_FINALIZE, but that seemed
> > > overkill.  Or document KVM_ARM_VCPU_FINALIZE as unconditionally
> > > supported, but make the individual feature values cap-dependent.  This
> > > works because the symptom of missing support is the same (EINVAL)
> > > ragardless of whether it is the specific feature or
> > > KVM_ARM_VCPU_FINALIZE that is unsupported.
> > > 
> > > Thoughts?
> > > 
> > 
> > I like that unconditionally supported idea.
> 
> OK, I'll see how to write this up in the documentation.
> 
> > > > > +Architectures: arm, arm64
> > > > > +Type: vcpu ioctl
> > > > > +Parameters: int feature (in)
> > > > 
> > > > This was called 'what' in the code.
> > > 
> > > Indeed it is.  I wanted to avoid the implication that this paramter
> > > exactly maps onto the KVM_ARM_VCPU_INIT features.  But "what" seemed
> > > a bit too vague for the documentation.
> > > 
> > > Mind you, if lseek() can have a "whence" parameter, perhaps "what" is
> > > also acceptable.
> > > 
> > > OTOH I don't mind changing the name in the code to "feature" if you
> > > think that's preferable.
> > > 
> > > Thoughts?
> > 
> > I prefer them to be the same, and I think both are fine.
> 
> OK.  I'll go with "feature".
> 
> > > > > +Returns: 0 on success, -1 on error
> > > > > +Errors:
> > > > > +  EPERM:     feature not enabled, needs configuration, or already finalized
> > > > > +  EINVAL:    unknown feature
> > > > > +
> > > > > +Recognised values for feature:
> > > > > +  arm64      KVM_ARM_VCPU_SVE
> > > > > +
> > > > > +Finalizes the configuration of the specified vcpu feature.
> > > > > +
> > > > > +The vcpu must already have been initialised, enabling the affected feature, by
> > > > > +means of a successful KVM_ARM_VCPU_INIT call with the appropriate flag set in
> > > > > +features[].
> > > > > +
> > > > > +For affected vcpu features, this is a mandatory step that must be performed
> > > > > +before the vcpu is fully usable.
> > > > > +
> > > > > +Between KVM_ARM_VCPU_INIT and KVM_ARM_VCPU_FINALIZE, the feature may be
> > > > > +configured by use of ioctls such as KVM_SET_ONE_REG.  The exact configuration
> > > > > +that should be performaned and how to do it are feature-dependent.
> > > > > +
> > > > > +Other calls that depend on a particular feature being finalized, such as
> > > > > +KVM_RUN, KVM_GET_REG_LIST, KVM_GET_ONE_REG and KVM_SET_ONE_REG, will fail with
> > > > > +-EPERM unless the feature has already been finalized by means of a
> > > > > +KVM_ARM_VCPU_FINALIZE call.
> > > > > +
> > > > > +See KVM_ARM_VCPU_INIT for details of vcpu features that require finalization
> > > > > +using this ioctl.
> > > > > +
> > > > >  5. The kvm_run structure
> > > > >  ------------------------
> > > > >
> > > > 
> > > > I'm still not sure about EPERM vs. ENOEXEC.
> > > 
> > > There is no need to distinguish the two: this is just a generic "vcpu in
> > > wrong state for this to work" error.  I can't think of another subsystem
> > > that uses ENOEXEC for this meaning, but it's established in KVM.
> > > 
> > > If you can't see a reason why we would need these to be distinct
> > > errors (?) then I'm happy for this to be ENOEXEC for all cases.
> > > 
> > 
> > I do see some value in keeping them distinct. I think it's just the use
> > of EPERM specifically that bothers me, but I don't have that strong of
> > an opinion against its use either. So I'll just shut up :)
> 
> In an earlier incarnation I had EBADFD, which does kind of mean the
> right thing.
> 
> If there's not a clear way forward, I may leave this all as-is for now
> (but I'll remove the explicit documentation for KVM_{GET,SET}_ONE_REG
> error codes to give us more flexibility about this in the future, as
> discussed).
> 
> Any objection?

Nope. Let's do that. EBADFD doesn't sound good, because we're using the FD
without trouble before and even after we attempt these ioctls. I think
EBADFD would indicate that no future ioctl (or read,write) should be
expected to work.

Thanks,
drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
  2019-04-05 14:06           ` Dave Martin
@ 2019-04-05 15:41             ` Andrew Jones
  -1 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-05 15:41 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 03:06:40PM +0100, Dave Martin wrote:
> On Fri, Apr 05, 2019 at 12:22:04PM +0200, Andrew Jones wrote:
> > On Fri, Apr 05, 2019 at 10:36:10AM +0100, Dave Martin wrote:
> > > On Thu, Apr 04, 2019 at 10:31:09PM +0200, Andrew Jones wrote:
> > > > On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> > > > > This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> > > > > allow userspace to set and query the set of vector lengths visible
> > > > > to the guest.
> > > > > 
> > > > > In the future, multiple register slices per SVE register may be
> > > > > visible through the ioctl interface.  Once the set of slices has
> > > > > been determined we would not be able to allow the vector length set
> > > > > to be changed any more, in order to avoid userspace seeing
> > > > > inconsistent sets of registers.  For this reason, this patch adds
> > > > > support for explicit finalization of the SVE configuration via the
> > > > > KVM_ARM_VCPU_FINALIZE ioctl.
> > > > > 
> > > > > Finalization is the proper place to allocate the SVE register state
> > > > > storage in vcpu->arch.sve_state, so this patch adds that as
> > > > > appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> > > > > was previously a no-op on arm64.
> > > > > 
> > > > > To simplify the logic for determining what vector lengths can be
> > > > > supported, some code is added to KVM init to work this out, in the
> > > > > kvm_arm_init_arch_resources() hook.
> > > > > 
> > > > > The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> > > > > Subsequent patches will allow SVE to be turned on for guest vcpus,
> > > > > making it visible.
> > > > > 
> > > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > 
> > > [...]
> > > 
> > > > > diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> > > 
> > > [...]
> > > 
> > > > > +/*
> > > > > + * Finalize vcpu's maximum SVE vector length, allocating
> > > > > + * vcpu->arch.sve_state as necessary.
> > > > > + */
> > > > > +static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
> > > > > +{
> > > > > +	void *buf;
> > > > > +	unsigned int vl;
> > > > > +
> > > > > +	vl = vcpu->arch.sve_max_vl;
> > > > > +
> > > > > +	/*
> > > > > +	 * Resposibility for these properties is shared between
> > > > > +	 * kvm_arm_init_arch_resources(), kvm_vcpu_enable_sve() and
> > > > > +	 * set_sve_vls().  Double-check here just to be sure:
> > > > > +	 */
> > > > > +	if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl ||
> > > > > +		    vl > SVE_VL_ARCH_MAX))
> > > > > +		return -EIO;
> > > > > +
> > > > > +	buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL);
> > > > > +	if (!buf)
> > > > > +		return -ENOMEM;
> > > > > +
> > > > > +	vcpu->arch.sve_state = buf;
> > > > > +	vcpu->arch.flags |= KVM_ARM64_VCPU_SVE_FINALIZED;
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what)
> > > > > +{
> > > > > +	switch (what) {
> > > > > +	case KVM_ARM_VCPU_SVE:
> > > > > +		if (!vcpu_has_sve(vcpu))
> > > > > +			return -EINVAL;
> > > > > +
> > > > > +		if (kvm_arm_vcpu_sve_finalized(vcpu))
> > > > > +			return -EPERM;
> > > > > +
> > > > > +		return kvm_vcpu_finalize_sve(vcpu);
> > > > 
> > > > In the next patch I see that we already have KVM_ARM64_GUEST_HAS_SVE
> > > > set in vcpu->arch.flags at this point. So if this kvm_vcpu_finalize_sve()
> > > > call fails, shouldn't we unset KVM_ARM64_GUEST_HAS_SVE and anything
> > > > else used to indicate the vcpu has sve?
> > > 
> > > If this fails, either userspace did the wrong thing, or there was some
> > > fatal error (like the ENOMEM case).  Either way, the vcpu is not runnable
> > > and userspace is expected to bail out.
> > > 
> > > Further, KVM_ARM_VCPU_INIT fixes the set of features requested by
> > > userspace: we shouldn't change the set of features under userspace's
> > > feet and try to limp on somehow.  We have no means for userspace to find
> > > out that some features went away in the meantime...
> > > 
> > > So, what would you be trying to achieve with this change?
> > 
> > Being able to do additional vcpu ioctls with only partially initialized
> > sve (sve_state is still null, but we otherwise believe the vcpu has sve).
> > That sounds risky. Although I see we only set KVM_ARM64_VCPU_SVE_FINALIZED
> > when everything, like the memory allocation, succeeds, so we're probably
> > fine. Indeed having KVM_ARM64_GUEST_HAS_SVE and not KVM_ARM64_VCPU_SVE_FINALIZED
> > is likely the safest vcpu state for a vcpu that failed to finalize sve.
> 
> This was my rationale: every non-trivial operation that is affected by
> SVE operation checks for kvm_arm_vcpu_sve_finalized(): accessing
> KVM_REG_ARM64_SVE_VLS should be the only exception.
> 
> Of course, people might forget that in new code, but I think all the
> major ABI code paths that are likely to exist for SVE are already there
> now.
> 
> Does this sound OK, or do you still have concerns?
> 
> Clearing KVM_ARM64_GUEST_HAS_SVE could be done on finalization failure;
> it just feels a bit weird.

Let's leave it. It's safe now, and there's always risk new code could
screw something up, no matter which way we go now, so let's pick the
simpler way.

Thanks,
drew

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

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
@ 2019-04-05 15:41             ` Andrew Jones
  0 siblings, 0 replies; 224+ messages in thread
From: Andrew Jones @ 2019-04-05 15:41 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 03:06:40PM +0100, Dave Martin wrote:
> On Fri, Apr 05, 2019 at 12:22:04PM +0200, Andrew Jones wrote:
> > On Fri, Apr 05, 2019 at 10:36:10AM +0100, Dave Martin wrote:
> > > On Thu, Apr 04, 2019 at 10:31:09PM +0200, Andrew Jones wrote:
> > > > On Fri, Mar 29, 2019 at 01:00:48PM +0000, Dave Martin wrote:
> > > > > This patch adds a new pseudo-register KVM_REG_ARM64_SVE_VLS to
> > > > > allow userspace to set and query the set of vector lengths visible
> > > > > to the guest.
> > > > > 
> > > > > In the future, multiple register slices per SVE register may be
> > > > > visible through the ioctl interface.  Once the set of slices has
> > > > > been determined we would not be able to allow the vector length set
> > > > > to be changed any more, in order to avoid userspace seeing
> > > > > inconsistent sets of registers.  For this reason, this patch adds
> > > > > support for explicit finalization of the SVE configuration via the
> > > > > KVM_ARM_VCPU_FINALIZE ioctl.
> > > > > 
> > > > > Finalization is the proper place to allocate the SVE register state
> > > > > storage in vcpu->arch.sve_state, so this patch adds that as
> > > > > appropriate.  The data is freed via kvm_arch_vcpu_uninit(), which
> > > > > was previously a no-op on arm64.
> > > > > 
> > > > > To simplify the logic for determining what vector lengths can be
> > > > > supported, some code is added to KVM init to work this out, in the
> > > > > kvm_arm_init_arch_resources() hook.
> > > > > 
> > > > > The KVM_REG_ARM64_SVE_VLS pseudo-register is not exposed yet.
> > > > > Subsequent patches will allow SVE to be turned on for guest vcpus,
> > > > > making it visible.
> > > > > 
> > > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> > > 
> > > [...]
> > > 
> > > > > diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
> > > 
> > > [...]
> > > 
> > > > > +/*
> > > > > + * Finalize vcpu's maximum SVE vector length, allocating
> > > > > + * vcpu->arch.sve_state as necessary.
> > > > > + */
> > > > > +static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
> > > > > +{
> > > > > +	void *buf;
> > > > > +	unsigned int vl;
> > > > > +
> > > > > +	vl = vcpu->arch.sve_max_vl;
> > > > > +
> > > > > +	/*
> > > > > +	 * Resposibility for these properties is shared between
> > > > > +	 * kvm_arm_init_arch_resources(), kvm_vcpu_enable_sve() and
> > > > > +	 * set_sve_vls().  Double-check here just to be sure:
> > > > > +	 */
> > > > > +	if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl ||
> > > > > +		    vl > SVE_VL_ARCH_MAX))
> > > > > +		return -EIO;
> > > > > +
> > > > > +	buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL);
> > > > > +	if (!buf)
> > > > > +		return -ENOMEM;
> > > > > +
> > > > > +	vcpu->arch.sve_state = buf;
> > > > > +	vcpu->arch.flags |= KVM_ARM64_VCPU_SVE_FINALIZED;
> > > > > +	return 0;
> > > > > +}
> > > > > +
> > > > > +int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int what)
> > > > > +{
> > > > > +	switch (what) {
> > > > > +	case KVM_ARM_VCPU_SVE:
> > > > > +		if (!vcpu_has_sve(vcpu))
> > > > > +			return -EINVAL;
> > > > > +
> > > > > +		if (kvm_arm_vcpu_sve_finalized(vcpu))
> > > > > +			return -EPERM;
> > > > > +
> > > > > +		return kvm_vcpu_finalize_sve(vcpu);
> > > > 
> > > > In the next patch I see that we already have KVM_ARM64_GUEST_HAS_SVE
> > > > set in vcpu->arch.flags at this point. So if this kvm_vcpu_finalize_sve()
> > > > call fails, shouldn't we unset KVM_ARM64_GUEST_HAS_SVE and anything
> > > > else used to indicate the vcpu has sve?
> > > 
> > > If this fails, either userspace did the wrong thing, or there was some
> > > fatal error (like the ENOMEM case).  Either way, the vcpu is not runnable
> > > and userspace is expected to bail out.
> > > 
> > > Further, KVM_ARM_VCPU_INIT fixes the set of features requested by
> > > userspace: we shouldn't change the set of features under userspace's
> > > feet and try to limp on somehow.  We have no means for userspace to find
> > > out that some features went away in the meantime...
> > > 
> > > So, what would you be trying to achieve with this change?
> > 
> > Being able to do additional vcpu ioctls with only partially initialized
> > sve (sve_state is still null, but we otherwise believe the vcpu has sve).
> > That sounds risky. Although I see we only set KVM_ARM64_VCPU_SVE_FINALIZED
> > when everything, like the memory allocation, succeeds, so we're probably
> > fine. Indeed having KVM_ARM64_GUEST_HAS_SVE and not KVM_ARM64_VCPU_SVE_FINALIZED
> > is likely the safest vcpu state for a vcpu that failed to finalize sve.
> 
> This was my rationale: every non-trivial operation that is affected by
> SVE operation checks for kvm_arm_vcpu_sve_finalized(): accessing
> KVM_REG_ARM64_SVE_VLS should be the only exception.
> 
> Of course, people might forget that in new code, but I think all the
> major ABI code paths that are likely to exist for SVE are already there
> now.
> 
> Does this sound OK, or do you still have concerns?
> 
> Clearing KVM_ARM64_GUEST_HAS_SVE could be done on finalization failure;
> it just feels a bit weird.

Let's leave it. It's safe now, and there's always risk new code could
screw something up, no matter which way we go now, so let's pick the
simpler way.

Thanks,
drew

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 00/27] KVM: arm64: SVE guest support
  2019-03-29 13:00 ` Dave Martin
@ 2019-04-05 16:41   ` Dave Martin
  -1 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05 16:41 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:25PM +0000, Dave Martin wrote:
> This series implements support for allowing KVM guests to use the Arm
> Scalable Vector Extension (SVE), superseding the previous v6 series [1].

[...]

FYI, I'm working on a series of minor fixups based on Andrew's comments
which I should get out early next week, probably Tuesday.

Apart from some discussion about which error codes should be returned
in certain situations, all the changes discussed so far will be
non-functional.

Except for adding a couple of #defines to the UAPI headers, there's no
other ABI impact so far.

Thanks to Andrew for his review efforts...

Cheers
---Dave

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

* Re: [PATCH v7 00/27] KVM: arm64: SVE guest support
@ 2019-04-05 16:41   ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-05 16:41 UTC (permalink / raw)
  To: kvmarm
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall,
	linux-arm-kernel

On Fri, Mar 29, 2019 at 01:00:25PM +0000, Dave Martin wrote:
> This series implements support for allowing KVM guests to use the Arm
> Scalable Vector Extension (SVE), superseding the previous v6 series [1].

[...]

FYI, I'm working on a series of minor fixups based on Andrew's comments
which I should get out early next week, probably Tuesday.

Apart from some discussion about which error codes should be returned
in certain situations, all the changes discussed so far will be
non-functional.

Except for adding a couple of #defines to the UAPI headers, there's no
other ABI impact so far.

Thanks to Andrew for his review efforts...

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 27/27] KVM: arm64/sve: Document KVM API extensions for SVE
@ 2019-04-10 12:34               ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-10 12:34 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 05:38:04PM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 02:00:07PM +0100, Dave Martin wrote:
> > On Fri, Apr 05, 2019 at 12:39:37PM +0200, Andrew Jones wrote:
> > > On Fri, Apr 05, 2019 at 10:36:17AM +0100, Dave Martin wrote:
> > > > On Thu, Apr 04, 2019 at 11:09:21PM +0200, Andrew Jones wrote:

[...]

> > > > > I'm still not sure about EPERM vs. ENOEXEC.
> > > > 
> > > > There is no need to distinguish the two: this is just a generic "vcpu in
> > > > wrong state for this to work" error.  I can't think of another subsystem
> > > > that uses ENOEXEC for this meaning, but it's established in KVM.
> > > > 
> > > > If you can't see a reason why we would need these to be distinct
> > > > errors (?) then I'm happy for this to be ENOEXEC for all cases.
> > > > 
> > > 
> > > I do see some value in keeping them distinct. I think it's just the use
> > > of EPERM specifically that bothers me, but I don't have that strong of
> > > an opinion against its use either. So I'll just shut up :)
> > 
> > In an earlier incarnation I had EBADFD, which does kind of mean the
> > right thing.
> > 
> > If there's not a clear way forward, I may leave this all as-is for now
> > (but I'll remove the explicit documentation for KVM_{GET,SET}_ONE_REG
> > error codes to give us more flexibility about this in the future, as
> > discussed).
> > 
> > Any objection?
> 
> Nope. Let's do that. EBADFD doesn't sound good, because we're using the FD
> without trouble before and even after we attempt these ioctls. I think
> EBADFD would indicate that no future ioctl (or read,write) should be
> expected to work.

OK.  I may also keep some of the error code documentation, but water it
down a bit to make it clearer that the error codes are indicate and
arm64-specifc.

We can see how it looks when I have a series to post.

Cheers
---Dave

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

* Re: [PATCH v7 27/27] KVM: arm64/sve: Document KVM API extensions for SVE
@ 2019-04-10 12:34               ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-10 12:34 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 05:38:04PM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 02:00:07PM +0100, Dave Martin wrote:
> > On Fri, Apr 05, 2019 at 12:39:37PM +0200, Andrew Jones wrote:
> > > On Fri, Apr 05, 2019 at 10:36:17AM +0100, Dave Martin wrote:
> > > > On Thu, Apr 04, 2019 at 11:09:21PM +0200, Andrew Jones wrote:

[...]

> > > > > I'm still not sure about EPERM vs. ENOEXEC.
> > > > 
> > > > There is no need to distinguish the two: this is just a generic "vcpu in
> > > > wrong state for this to work" error.  I can't think of another subsystem
> > > > that uses ENOEXEC for this meaning, but it's established in KVM.
> > > > 
> > > > If you can't see a reason why we would need these to be distinct
> > > > errors (?) then I'm happy for this to be ENOEXEC for all cases.
> > > > 
> > > 
> > > I do see some value in keeping them distinct. I think it's just the use
> > > of EPERM specifically that bothers me, but I don't have that strong of
> > > an opinion against its use either. So I'll just shut up :)
> > 
> > In an earlier incarnation I had EBADFD, which does kind of mean the
> > right thing.
> > 
> > If there's not a clear way forward, I may leave this all as-is for now
> > (but I'll remove the explicit documentation for KVM_{GET,SET}_ONE_REG
> > error codes to give us more flexibility about this in the future, as
> > discussed).
> > 
> > Any objection?
> 
> Nope. Let's do that. EBADFD doesn't sound good, because we're using the FD
> without trouble before and even after we attempt these ioctls. I think
> EBADFD would indicate that no future ioctl (or read,write) should be
> expected to work.

OK.  I may also keep some of the error code documentation, but water it
down a bit to make it clearer that the error codes are indicate and
arm64-specifc.

We can see how it looks when I have a series to post.

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

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

* Re: [PATCH v7 27/27] KVM: arm64/sve: Document KVM API extensions for SVE
@ 2019-04-10 12:34               ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-10 12:34 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 05:38:04PM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 02:00:07PM +0100, Dave Martin wrote:
> > On Fri, Apr 05, 2019 at 12:39:37PM +0200, Andrew Jones wrote:
> > > On Fri, Apr 05, 2019 at 10:36:17AM +0100, Dave Martin wrote:
> > > > On Thu, Apr 04, 2019 at 11:09:21PM +0200, Andrew Jones wrote:

[...]

> > > > > I'm still not sure about EPERM vs. ENOEXEC.
> > > > 
> > > > There is no need to distinguish the two: this is just a generic "vcpu in
> > > > wrong state for this to work" error.  I can't think of another subsystem
> > > > that uses ENOEXEC for this meaning, but it's established in KVM.
> > > > 
> > > > If you can't see a reason why we would need these to be distinct
> > > > errors (?) then I'm happy for this to be ENOEXEC for all cases.
> > > > 
> > > 
> > > I do see some value in keeping them distinct. I think it's just the use
> > > of EPERM specifically that bothers me, but I don't have that strong of
> > > an opinion against its use either. So I'll just shut up :)
> > 
> > In an earlier incarnation I had EBADFD, which does kind of mean the
> > right thing.
> > 
> > If there's not a clear way forward, I may leave this all as-is for now
> > (but I'll remove the explicit documentation for KVM_{GET,SET}_ONE_REG
> > error codes to give us more flexibility about this in the future, as
> > discussed).
> > 
> > Any objection?
> 
> Nope. Let's do that. EBADFD doesn't sound good, because we're using the FD
> without trouble before and even after we attempt these ioctls. I think
> EBADFD would indicate that no future ioctl (or read,write) should be
> expected to work.

OK.  I may also keep some of the error code documentation, but water it
down a bit to make it clearer that the error codes are indicate and
arm64-specifc.

We can see how it looks when I have a series to post.

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
@ 2019-04-10 12:35               ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-10 12:35 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 05:41:31PM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 03:06:40PM +0100, Dave Martin wrote:

[...]

> > Clearing KVM_ARM64_GUEST_HAS_SVE could be done on finalization failure;
> > it just feels a bit weird.
> 
> Let's leave it. It's safe now, and there's always risk new code could
> screw something up, no matter which way we go now, so let's pick the
> simpler way.

OK, I can't argue with that.

Cheers
---Dave

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

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
@ 2019-04-10 12:35               ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-10 12:35 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 05:41:31PM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 03:06:40PM +0100, Dave Martin wrote:

[...]

> > Clearing KVM_ARM64_GUEST_HAS_SVE could be done on finalization failure;
> > it just feels a bit weird.
> 
> Let's leave it. It's safe now, and there's always risk new code could
> screw something up, no matter which way we go now, so let's pick the
> simpler way.

OK, I can't argue with that.

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

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

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
@ 2019-04-10 12:35               ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-10 12:35 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 05:41:31PM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 03:06:40PM +0100, Dave Martin wrote:

[...]

> > Clearing KVM_ARM64_GUEST_HAS_SVE could be done on finalization failure;
> > it just feels a bit weird.
> 
> Let's leave it. It's safe now, and there's always risk new code could
> screw something up, no matter which way we go now, so let's pick the
> simpler way.

OK, I can't argue with that.

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
@ 2019-04-10 12:42               ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-10 12:42 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 05:33:21PM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 01:54:13PM +0100, Dave Martin wrote:

[...]

> > If you think the above is enough for ABI documentation purposes, I will
> > aim to drop the following comment into set_sve_vls():
> > 
> > 	/*
> > 	 * Vector lengths supported by the host can't currently be
> > 	 * hidden from the guest individually: instead we can only set a
> > 	 * maxmium via ZCR_EL2.LEN.  So, make sure the available vector
> > 	 * length match the set requested exactly up to the requested
> > 	 * maximum:
> > 	 */
> > 	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > 		if (vq_present(&vqs, vq) != sve_vq_available(vq))
> > 			return -EINVAL;
> > 
> > Do you think that's enough?
> >
> 
> That works for me, and I'm glad I now have it understood, because this
> will be a key piece of the QEMU uesr interface to work out. I.e. we
> need to be able to provide the user with the current host's VL list
> up to the max virtualizable VL when queried, allow them to choose a max
> from that list for a guest, and then commit to that VL sublist for the
> guest. I'll dive into QEMU on Monday, hopefully I won't drown there.

Agreed.

How to make this user-friendly is a separate problem, provided that the
kernel provides userspace with sufficient tools to do the job.

Cheers
---Dave

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

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
@ 2019-04-10 12:42               ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-10 12:42 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 05:33:21PM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 01:54:13PM +0100, Dave Martin wrote:

[...]

> > If you think the above is enough for ABI documentation purposes, I will
> > aim to drop the following comment into set_sve_vls():
> > 
> > 	/*
> > 	 * Vector lengths supported by the host can't currently be
> > 	 * hidden from the guest individually: instead we can only set a
> > 	 * maxmium via ZCR_EL2.LEN.  So, make sure the available vector
> > 	 * length match the set requested exactly up to the requested
> > 	 * maximum:
> > 	 */
> > 	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > 		if (vq_present(&vqs, vq) != sve_vq_available(vq))
> > 			return -EINVAL;
> > 
> > Do you think that's enough?
> >
> 
> That works for me, and I'm glad I now have it understood, because this
> will be a key piece of the QEMU uesr interface to work out. I.e. we
> need to be able to provide the user with the current host's VL list
> up to the max virtualizable VL when queried, allow them to choose a max
> from that list for a guest, and then commit to that VL sublist for the
> guest. I'll dive into QEMU on Monday, hopefully I won't drown there.

Agreed.

How to make this user-friendly is a separate problem, provided that the
kernel provides userspace with sufficient tools to do the job.

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

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

* Re: [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths
@ 2019-04-10 12:42               ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-10 12:42 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Fri, Apr 05, 2019 at 05:33:21PM +0200, Andrew Jones wrote:
> On Fri, Apr 05, 2019 at 01:54:13PM +0100, Dave Martin wrote:

[...]

> > If you think the above is enough for ABI documentation purposes, I will
> > aim to drop the following comment into set_sve_vls():
> > 
> > 	/*
> > 	 * Vector lengths supported by the host can't currently be
> > 	 * hidden from the guest individually: instead we can only set a
> > 	 * maxmium via ZCR_EL2.LEN.  So, make sure the available vector
> > 	 * length match the set requested exactly up to the requested
> > 	 * maximum:
> > 	 */
> > 	for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq)
> > 		if (vq_present(&vqs, vq) != sve_vq_available(vq))
> > 			return -EINVAL;
> > 
> > Do you think that's enough?
> >
> 
> That works for me, and I'm glad I now have it understood, because this
> will be a key piece of the QEMU uesr interface to work out. I.e. we
> need to be able to provide the user with the current host's VL list
> up to the max virtualizable VL when queried, allow them to choose a max
> from that list for a guest, and then commit to that VL sublist for the
> guest. I'll dive into QEMU on Monday, hopefully I won't drown there.

Agreed.

How to make this user-friendly is a separate problem, provided that the
kernel provides userspace with sufficient tools to do the job.

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 01/27] KVM: Documentation: Document arm64 core registers in detail
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-24  9:25     ` Alex Bennée
  -1 siblings, 0 replies; 224+ messages in thread
From: Alex Bennée @ 2019-04-24  9:25 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel


Dave Martin <Dave.Martin@arm.com> writes:

> Since the the sizes of individual members of the core arm64
> registers vary, the list of register encodings that make sense is
> not a simple linear sequence.
>
> To clarify which encodings to use, this patch adds a brief list
> to the documentation.
>
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  Documentation/virtual/kvm/api.txt | 24 ++++++++++++++++++++++++
>  1 file changed, 24 insertions(+)
>
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index 7de9eee..2d4f7ce 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -2107,6 +2107,30 @@ contains elements ranging from 32 to 128 bits. The index is a 32bit
>  value in the kvm_regs structure seen as a 32bit array.
>    0x60x0 0000 0010 <index into the kvm_regs struct:16>
>
> +Specifically:
> +    Encoding            Register  Bits  kvm_regs member
> +----------------------------------------------------------------
> +  0x6030 0000 0010 0000 X0          64  regs.regs[0]
> +  0x6030 0000 0010 0002 X1          64  regs.regs[1]
> +    ...
> +  0x6030 0000 0010 003c X30         64  regs.regs[30]
> +  0x6030 0000 0010 003e SP          64  regs.sp
> +  0x6030 0000 0010 0040 PC          64  regs.pc
> +  0x6030 0000 0010 0042 PSTATE      64  regs.pstate
> +  0x6030 0000 0010 0044 SP_EL1      64  sp_el1
> +  0x6030 0000 0010 0046 ELR_EL1     64  elr_el1
> +  0x6030 0000 0010 0048 SPSR_EL1    64  spsr[KVM_SPSR_EL1] (alias SPSR_SVC)
> +  0x6030 0000 0010 004a SPSR_ABT    64  spsr[KVM_SPSR_ABT]
> +  0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
> +  0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
> +  0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
> +  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]
> +  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]
> +    ...
> +  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]
> +  0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
> +  0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
> +
>  arm64 CCSIDR registers are demultiplexed by CSSELR value:
>    0x6020 0000 0011 00 <csselr:8>


--
Alex Bennée
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v7 01/27] KVM: Documentation: Document arm64 core registers in detail
@ 2019-04-24  9:25     ` Alex Bennée
  0 siblings, 0 replies; 224+ messages in thread
From: Alex Bennée @ 2019-04-24  9:25 UTC (permalink / raw)
  To: Dave Martin
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, kvmarm, linux-arm-kernel


Dave Martin <Dave.Martin@arm.com> writes:

> Since the the sizes of individual members of the core arm64
> registers vary, the list of register encodings that make sense is
> not a simple linear sequence.
>
> To clarify which encodings to use, this patch adds a brief list
> to the documentation.
>
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

> ---
>  Documentation/virtual/kvm/api.txt | 24 ++++++++++++++++++++++++
>  1 file changed, 24 insertions(+)
>
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index 7de9eee..2d4f7ce 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -2107,6 +2107,30 @@ contains elements ranging from 32 to 128 bits. The index is a 32bit
>  value in the kvm_regs structure seen as a 32bit array.
>    0x60x0 0000 0010 <index into the kvm_regs struct:16>
>
> +Specifically:
> +    Encoding            Register  Bits  kvm_regs member
> +----------------------------------------------------------------
> +  0x6030 0000 0010 0000 X0          64  regs.regs[0]
> +  0x6030 0000 0010 0002 X1          64  regs.regs[1]
> +    ...
> +  0x6030 0000 0010 003c X30         64  regs.regs[30]
> +  0x6030 0000 0010 003e SP          64  regs.sp
> +  0x6030 0000 0010 0040 PC          64  regs.pc
> +  0x6030 0000 0010 0042 PSTATE      64  regs.pstate
> +  0x6030 0000 0010 0044 SP_EL1      64  sp_el1
> +  0x6030 0000 0010 0046 ELR_EL1     64  elr_el1
> +  0x6030 0000 0010 0048 SPSR_EL1    64  spsr[KVM_SPSR_EL1] (alias SPSR_SVC)
> +  0x6030 0000 0010 004a SPSR_ABT    64  spsr[KVM_SPSR_ABT]
> +  0x6030 0000 0010 004c SPSR_UND    64  spsr[KVM_SPSR_UND]
> +  0x6030 0000 0010 004e SPSR_IRQ    64  spsr[KVM_SPSR_IRQ]
> +  0x6060 0000 0010 0050 SPSR_FIQ    64  spsr[KVM_SPSR_FIQ]
> +  0x6040 0000 0010 0054 V0         128  fp_regs.vregs[0]
> +  0x6040 0000 0010 0058 V1         128  fp_regs.vregs[1]
> +    ...
> +  0x6040 0000 0010 00d0 V31        128  fp_regs.vregs[31]
> +  0x6020 0000 0010 00d4 FPSR        32  fp_regs.fpsr
> +  0x6020 0000 0010 00d5 FPCR        32  fp_regs.fpcr
> +
>  arm64 CCSIDR registers are demultiplexed by CSSELR value:
>    0x6020 0000 0011 00 <csselr:8>


--
Alex Bennée

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 11/27] KVM: arm64: Support runtime sysreg visibility filtering
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-24  9:39     ` Alex Bennée
  -1 siblings, 0 replies; 224+ messages in thread
From: Alex Bennée @ 2019-04-24  9:39 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel


Dave Martin <Dave.Martin@arm.com> writes:

> Some optional features of the Arm architecture add new system
> registers that are not present in the base architecture.
>
> Where these features are optional for the guest, the visibility of
> these registers may need to depend on some runtime configuration,
> such as a flag passed to KVM_ARM_VCPU_INIT.

This combined with...
> --- a/arch/arm64/kvm/sys_regs.h
> +++ b/arch/arm64/kvm/sys_regs.h
> @@ -64,8 +64,15 @@ struct sys_reg_desc {
>  			const struct kvm_one_reg *reg, void __user *uaddr);
>  	int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
>  			const struct kvm_one_reg *reg, void __user *uaddr);
> +
> +	/* Return mask of REG_* runtime visibility overrides */
> +	unsigned int (*visibility)(const struct kvm_vcpu *vcpu,
> +				   const struct sys_reg_desc *rd);
>  };

this makes me wonder what sort of machines will see different register
visibility depending on which vcpu you are running on?

Otherwise is looks good to me:

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

--
Alex Bennée
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v7 11/27] KVM: arm64: Support runtime sysreg visibility filtering
@ 2019-04-24  9:39     ` Alex Bennée
  0 siblings, 0 replies; 224+ messages in thread
From: Alex Bennée @ 2019-04-24  9:39 UTC (permalink / raw)
  To: Dave Martin
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, kvmarm, linux-arm-kernel


Dave Martin <Dave.Martin@arm.com> writes:

> Some optional features of the Arm architecture add new system
> registers that are not present in the base architecture.
>
> Where these features are optional for the guest, the visibility of
> these registers may need to depend on some runtime configuration,
> such as a flag passed to KVM_ARM_VCPU_INIT.

This combined with...
> --- a/arch/arm64/kvm/sys_regs.h
> +++ b/arch/arm64/kvm/sys_regs.h
> @@ -64,8 +64,15 @@ struct sys_reg_desc {
>  			const struct kvm_one_reg *reg, void __user *uaddr);
>  	int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
>  			const struct kvm_one_reg *reg, void __user *uaddr);
> +
> +	/* Return mask of REG_* runtime visibility overrides */
> +	unsigned int (*visibility)(const struct kvm_vcpu *vcpu,
> +				   const struct sys_reg_desc *rd);
>  };

this makes me wonder what sort of machines will see different register
visibility depending on which vcpu you are running on?

Otherwise is looks good to me:

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

--
Alex Bennée

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 17/27] KVM: arm64: Reject ioctl access to FPSIMD V-regs on SVE vcpus
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-24 13:45     ` Alex Bennée
  -1 siblings, 0 replies; 224+ messages in thread
From: Alex Bennée @ 2019-04-24 13:45 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel


Dave Martin <Dave.Martin@arm.com> writes:

> In order to avoid the pointless complexity of maintaining two ioctl
> register access views of the same data, this patch blocks ioctl
> access to the FPSIMD V-registers on vcpus that support SVE.
>
> This will make it more straightforward to add SVE register access
> support.
>
> Since SVE is an opt-in feature for userspace, this will not affect
> existing users.
>
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

>
> ---
>
> Changes since v5:
>
>  * Refactored to cope with the removal of core_reg_size_from_offset()
>    (which was added by another series which will now be handled
>    independently).
>
>    This leaves some duplication in that we still filter the V-regs out
>    in two places, but this no worse than other existing code in guest.c.
>    I plan to tidy this up independently later on.
> ---
>  arch/arm64/kvm/guest.c | 48 ++++++++++++++++++++++++++++++++++++------------
>  1 file changed, 36 insertions(+), 12 deletions(-)
>
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index a391a61..756d0d6 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -54,12 +54,19 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
>  	return 0;
>  }
>
> +static bool core_reg_offset_is_vreg(u64 off)
> +{
> +	return off >= KVM_REG_ARM_CORE_REG(fp_regs.vregs) &&
> +		off < KVM_REG_ARM_CORE_REG(fp_regs.fpsr);
> +}
> +
>  static u64 core_reg_offset_from_id(u64 id)
>  {
>  	return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
>  }
>
> -static int validate_core_offset(const struct kvm_one_reg *reg)
> +static int validate_core_offset(const struct kvm_vcpu *vcpu,
> +				const struct kvm_one_reg *reg)
>  {
>  	u64 off = core_reg_offset_from_id(reg->id);
>  	int size;
> @@ -91,11 +98,19 @@ static int validate_core_offset(const struct kvm_one_reg *reg)
>  		return -EINVAL;
>  	}
>
> -	if (KVM_REG_SIZE(reg->id) == size &&
> -	    IS_ALIGNED(off, size / sizeof(__u32)))
> -		return 0;
> +	if (KVM_REG_SIZE(reg->id) != size ||
> +	    !IS_ALIGNED(off, size / sizeof(__u32)))
> +		return -EINVAL;
>
> -	return -EINVAL;
> +	/*
> +	 * The KVM_REG_ARM64_SVE regs must be used instead of
> +	 * KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on
> +	 * SVE-enabled vcpus:
> +	 */
> +	if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(off))
> +		return -EINVAL;
> +
> +	return 0;
>  }
>
>  static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> @@ -117,7 +132,7 @@ static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	    (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
>  		return -ENOENT;
>
> -	if (validate_core_offset(reg))
> +	if (validate_core_offset(vcpu, reg))
>  		return -EINVAL;
>
>  	if (copy_to_user(uaddr, ((u32 *)regs) + off, KVM_REG_SIZE(reg->id)))
> @@ -142,7 +157,7 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	    (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
>  		return -ENOENT;
>
> -	if (validate_core_offset(reg))
> +	if (validate_core_offset(vcpu, reg))
>  		return -EINVAL;
>
>  	if (KVM_REG_SIZE(reg->id) > sizeof(tmp))
> @@ -195,13 +210,22 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
>  	return -EINVAL;
>  }
>
> -static int kvm_arm_copy_core_reg_indices(u64 __user *uindices)
> +static int copy_core_reg_indices(const struct kvm_vcpu *vcpu,
> +				 u64 __user *uindices)
>  {
>  	unsigned int i;
>  	int n = 0;
>  	const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
>
>  	for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
> +		/*
> +		 * The KVM_REG_ARM64_SVE regs must be used instead of
> +		 * KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on
> +		 * SVE-enabled vcpus:
> +		 */
> +		if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(i))
> +			continue;
> +
>  		if (uindices) {
>  			if (put_user(core_reg | i, uindices))
>  				return -EFAULT;
> @@ -214,9 +238,9 @@ static int kvm_arm_copy_core_reg_indices(u64 __user *uindices)
>  	return n;
>  }
>
> -static unsigned long num_core_regs(void)
> +static unsigned long num_core_regs(const struct kvm_vcpu *vcpu)
>  {
> -	return kvm_arm_copy_core_reg_indices(NULL);
> +	return copy_core_reg_indices(vcpu, NULL);
>  }
>
>  /**
> @@ -281,7 +305,7 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
>  {
>  	unsigned long res = 0;
>
> -	res += num_core_regs();
> +	res += num_core_regs(vcpu);
>  	res += kvm_arm_num_sys_reg_descs(vcpu);
>  	res += kvm_arm_get_fw_num_regs(vcpu);
>  	res += NUM_TIMER_REGS;
> @@ -298,7 +322,7 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
>  {
>  	int ret;
>
> -	ret = kvm_arm_copy_core_reg_indices(uindices);
> +	ret = copy_core_reg_indices(vcpu, uindices);
>  	if (ret)
>  		return ret;
>  	uindices += ret;


--
Alex Bennée
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v7 17/27] KVM: arm64: Reject ioctl access to FPSIMD V-regs on SVE vcpus
@ 2019-04-24 13:45     ` Alex Bennée
  0 siblings, 0 replies; 224+ messages in thread
From: Alex Bennée @ 2019-04-24 13:45 UTC (permalink / raw)
  To: Dave Martin
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, kvmarm, linux-arm-kernel


Dave Martin <Dave.Martin@arm.com> writes:

> In order to avoid the pointless complexity of maintaining two ioctl
> register access views of the same data, this patch blocks ioctl
> access to the FPSIMD V-registers on vcpus that support SVE.
>
> This will make it more straightforward to add SVE register access
> support.
>
> Since SVE is an opt-in feature for userspace, this will not affect
> existing users.
>
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

>
> ---
>
> Changes since v5:
>
>  * Refactored to cope with the removal of core_reg_size_from_offset()
>    (which was added by another series which will now be handled
>    independently).
>
>    This leaves some duplication in that we still filter the V-regs out
>    in two places, but this no worse than other existing code in guest.c.
>    I plan to tidy this up independently later on.
> ---
>  arch/arm64/kvm/guest.c | 48 ++++++++++++++++++++++++++++++++++++------------
>  1 file changed, 36 insertions(+), 12 deletions(-)
>
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index a391a61..756d0d6 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -54,12 +54,19 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
>  	return 0;
>  }
>
> +static bool core_reg_offset_is_vreg(u64 off)
> +{
> +	return off >= KVM_REG_ARM_CORE_REG(fp_regs.vregs) &&
> +		off < KVM_REG_ARM_CORE_REG(fp_regs.fpsr);
> +}
> +
>  static u64 core_reg_offset_from_id(u64 id)
>  {
>  	return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
>  }
>
> -static int validate_core_offset(const struct kvm_one_reg *reg)
> +static int validate_core_offset(const struct kvm_vcpu *vcpu,
> +				const struct kvm_one_reg *reg)
>  {
>  	u64 off = core_reg_offset_from_id(reg->id);
>  	int size;
> @@ -91,11 +98,19 @@ static int validate_core_offset(const struct kvm_one_reg *reg)
>  		return -EINVAL;
>  	}
>
> -	if (KVM_REG_SIZE(reg->id) == size &&
> -	    IS_ALIGNED(off, size / sizeof(__u32)))
> -		return 0;
> +	if (KVM_REG_SIZE(reg->id) != size ||
> +	    !IS_ALIGNED(off, size / sizeof(__u32)))
> +		return -EINVAL;
>
> -	return -EINVAL;
> +	/*
> +	 * The KVM_REG_ARM64_SVE regs must be used instead of
> +	 * KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on
> +	 * SVE-enabled vcpus:
> +	 */
> +	if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(off))
> +		return -EINVAL;
> +
> +	return 0;
>  }
>
>  static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
> @@ -117,7 +132,7 @@ static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	    (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
>  		return -ENOENT;
>
> -	if (validate_core_offset(reg))
> +	if (validate_core_offset(vcpu, reg))
>  		return -EINVAL;
>
>  	if (copy_to_user(uaddr, ((u32 *)regs) + off, KVM_REG_SIZE(reg->id)))
> @@ -142,7 +157,7 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
>  	    (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
>  		return -ENOENT;
>
> -	if (validate_core_offset(reg))
> +	if (validate_core_offset(vcpu, reg))
>  		return -EINVAL;
>
>  	if (KVM_REG_SIZE(reg->id) > sizeof(tmp))
> @@ -195,13 +210,22 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
>  	return -EINVAL;
>  }
>
> -static int kvm_arm_copy_core_reg_indices(u64 __user *uindices)
> +static int copy_core_reg_indices(const struct kvm_vcpu *vcpu,
> +				 u64 __user *uindices)
>  {
>  	unsigned int i;
>  	int n = 0;
>  	const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
>
>  	for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
> +		/*
> +		 * The KVM_REG_ARM64_SVE regs must be used instead of
> +		 * KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on
> +		 * SVE-enabled vcpus:
> +		 */
> +		if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(i))
> +			continue;
> +
>  		if (uindices) {
>  			if (put_user(core_reg | i, uindices))
>  				return -EFAULT;
> @@ -214,9 +238,9 @@ static int kvm_arm_copy_core_reg_indices(u64 __user *uindices)
>  	return n;
>  }
>
> -static unsigned long num_core_regs(void)
> +static unsigned long num_core_regs(const struct kvm_vcpu *vcpu)
>  {
> -	return kvm_arm_copy_core_reg_indices(NULL);
> +	return copy_core_reg_indices(vcpu, NULL);
>  }
>
>  /**
> @@ -281,7 +305,7 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
>  {
>  	unsigned long res = 0;
>
> -	res += num_core_regs();
> +	res += num_core_regs(vcpu);
>  	res += kvm_arm_num_sys_reg_descs(vcpu);
>  	res += kvm_arm_get_fw_num_regs(vcpu);
>  	res += NUM_TIMER_REGS;
> @@ -298,7 +322,7 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
>  {
>  	int ret;
>
> -	ret = kvm_arm_copy_core_reg_indices(uindices);
> +	ret = copy_core_reg_indices(vcpu, uindices);
>  	if (ret)
>  		return ret;
>  	uindices += ret;


--
Alex Bennée

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 11/27] KVM: arm64: Support runtime sysreg visibility filtering
@ 2019-04-24 13:47       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-24 13:47 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Wed, Apr 24, 2019 at 09:39:31AM +0000, Alex Bennée wrote:
> 
> Dave Martin <Dave.Martin@arm.com> writes:
> 
> > Some optional features of the Arm architecture add new system
> > registers that are not present in the base architecture.
> >
> > Where these features are optional for the guest, the visibility of
> > these registers may need to depend on some runtime configuration,
> > such as a flag passed to KVM_ARM_VCPU_INIT.
> 
> This combined with...
> > --- a/arch/arm64/kvm/sys_regs.h
> > +++ b/arch/arm64/kvm/sys_regs.h
> > @@ -64,8 +64,15 @@ struct sys_reg_desc {
> >  			const struct kvm_one_reg *reg, void __user *uaddr);
> >  	int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
> >  			const struct kvm_one_reg *reg, void __user *uaddr);
> > +
> > +	/* Return mask of REG_* runtime visibility overrides */
> > +	unsigned int (*visibility)(const struct kvm_vcpu *vcpu,
> > +				   const struct sys_reg_desc *rd);
> >  };
> 
> this makes me wonder what sort of machines will see different register
> visibility depending on which vcpu you are running on?

Userspace can consciously set KVM_ARM_VCPU_SVE in vcpu_init.features[0]
for some vcpus and not for others.

For one thing, this is useful for testing how the guest responds to that
configuration.

This will for example allow Linux's handling of these weird
configurations to be tested directly rather than by hacking the
guest kernel to fake it up -- which is what I've had to do up to now.

> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

Thanks!

(Note, Marc already picked the patches into kvmarm/next, so new tags
won't be applied.  But the review is still appreciated, and if you spot
any issues I'd certainly like to know :)

Cheers
---Dave

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

* Re: [PATCH v7 11/27] KVM: arm64: Support runtime sysreg visibility filtering
@ 2019-04-24 13:47       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-24 13:47 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="UTF-8", Size: 1943 bytes --]

On Wed, Apr 24, 2019 at 09:39:31AM +0000, Alex Bennée wrote:
> 
> Dave Martin <Dave.Martin@arm.com> writes:
> 
> > Some optional features of the Arm architecture add new system
> > registers that are not present in the base architecture.
> >
> > Where these features are optional for the guest, the visibility of
> > these registers may need to depend on some runtime configuration,
> > such as a flag passed to KVM_ARM_VCPU_INIT.
> 
> This combined with...
> > --- a/arch/arm64/kvm/sys_regs.h
> > +++ b/arch/arm64/kvm/sys_regs.h
> > @@ -64,8 +64,15 @@ struct sys_reg_desc {
> >  			const struct kvm_one_reg *reg, void __user *uaddr);
> >  	int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
> >  			const struct kvm_one_reg *reg, void __user *uaddr);
> > +
> > +	/* Return mask of REG_* runtime visibility overrides */
> > +	unsigned int (*visibility)(const struct kvm_vcpu *vcpu,
> > +				   const struct sys_reg_desc *rd);
> >  };
> 
> this makes me wonder what sort of machines will see different register
> visibility depending on which vcpu you are running on?

Userspace can consciously set KVM_ARM_VCPU_SVE in vcpu_init.features[0]
for some vcpus and not for others.

For one thing, this is useful for testing how the guest responds to that
configuration.

This will for example allow Linux's handling of these weird
configurations to be tested directly rather than by hacking the
guest kernel to fake it up -- which is what I've had to do up to now.

> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

Thanks!

(Note, Marc already picked the patches into kvmarm/next, so new tags
won't be applied.  But the review is still appreciated, and if you spot
any issues I'd certainly like to know :)

Cheers
---Dave

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

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

* Re: [PATCH v7 11/27] KVM: arm64: Support runtime sysreg visibility filtering
@ 2019-04-24 13:47       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-24 13:47 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Wed, Apr 24, 2019 at 09:39:31AM +0000, Alex Bennée wrote:
> 
> Dave Martin <Dave.Martin@arm.com> writes:
> 
> > Some optional features of the Arm architecture add new system
> > registers that are not present in the base architecture.
> >
> > Where these features are optional for the guest, the visibility of
> > these registers may need to depend on some runtime configuration,
> > such as a flag passed to KVM_ARM_VCPU_INIT.
> 
> This combined with...
> > --- a/arch/arm64/kvm/sys_regs.h
> > +++ b/arch/arm64/kvm/sys_regs.h
> > @@ -64,8 +64,15 @@ struct sys_reg_desc {
> >  			const struct kvm_one_reg *reg, void __user *uaddr);
> >  	int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
> >  			const struct kvm_one_reg *reg, void __user *uaddr);
> > +
> > +	/* Return mask of REG_* runtime visibility overrides */
> > +	unsigned int (*visibility)(const struct kvm_vcpu *vcpu,
> > +				   const struct sys_reg_desc *rd);
> >  };
> 
> this makes me wonder what sort of machines will see different register
> visibility depending on which vcpu you are running on?

Userspace can consciously set KVM_ARM_VCPU_SVE in vcpu_init.features[0]
for some vcpus and not for others.

For one thing, this is useful for testing how the guest responds to that
configuration.

This will for example allow Linux's handling of these weird
configurations to be tested directly rather than by hacking the
guest kernel to fake it up -- which is what I've had to do up to now.

> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

Thanks!

(Note, Marc already picked the patches into kvmarm/next, so new tags
won't be applied.  But the review is still appreciated, and if you spot
any issues I'd certainly like to know :)

Cheers
---Dave


_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 13/27] KVM: arm64/sve: Context switch the SVE registers
  2019-04-04  8:36           ` Dave Martin
@ 2019-04-24 14:51             ` Alex Bennée
  -1 siblings, 0 replies; 224+ messages in thread
From: Alex Bennée @ 2019-04-24 14:51 UTC (permalink / raw)
  To: kvmarm
  Cc: Christoffer Dall, Ard Biesheuvel, Marc Zyngier, Catalin Marinas,
	Will Deacon, Okamoto Takayuki, Zhang Lei, Julien Grall,
	linux-arm-kernel


Dave Martin <Dave.Martin@arm.com> writes:

> On Thu, Apr 04, 2019 at 10:35:02AM +0200, Andrew Jones wrote:
>> On Thu, Apr 04, 2019 at 09:10:08AM +0100, Dave Martin wrote:
>> > On Wed, Apr 03, 2019 at 10:01:45PM +0200, Andrew Jones wrote:
>> > > On Fri, Mar 29, 2019 at 01:00:38PM +0000, Dave Martin wrote:
>> > > > In order to give each vcpu its own view of the SVE registers, this
>> > > > patch adds context storage via a new sve_state pointer in struct
>> > > > vcpu_arch.  An additional member sve_max_vl is also added for each
>> > > > vcpu, to determine the maximum vector length visible to the guest
>> > > > and thus the value to be configured in ZCR_EL2.LEN while the vcpu
>> > > > is active.  This also determines the layout and size of the storage
>> > > > in sve_state, which is read and written by the same backend
>> > > > functions that are used for context-switching the SVE state for
>> > > > host tasks.
>> > > >
>> > > > On SVE-enabled vcpus, SVE access traps are now handled by switching
>> > > > in the vcpu's SVE context and disabling the trap before returning
>> > > > to the guest.  On other vcpus, the trap is not handled and an exit
>> > > > back to the host occurs, where the handle_sve() fallback path
>> > > > reflects an undefined instruction exception back to the guest,
>> > > > consistently with the behaviour of non-SVE-capable hardware (as was
>> > > > done unconditionally prior to this patch).
>> > > >
>> > > > No SVE handling is added on non-VHE-only paths, since VHE is an
>> > > > architectural and Kconfig prerequisite of SVE.
>> > > >
>> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
>> > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
>> > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
>> > > >
>> > > > ---
>> > > >
>> > > > Changes since v5:
>> > > >
>> > > >  * [Julien Thierry, Julien Grall] Commit message typo fixes
>> > > >
>> > > >  * [Mark Rutland] Rename trap_class to hsr_ec, for consistency with
>> > > >    existing code.
>> > > >
>> > > >  * [Mark Rutland] Simplify condition for refusing to handle an
>> > > >    FPSIMD/SVE trap, using multiple if () statements for clarity.  The
>> > > >    previous condition was a bit tortuous, and how that the static_key
>> > > >    checks have been hoisted out, it makes little difference to the
>> > > >    compiler how we express the condition here.
>> > > > ---
>> > > >  arch/arm64/include/asm/kvm_host.h |  6 ++++
>> > > >  arch/arm64/kvm/fpsimd.c           |  5 +--
>> > > >  arch/arm64/kvm/hyp/switch.c       | 75 +++++++++++++++++++++++++++++----------
>> > > >  3 files changed, 66 insertions(+), 20 deletions(-)
>> > > >
>> > > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
>> > > > index 22cf484..4fabfd2 100644
>> > > > --- a/arch/arm64/include/asm/kvm_host.h
>> > > > +++ b/arch/arm64/include/asm/kvm_host.h
>> > > > @@ -228,6 +228,8 @@ struct vcpu_reset_state {
>> > > >
>> > > >  struct kvm_vcpu_arch {
>> > > >  	struct kvm_cpu_context ctxt;
>> > > > +	void *sve_state;
>> > > > +	unsigned int sve_max_vl;
>> > > >
>> > > >  	/* HYP configuration */
>> > > >  	u64 hcr_el2;
>> > > > @@ -323,6 +325,10 @@ struct kvm_vcpu_arch {
>> > > >  	bool sysregs_loaded_on_cpu;
>> > > >  };
>> > > >
>> > > > +/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
>> > > > +#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
>> > > > +				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
>> > >
>> > > Maybe an inline function instead?
>> >
>> > I tried, but that requires the definition of struct kvm_vcpu to be
>> > visible.  I failed to get that here without circular #include problems,
>> > and it looked tricky to fix.
>>
>> Ah, OK
>>
>> >
>> > Since this is a small bit of code which is unlikely to get used by
>> > accident, I decided it was OK to keep it as a macro.
>> >
>> > Can you see another way around this?
>>
>> Nope
>
> OK.  If someone eventually solves this, I'd be happy to change to an
> inline function.

Is the function intended to be used by more call sites? Currently in the
tree with this plus the v2 fixups I can only see:

  arch/arm64/include/asm/kvm_host.h:333:#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
  arch/arm64/kvm/hyp/switch.c:388:		sve_load_state(vcpu_sve_pffr(vcpu),

--
Alex Bennée
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v7 13/27] KVM: arm64/sve: Context switch the SVE registers
@ 2019-04-24 14:51             ` Alex Bennée
  0 siblings, 0 replies; 224+ messages in thread
From: Alex Bennée @ 2019-04-24 14:51 UTC (permalink / raw)
  To: kvmarm
  Cc: Andrew Jones, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Okamoto Takayuki, Zhang Lei,
	Julien Grall, linux-arm-kernel


Dave Martin <Dave.Martin@arm.com> writes:

> On Thu, Apr 04, 2019 at 10:35:02AM +0200, Andrew Jones wrote:
>> On Thu, Apr 04, 2019 at 09:10:08AM +0100, Dave Martin wrote:
>> > On Wed, Apr 03, 2019 at 10:01:45PM +0200, Andrew Jones wrote:
>> > > On Fri, Mar 29, 2019 at 01:00:38PM +0000, Dave Martin wrote:
>> > > > In order to give each vcpu its own view of the SVE registers, this
>> > > > patch adds context storage via a new sve_state pointer in struct
>> > > > vcpu_arch.  An additional member sve_max_vl is also added for each
>> > > > vcpu, to determine the maximum vector length visible to the guest
>> > > > and thus the value to be configured in ZCR_EL2.LEN while the vcpu
>> > > > is active.  This also determines the layout and size of the storage
>> > > > in sve_state, which is read and written by the same backend
>> > > > functions that are used for context-switching the SVE state for
>> > > > host tasks.
>> > > >
>> > > > On SVE-enabled vcpus, SVE access traps are now handled by switching
>> > > > in the vcpu's SVE context and disabling the trap before returning
>> > > > to the guest.  On other vcpus, the trap is not handled and an exit
>> > > > back to the host occurs, where the handle_sve() fallback path
>> > > > reflects an undefined instruction exception back to the guest,
>> > > > consistently with the behaviour of non-SVE-capable hardware (as was
>> > > > done unconditionally prior to this patch).
>> > > >
>> > > > No SVE handling is added on non-VHE-only paths, since VHE is an
>> > > > architectural and Kconfig prerequisite of SVE.
>> > > >
>> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
>> > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
>> > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
>> > > >
>> > > > ---
>> > > >
>> > > > Changes since v5:
>> > > >
>> > > >  * [Julien Thierry, Julien Grall] Commit message typo fixes
>> > > >
>> > > >  * [Mark Rutland] Rename trap_class to hsr_ec, for consistency with
>> > > >    existing code.
>> > > >
>> > > >  * [Mark Rutland] Simplify condition for refusing to handle an
>> > > >    FPSIMD/SVE trap, using multiple if () statements for clarity.  The
>> > > >    previous condition was a bit tortuous, and how that the static_key
>> > > >    checks have been hoisted out, it makes little difference to the
>> > > >    compiler how we express the condition here.
>> > > > ---
>> > > >  arch/arm64/include/asm/kvm_host.h |  6 ++++
>> > > >  arch/arm64/kvm/fpsimd.c           |  5 +--
>> > > >  arch/arm64/kvm/hyp/switch.c       | 75 +++++++++++++++++++++++++++++----------
>> > > >  3 files changed, 66 insertions(+), 20 deletions(-)
>> > > >
>> > > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
>> > > > index 22cf484..4fabfd2 100644
>> > > > --- a/arch/arm64/include/asm/kvm_host.h
>> > > > +++ b/arch/arm64/include/asm/kvm_host.h
>> > > > @@ -228,6 +228,8 @@ struct vcpu_reset_state {
>> > > >
>> > > >  struct kvm_vcpu_arch {
>> > > >  	struct kvm_cpu_context ctxt;
>> > > > +	void *sve_state;
>> > > > +	unsigned int sve_max_vl;
>> > > >
>> > > >  	/* HYP configuration */
>> > > >  	u64 hcr_el2;
>> > > > @@ -323,6 +325,10 @@ struct kvm_vcpu_arch {
>> > > >  	bool sysregs_loaded_on_cpu;
>> > > >  };
>> > > >
>> > > > +/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
>> > > > +#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
>> > > > +				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
>> > >
>> > > Maybe an inline function instead?
>> >
>> > I tried, but that requires the definition of struct kvm_vcpu to be
>> > visible.  I failed to get that here without circular #include problems,
>> > and it looked tricky to fix.
>>
>> Ah, OK
>>
>> >
>> > Since this is a small bit of code which is unlikely to get used by
>> > accident, I decided it was OK to keep it as a macro.
>> >
>> > Can you see another way around this?
>>
>> Nope
>
> OK.  If someone eventually solves this, I'd be happy to change to an
> inline function.

Is the function intended to be used by more call sites? Currently in the
tree with this plus the v2 fixups I can only see:

  arch/arm64/include/asm/kvm_host.h:333:#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
  arch/arm64/kvm/hyp/switch.c:388:		sve_load_state(vcpu_sve_pffr(vcpu),

--
Alex Bennée

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 12/27] KVM: arm64/sve: System register context switch and access support
  2019-03-29 13:00   ` Dave Martin
@ 2019-04-24 15:21     ` Alex Bennée
  -1 siblings, 0 replies; 224+ messages in thread
From: Alex Bennée @ 2019-04-24 15:21 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel


Dave Martin <Dave.Martin@arm.com> writes:

> This patch adds the necessary support for context switching ZCR_EL1
> for each vcpu.
>
> ZCR_EL1 is trapped alongside the FPSIMD/SVE registers, so it makes
> sense for it to be handled as part of the guest FPSIMD/SVE context
> for context switch purposes instead of handling it as a general
> system register.  This means that it can be switched in lazily at
> the appropriate time.  No effort is made to track host context for
> this register, since SVE requires VHE: thus the hosts's value for
> this register lives permanently in ZCR_EL2 and does not alias the
> guest's value at any time.
>
> The Hyp switch and fpsimd context handling code is extended
> appropriately.
>
> Accessors are added in sys_regs.c to expose the SVE system
> registers and ID register fields.  Because these need to be
> conditionally visible based on the guest configuration, they are
> implemented separately for now rather than by use of the generic
> system register helpers.  This may be abstracted better later on
> when/if there are more features requiring this model.
>
> ID_AA64ZFR0_EL1 is RO-RAZ for MRS/MSR when SVE is disabled for the
> guest, but for compatibility with non-SVE aware KVM implementations
> the register should not be enumerated at all for KVM_GET_REG_LIST
> in this case.  For consistency we also reject ioctl access to the
> register.  This ensures that a non-SVE-enabled guest looks the same
> to userspace, irrespective of whether the kernel KVM implementation
> supports SVE.
>
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
>
> ---
>
> Changes since v5:
>
>  * Port to the renamed visibility() framework.
>
>  * Swap visiblity() helpers so that they appear by the relevant accessor
>    functions.
>
>  * [Julien Grall] With the visibility() checks, {get,set}_zcr_el1()
>    degenerate to doing exactly what the common code does, so drop them.
>
>    The ID_AA64ZFR0_EL1 handlers are still needed to provide contitional
>    RAZ behaviour.  This could be moved to the common code too, but since
>    this is a one-off case I don't do this for now.  We can address this
>    later if other regs need to follow the same pattern.
>
>  * [Julien Thierry] Reset ZCR_EL1 to a fixed value using reset_val
>    instead of using relying on reset_unknown() honouring set bits in val
>    as RES0.
>
>    Most of the bits in ZCR_EL1 are RES0 anyway, and many implementations
>    of SVE will support larger vectors than 128 bits, so 0 seems as good
>    a value as any to expose guests that forget to initialise this
>    register properly.
> ---
>  arch/arm64/include/asm/kvm_host.h |  1 +
>  arch/arm64/include/asm/sysreg.h   |  3 ++
>  arch/arm64/kvm/fpsimd.c           |  9 ++++-
>  arch/arm64/kvm/hyp/switch.c       |  3 ++
>  arch/arm64/kvm/sys_regs.c         | 83 ++++++++++++++++++++++++++++++++++++---
>  5 files changed, 93 insertions(+), 6 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index ad4f7f0..22cf484 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -121,6 +121,7 @@ enum vcpu_sysreg {
>  	SCTLR_EL1,	/* System Control Register */
>  	ACTLR_EL1,	/* Auxiliary Control Register */
>  	CPACR_EL1,	/* Coprocessor Access Control */
> +	ZCR_EL1,	/* SVE Control */
>  	TTBR0_EL1,	/* Translation Table Base Register 0 */
>  	TTBR1_EL1,	/* Translation Table Base Register 1 */
>  	TCR_EL1,	/* Translation Control Register */
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index 5b267de..4d6262d 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -454,6 +454,9 @@
>  #define SYS_ICH_LR14_EL2		__SYS__LR8_EL2(6)
>  #define SYS_ICH_LR15_EL2		__SYS__LR8_EL2(7)
>
> +/* VHE encodings for architectural EL0/1 system registers */
> +#define SYS_ZCR_EL12			sys_reg(3, 5, 1, 2, 0)
> +
>  /* Common SCTLR_ELx flags. */
>  #define SCTLR_ELx_DSSBS	(_BITUL(44))
>  #define SCTLR_ELx_ENIA	(_BITUL(31))
> diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
> index 1cf4f02..7053bf4 100644
> --- a/arch/arm64/kvm/fpsimd.c
> +++ b/arch/arm64/kvm/fpsimd.c
> @@ -103,14 +103,21 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
>  void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
>  {
>  	unsigned long flags;
> +	bool host_has_sve = system_supports_sve();
> +	bool guest_has_sve = vcpu_has_sve(vcpu);
>
>  	local_irq_save(flags);
>
>  	if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
> +		u64 *guest_zcr = &vcpu->arch.ctxt.sys_regs[ZCR_EL1];
> +

Is this just to avoid:

   vcpu->arch.ctxt.sys_regs[ZCR_EL1] = read_sysreg_s(SYS_ZCR_EL12);

in fact wouldn't:

   __vcpu_sys_reg(vcpu,ZCR_EL1) = read_sysreg_s(SYS_ZCR_EL12);

do?

>  		/* Clean guest FP state to memory and invalidate cpu view */
>  		fpsimd_save();
>  		fpsimd_flush_cpu_state();
> -	} else if (system_supports_sve()) {
> +
> +		if (guest_has_sve)
> +			*guest_zcr = read_sysreg_s(SYS_ZCR_EL12);
> +	} else if (host_has_sve) {
>  		/*
>  		 * The FPSIMD/SVE state in the CPU has not been touched, and we
>  		 * have SVE (and VHE): CPACR_EL1 (alias CPTR_EL2) has been
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 3563fe6..9d46066 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -351,6 +351,9 @@ static bool __hyp_text __hyp_switch_fpsimd(struct kvm_vcpu *vcpu)
>
>  	__fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
>
> +	if (vcpu_has_sve(vcpu))
> +		write_sysreg_s(vcpu->arch.ctxt.sys_regs[ZCR_EL1], SYS_ZCR_EL12);
> +

__vcpu_sys_reg?

>  	/* Skip restoring fpexc32 for AArch64 guests */
>  	if (!(read_sysreg(hcr_el2) & HCR_RW))
>  		write_sysreg(vcpu->arch.ctxt.sys_regs[FPEXC32_EL2],
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index c86a7b0..09e9b06 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -1051,10 +1051,7 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
>  			 (u32)r->CRn, (u32)r->CRm, (u32)r->Op2);
>  	u64 val = raz ? 0 : read_sanitised_ftr_reg(id);
>
> -	if (id == SYS_ID_AA64PFR0_EL1) {
> -		if (val & (0xfUL << ID_AA64PFR0_SVE_SHIFT))
> -			kvm_debug("SVE unsupported for guests, suppressing\n");
> -
> +	if (id == SYS_ID_AA64PFR0_EL1 && !vcpu_has_sve(vcpu)) {
>  		val &= ~(0xfUL << ID_AA64PFR0_SVE_SHIFT);
>  	} else if (id == SYS_ID_AA64ISAR1_EL1) {
>  		const u64 ptrauth_mask = (0xfUL << ID_AA64ISAR1_APA_SHIFT) |
> @@ -1101,6 +1098,81 @@ static int reg_from_user(u64 *val, const void __user *uaddr, u64 id);
>  static int reg_to_user(void __user *uaddr, const u64 *val, u64 id);
>  static u64 sys_reg_to_index(const struct sys_reg_desc *reg);
>
> +/* Visibility overrides for SVE-specific control registers */
> +static unsigned int sve_visibility(const struct kvm_vcpu *vcpu,
> +				   const struct sys_reg_desc *rd)
> +{
> +	if (vcpu_has_sve(vcpu))
> +		return 0;
> +
> +	return REG_HIDDEN_USER | REG_HIDDEN_GUEST;
> +}
> +
> +/* Visibility overrides for SVE-specific ID registers */
> +static unsigned int sve_id_visibility(const struct kvm_vcpu *vcpu,
> +				      const struct sys_reg_desc *rd)
> +{
> +	if (vcpu_has_sve(vcpu))
> +		return 0;
> +
> +	return REG_HIDDEN_USER;
> +}
> +
> +/* Generate the emulated ID_AA64ZFR0_EL1 value exposed to the guest */
> +static u64 guest_id_aa64zfr0_el1(const struct kvm_vcpu *vcpu)
> +{
> +	if (!vcpu_has_sve(vcpu))
> +		return 0;
> +
> +	return read_sanitised_ftr_reg(SYS_ID_AA64ZFR0_EL1);
> +}
> +
> +static bool access_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> +				   struct sys_reg_params *p,
> +				   const struct sys_reg_desc *rd)
> +{
> +	if (p->is_write)
> +		return write_to_read_only(vcpu, p, rd);
> +
> +	p->regval = guest_id_aa64zfr0_el1(vcpu);
> +	return true;
> +}
> +
> +static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> +		const struct sys_reg_desc *rd,
> +		const struct kvm_one_reg *reg, void __user *uaddr)
> +{
> +	u64 val;
> +
> +	if (!vcpu_has_sve(vcpu))
> +		return -ENOENT;
> +
> +	val = guest_id_aa64zfr0_el1(vcpu);
> +	return reg_to_user(uaddr, &val, reg->id);
> +}
> +
> +static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> +		const struct sys_reg_desc *rd,
> +		const struct kvm_one_reg *reg, void __user *uaddr)
> +{
> +	const u64 id = sys_reg_to_index(rd);
> +	int err;
> +	u64 val;
> +
> +	if (!vcpu_has_sve(vcpu))
> +		return -ENOENT;
> +
> +	err = reg_from_user(&val, uaddr, id);
> +	if (err)
> +		return err;
> +
> +	/* This is what we mean by invariant: you can't change it. */
> +	if (val != guest_id_aa64zfr0_el1(vcpu))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /*
>   * cpufeature ID register user accessors
>   *
> @@ -1346,7 +1418,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  	ID_SANITISED(ID_AA64PFR1_EL1),
>  	ID_UNALLOCATED(4,2),
>  	ID_UNALLOCATED(4,3),
> -	ID_UNALLOCATED(4,4),
> +	{ SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility },

long line...

>  	ID_UNALLOCATED(4,5),
>  	ID_UNALLOCATED(4,6),
>  	ID_UNALLOCATED(4,7),
> @@ -1383,6 +1455,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>
>  	{ SYS_DESC(SYS_SCTLR_EL1), access_vm_reg, reset_val, SCTLR_EL1, 0x00C50078 },
>  	{ SYS_DESC(SYS_CPACR_EL1), NULL, reset_val, CPACR_EL1, 0 },
> +	{ SYS_DESC(SYS_ZCR_EL1), NULL, reset_val, ZCR_EL1, 0, .visibility = sve_visibility },
>  	{ SYS_DESC(SYS_TTBR0_EL1), access_vm_reg, reset_unknown, TTBR0_EL1 },
>  	{ SYS_DESC(SYS_TTBR1_EL1), access_vm_reg, reset_unknown, TTBR1_EL1 },
>  	{ SYS_DESC(SYS_TCR_EL1), access_vm_reg, reset_val, TCR_EL1, 0 },

Minor nits aside:

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

--
Alex Bennée
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v7 12/27] KVM: arm64/sve: System register context switch and access support
@ 2019-04-24 15:21     ` Alex Bennée
  0 siblings, 0 replies; 224+ messages in thread
From: Alex Bennée @ 2019-04-24 15:21 UTC (permalink / raw)
  To: Dave Martin
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, kvmarm, linux-arm-kernel


Dave Martin <Dave.Martin@arm.com> writes:

> This patch adds the necessary support for context switching ZCR_EL1
> for each vcpu.
>
> ZCR_EL1 is trapped alongside the FPSIMD/SVE registers, so it makes
> sense for it to be handled as part of the guest FPSIMD/SVE context
> for context switch purposes instead of handling it as a general
> system register.  This means that it can be switched in lazily at
> the appropriate time.  No effort is made to track host context for
> this register, since SVE requires VHE: thus the hosts's value for
> this register lives permanently in ZCR_EL2 and does not alias the
> guest's value at any time.
>
> The Hyp switch and fpsimd context handling code is extended
> appropriately.
>
> Accessors are added in sys_regs.c to expose the SVE system
> registers and ID register fields.  Because these need to be
> conditionally visible based on the guest configuration, they are
> implemented separately for now rather than by use of the generic
> system register helpers.  This may be abstracted better later on
> when/if there are more features requiring this model.
>
> ID_AA64ZFR0_EL1 is RO-RAZ for MRS/MSR when SVE is disabled for the
> guest, but for compatibility with non-SVE aware KVM implementations
> the register should not be enumerated at all for KVM_GET_REG_LIST
> in this case.  For consistency we also reject ioctl access to the
> register.  This ensures that a non-SVE-enabled guest looks the same
> to userspace, irrespective of whether the kernel KVM implementation
> supports SVE.
>
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
>
> ---
>
> Changes since v5:
>
>  * Port to the renamed visibility() framework.
>
>  * Swap visiblity() helpers so that they appear by the relevant accessor
>    functions.
>
>  * [Julien Grall] With the visibility() checks, {get,set}_zcr_el1()
>    degenerate to doing exactly what the common code does, so drop them.
>
>    The ID_AA64ZFR0_EL1 handlers are still needed to provide contitional
>    RAZ behaviour.  This could be moved to the common code too, but since
>    this is a one-off case I don't do this for now.  We can address this
>    later if other regs need to follow the same pattern.
>
>  * [Julien Thierry] Reset ZCR_EL1 to a fixed value using reset_val
>    instead of using relying on reset_unknown() honouring set bits in val
>    as RES0.
>
>    Most of the bits in ZCR_EL1 are RES0 anyway, and many implementations
>    of SVE will support larger vectors than 128 bits, so 0 seems as good
>    a value as any to expose guests that forget to initialise this
>    register properly.
> ---
>  arch/arm64/include/asm/kvm_host.h |  1 +
>  arch/arm64/include/asm/sysreg.h   |  3 ++
>  arch/arm64/kvm/fpsimd.c           |  9 ++++-
>  arch/arm64/kvm/hyp/switch.c       |  3 ++
>  arch/arm64/kvm/sys_regs.c         | 83 ++++++++++++++++++++++++++++++++++++---
>  5 files changed, 93 insertions(+), 6 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index ad4f7f0..22cf484 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -121,6 +121,7 @@ enum vcpu_sysreg {
>  	SCTLR_EL1,	/* System Control Register */
>  	ACTLR_EL1,	/* Auxiliary Control Register */
>  	CPACR_EL1,	/* Coprocessor Access Control */
> +	ZCR_EL1,	/* SVE Control */
>  	TTBR0_EL1,	/* Translation Table Base Register 0 */
>  	TTBR1_EL1,	/* Translation Table Base Register 1 */
>  	TCR_EL1,	/* Translation Control Register */
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index 5b267de..4d6262d 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -454,6 +454,9 @@
>  #define SYS_ICH_LR14_EL2		__SYS__LR8_EL2(6)
>  #define SYS_ICH_LR15_EL2		__SYS__LR8_EL2(7)
>
> +/* VHE encodings for architectural EL0/1 system registers */
> +#define SYS_ZCR_EL12			sys_reg(3, 5, 1, 2, 0)
> +
>  /* Common SCTLR_ELx flags. */
>  #define SCTLR_ELx_DSSBS	(_BITUL(44))
>  #define SCTLR_ELx_ENIA	(_BITUL(31))
> diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
> index 1cf4f02..7053bf4 100644
> --- a/arch/arm64/kvm/fpsimd.c
> +++ b/arch/arm64/kvm/fpsimd.c
> @@ -103,14 +103,21 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
>  void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
>  {
>  	unsigned long flags;
> +	bool host_has_sve = system_supports_sve();
> +	bool guest_has_sve = vcpu_has_sve(vcpu);
>
>  	local_irq_save(flags);
>
>  	if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
> +		u64 *guest_zcr = &vcpu->arch.ctxt.sys_regs[ZCR_EL1];
> +

Is this just to avoid:

   vcpu->arch.ctxt.sys_regs[ZCR_EL1] = read_sysreg_s(SYS_ZCR_EL12);

in fact wouldn't:

   __vcpu_sys_reg(vcpu,ZCR_EL1) = read_sysreg_s(SYS_ZCR_EL12);

do?

>  		/* Clean guest FP state to memory and invalidate cpu view */
>  		fpsimd_save();
>  		fpsimd_flush_cpu_state();
> -	} else if (system_supports_sve()) {
> +
> +		if (guest_has_sve)
> +			*guest_zcr = read_sysreg_s(SYS_ZCR_EL12);
> +	} else if (host_has_sve) {
>  		/*
>  		 * The FPSIMD/SVE state in the CPU has not been touched, and we
>  		 * have SVE (and VHE): CPACR_EL1 (alias CPTR_EL2) has been
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 3563fe6..9d46066 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -351,6 +351,9 @@ static bool __hyp_text __hyp_switch_fpsimd(struct kvm_vcpu *vcpu)
>
>  	__fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
>
> +	if (vcpu_has_sve(vcpu))
> +		write_sysreg_s(vcpu->arch.ctxt.sys_regs[ZCR_EL1], SYS_ZCR_EL12);
> +

__vcpu_sys_reg?

>  	/* Skip restoring fpexc32 for AArch64 guests */
>  	if (!(read_sysreg(hcr_el2) & HCR_RW))
>  		write_sysreg(vcpu->arch.ctxt.sys_regs[FPEXC32_EL2],
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index c86a7b0..09e9b06 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -1051,10 +1051,7 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
>  			 (u32)r->CRn, (u32)r->CRm, (u32)r->Op2);
>  	u64 val = raz ? 0 : read_sanitised_ftr_reg(id);
>
> -	if (id == SYS_ID_AA64PFR0_EL1) {
> -		if (val & (0xfUL << ID_AA64PFR0_SVE_SHIFT))
> -			kvm_debug("SVE unsupported for guests, suppressing\n");
> -
> +	if (id == SYS_ID_AA64PFR0_EL1 && !vcpu_has_sve(vcpu)) {
>  		val &= ~(0xfUL << ID_AA64PFR0_SVE_SHIFT);
>  	} else if (id == SYS_ID_AA64ISAR1_EL1) {
>  		const u64 ptrauth_mask = (0xfUL << ID_AA64ISAR1_APA_SHIFT) |
> @@ -1101,6 +1098,81 @@ static int reg_from_user(u64 *val, const void __user *uaddr, u64 id);
>  static int reg_to_user(void __user *uaddr, const u64 *val, u64 id);
>  static u64 sys_reg_to_index(const struct sys_reg_desc *reg);
>
> +/* Visibility overrides for SVE-specific control registers */
> +static unsigned int sve_visibility(const struct kvm_vcpu *vcpu,
> +				   const struct sys_reg_desc *rd)
> +{
> +	if (vcpu_has_sve(vcpu))
> +		return 0;
> +
> +	return REG_HIDDEN_USER | REG_HIDDEN_GUEST;
> +}
> +
> +/* Visibility overrides for SVE-specific ID registers */
> +static unsigned int sve_id_visibility(const struct kvm_vcpu *vcpu,
> +				      const struct sys_reg_desc *rd)
> +{
> +	if (vcpu_has_sve(vcpu))
> +		return 0;
> +
> +	return REG_HIDDEN_USER;
> +}
> +
> +/* Generate the emulated ID_AA64ZFR0_EL1 value exposed to the guest */
> +static u64 guest_id_aa64zfr0_el1(const struct kvm_vcpu *vcpu)
> +{
> +	if (!vcpu_has_sve(vcpu))
> +		return 0;
> +
> +	return read_sanitised_ftr_reg(SYS_ID_AA64ZFR0_EL1);
> +}
> +
> +static bool access_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> +				   struct sys_reg_params *p,
> +				   const struct sys_reg_desc *rd)
> +{
> +	if (p->is_write)
> +		return write_to_read_only(vcpu, p, rd);
> +
> +	p->regval = guest_id_aa64zfr0_el1(vcpu);
> +	return true;
> +}
> +
> +static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> +		const struct sys_reg_desc *rd,
> +		const struct kvm_one_reg *reg, void __user *uaddr)
> +{
> +	u64 val;
> +
> +	if (!vcpu_has_sve(vcpu))
> +		return -ENOENT;
> +
> +	val = guest_id_aa64zfr0_el1(vcpu);
> +	return reg_to_user(uaddr, &val, reg->id);
> +}
> +
> +static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
> +		const struct sys_reg_desc *rd,
> +		const struct kvm_one_reg *reg, void __user *uaddr)
> +{
> +	const u64 id = sys_reg_to_index(rd);
> +	int err;
> +	u64 val;
> +
> +	if (!vcpu_has_sve(vcpu))
> +		return -ENOENT;
> +
> +	err = reg_from_user(&val, uaddr, id);
> +	if (err)
> +		return err;
> +
> +	/* This is what we mean by invariant: you can't change it. */
> +	if (val != guest_id_aa64zfr0_el1(vcpu))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /*
>   * cpufeature ID register user accessors
>   *
> @@ -1346,7 +1418,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  	ID_SANITISED(ID_AA64PFR1_EL1),
>  	ID_UNALLOCATED(4,2),
>  	ID_UNALLOCATED(4,3),
> -	ID_UNALLOCATED(4,4),
> +	{ SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility },

long line...

>  	ID_UNALLOCATED(4,5),
>  	ID_UNALLOCATED(4,6),
>  	ID_UNALLOCATED(4,7),
> @@ -1383,6 +1455,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>
>  	{ SYS_DESC(SYS_SCTLR_EL1), access_vm_reg, reset_val, SCTLR_EL1, 0x00C50078 },
>  	{ SYS_DESC(SYS_CPACR_EL1), NULL, reset_val, CPACR_EL1, 0 },
> +	{ SYS_DESC(SYS_ZCR_EL1), NULL, reset_val, ZCR_EL1, 0, .visibility = sve_visibility },
>  	{ SYS_DESC(SYS_TTBR0_EL1), access_vm_reg, reset_unknown, TTBR0_EL1 },
>  	{ SYS_DESC(SYS_TTBR1_EL1), access_vm_reg, reset_unknown, TTBR1_EL1 },
>  	{ SYS_DESC(SYS_TCR_EL1), access_vm_reg, reset_val, TCR_EL1, 0 },

Minor nits aside:

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

--
Alex Bennée

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 00/27] KVM: arm64: SVE guest support
  2019-03-29 13:00 ` Dave Martin
@ 2019-04-25 10:33   ` Alex Bennée
  -1 siblings, 0 replies; 224+ messages in thread
From: Alex Bennée @ 2019-04-25 10:33 UTC (permalink / raw)
  To: Dave Martin
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel


Dave Martin <Dave.Martin@arm.com> writes:

> This series implements support for allowing KVM guests to use the Arm
> Scalable Vector Extension (SVE), superseding the previous v6 series [1].
>
> The patches are also available on a branch for reviewer convenience. [2]
>
> The patches are based on v5.1-rc2.
>
> This series addresses a couple of minor review comments received on v6
> and otherwise applies reviewer tags only.  The code differences
> between v6 and this series consist of minor cosmetic fixups only.
>
> Draft kvmtool patches were posted separately [3], [4].
>
> For a description of minor updates, see the individual patches.
>
>
> Thanks go to Julien Thierry and Julian Grall for their review efforts,
> and to Zhang Lei for testing the series -- many thanks for their help
> in getting the series to this point!
>
>
> Reviewers' attention is drawn to the following patches, which have no
> Reviewed-by/Acked-by.  Please take a look if you have a moment.
>
>  * Patch 11 (KVM: arm64: Support runtime sysreg visibility filtering)
>
>    Previously Reviewed-by Julien Thierry, but this version of the
>    patch contains some minor rework suggested by Mark Rutland during
>    the v5 review [5].
>
>  * Patch 15 (KVM: arm64: Add missing #include of <linux/string.h>
>    in guest.c)
>
>    (Trivial patch.)
>
>  * Patch 26: (KVM: Document errors for KVM_GET_ONE_REG and
>    KVM_SET_ONE_REG)
>
>    (Documentation only.)
>
>  * Patch 27: KVM: arm64/sve: Document KVM API extensions for SVE
>
>    (Documentation only.)

I've finished going through the series. Aside from a few minor nits and
the discussion you've already had with drew happy with it. Have a
general:

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

for the mail record...
>
> Known issues: none
>
>
> Testing status:
>
>  * Lightweight testing on the Arm Fast Model, primarily to exercise the
>    new vcpu finalization API.
>
>    Ran sve-stress testing for several days on v6 on the Arm Fast Model,
>    with no errors observed.

Once we have VHE support in QEMU I intend to give it a bit more testing.

--
Alex Bennée
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH v7 00/27] KVM: arm64: SVE guest support
@ 2019-04-25 10:33   ` Alex Bennée
  0 siblings, 0 replies; 224+ messages in thread
From: Alex Bennée @ 2019-04-25 10:33 UTC (permalink / raw)
  To: Dave Martin
  Cc: Peter Maydell, Okamoto Takayuki, Christoffer Dall,
	Ard Biesheuvel, Marc Zyngier, Catalin Marinas, Will Deacon,
	Zhang Lei, Julien Grall, kvmarm, linux-arm-kernel


Dave Martin <Dave.Martin@arm.com> writes:

> This series implements support for allowing KVM guests to use the Arm
> Scalable Vector Extension (SVE), superseding the previous v6 series [1].
>
> The patches are also available on a branch for reviewer convenience. [2]
>
> The patches are based on v5.1-rc2.
>
> This series addresses a couple of minor review comments received on v6
> and otherwise applies reviewer tags only.  The code differences
> between v6 and this series consist of minor cosmetic fixups only.
>
> Draft kvmtool patches were posted separately [3], [4].
>
> For a description of minor updates, see the individual patches.
>
>
> Thanks go to Julien Thierry and Julian Grall for their review efforts,
> and to Zhang Lei for testing the series -- many thanks for their help
> in getting the series to this point!
>
>
> Reviewers' attention is drawn to the following patches, which have no
> Reviewed-by/Acked-by.  Please take a look if you have a moment.
>
>  * Patch 11 (KVM: arm64: Support runtime sysreg visibility filtering)
>
>    Previously Reviewed-by Julien Thierry, but this version of the
>    patch contains some minor rework suggested by Mark Rutland during
>    the v5 review [5].
>
>  * Patch 15 (KVM: arm64: Add missing #include of <linux/string.h>
>    in guest.c)
>
>    (Trivial patch.)
>
>  * Patch 26: (KVM: Document errors for KVM_GET_ONE_REG and
>    KVM_SET_ONE_REG)
>
>    (Documentation only.)
>
>  * Patch 27: KVM: arm64/sve: Document KVM API extensions for SVE
>
>    (Documentation only.)

I've finished going through the series. Aside from a few minor nits and
the discussion you've already had with drew happy with it. Have a
general:

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

for the mail record...
>
> Known issues: none
>
>
> Testing status:
>
>  * Lightweight testing on the Arm Fast Model, primarily to exercise the
>    new vcpu finalization API.
>
>    Ran sve-stress testing for several days on v6 on the Arm Fast Model,
>    with no errors observed.

Once we have VHE support in QEMU I intend to give it a bit more testing.

--
Alex Bennée

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 12/27] KVM: arm64/sve: System register context switch and access support
@ 2019-04-25 13:28       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-25 13:28 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Wed, Apr 24, 2019 at 04:21:22PM +0100, Alex Bennée wrote:
> 
> Dave Martin <Dave.Martin@arm.com> writes:
> 
> > This patch adds the necessary support for context switching ZCR_EL1
> > for each vcpu.
> >
> > ZCR_EL1 is trapped alongside the FPSIMD/SVE registers, so it makes
> > sense for it to be handled as part of the guest FPSIMD/SVE context
> > for context switch purposes instead of handling it as a general
> > system register.  This means that it can be switched in lazily at
> > the appropriate time.  No effort is made to track host context for
> > this register, since SVE requires VHE: thus the hosts's value for
> > this register lives permanently in ZCR_EL2 and does not alias the
> > guest's value at any time.
> >
> > The Hyp switch and fpsimd context handling code is extended
> > appropriately.
> >
> > Accessors are added in sys_regs.c to expose the SVE system
> > registers and ID register fields.  Because these need to be
> > conditionally visible based on the guest configuration, they are
> > implemented separately for now rather than by use of the generic
> > system register helpers.  This may be abstracted better later on
> > when/if there are more features requiring this model.
> >
> > ID_AA64ZFR0_EL1 is RO-RAZ for MRS/MSR when SVE is disabled for the
> > guest, but for compatibility with non-SVE aware KVM implementations
> > the register should not be enumerated at all for KVM_GET_REG_LIST
> > in this case.  For consistency we also reject ioctl access to the
> > register.  This ensures that a non-SVE-enabled guest looks the same
> > to userspace, irrespective of whether the kernel KVM implementation
> > supports SVE.
> >
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> >
> > ---
> >

[...]

> > diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
> > index 1cf4f02..7053bf4 100644
> > --- a/arch/arm64/kvm/fpsimd.c
> > +++ b/arch/arm64/kvm/fpsimd.c
> > @@ -103,14 +103,21 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
> >  void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
> >  {
> >  	unsigned long flags;
> > +	bool host_has_sve = system_supports_sve();
> > +	bool guest_has_sve = vcpu_has_sve(vcpu);
> >
> >  	local_irq_save(flags);
> >
> >  	if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
> > +		u64 *guest_zcr = &vcpu->arch.ctxt.sys_regs[ZCR_EL1];
> > +
> 
> Is this just to avoid:
> 
>    vcpu->arch.ctxt.sys_regs[ZCR_EL1] = read_sysreg_s(SYS_ZCR_EL12);

No, it's just done to shorten the line.  Otherwise a trailing = is hard
to avoid (which Marc didn't like) or the line has to be over 80 chars
(which I didn't like).

> in fact wouldn't:
> 
>    __vcpu_sys_reg(vcpu,ZCR_EL1) = read_sysreg_s(SYS_ZCR_EL12);

We could use __vcpu_sys_reg() yes, I missed that.

I could spin a patch for this, but it doesn't feel like a high priority
at this stage.

[...]

> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

Thanks
---Dave

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

* Re: [PATCH v7 12/27] KVM: arm64/sve: System register context switch and access support
@ 2019-04-25 13:28       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-25 13:28 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="UTF-8", Size: 3247 bytes --]

On Wed, Apr 24, 2019 at 04:21:22PM +0100, Alex Bennée wrote:
> 
> Dave Martin <Dave.Martin@arm.com> writes:
> 
> > This patch adds the necessary support for context switching ZCR_EL1
> > for each vcpu.
> >
> > ZCR_EL1 is trapped alongside the FPSIMD/SVE registers, so it makes
> > sense for it to be handled as part of the guest FPSIMD/SVE context
> > for context switch purposes instead of handling it as a general
> > system register.  This means that it can be switched in lazily at
> > the appropriate time.  No effort is made to track host context for
> > this register, since SVE requires VHE: thus the hosts's value for
> > this register lives permanently in ZCR_EL2 and does not alias the
> > guest's value at any time.
> >
> > The Hyp switch and fpsimd context handling code is extended
> > appropriately.
> >
> > Accessors are added in sys_regs.c to expose the SVE system
> > registers and ID register fields.  Because these need to be
> > conditionally visible based on the guest configuration, they are
> > implemented separately for now rather than by use of the generic
> > system register helpers.  This may be abstracted better later on
> > when/if there are more features requiring this model.
> >
> > ID_AA64ZFR0_EL1 is RO-RAZ for MRS/MSR when SVE is disabled for the
> > guest, but for compatibility with non-SVE aware KVM implementations
> > the register should not be enumerated at all for KVM_GET_REG_LIST
> > in this case.  For consistency we also reject ioctl access to the
> > register.  This ensures that a non-SVE-enabled guest looks the same
> > to userspace, irrespective of whether the kernel KVM implementation
> > supports SVE.
> >
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> >
> > ---
> >

[...]

> > diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
> > index 1cf4f02..7053bf4 100644
> > --- a/arch/arm64/kvm/fpsimd.c
> > +++ b/arch/arm64/kvm/fpsimd.c
> > @@ -103,14 +103,21 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
> >  void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
> >  {
> >  	unsigned long flags;
> > +	bool host_has_sve = system_supports_sve();
> > +	bool guest_has_sve = vcpu_has_sve(vcpu);
> >
> >  	local_irq_save(flags);
> >
> >  	if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
> > +		u64 *guest_zcr = &vcpu->arch.ctxt.sys_regs[ZCR_EL1];
> > +
> 
> Is this just to avoid:
> 
>    vcpu->arch.ctxt.sys_regs[ZCR_EL1] = read_sysreg_s(SYS_ZCR_EL12);

No, it's just done to shorten the line.  Otherwise a trailing = is hard
to avoid (which Marc didn't like) or the line has to be over 80 chars
(which I didn't like).

> in fact wouldn't:
> 
>    __vcpu_sys_reg(vcpu,ZCR_EL1) = read_sysreg_s(SYS_ZCR_EL12);

We could use __vcpu_sys_reg() yes, I missed that.

I could spin a patch for this, but it doesn't feel like a high priority
at this stage.

[...]

> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

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

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

* Re: [PATCH v7 12/27] KVM: arm64/sve: System register context switch and access support
@ 2019-04-25 13:28       ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-25 13:28 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Wed, Apr 24, 2019 at 04:21:22PM +0100, Alex Bennée wrote:
> 
> Dave Martin <Dave.Martin@arm.com> writes:
> 
> > This patch adds the necessary support for context switching ZCR_EL1
> > for each vcpu.
> >
> > ZCR_EL1 is trapped alongside the FPSIMD/SVE registers, so it makes
> > sense for it to be handled as part of the guest FPSIMD/SVE context
> > for context switch purposes instead of handling it as a general
> > system register.  This means that it can be switched in lazily at
> > the appropriate time.  No effort is made to track host context for
> > this register, since SVE requires VHE: thus the hosts's value for
> > this register lives permanently in ZCR_EL2 and does not alias the
> > guest's value at any time.
> >
> > The Hyp switch and fpsimd context handling code is extended
> > appropriately.
> >
> > Accessors are added in sys_regs.c to expose the SVE system
> > registers and ID register fields.  Because these need to be
> > conditionally visible based on the guest configuration, they are
> > implemented separately for now rather than by use of the generic
> > system register helpers.  This may be abstracted better later on
> > when/if there are more features requiring this model.
> >
> > ID_AA64ZFR0_EL1 is RO-RAZ for MRS/MSR when SVE is disabled for the
> > guest, but for compatibility with non-SVE aware KVM implementations
> > the register should not be enumerated at all for KVM_GET_REG_LIST
> > in this case.  For consistency we also reject ioctl access to the
> > register.  This ensures that a non-SVE-enabled guest looks the same
> > to userspace, irrespective of whether the kernel KVM implementation
> > supports SVE.
> >
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> >
> > ---
> >

[...]

> > diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
> > index 1cf4f02..7053bf4 100644
> > --- a/arch/arm64/kvm/fpsimd.c
> > +++ b/arch/arm64/kvm/fpsimd.c
> > @@ -103,14 +103,21 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
> >  void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
> >  {
> >  	unsigned long flags;
> > +	bool host_has_sve = system_supports_sve();
> > +	bool guest_has_sve = vcpu_has_sve(vcpu);
> >
> >  	local_irq_save(flags);
> >
> >  	if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) {
> > +		u64 *guest_zcr = &vcpu->arch.ctxt.sys_regs[ZCR_EL1];
> > +
> 
> Is this just to avoid:
> 
>    vcpu->arch.ctxt.sys_regs[ZCR_EL1] = read_sysreg_s(SYS_ZCR_EL12);

No, it's just done to shorten the line.  Otherwise a trailing = is hard
to avoid (which Marc didn't like) or the line has to be over 80 chars
(which I didn't like).

> in fact wouldn't:
> 
>    __vcpu_sys_reg(vcpu,ZCR_EL1) = read_sysreg_s(SYS_ZCR_EL12);

We could use __vcpu_sys_reg() yes, I missed that.

I could spin a patch for this, but it doesn't feel like a high priority
at this stage.

[...]

> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

Thanks
---Dave

_______________________________________________
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] 224+ messages in thread

* Re: [PATCH v7 13/27] KVM: arm64/sve: Context switch the SVE registers
@ 2019-04-25 13:35               ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-25 13:35 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Wed, Apr 24, 2019 at 03:51:32PM +0100, Alex Bennée wrote:
> 
> Dave Martin <Dave.Martin@arm.com> writes:
> 
> > On Thu, Apr 04, 2019 at 10:35:02AM +0200, Andrew Jones wrote:
> >> On Thu, Apr 04, 2019 at 09:10:08AM +0100, Dave Martin wrote:
> >> > On Wed, Apr 03, 2019 at 10:01:45PM +0200, Andrew Jones wrote:
> >> > > On Fri, Mar 29, 2019 at 01:00:38PM +0000, Dave Martin wrote:
> >> > > > In order to give each vcpu its own view of the SVE registers, this
> >> > > > patch adds context storage via a new sve_state pointer in struct
> >> > > > vcpu_arch.  An additional member sve_max_vl is also added for each
> >> > > > vcpu, to determine the maximum vector length visible to the guest
> >> > > > and thus the value to be configured in ZCR_EL2.LEN while the vcpu
> >> > > > is active.  This also determines the layout and size of the storage
> >> > > > in sve_state, which is read and written by the same backend
> >> > > > functions that are used for context-switching the SVE state for
> >> > > > host tasks.
> >> > > >
> >> > > > On SVE-enabled vcpus, SVE access traps are now handled by switching
> >> > > > in the vcpu's SVE context and disabling the trap before returning
> >> > > > to the guest.  On other vcpus, the trap is not handled and an exit
> >> > > > back to the host occurs, where the handle_sve() fallback path
> >> > > > reflects an undefined instruction exception back to the guest,
> >> > > > consistently with the behaviour of non-SVE-capable hardware (as was
> >> > > > done unconditionally prior to this patch).
> >> > > >
> >> > > > No SVE handling is added on non-VHE-only paths, since VHE is an
> >> > > > architectural and Kconfig prerequisite of SVE.
> >> > > >
> >> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> >> > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> >> > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> >> > > >
> >> > > > ---
> >> > > >
> >> > > > Changes since v5:
> >> > > >
> >> > > >  * [Julien Thierry, Julien Grall] Commit message typo fixes
> >> > > >
> >> > > >  * [Mark Rutland] Rename trap_class to hsr_ec, for consistency with
> >> > > >    existing code.
> >> > > >
> >> > > >  * [Mark Rutland] Simplify condition for refusing to handle an
> >> > > >    FPSIMD/SVE trap, using multiple if () statements for clarity.  The
> >> > > >    previous condition was a bit tortuous, and how that the static_key
> >> > > >    checks have been hoisted out, it makes little difference to the
> >> > > >    compiler how we express the condition here.
> >> > > > ---
> >> > > >  arch/arm64/include/asm/kvm_host.h |  6 ++++
> >> > > >  arch/arm64/kvm/fpsimd.c           |  5 +--
> >> > > >  arch/arm64/kvm/hyp/switch.c       | 75 +++++++++++++++++++++++++++++----------
> >> > > >  3 files changed, 66 insertions(+), 20 deletions(-)
> >> > > >
> >> > > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> >> > > > index 22cf484..4fabfd2 100644
> >> > > > --- a/arch/arm64/include/asm/kvm_host.h
> >> > > > +++ b/arch/arm64/include/asm/kvm_host.h
> >> > > > @@ -228,6 +228,8 @@ struct vcpu_reset_state {
> >> > > >
> >> > > >  struct kvm_vcpu_arch {
> >> > > >  	struct kvm_cpu_context ctxt;
> >> > > > +	void *sve_state;
> >> > > > +	unsigned int sve_max_vl;
> >> > > >
> >> > > >  	/* HYP configuration */
> >> > > >  	u64 hcr_el2;
> >> > > > @@ -323,6 +325,10 @@ struct kvm_vcpu_arch {
> >> > > >  	bool sysregs_loaded_on_cpu;
> >> > > >  };
> >> > > >
> >> > > > +/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
> >> > > > +#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
> >> > > > +				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
> >> > >
> >> > > Maybe an inline function instead?
> >> >
> >> > I tried, but that requires the definition of struct kvm_vcpu to be
> >> > visible.  I failed to get that here without circular #include problems,
> >> > and it looked tricky to fix.
> >>
> >> Ah, OK
> >>
> >> >
> >> > Since this is a small bit of code which is unlikely to get used by
> >> > accident, I decided it was OK to keep it as a macro.
> >> >
> >> > Can you see another way around this?
> >>
> >> Nope
> >
> > OK.  If someone eventually solves this, I'd be happy to change to an
> > inline function.
> 
> Is the function intended to be used by more call sites? Currently in the
> tree with this plus the v2 fixups I can only see:
> 
>   arch/arm64/include/asm/kvm_host.h:333:#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
>   arch/arm64/kvm/hyp/switch.c:388:		sve_load_state(vcpu_sve_pffr(vcpu),

Probably not, although it was probably used to save the state back
before things were refactored so that fpsimd_save() in
arch/arm64/kernel/fpsimd.c is used instead of separate code to save the
vcpu state.

The expression is ugly so it's nice to abstract it.  This also keeps
the sve_load_state() call feeling consistent to the equivalent call in
task_fpsimd_load() in arm64/kernel/fpsimd.c

Other than that, there's no underlying reason for having a macro.

Cheers
---Dave

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

* Re: [PATCH v7 13/27] KVM: arm64/sve: Context switch the SVE registers
@ 2019-04-25 13:35               ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-25 13:35 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="UTF-8", Size: 5334 bytes --]

On Wed, Apr 24, 2019 at 03:51:32PM +0100, Alex Bennée wrote:
> 
> Dave Martin <Dave.Martin@arm.com> writes:
> 
> > On Thu, Apr 04, 2019 at 10:35:02AM +0200, Andrew Jones wrote:
> >> On Thu, Apr 04, 2019 at 09:10:08AM +0100, Dave Martin wrote:
> >> > On Wed, Apr 03, 2019 at 10:01:45PM +0200, Andrew Jones wrote:
> >> > > On Fri, Mar 29, 2019 at 01:00:38PM +0000, Dave Martin wrote:
> >> > > > In order to give each vcpu its own view of the SVE registers, this
> >> > > > patch adds context storage via a new sve_state pointer in struct
> >> > > > vcpu_arch.  An additional member sve_max_vl is also added for each
> >> > > > vcpu, to determine the maximum vector length visible to the guest
> >> > > > and thus the value to be configured in ZCR_EL2.LEN while the vcpu
> >> > > > is active.  This also determines the layout and size of the storage
> >> > > > in sve_state, which is read and written by the same backend
> >> > > > functions that are used for context-switching the SVE state for
> >> > > > host tasks.
> >> > > >
> >> > > > On SVE-enabled vcpus, SVE access traps are now handled by switching
> >> > > > in the vcpu's SVE context and disabling the trap before returning
> >> > > > to the guest.  On other vcpus, the trap is not handled and an exit
> >> > > > back to the host occurs, where the handle_sve() fallback path
> >> > > > reflects an undefined instruction exception back to the guest,
> >> > > > consistently with the behaviour of non-SVE-capable hardware (as was
> >> > > > done unconditionally prior to this patch).
> >> > > >
> >> > > > No SVE handling is added on non-VHE-only paths, since VHE is an
> >> > > > architectural and Kconfig prerequisite of SVE.
> >> > > >
> >> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> >> > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> >> > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> >> > > >
> >> > > > ---
> >> > > >
> >> > > > Changes since v5:
> >> > > >
> >> > > >  * [Julien Thierry, Julien Grall] Commit message typo fixes
> >> > > >
> >> > > >  * [Mark Rutland] Rename trap_class to hsr_ec, for consistency with
> >> > > >    existing code.
> >> > > >
> >> > > >  * [Mark Rutland] Simplify condition for refusing to handle an
> >> > > >    FPSIMD/SVE trap, using multiple if () statements for clarity.  The
> >> > > >    previous condition was a bit tortuous, and how that the static_key
> >> > > >    checks have been hoisted out, it makes little difference to the
> >> > > >    compiler how we express the condition here.
> >> > > > ---
> >> > > >  arch/arm64/include/asm/kvm_host.h |  6 ++++
> >> > > >  arch/arm64/kvm/fpsimd.c           |  5 +--
> >> > > >  arch/arm64/kvm/hyp/switch.c       | 75 +++++++++++++++++++++++++++++----------
> >> > > >  3 files changed, 66 insertions(+), 20 deletions(-)
> >> > > >
> >> > > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> >> > > > index 22cf484..4fabfd2 100644
> >> > > > --- a/arch/arm64/include/asm/kvm_host.h
> >> > > > +++ b/arch/arm64/include/asm/kvm_host.h
> >> > > > @@ -228,6 +228,8 @@ struct vcpu_reset_state {
> >> > > >
> >> > > >  struct kvm_vcpu_arch {
> >> > > >  	struct kvm_cpu_context ctxt;
> >> > > > +	void *sve_state;
> >> > > > +	unsigned int sve_max_vl;
> >> > > >
> >> > > >  	/* HYP configuration */
> >> > > >  	u64 hcr_el2;
> >> > > > @@ -323,6 +325,10 @@ struct kvm_vcpu_arch {
> >> > > >  	bool sysregs_loaded_on_cpu;
> >> > > >  };
> >> > > >
> >> > > > +/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
> >> > > > +#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
> >> > > > +				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
> >> > >
> >> > > Maybe an inline function instead?
> >> >
> >> > I tried, but that requires the definition of struct kvm_vcpu to be
> >> > visible.  I failed to get that here without circular #include problems,
> >> > and it looked tricky to fix.
> >>
> >> Ah, OK
> >>
> >> >
> >> > Since this is a small bit of code which is unlikely to get used by
> >> > accident, I decided it was OK to keep it as a macro.
> >> >
> >> > Can you see another way around this?
> >>
> >> Nope
> >
> > OK.  If someone eventually solves this, I'd be happy to change to an
> > inline function.
> 
> Is the function intended to be used by more call sites? Currently in the
> tree with this plus the v2 fixups I can only see:
> 
>   arch/arm64/include/asm/kvm_host.h:333:#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
>   arch/arm64/kvm/hyp/switch.c:388:		sve_load_state(vcpu_sve_pffr(vcpu),

Probably not, although it was probably used to save the state back
before things were refactored so that fpsimd_save() in
arch/arm64/kernel/fpsimd.c is used instead of separate code to save the
vcpu state.

The expression is ugly so it's nice to abstract it.  This also keeps
the sve_load_state() call feeling consistent to the equivalent call in
task_fpsimd_load() in arm64/kernel/fpsimd.c

Other than that, there's no underlying reason for having a macro.

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

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

* Re: [PATCH v7 13/27] KVM: arm64/sve: Context switch the SVE registers
@ 2019-04-25 13:35               ` Dave Martin
  0 siblings, 0 replies; 224+ messages in thread
From: Dave Martin @ 2019-04-25 13:35 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Okamoto Takayuki, Christoffer Dall, Ard Biesheuvel, Marc Zyngier,
	Catalin Marinas, Will Deacon, Zhang Lei, Julien Grall, kvmarm,
	linux-arm-kernel

On Wed, Apr 24, 2019 at 03:51:32PM +0100, Alex Bennée wrote:
> 
> Dave Martin <Dave.Martin@arm.com> writes:
> 
> > On Thu, Apr 04, 2019 at 10:35:02AM +0200, Andrew Jones wrote:
> >> On Thu, Apr 04, 2019 at 09:10:08AM +0100, Dave Martin wrote:
> >> > On Wed, Apr 03, 2019 at 10:01:45PM +0200, Andrew Jones wrote:
> >> > > On Fri, Mar 29, 2019 at 01:00:38PM +0000, Dave Martin wrote:
> >> > > > In order to give each vcpu its own view of the SVE registers, this
> >> > > > patch adds context storage via a new sve_state pointer in struct
> >> > > > vcpu_arch.  An additional member sve_max_vl is also added for each
> >> > > > vcpu, to determine the maximum vector length visible to the guest
> >> > > > and thus the value to be configured in ZCR_EL2.LEN while the vcpu
> >> > > > is active.  This also determines the layout and size of the storage
> >> > > > in sve_state, which is read and written by the same backend
> >> > > > functions that are used for context-switching the SVE state for
> >> > > > host tasks.
> >> > > >
> >> > > > On SVE-enabled vcpus, SVE access traps are now handled by switching
> >> > > > in the vcpu's SVE context and disabling the trap before returning
> >> > > > to the guest.  On other vcpus, the trap is not handled and an exit
> >> > > > back to the host occurs, where the handle_sve() fallback path
> >> > > > reflects an undefined instruction exception back to the guest,
> >> > > > consistently with the behaviour of non-SVE-capable hardware (as was
> >> > > > done unconditionally prior to this patch).
> >> > > >
> >> > > > No SVE handling is added on non-VHE-only paths, since VHE is an
> >> > > > architectural and Kconfig prerequisite of SVE.
> >> > > >
> >> > > > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> >> > > > Reviewed-by: Julien Thierry <julien.thierry@arm.com>
> >> > > > Tested-by: zhang.lei <zhang.lei@jp.fujitsu.com>
> >> > > >
> >> > > > ---
> >> > > >
> >> > > > Changes since v5:
> >> > > >
> >> > > >  * [Julien Thierry, Julien Grall] Commit message typo fixes
> >> > > >
> >> > > >  * [Mark Rutland] Rename trap_class to hsr_ec, for consistency with
> >> > > >    existing code.
> >> > > >
> >> > > >  * [Mark Rutland] Simplify condition for refusing to handle an
> >> > > >    FPSIMD/SVE trap, using multiple if () statements for clarity.  The
> >> > > >    previous condition was a bit tortuous, and how that the static_key
> >> > > >    checks have been hoisted out, it makes little difference to the
> >> > > >    compiler how we express the condition here.
> >> > > > ---
> >> > > >  arch/arm64/include/asm/kvm_host.h |  6 ++++
> >> > > >  arch/arm64/kvm/fpsimd.c           |  5 +--
> >> > > >  arch/arm64/kvm/hyp/switch.c       | 75 +++++++++++++++++++++++++++++----------
> >> > > >  3 files changed, 66 insertions(+), 20 deletions(-)
> >> > > >
> >> > > > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> >> > > > index 22cf484..4fabfd2 100644
> >> > > > --- a/arch/arm64/include/asm/kvm_host.h
> >> > > > +++ b/arch/arm64/include/asm/kvm_host.h
> >> > > > @@ -228,6 +228,8 @@ struct vcpu_reset_state {
> >> > > >
> >> > > >  struct kvm_vcpu_arch {
> >> > > >  	struct kvm_cpu_context ctxt;
> >> > > > +	void *sve_state;
> >> > > > +	unsigned int sve_max_vl;
> >> > > >
> >> > > >  	/* HYP configuration */
> >> > > >  	u64 hcr_el2;
> >> > > > @@ -323,6 +325,10 @@ struct kvm_vcpu_arch {
> >> > > >  	bool sysregs_loaded_on_cpu;
> >> > > >  };
> >> > > >
> >> > > > +/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
> >> > > > +#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
> >> > > > +				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
> >> > >
> >> > > Maybe an inline function instead?
> >> >
> >> > I tried, but that requires the definition of struct kvm_vcpu to be
> >> > visible.  I failed to get that here without circular #include problems,
> >> > and it looked tricky to fix.
> >>
> >> Ah, OK
> >>
> >> >
> >> > Since this is a small bit of code which is unlikely to get used by
> >> > accident, I decided it was OK to keep it as a macro.
> >> >
> >> > Can you see another way around this?
> >>
> >> Nope
> >
> > OK.  If someone eventually solves this, I'd be happy to change to an
> > inline function.
> 
> Is the function intended to be used by more call sites? Currently in the
> tree with this plus the v2 fixups I can only see:
> 
>   arch/arm64/include/asm/kvm_host.h:333:#define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
>   arch/arm64/kvm/hyp/switch.c:388:		sve_load_state(vcpu_sve_pffr(vcpu),

Probably not, although it was probably used to save the state back
before things were refactored so that fpsimd_save() in
arch/arm64/kernel/fpsimd.c is used instead of separate code to save the
vcpu state.

The expression is ugly so it's nice to abstract it.  This also keeps
the sve_load_state() call feeling consistent to the equivalent call in
task_fpsimd_load() in arm64/kernel/fpsimd.c

Other than that, there's no underlying reason for having a macro.

Cheers
---Dave

_______________________________________________
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] 224+ messages in thread

end of thread, other threads:[~2019-04-25 13:35 UTC | newest]

Thread overview: 224+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-29 13:00 [PATCH v7 00/27] KVM: arm64: SVE guest support Dave Martin
2019-03-29 13:00 ` Dave Martin
2019-03-29 13:00 ` [PATCH v7 01/27] KVM: Documentation: Document arm64 core registers in detail Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-24  9:25   ` Alex Bennée
2019-04-24  9:25     ` Alex Bennée
2019-03-29 13:00 ` [PATCH v7 02/27] arm64: fpsimd: Always set TIF_FOREIGN_FPSTATE on task state flush Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-03-29 13:00 ` [PATCH v7 03/27] KVM: arm64: Delete orphaned declaration for __fpsimd_enabled() Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-03-29 13:00 ` [PATCH v7 04/27] KVM: arm64: Refactor kvm_arm_num_regs() for easier maintenance Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-03-29 13:00 ` [PATCH v7 05/27] KVM: arm64: Add missing #includes to kvm_host.h Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-03-29 13:00 ` [PATCH v7 06/27] arm64/sve: Clarify role of the VQ map maintenance functions Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-04 21:21   ` Andrew Jones
2019-04-04 21:21     ` Andrew Jones
2019-03-29 13:00 ` [PATCH v7 07/27] arm64/sve: Check SVE virtualisability Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-04 21:21   ` Andrew Jones
2019-04-04 21:21     ` Andrew Jones
2019-04-05  9:35     ` Dave Martin
2019-04-05  9:35       ` Dave Martin
2019-03-29 13:00 ` [PATCH v7 08/27] arm64/sve: Enable SVE state tracking for non-task contexts Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-03-29 13:00 ` [PATCH v7 09/27] KVM: arm64: Add a vcpu flag to control SVE visibility for the guest Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-03 19:14   ` Andrew Jones
2019-04-03 19:14     ` Andrew Jones
2019-04-04  3:17     ` Marc Zyngier
2019-04-04  3:17       ` Marc Zyngier
2019-04-04  7:53       ` Dave Martin
2019-04-04  7:53         ` Dave Martin
2019-04-04 21:15   ` Andrew Jones
2019-04-04 21:15     ` Andrew Jones
2019-03-29 13:00 ` [PATCH v7 10/27] KVM: arm64: Propagate vcpu into read_id_reg() Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-04 21:15   ` Andrew Jones
2019-04-04 21:15     ` Andrew Jones
2019-03-29 13:00 ` [PATCH v7 11/27] KVM: arm64: Support runtime sysreg visibility filtering Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-03 19:17   ` Andrew Jones
2019-04-03 19:17     ` Andrew Jones
2019-04-24  9:39   ` Alex Bennée
2019-04-24  9:39     ` Alex Bennée
2019-04-24 13:47     ` Dave Martin
2019-04-24 13:47       ` Dave Martin
2019-04-24 13:47       ` Dave Martin
2019-03-29 13:00 ` [PATCH v7 12/27] KVM: arm64/sve: System register context switch and access support Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-03 19:39   ` Andrew Jones
2019-04-03 19:39     ` Andrew Jones
2019-04-04  8:06     ` Dave Martin
2019-04-04  8:06       ` Dave Martin
2019-04-04  8:32       ` Andrew Jones
2019-04-04  8:32         ` Andrew Jones
2019-04-04  8:47         ` Dave Martin
2019-04-04  8:47           ` Dave Martin
2019-04-04  8:59   ` Andrew Jones
2019-04-04  8:59     ` Andrew Jones
2019-04-24 15:21   ` Alex Bennée
2019-04-24 15:21     ` Alex Bennée
2019-04-25 13:28     ` Dave Martin
2019-04-25 13:28       ` Dave Martin
2019-04-25 13:28       ` Dave Martin
2019-03-29 13:00 ` [PATCH v7 13/27] KVM: arm64/sve: Context switch the SVE registers Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-03 20:01   ` Andrew Jones
2019-04-03 20:01     ` Andrew Jones
2019-04-04  8:10     ` Dave Martin
2019-04-04  8:10       ` Dave Martin
2019-04-04  8:35       ` Andrew Jones
2019-04-04  8:35         ` Andrew Jones
2019-04-04  8:36         ` Dave Martin
2019-04-04  8:36           ` Dave Martin
2019-04-24 14:51           ` Alex Bennée
2019-04-24 14:51             ` Alex Bennée
2019-04-25 13:35             ` Dave Martin
2019-04-25 13:35               ` Dave Martin
2019-04-25 13:35               ` Dave Martin
2019-03-29 13:00 ` [PATCH v7 14/27] KVM: Allow 2048-bit register access via ioctl interface Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-04 21:11   ` Andrew Jones
2019-04-04 21:11     ` Andrew Jones
2019-03-29 13:00 ` [PATCH v7 15/27] KVM: arm64: Add missing #include of <linux/string.h> in guest.c Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-03-29 13:00 ` [PATCH v7 16/27] KVM: arm64: Factor out core register ID enumeration Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-02  2:41   ` Marc Zyngier
2019-04-02  2:41     ` Marc Zyngier
2019-04-02  8:59     ` Dave Martin
2019-04-02  8:59       ` Dave Martin
2019-04-02  9:32       ` Marc Zyngier
2019-04-02  9:32         ` Marc Zyngier
2019-04-02  9:54         ` Dave P Martin
2019-04-02  9:54           ` Dave P Martin
2019-03-29 13:00 ` [PATCH v7 17/27] KVM: arm64: Reject ioctl access to FPSIMD V-regs on SVE vcpus Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-03 20:15   ` Andrew Jones
2019-04-03 20:15     ` Andrew Jones
2019-04-24 13:45   ` Alex Bennée
2019-04-24 13:45     ` Alex Bennée
2019-03-29 13:00 ` [PATCH v7 18/27] KVM: arm64/sve: Add SVE support to register access ioctl interface Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-04 13:57   ` Andrew Jones
2019-04-04 13:57     ` Andrew Jones
2019-04-04 14:50     ` Dave Martin
2019-04-04 14:50       ` Dave Martin
2019-04-04 16:25       ` Andrew Jones
2019-04-04 16:25         ` Andrew Jones
2019-04-04 16:56         ` Dave Martin
2019-04-04 16:56           ` Dave Martin
2019-03-29 13:00 ` [PATCH v7 19/27] KVM: arm64: Enumerate SVE register indices for KVM_GET_REG_LIST Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-04 14:08   ` Andrew Jones
2019-04-04 14:08     ` Andrew Jones
2019-04-05  9:35     ` Dave Martin
2019-04-05  9:35       ` Dave Martin
2019-04-05  9:45       ` Andrew Jones
2019-04-05  9:45         ` Andrew Jones
2019-04-05 11:11         ` Dave Martin
2019-04-05 11:11           ` Dave Martin
2019-03-29 13:00 ` [PATCH v7 20/27] arm64/sve: In-kernel vector length availability query interface Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-04 14:20   ` Andrew Jones
2019-04-04 14:20     ` Andrew Jones
2019-04-05  9:35     ` Dave Martin
2019-04-05  9:35       ` Dave Martin
2019-04-05  9:54       ` Andrew Jones
2019-04-05  9:54         ` Andrew Jones
2019-04-05 11:13         ` Dave Martin
2019-04-05 11:13           ` Dave Martin
2019-03-29 13:00 ` [PATCH v7 21/27] KVM: arm/arm64: Add hook for arch-specific KVM initialisation Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-04 14:25   ` Andrew Jones
2019-04-04 14:25     ` Andrew Jones
2019-04-04 14:53     ` Dave Martin
2019-04-04 14:53       ` Dave Martin
2019-04-04 16:33       ` Andrew Jones
2019-04-04 16:33         ` Andrew Jones
2019-04-05  9:36         ` Dave Martin
2019-04-05  9:36           ` Dave Martin
2019-04-05 10:40           ` Andrew Jones
2019-04-05 10:40             ` Andrew Jones
2019-04-05 11:14             ` Dave Martin
2019-04-05 11:14               ` Dave Martin
2019-03-29 13:00 ` [PATCH v7 22/27] KVM: arm/arm64: Add KVM_ARM_VCPU_FINALIZE ioctl Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-04 15:07   ` Andrew Jones
2019-04-04 15:07     ` Andrew Jones
2019-04-04 16:47     ` Dave Martin
2019-04-04 16:47       ` Dave Martin
2019-03-29 13:00 ` [PATCH v7 23/27] KVM: arm64/sve: Add pseudo-register for the guest's vector lengths Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-04 20:18   ` Andrew Jones
2019-04-04 20:18     ` Andrew Jones
2019-04-05  9:36     ` Dave Martin
2019-04-05  9:36       ` Dave Martin
2019-04-05 10:14       ` Andrew Jones
2019-04-05 10:14         ` Andrew Jones
2019-04-05 12:54         ` Dave Martin
2019-04-05 12:54           ` Dave Martin
2019-04-05 15:33           ` Andrew Jones
2019-04-05 15:33             ` Andrew Jones
2019-04-10 12:42             ` Dave Martin
2019-04-10 12:42               ` Dave Martin
2019-04-10 12:42               ` Dave Martin
2019-04-04 20:31   ` Andrew Jones
2019-04-04 20:31     ` Andrew Jones
2019-04-05  9:36     ` Dave Martin
2019-04-05  9:36       ` Dave Martin
2019-04-05 10:22       ` Andrew Jones
2019-04-05 10:22         ` Andrew Jones
2019-04-05 14:06         ` Dave Martin
2019-04-05 14:06           ` Dave Martin
2019-04-05 15:41           ` Andrew Jones
2019-04-05 15:41             ` Andrew Jones
2019-04-10 12:35             ` Dave Martin
2019-04-10 12:35               ` Dave Martin
2019-04-10 12:35               ` Dave Martin
2019-03-29 13:00 ` [PATCH v7 24/27] KVM: arm64/sve: Allow userspace to enable SVE for vcpus Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-04 20:36   ` Andrew Jones
2019-04-04 20:36     ` Andrew Jones
2019-03-29 13:00 ` [PATCH v7 25/27] KVM: arm64: Add a capability to advertise SVE support Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-04 20:39   ` Andrew Jones
2019-04-04 20:39     ` Andrew Jones
2019-03-29 13:00 ` [PATCH v7 26/27] KVM: Document errors for KVM_GET_ONE_REG and KVM_SET_ONE_REG Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-03 20:27   ` Andrew Jones
2019-04-03 20:27     ` Andrew Jones
2019-04-04  8:35     ` Dave Martin
2019-04-04  8:35       ` Dave Martin
2019-04-04  9:34       ` Andrew Jones
2019-04-04  9:34         ` Andrew Jones
2019-04-04  9:38         ` Dave P Martin
2019-04-04  9:38           ` Dave P Martin
2019-04-04  9:45           ` Andrew Jones
2019-04-04  9:45             ` Andrew Jones
2019-03-29 13:00 ` [PATCH v7 27/27] KVM: arm64/sve: Document KVM API extensions for SVE Dave Martin
2019-03-29 13:00   ` Dave Martin
2019-04-04 21:09   ` Andrew Jones
2019-04-04 21:09     ` Andrew Jones
2019-04-05  9:36     ` Dave Martin
2019-04-05  9:36       ` Dave Martin
2019-04-05 10:39       ` Andrew Jones
2019-04-05 10:39         ` Andrew Jones
2019-04-05 13:00         ` Dave Martin
2019-04-05 13:00           ` Dave Martin
2019-04-05 15:38           ` Andrew Jones
2019-04-05 15:38             ` Andrew Jones
2019-04-10 12:34             ` Dave Martin
2019-04-10 12:34               ` Dave Martin
2019-04-10 12:34               ` Dave Martin
2019-03-29 14:56 ` [PATCH v7 00/27] KVM: arm64: SVE guest support Marc Zyngier
2019-03-29 14:56   ` Marc Zyngier
2019-03-29 15:06   ` Dave Martin
2019-03-29 15:06     ` Dave Martin
2019-04-05 16:41 ` Dave Martin
2019-04-05 16:41   ` Dave Martin
2019-04-25 10:33 ` Alex Bennée
2019-04-25 10:33   ` Alex Bennée

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.