From: Dave.Martin@arm.com (Dave Martin)
To: linux-arm-kernel@lists.infradead.org
Subject: [RFC PATCH v2 15/23] KVM: arm64/sve: Add SVE support to register access ioctl interface
Date: Fri, 28 Sep 2018 14:39:19 +0100 [thread overview]
Message-ID: <1538141967-15375-16-git-send-email-Dave.Martin@arm.com> (raw)
In-Reply-To: <1538141967-15375-1-git-send-email-Dave.Martin@arm.com>
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 divided up into slices as noted above: the i
parameter denotes the slice index.
For simplicity, bits or slices that exceed the maximum vector
length supported for the vcpu are ignored for KVM_SET_ONE_REG, and
read as zero for KVM_GET_ONE_REG.
For the current architecture, only slice i = 0 is significant. The
interface design allows i to increase to up to 31 in the future if
required by future architectural amendments.
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. In all cases, surplus slices are not enumerated by
KVM_GET_REG_LIST.
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 emluation
in the kernel.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
Changes since RFCv1:
* Refactored to remove emulation of FPSIMD registers with the SVE
register view and vice-versa. This simplifies the code a fair bit.
* Fixed a couple of range errors.
* Inlined various trivial helpers that now have only one call site.
* Use KVM_REG_SIZE() as a symbolic way of getting SVE register slice
sizes.
---
arch/arm64/include/uapi/asm/kvm.h | 10 +++
arch/arm64/kvm/guest.c | 147 ++++++++++++++++++++++++++++++++++----
2 files changed, 145 insertions(+), 12 deletions(-)
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 97c3478..1ff68fa 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -226,6 +226,16 @@ 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)
+#define KVM_REG_ARM64_SVE_ZREG(n, i) (KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
+ KVM_REG_SIZE_U2048 | \
+ ((n) << 5) | (i))
+#define KVM_REG_ARM64_SVE_PREG(n, i) (KVM_REG_ARM64 | KVM_REG_ARM64_SVE | \
+ KVM_REG_SIZE_U256 | \
+ ((n) << 5) | (i) | 0x400)
+#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 953a5c9..320db0f 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -21,6 +21,7 @@
#include <linux/errno.h>
#include <linux/err.h>
+#include <linux/kernel.h>
#include <linux/kvm_host.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
@@ -28,9 +29,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"
@@ -57,6 +61,12 @@ static u64 core_reg_offset_from_id(u64 id)
return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
}
+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 int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
{
/*
@@ -76,6 +86,13 @@ 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;
+ /*
+ * For SVE-enabled vcpus, access to the FPSIMD V-regs must use
+ * KVM_REG_ARM64_SVE instead:
+ */
+ if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(off))
+ return -EINVAL;
+
if (copy_to_user(uaddr, ((u32 *)regs) + off, KVM_REG_SIZE(reg->id)))
return -EFAULT;
@@ -98,6 +115,13 @@ 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;
+ /*
+ * For SVE-enabled vcpus, access to the FPSIMD V-regs must use
+ * KVM_REG_ARM64_SVE instead:
+ */
+ if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(off))
+ return -EINVAL;
+
if (KVM_REG_SIZE(reg->id) > sizeof(tmp))
return -EINVAL;
@@ -130,6 +154,107 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
return err;
}
+struct kreg_region {
+ char *kptr;
+ size_t size;
+ size_t zeropad;
+};
+
+#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_BITS - 1, 0) << SVE_REG_SLICE_SHIFT)
+#define SVE_REG_ID_MASK \
+ (GENMASK(SVE_REG_ID_BITS - 1, 0) << SVE_REG_ID_SHIFT)
+
+#define SVE_NUM_SLICES (1 << SVE_REG_SLICE_BITS)
+
+static int sve_reg_region(struct kreg_region *b,
+ const struct kvm_vcpu *vcpu,
+ const struct kvm_one_reg *reg)
+{
+ const unsigned int vl = vcpu->arch.sve_max_vl;
+ const unsigned int vq = sve_vq_from_vl(vl);
+
+ const unsigned int reg_num =
+ (reg->id & SVE_REG_ID_MASK) >> SVE_REG_ID_SHIFT;
+ const unsigned int slice_num =
+ (reg->id & SVE_REG_SLICE_MASK) >> SVE_REG_SLICE_SHIFT;
+
+ unsigned int slice_size, offset, limit;
+
+ if (reg->id >= KVM_REG_ARM64_SVE_ZREG(0, 0) &&
+ reg->id <= KVM_REG_ARM64_SVE_ZREG(SVE_NUM_ZREGS - 1,
+ SVE_NUM_SLICES - 1)) {
+ slice_size = KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0));
+
+ /* Compute start and end of the register: */
+ offset = SVE_SIG_ZREG_OFFSET(vq, reg_num) - SVE_SIG_REGS_OFFSET;
+ limit = offset + SVE_SIG_ZREG_SIZE(vq);
+
+ offset += slice_size * slice_num; /* start of requested slice */
+
+ } else if (reg->id >= KVM_REG_ARM64_SVE_PREG(0, 0) &&
+ reg->id <= KVM_REG_ARM64_SVE_FFR(SVE_NUM_SLICES - 1)) {
+ /* (FFR is P16 for our purposes) */
+
+ slice_size = KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0));
+
+ /* Compute start and end of the register: */
+ offset = SVE_SIG_PREG_OFFSET(vq, reg_num) - SVE_SIG_REGS_OFFSET;
+ limit = offset + SVE_SIG_PREG_SIZE(vq);
+
+ offset += slice_size * slice_num; /* start of requested slice */
+
+ } else {
+ return -ENOENT;
+ }
+
+ b->kptr = (char *)vcpu->arch.sve_state + offset;
+
+ /*
+ * If the slice starts after the end of the reg, just pad.
+ * Otherwise, copy as much as possible up to slice_size and pad
+ * the remainder:
+ */
+ b->size = offset >= limit ? 0 : min(limit - offset, slice_size);
+ b->zeropad = slice_size - b->size;
+
+ return 0;
+}
+
+static int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ struct kreg_region kreg;
+ char __user *uptr = (char __user *)reg->addr;
+
+ if (!vcpu_has_sve(vcpu) || sve_reg_region(&kreg, vcpu, reg))
+ return -ENOENT;
+
+ if (copy_to_user(uptr, kreg.kptr, kreg.size) ||
+ clear_user(uptr + kreg.size, kreg.zeropad))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ struct kreg_region kreg;
+ char __user *uptr = (char __user *)reg->addr;
+
+ if (!vcpu_has_sve(vcpu) || sve_reg_region(&kreg, vcpu, reg))
+ return -ENOENT;
+
+ if (copy_from_user(kreg.kptr, uptr, kreg.size))
+ return -EFAULT;
+
+ return 0;
+}
+
int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
{
return -EINVAL;
@@ -251,12 +376,11 @@ 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);
+ }
if (is_timer_reg(reg->id))
return get_timer_reg(vcpu, reg);
@@ -270,12 +394,11 @@ 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);
+ }
if (is_timer_reg(reg->id))
return set_timer_reg(vcpu, reg);
--
2.1.4
next prev parent reply other threads:[~2018-09-28 13:39 UTC|newest]
Thread overview: 77+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-09-28 13:39 [RFC PATCH v2 00/23] KVM: arm64: Initial support for SVE guests Dave Martin
2018-09-28 13:39 ` [RFC PATCH v2 01/23] arm64: fpsimd: Always set TIF_FOREIGN_FPSTATE on task state flush Dave Martin
2018-09-28 13:39 ` [RFC PATCH v2 02/23] KVM: arm64: Delete orphaned declaration for __fpsimd_enabled() Dave Martin
2018-09-28 13:39 ` [RFC PATCH v2 03/23] KVM: arm64: Refactor kvm_arm_num_regs() for easier maintenance Dave Martin
2018-09-28 13:39 ` [RFC PATCH v2 04/23] KVM: arm64: Add missing #include of <linux/bitmap.h> to kvm_host.h Dave Martin
2018-09-28 13:39 ` [RFC PATCH v2 05/23] KVM: arm: Add arch vcpu uninit hook Dave Martin
2018-11-02 8:05 ` Christoffer Dall
2018-11-15 16:40 ` Dave Martin
2018-11-20 10:56 ` Christoffer Dall
2018-09-28 13:39 ` [RFC PATCH v2 06/23] arm64/sve: Check SVE virtualisability Dave Martin
2018-11-15 15:39 ` Alex Bennée
2018-11-15 17:09 ` Dave Martin
2018-11-16 12:32 ` Alex Bennée
2018-11-16 15:09 ` Dave Martin
2018-09-28 13:39 ` [RFC PATCH v2 07/23] arm64/sve: Enable SVE state tracking for non-task contexts Dave Martin
2018-09-28 13:39 ` [RFC PATCH v2 08/23] KVM: arm64: Add a vcpu flag to control SVE visibility for the guest Dave Martin
2018-11-15 15:44 ` Alex Bennée
2018-09-28 13:39 ` [RFC PATCH v2 09/23] KVM: arm64: Propagate vcpu into read_id_reg() Dave Martin
2018-11-15 15:56 ` Alex Bennée
2018-09-28 13:39 ` [RFC PATCH v2 10/23] KVM: arm64: Extend reset_unknown() to handle mixed RES0/UNKNOWN registers Dave Martin
2018-11-02 8:11 ` Christoffer Dall
2018-11-15 17:11 ` Dave Martin
2018-09-28 13:39 ` [RFC PATCH v2 11/23] KVM: arm64: Support runtime sysreg filtering for KVM_GET_REG_LIST Dave Martin
2018-11-02 8:16 ` Christoffer Dall
2018-11-15 17:27 ` Dave Martin
2018-11-22 10:53 ` Christoffer Dall
2018-11-22 11:13 ` Peter Maydell
2018-11-22 12:34 ` Christoffer Dall
2018-11-22 12:59 ` Peter Maydell
2018-11-22 11:27 ` Alex Bennée
2018-11-22 12:32 ` Dave P Martin
2018-11-22 13:07 ` Christoffer Dall
2018-11-23 17:42 ` Dave Martin
2018-09-28 13:39 ` [RFC PATCH v2 12/23] KVM: arm64/sve: System register context switch and access support Dave Martin
2018-11-15 16:37 ` Alex Bennée
2018-11-15 17:59 ` Dave Martin
2018-09-28 13:39 ` [RFC PATCH v2 13/23] KVM: arm64/sve: Context switch the SVE registers Dave Martin
2018-11-19 16:36 ` Alex Bennée
2018-11-19 17:03 ` Dave Martin
2018-11-20 12:25 ` Alex Bennée
2018-11-20 14:17 ` Dave Martin
2018-11-20 15:30 ` Alex Bennée
2018-11-20 17:18 ` Dave Martin
2018-09-28 13:39 ` [RFC PATCH v2 14/23] KVM: Allow 2048-bit register access via ioctl interface Dave Martin
2018-11-19 16:48 ` Alex Bennée
2018-11-19 17:07 ` Dave Martin
2018-11-20 11:20 ` Alex Bennée
2018-09-28 13:39 ` Dave Martin [this message]
2018-11-21 15:20 ` [RFC PATCH v2 15/23] KVM: arm64/sve: Add SVE support to register access " Alex Bennée
2018-11-21 18:05 ` Dave Martin
2018-09-28 13:39 ` [RFC PATCH v2 16/23] KVM: arm64: Enumerate SVE register indices for KVM_GET_REG_LIST Dave Martin
2018-11-21 16:09 ` Alex Bennée
2018-11-21 16:32 ` Dave Martin
2018-11-21 16:49 ` Alex Bennée
2018-11-21 17:46 ` Dave Martin
2018-09-28 13:39 ` [RFC PATCH v2 17/23] arm64/sve: In-kernel vector length availability query interface Dave Martin
2018-11-21 16:16 ` Alex Bennée
2018-11-21 16:35 ` Dave Martin
2018-11-21 16:46 ` Alex Bennée
2018-09-28 13:39 ` [RFC PATCH v2 18/23] KVM: arm64: Add arch vcpu ioctl hook Dave Martin
2018-11-02 8:30 ` Christoffer Dall
2018-09-28 13:39 ` [RFC PATCH v2 19/23] KVM: arm64/sve: Report and enable SVE API extensions for userspace Dave Martin
2018-11-22 15:23 ` Alex Bennée
2018-12-05 18:22 ` Dave Martin
2018-09-28 13:39 ` [RFC PATCH v2 20/23] KVM: arm64: Add arch vm ioctl hook Dave Martin
2018-11-02 8:32 ` Christoffer Dall
2018-11-15 18:04 ` Dave Martin
2018-11-20 10:58 ` Christoffer Dall
2018-11-20 14:19 ` Dave Martin
2018-09-28 13:39 ` [RFC PATCH v2 21/23] KVM: arm64/sve: allow KVM_ARM_SVE_CONFIG_QUERY on vm fd Dave Martin
2018-11-22 15:29 ` Alex Bennée
2018-09-28 13:39 ` [RFC PATCH v2 22/23] KVM: Documentation: Document arm64 core registers in detail Dave Martin
2018-09-28 13:39 ` [RFC PATCH v2 23/23] KVM: arm64/sve: Document KVM API extensions for SVE Dave Martin
2018-11-22 15:31 ` Alex Bennée
2018-12-05 17:59 ` Dave Martin
2018-11-22 15:34 ` [RFC PATCH v2 00/23] KVM: arm64: Initial support for SVE guests Alex Bennée
2018-12-04 15:50 ` Dave Martin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1538141967-15375-16-git-send-email-Dave.Martin@arm.com \
--to=dave.martin@arm.com \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).